Dockerfile & Image Building
Cú pháp Dockerfile, cơ chế layer & build cache, multi-stage build để giảm kích thước image, best practices.
Dockerfile là "mã nguồn" định nghĩa image của bạn — viết tốt giúp build nhanh hơn nhiều lần (tận dụng cache) và image nhỏ hơn nhiều lần (ảnh hưởng trực tiếp đến tốc độ deploy và chi phí lưu trữ/băng thông registry). Đây là kỹ năng thực hành cốt lõi nhất của cả khoá học.
🎯 Mục tiêu học tập
- Viết Dockerfile đúng cú pháp với các instruction phổ biến nhất
- Hiểu cơ chế layer và build cache để viết Dockerfile build nhanh
- Áp dụng multi-stage build để tách biệt môi trường build và môi trường chạy, giảm kích thước image
- Áp dụng các best practice giảm kích thước và tăng tốc build
Cú pháp Dockerfile cơ bản
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
| Instruction | Vai trò |
|---|---|
FROM | Chọn base image làm điểm khởi đầu |
WORKDIR | Đặt thư mục làm việc bên trong image cho các lệnh tiếp theo |
COPY / ADD | Sao chép file từ máy build vào image (COPY nên ưu tiên hơn ADD trừ khi cần tính năng đặc biệt như tự giải nén) |
RUN | Chạy lệnh lúc build image (cài package, biên dịch...) |
CMD | Lệnh mặc định chạy khi container khởi động (có thể bị ghi đè lúc docker run) |
ENTRYPOINT | Tương tự CMD nhưng khó ghi đè hơn — thường dùng khi image chỉ nên chạy đúng 1 chương trình cố định |
EXPOSE | Khai báo (mang tính tài liệu) port ứng dụng lắng nghe — không tự động publish port ra ngoài |
ENV | Đặt biến môi trường có sẵn trong container |
Layer & Build Cache — vì sao thứ tự trong Dockerfile quan trọng
Mỗi instruction (RUN, COPY...) tạo ra một layer mới, được
cache lại. Khi build lại, Docker so sánh từng layer với lần build trước — nếu instruction và input không
đổi, dùng lại cache thay vì chạy lại, giúp build nhanh hơn rất nhiều. Nhưng ngay khi một
layer bị "cache miss" (thay đổi), mọi layer phía sau đều phải build lại — đây là lý do
thứ tự trong ví dụ trên quan trọng: COPY requirements.txt + RUN pip install được
đặt trước COPY . . (copy toàn bộ code) — vì code ứng dụng đổi liên tục nhưng
dependency ít đổi hơn, tách riêng giúp pip install (bước chậm) được cache lại hầu hết các lần
build, chỉ chạy lại khi requirements.txt thực sự thay đổi.
COPY . . rồi mới
RUN pip install — bất kỳ thay đổi nhỏ nào trong code cũng làm mất cache của bước cài
dependency, khiến build luôn chậm dù chỉ sửa 1 dòng code.
Multi-stage Build — tách môi trường Build và Runtime
Nhiều ngôn ngữ cần công cụ build nặng (compiler, dev dependency) nhưng runtime thực tế không cần đến
chúng. Multi-stage build cho phép dùng nhiều FROM trong 1 Dockerfile, mỗi
stage có thể lấy kết quả từ stage trước, nhưng image cuối cùng chỉ chứa những gì thực sự cần để chạy:
# Stage 1: build — dùng image đầy đủ có công cụ biên dịch
FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: runtime — chỉ lấy kết quả build, dùng image nhỏ hơn nhiều
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
Kết quả: image cuối không hề chứa Node.js, npm, hay source code gốc — chỉ có file tĩnh đã build và nginx, thường nhỏ hơn hàng trăm MB so với cách build gộp 1 stage.
Best Practices giảm kích thước & tăng tốc build
- Chọn base image tối giản: ưu tiên bản
-slimhoặc-alpinethay vì bản đầy đủ, trừ khi cần các thư viện hệ thống mà bản tối giản thiếu. - Gộp RUN liên quan bằng
&&: mỗiRUNtạo 1 layer — gộp các lệnh liên quan (update, install, cleanup cache) trong cùng 1RUNđể tránh layer trung gian giữ lại dữ liệu tạm không cần thiết. - Dùng
.dockerignore: loại trừnode_modules,.git, file log... khỏi build context — giảm thời gian gửi context lên daemon và tránh copy nhầm file không cần thiết vào image. - Xoá cache package manager trong cùng layer cài đặt: ví dụ
apt-get install ... && rm -rf /var/lib/apt/lists/*trong cùng 1RUN, không phải ởRUNriêng (nếu tách riêng, dữ liệu vẫn tồn tại ở layer trước, không giảm kích thước tổng).
🏋️ Bài tập thực hành
Viết Dockerfile cho 1 ứng dụng FastAPI đơn giản (từ khoá AI Engineer) theo cách "ngây thơ" (COPY toàn bộ trước, RUN pip install sau), đo thời gian build lại sau khi sửa 1 dòng code. Sau đó viết lại theo đúng thứ tự tối ưu cache, đo lại thời gian build lại. Áp dụng multi-stage nếu phù hợp, so sánh kích thước image cuối cùng bằng docker images.
📚 Tài nguyên học tập
-
Docker — Dockerfile referenceTham chiếu đầy đủ cú pháp DockerfileDocs
-
Docker — Best practices for building imagesHướng dẫn chính thức best practicesDocs
-
Docker — Multi-stage buildsTài liệu chính thức multi-stage buildDocs
✅ Tự đánh giá hoàn thành
- Viết được Dockerfile đúng cú pháp cho 1 ứng dụng thực tế
- Giải thích được cơ chế layer/cache và sắp xếp instruction đúng thứ tự tối ưu
- Áp dụng được multi-stage build để giảm kích thước image
- Dùng .dockerignore đúng cách