“Trên máy tôi chạy được” là câu nói đùa quen thuộc của giới lập trình. Docker đóng gói cả ứng dụng lẫn môi trường vào một image, để nó chạy giống hệt nhau ở mọi nơi.
Dockerfile cơ bản
FROM python:3.12-slim
WORKDIR /app
# Copy requirements TRƯỚC để tận dụng cache
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "main.py"]
Thứ tự này rất quan trọng. Docker lưu cache theo từng lớp — vì requirements.txt hiếm khi đổi, bước cài thư viện được dùng lại và mỗi lần build sau chỉ mất vài giây thay vì vài phút.
Build và chạy
docker build -t ungdung-cua-toi .
docker run --rm -p 8000:8000 ungdung-cua-toi
Bỏ qua file không cần thiết
# .dockerignore
__pycache__/
*.pyc
.venv/
.git/
.env
tests/
Thiếu file này, image của bạn sẽ phình to và — nguy hiểm hơn — có thể chứa cả file .env với mật khẩu bên trong.
Multi-stage build cho image gọn
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Không chạy bằng quyền root
RUN useradd -m ungdung
USER ungdung
Nhiều dịch vụ với docker compose
# compose.yaml
services:
web:
build: .
ports: ["8000:8000"]
environment:
DATABASE_URL: postgresql://postgres:matkhau@db:5432/app
depends_on: [db]
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: matkhau
volumes:
- dulieu:/var/lib/postgresql/data
volumes:
dulieu:
docker compose up -d
docker compose logs -f web
Vài điều nên nhớ
- Ghim phiên bản image (
python:3.12-slim), đừng dùnglatest. - Truyền cấu hình qua biến môi trường, đừng nướng secret vào image.
- Dữ liệu cần giữ lại phải nằm trong volume — container là thứ dùng xong bỏ đi.
Khi đã quen, bạn sẽ thấy việc dựng lại toàn bộ môi trường cho một dự án cũ chỉ còn là một câu lệnh.
