Các ứng dụng không thể đơn giản mãi. Càng nhiều tính năng thì càng nhiều phụ thuộc, quá trình build chậm hơn và Docker image nặng hơn. Và đó là lúc rắc rối bắt đầu.
Docker giúp đỡ phần nào, nhưng nếu không thiết lập đúng, quá trình build của bạn sẽ nhanh chóng trở nên cồng kềnh.
Multi-stage builds giúp mọi thứ trở nên mượt mà hơn bằng cách giữ cho image của bạn nhanh, sạch và sẵn sàng cho production. Trong hướng dẫn này, bạn sẽ học cách sử dụng chúng để tăng tốc workflow Docker của mình.
Hãy bắt đầu thôi.
Docker Image là gì?
Trước khi tối ưu hóa, hãy cùng làm rõ Docker image là gì.
Docker image là một gói độc lập, nhẹ, chứa mọi thứ ứng dụng của bạn cần để chạy – mã nguồn, thư viện phụ thuộc, biến môi trường, và các file cấu hình. Hãy tưởng tượng nó là một bản chụp nhanh của ứng dụng, sẵn sàng khởi động ở bất kỳ đâu.
Khi bạn chạy một image, Docker biến nó thành container – một môi trường tự chứa hoạt động giống nhau trên máy bạn, môi trường staging, hoặc production. Tính nhất quán đó là lợi thế rất lớn cho việc phát triển và triển khai.
Giờ khi đã hiểu cơ bản, hãy nói về cách làm cho image nhỏ hơn và nhanh hơn.
Cách triển khai Multi-Stage Build
Hãy thực hành bằng cách tạo một ứng dụng Flask đơn giản và sử dụng multi-stage build để giữ Docker image gọn nhẹ.
Bước 1: Tạo app.py
from flask import Flask app = Flask(__name__) @app.route('/')
def hello(): return "Hello, Docker Multi-stage Builds! 🐳" if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)
Bước 2: Cài đặt và lưu phụ thuộc
Cài Flask và Gunicorn:
pip install flask gunicorn
Sau đó lưu lại môi trường vào file requirements.txt
:
pip freeze > requirements.txt
Docker sẽ dùng file này để cài đặt phụ thuộc trong container.
Bước 3: Tạo Dockerfile với Multi-Stage
# Stage 1: Build Stage
FROM python:3.9-slim AS builder WORKDIR /app COPY requirements.txt . RUN python -m venv /opt/venv && \\ . /opt/venv/bin/activate && \\ pip install --no-cache-dir -r requirements.txt # Stage 2: Production Stage
FROM python:3.9-slim COPY --from=builder /opt/venv /opt/venv WORKDIR /app COPY . . ENV PATH="/opt/venv/bin/:$PATH" EXPOSE 5000 CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
Dockerfile trên định nghĩa hai giai đoạn:
- Giai đoạn Build: Cài đặt các phụ thuộc vào một môi trường ảo.
- Giai đoạn Production: Sao chép môi trường ảo và mã ứng dụng, sau đó chạy ứng dụng với Gunicorn.
Sử dụng cùng phiên bản Python trong cả hai giai đoạn giúp tránh lỗi không tương thích do khác biệt phụ thuộc.
Bước 4: Build và chạy image
# Build the image
docker build -t my-python-app . # Run the container
docker run -p 5000:5000 my-python-app
Nếu mọi thứ đúng, ứng dụng Flask sẽ chạy tại http://localhost:5000.
So Sánh: Dockerfile một giai đoạn (Chunky)
FROM python:3.9-slim WORKDIR /app RUN apt-get update && apt-get install -y \\ build-essential \\ python3-dev \\ gcc \\ && rm -rf /var/lib/apt/lists/* COPY requirements.txt . RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH" RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 5000 CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
Cách build một giai đoạn truyền thống chứa mọi thứ trong một bước duy nhất. Nó dễ thực hiện nhưng thường tạo ra Docker image lớn và build lâu hơn.
Build image:
docker build -t my-chunky-app .
So sánh kích thước:
docker images | grep 'my-'
Kết quả:
my-python-app
: nhỏ và nhẹ (multi-stage)my-chunky-app
: lớn và nặng (single-stage)- Thời gian build chênh lệch: multi-stage chỉ mất ~1.2 giây, trong khi single-stage mất tới 1 phút 21 giây!
Khi nào dùng Multi-Stage Build?
Nên dùng Multi-Stage Build nếu:
- Ứng dụng cần tool build (compiler, dev deps)
- Muốn image nhẹ và nhanh
- Quan tâm đến bảo mật và hiệu năng
Dùng Single-Stage Build nếu:
- Đang test hoặc prototype nhanh
- Ứng dụng nhỏ, không có tool bên ngoài
- Mới học Docker, muốn đơn giản
Chọn phương án phù hợp với quy mô và độ phức tạp của dự án.
Kết luận
Multi-stage builds là một lợi thế dễ đạt được. Chúng giúp Docker image gọn nhẹ, nhanh chóng và bảo mật hơn – đặc biệt khi ứng dụng ngày càng phát triển.
Không phải dự án nào cũng cần, nhưng khi cần thì rất đáng giá. Lần tới khi bạn Dockerize một dự án nghiêm túc, hãy cân nhắc multi-stage. Bạn trong tương lai sẽ cảm ơn bạn bây giờ.