Dockerfile với Ubuntu: Hướng dẫn toàn diện từ cơ bản đến nâng cao để xây dựng Docker Images

.## 1. Giới thiệu

目次

Docker và Dockerfile là gì?

Trong những năm gần đây, Docker đã nhanh chóng trở nên phổ biến như một cách hiệu quả để tối ưu hoá môi trường phát triển và triển khai ứng dụng. Docker đóng gói các ứng dụng và các phụ thuộc của chúng vào một đơn vị duy nhất gọi là “container”, cho phép chúng chạy một cách nhất quán trên các môi trường khác nhau.

Để xây dựng các container Docker này, cần một bản thiết kế gọi là Dockerfile. Dockerfile là một tệp văn bản định nghĩa hình ảnh hệ điều hành cơ sở, phần mềm được cài đặt, các biến môi trường và các chi tiết cấu hình khác. Các nhà phát triển có thể sử dụng nó để tự động xây dựng các môi trường tùy chỉnh.

Tại sao lại sử dụng Ubuntu làm Image cơ sở?

Khi tạo Dockerfile, bước đầu tiên là chọn một image hệ điều hành cơ sở. Trong số nhiều lựa chọn có sẵn, Ubuntu là một trong những hệ điều hành phổ biến nhất. Ubuntu là một bản phân phối Linux dựa trên Debian, nổi tiếng với tính dễ sử dụng và khả năng thiết lập môi trường linh hoạt, được hỗ trợ bởi một hệ sinh thái gói phần mềm rộng lớn.

Dockerfile dựa trên Ubuntu mang lại một số ưu điểm:

  • Tài liệu chính thức và cộng đồng phong phú, giúp giảm độ khó học
  • Cài đặt gói và công cụ dễ dàng bằng APT
  • Các image nhẹ và tối thiểu được cung cấp chính thức (ví dụ ubuntu:20.04ubuntu:24.04 )

Mục đích của bài viết và đối tượng độc giả

Bài viết này tập trung vào từ khóa “Dockerfile Ubuntu” và giải thích cách tạo Dockerfile dựa trên Ubuntu một cách dễ hiểu cho người mới bắt đầu.

Nó bao gồm mọi thứ từ cấu trúc cơ bản của Dockerfile đến hướng dẫn chi tiết từng bước để xây dựng môi trường Ubuntu, ví dụ về thiết lập môi trường ứng dụng như Python, và các lỗi thường gặp cùng giải pháp.

Bài viết này được khuyến nghị cho:

  • Những người muốn xây dựng môi trường bằng Dockerfile lần đầu tiên
  • Các nhà phát triển muốn tạo môi trường phát triển có thể tái tạo trên Ubuntu
  • Bất kỳ ai muốn nâng cao hiểu biết, bao gồm các kỹ thuật khắc phục sự cố

2. Cấu trúc cơ bản của Dockerfile

Dockerfile là gì và vai trò của nó?

Dockerfile giống như một công thức để tạo ra các image Docker. Nó định nghĩa hệ điều hành cơ sở nào sẽ dùng, phần mềm nào sẽ cài đặt, và cách cấu hình môi trường.

Bằng cách chạy lệnh docker build dựa trên tệp này, bạn có thể dễ dàng tạo ra các môi trường phát triển và chạy lại được một cách nhất quán.

Lợi ích của việc sử dụng Dockerfile:

  • Tự động thiết lập môi trường (không cần lặp lại thủ công)
  • Loại bỏ sự không đồng nhất môi trường trong phát triển nhóm
  • Dễ dàng tích hợp vào các pipeline CI/CD

Các lệnh Dockerfile thường dùng

Dockerfile bao gồm nhiều lệnh (directive). Dưới đây là một số lệnh thường dùng nhất. Khi kết hợp chúng một cách hợp lý, bạn có thể xây dựng Dockerfile dựa trên Ubuntu.

InstructionDescription
FROMSpecifies the base Docker image (e.g., FROM ubuntu:24.04)
RUNExecutes shell commands, typically for installing packages
COPYCopies local files into the image
ADDSimilar to COPY, but also supports URLs and archive extraction
WORKDIRSets the working directory
ENVDefines environment variables
CMDDefines the default command executed at container startup (can be overridden)
ENTRYPOINTDefines a command that is always executed at container startup

Ví dụ Dockerfile tối thiểu dựa trên Ubuntu

Dưới đây là một ví dụ rất cơ bản về Dockerfile sử dụng Ubuntu làm image cơ sở.

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y \
    curl \
    vim

CMD ["/bin/bash"]

Dockerfile này sử dụng Ubuntu 24.04 làm image cơ sở, cài đặt các tiện ích curlvim, và khởi chạy một shell Bash khi container bắt đầu.

Lựa chọn Tag Ubuntu phù hợp

Các image Ubuntu Docker được đăng tải trên kho chính thức Docker Hub. Khi chỉ định ubuntu:latest sẽ sử dụng phiên bản mới nhất, khuyến nghị nên gắn cố định một phiên bản cụ thể.

Ví dụ:

  • ubuntu:22.04 (LTS: Hỗ trợ dài hạn, tập trung vào độ ổn định)
  • ubuntu:24.04 (LTS mới nhất, tập trung vào các tính năng mới)

Chọn phiên bản dựa trên việc bạn ưu tiên độ ổn định hay các tính năng mới.

3. Thực hành: Tạo Dockerfile dựa trên Ubuntu

Cài đặt các gói cần thiết trong môi trường Ubuntu

Khi xây dựng môi trường Ubuntu bằng Dockerfile, thường cần cài đặt các gói bổ sung. Ví dụ, các tiện ích sau thường được sử dụng khi thiết lập môi trường phát triển:

  • curl : Dùng để tải tệp và kiểm thử API
  • vim : Trình soạn thảo văn bản nhẹ
  • git : Hệ thống quản lý phiên bản
  • build-essential : Các công cụ thiết yếu để biên dịch chương trình C/C++

Để cài đặt các gói này trong Dockerfile, sử dụng lệnh RUN.

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y \
    curl \
    vim \
    git \
    build-essential

Bằng cách chạy apt-get update trước, bạn đảm bảo rằng danh sách gói mới nhất được lấy về trước khi cài đặt.

Cấu hình Cài đặt Không Tương tác

Trên Ubuntu, apt-get install đôi khi yêu cầu người dùng nhập liệu. Tuy nhiên, các thao tác tương tác không thể thực hiện được trong quá trình build Docker. Để tránh điều này, nên đặt biến môi trường và bật chế độ không tương tác.

ENV DEBIAN_FRONTEND=noninteractive

Điều này sẽ loại bỏ các lời nhắc như chọn locale hay múi giờ và cho phép quá trình cài đặt diễn ra suôn sẻ.

Giảm Kích thước Image bằng Cách Xóa Cache Không Cần Thiết

Khi dùng APT, các tệp tạm thời đã tải về (cache) có thể còn lại trong image, làm tăng kích thước cuối cùng. Bạn có thể giảm kích thước image bằng cách xóa cache như sau:

RUN apt-get update && apt-get install -y \
    curl \
    vim \
    && rm -rf /var/lib/apt/lists/*

Kết hợp nhiều lệnh vào một lệnh RUN duy nhất cũng giúp ngăn ngừa việc tạo ra các lớp (layer) không cần thiết.

Các Thực Hành Tốt Khi Viết Dockerfile

Trong môi trường phát triển thực tế, các thực hành tốt cho Dockerfile sau đây được khuyến nghị rộng rãi:

  • Kết hợp các lệnh RUN khi có thể để giảm số lượng layer
  • Định nghĩa rõ ràng phiên bản và cài đặt bằng ENV
  • Sử dụng chú thích để mô tả mục đích của từng bước
  • Tránh để lại các tệp không cần thiết bằng cách dùng rm--no-install-recommends

Ví dụ:

RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    git \
    && rm -rf /var/lib/apt/lists/*

Cách tiếp cận này mang lại một Dockerfile nhẹ hơn và dễ bảo trì hơn.

4. Xây dựng và Kiểm tra Image Docker

Xây dựng Image Docker từ Dockerfile

Khi Dockerfile đã sẵn sàng, bước tiếp theo là xây dựng một image Docker. Thao tác này được thực hiện bằng lệnh docker build. Chạy lệnh sau trong thư mục chứa Dockerfile của bạn:

docker build -t my-ubuntu-image .
  • Tùy chọn -t gán tên (tag) cho image. Trong ví dụ này, image được đặt tên là my-ubuntu-image.
  • Dấu chấm (.) chỉ thư mục hiện tại chứa Dockerfile.

Docker sẽ đọc các chỉ thị trong Dockerfile theo thứ tự và xây dựng image tương ứng.

Kiểm tra Image Docker đã được xây dựng

Sau khi image được xây dựng thành công, bạn có thể xác nhận bằng lệnh sau:

docker images

Lệnh này hiển thị danh sách các image Docker được lưu trữ cục bộ, bao gồm các thông tin sau:

  • REPOSITORY (tên image)
  • TAG
  • IMAGE ID (định danh duy nhất)
  • CREATED (ngày tạo)
  • SIZE

Ví dụ:

REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
my-ubuntu-image   latest    abcd1234abcd   5 minutes ago    189MB

Điều này xác nhận rằng image đã được đăng ký đúng cách.

Chạy Container Docker để Xác minh

Để kiểm tra rằng image vừa tạo hoạt động như mong đợi, khởi động một container Docker bằng lệnh sau:

docker run -it my-ubuntu-image
  • Tùy chọn -it khởi chạy một phiên terminal tương tác.
  • Nếu thành công, một dấu nhắc Bash sẽ xuất hiện, cho biết bạn đang ở bên trong container Ubuntu.

Bên trong container, bạn có thể xác minh các công cụ đã cài đặt bằng các lệnh như:

curl --version
vim --version

Nếu các lệnh này hoạt động đúng, Dockerfile của bạn đã được cấu hình đúng.

Dọn dẹp Các Hình ảnh và Container Không Sử dụng

Các lần build và thí nghiệm lặp lại có thể để lại các hình ảnh Docker và container không sử dụng trên hệ thống của bạn. Khuyến nghị dọn dẹp chúng định kỳ bằng các lệnh sau:

  • Xóa các container đã dừng:
    docker container prune
    
  • Xóa các hình ảnh không sử dụng:
    docker image prune
    
  • Xóa tất cả dữ liệu không sử dụng (sử dụng cẩn thận):
    docker system prune
    

Các hoạt động này giúp tiết kiệm không gian đĩa và ngăn chặn các vấn đề tiềm ẩn.

5. Nâng cao: Xây dựng Môi trường Python

Kích hoạt Python trong Dockerfile Dựa trên Ubuntu

Khi xây dựng môi trường Ubuntu bằng Dockerfile, việc thêm môi trường runtime Python sẽ kích hoạt nhiều trường hợp sử dụng, bao gồm phát triển, kiểm thử và học máy. Mặc dù Python có thể đã được cài đặt mặc định trên Ubuntu, nhưng thực hành phổ biến là cấu hình rõ ràng để quản lý phiên bản và gói tốt hơn.

Cài đặt Python Sử dụng APT

Cách tiếp cận đơn giản nhất là cài đặt Python bằng các gói APT. Dưới đây là ví dụ:

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y \
    python3 \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

Phương pháp này cung cấp phiên bản Python hệ thống ổn định (như Python 3.10 hoặc 3.12, tùy thuộc vào bản phát hành Ubuntu). Bạn cũng có thể cài đặt các gói Python bổ sung bằng lệnh pip.

Quản lý Phiên bản Python với pyenv

Nếu bạn cần một phiên bản Python cụ thể hoặc muốn chuyển đổi giữa nhiều phiên bản, sử dụng pyenv được khuyến nghị cao.

Ví dụ sau cho thấy cách cài đặt Python 3.11.6 bằng pyenv trong Dockerfile:

FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y \
    git \
    curl \
    make \
    build-essential \
    libssl-dev \
    zlib1g-dev \
    libbz2-dev \
    libreadline-dev \
    libsqlite3-dev \
    wget \
    llvm \
    libncurses5-dev \
    libncursesw5-dev \
    xz-utils \
    tk-dev \
    libffi-dev \
    liblzma-dev \
    && rm -rf /var/lib/apt/lists/*

# Install pyenv
RUN git clone https://github.com/pyenv/pyenv.git ~/.pyenv

ENV PYENV_ROOT="$HOME/.pyenv"
ENV PATH="$PYENV_ROOT/bin:$PATH"

RUN echo 'eval "$(pyenv init --path)"' >> ~/.bashrc

# Install a specific Python version
RUN pyenv install 3.11.6 && pyenv global 3.11.6

Thiết lập này cung cấp môi trường Python linh hoạt và được kiểm soát tốt.

Quản lý Gói với requirements.txt

Hầu hết các dự án thực tế yêu cầu nhiều thư viện Python. Các phụ thuộc này thường được quản lý bằng tệp requirements.txt.

Đầu tiên, tạo tệp requirements.txt trong thư mục gốc dự án:

flask==2.3.2
requests>=2.25.1
pandas

Sau đó, tham chiếu nó trong Dockerfile như sau:

COPY requirements.txt /app/requirements.txt
WORKDIR /app

RUN pip install --no-cache-dir -r requirements.txt

Điều này cho phép cài đặt tất cả các thư viện cần thiết cùng lúc và cải thiện đáng kể khả năng tái tạo môi trường.

Các Thực hành Tốt nhất

  • Khi sử dụng Python, việc tạo môi trường ảo với virtualenv hoặc venv giúp ngăn chặn xung đột phụ thuộc.
  • Sử dụng các tùy chọn tắt cache như --no-cache-dir giúp giảm kích thước hình ảnh Docker.
  • Chạy pip install --upgrade pip trước khi cài đặt gói có thể giúp tránh lỗi cài đặt.

6. Các Vấn đề Phổ biến và Khắc phục Sự cố

Lỗi Quyền Truy cập

Ví dụ:

Permission denied

Lỗi này xảy ra khi các tệp được sao chép thiếu quyền thực thi hoặc khi quyền sở hữu tệp và người dùng thực thi bị cấu hình sai.

Giải pháp:

  • Làm cho tệp có thể thực thi:
    RUN chmod +x script.sh
    
  • Thay đổi quyền sở hữu tệp nếu cần:
    RUN chown root:root /path/to/file
    

Gói Không Tìm thấy hoặc Thất bại Cài đặt

Ví dụ:

E: Unable to locate package xxx

Lỗi này thường xảy ra khi apt-get update chưa được thực thi hoặc khi tên gói không chính xác.

Giải pháp:

  • Luôn chạy apt-get update trước khi cài đặt các gói:
    RUN apt-get update && apt-get install -y curl
    
  • Kiểm tra tên gói và kiểm tra lỗi chính tả

Lỗi Liên Quan Đến Mạng

Ví dụ:

Temporary failure resolving 'deb.debian.org'

Lỗi này cho thấy vấn đề phân giải DNS trong quá trình xây dựng.

Giải pháp:

  • Khởi động lại daemon Docker có thể giải quyết vấn đề:
    sudo systemctl restart docker
    
  • Xem xét cài đặt DNS của Docker bằng cách thêm máy chủ DNS vào /etc/docker/daemon.json :
    {
      "dns": ["8.8.8.8", "8.8.4.4"]
    }
    

Xây Dựng Sử Dụng Bộ Đệm Cũ

Docker sử dụng bộ đệm dựa trên lớp để tăng tốc xây dựng. Do đó, các thay đổi đối với Dockerfile có thể không luôn được phản ánh ngay lập tức.

Giải pháp:

  • Xây dựng lại mà không sử dụng bộ đệm:
    docker build --no-cache -t my-image .
    

Container Thoát Ngay Lập Tức Hoặc Lệnh Khởi Động Không Chạy

Nguyên nhân:

  • Lệnh được chỉ định trong CMD hoặc ENTRYPOINT chứa lỗi
  • Sử dụng CMD ["/bin/bash"] mà không có chế độ tương tác gây thoát ngay lập tức

Giải pháp:

  • Khởi động container ở chế độ debug:
    docker run -it my-image /bin/bash
    
  • Hiểu sự khác biệt giữa CMDENTRYPOINT và sử dụng chúng một cách phù hợp

Bằng cách gặp và giải quyết những vấn đề này, kỹ năng thiết kế Dockerfile của bạn sẽ cải thiện dần dần. Khi lỗi xảy ra, hãy đọc kỹ thông báo lỗi và xác định hướng dẫn và lớp nào gây ra vấn đề.

7. Tóm tắt

Những Điểm Chính Khi Tạo Dockerfile Dựa Trên Ubuntu

Bài viết này cung cấp giải thích từng bước về cách xây dựng môi trường Ubuntu sử dụng Dockerfile, bao quát cả các chủ đề cơ bản và nâng cao. Hãy ôn lại các điểm chính:

  • Hiểu các nguyên tắc cơ bản của Dockerfile là bước đầu tiên Các hướng dẫn như FROM , RUN , CMD , và ENV cho phép tạo môi trường tự động.
  • Ubuntu là hình ảnh cơ sở ổn định và linh hoạt Hệ sinh thái gói rộng lớn, cơ sở người dùng lớn và các bản phát hành LTS làm cho nó lý tưởng cho môi trường phát triển.
  • Quản lý gói thực tế cho phép cài đặt các công cụ và thư viện cần thiết Sử dụng đúng apt-get , dọn dẹp bộ đệm và cài đặt không tương tác là thiết yếu.
  • Xây dựng môi trường thực tế như Python được hỗ trợ đầy đủ bởi Dockerfile Các công cụ như pyenv , pip , và requirements.txt đảm bảo thiết lập có thể tái tạo.
  • Kỹ năng khắc phục sự cố trực tiếp ảnh hưởng đến hoạt động ổn định Hiểu về quyền, mạng và hành vi bộ đệm xây dựng cải thiện đáng kể năng suất.

Các Bước Tiếp Theo Trong Học Dockerfile

Một khi bạn quen sử dụng Dockerfile, bạn có thể mở rộng kỹ năng vượt ra ngoài phát triển vào kiểm thử và triển khai sản xuất. Hãy xem xét khám phá các chủ đề sau:

  • Quản lý thiết lập đa container với Docker Compose
  • Tích hợp với công cụ CI/CD như GitHub Actions và GitLab CI
  • Làm việc với các nền tảng dàn xếp container như Kubernetes

Tài Liệu Chính Thức Và Liên Kết Tham Khảo

8. Câu Hỏi Thường Gặp (FAQ)

C1. Phiên bản Ubuntu nào tôi nên chọn trong Dockerfile?

C1. Trong hầu hết các trường hợp, chọn bản phát hành LTS (Hỗ Trợ Dài Hạn) được khuyến nghị để ổn định và bảo trì dài hạn. Các phiên bản như ubuntu:22.04ubuntu:20.04 được sử dụng rộng rãi và hỗ trợ trong năm năm.

Nếu bạn cần các gói mới nhất hoặc phiên bản ngôn ngữ, bạn có thể chọn bản phát hành mới hơn như ubuntu:24.04, nhưng khuyến nghị kiểm thử kỹ lưỡng.

C2. Tại sao apt-get install báo “gói không tìm thấy”?

.A2. Lý do phổ biến nhất là không chạy apt-get update trước đó. Nếu không cập nhật danh sách gói, APT không thể tìm thấy các gói được yêu cầu.

Ví dụ đúng:

RUN apt-get update && apt-get install -y curl

Ngoài ra, hãy đảm bảo rằng tên gói là chính xác và không bị lỗi thời (ví dụ, dùng python3 thay vì python).

Q3. Làm thế nào để đặt biến môi trường trong Dockerfile?

A3. Sử dụng chỉ thị ENV để định nghĩa các biến môi trường có sẵn cả trong thời gian xây dựng và thời gian chạy container.

Ví dụ:

ENV DEBIAN_FRONTEND=noninteractive

Điều này thường được dùng để ẩn các lời nhắc tương tác trong quá trình cài đặt APT. Các biến môi trường cũng hữu ích cho cấu hình ứng dụng và khóa API.

Q4. Sự khác nhau giữa CMDENTRYPOINT là gì?

A4. Cả hai đều chỉ định lệnh sẽ chạy khi container khởi động, nhưng hành vi của chúng khác nhau.

ItemCMDENTRYPOINT
OverridableCan be overridden by docker runGenerally not overridden (treated as fixed command)
Use CaseDefine a default commandDefine a command that must always run

Ví dụ:

CMD ["python3", "app.py"]
# vs
ENTRYPOINT ["python3"]
CMD ["app.py"]

Trong trường hợp sau, bạn có thể truyền đối số bằng cách sử dụng docker run my-image another_script.py.

Q5. Tại sao các thay đổi trong Dockerfile của tôi không được phản ánh?

A5. Docker sử dụng bộ nhớ đệm xây dựng, có thể khiến các lớp không thay đổi được tái sử dụng ngay cả sau khi chỉnh sửa Dockerfile.

Giải pháp:

docker build --no-cache -t my-image .

Điều này buộc thực hiện xây dựng lại toàn bộ và đảm bảo mọi thay đổi được áp dụng.