
Bài 5: Tối ưu Docker image bằng multi-stage và distroless
Tách builder khỏi runtime, kiểm tra tương thích libc và native module; giảm thành phần không cần thiết mà không cam kết tỷ lệ dung lượng chưa đo.

Quản lý stack bằng Compose Specification, phân biệt .env với secrets và readiness với liveness; kiểm tra cấu hình trước khi recreate hoặc down.
Đối chiếu ngày 24/10/2026. Các nguồn ở cuối bài dùng để kiểm tra phiên bản và giới hạn. Ví dụ phải điều chỉnh theo hệ điều hành và ứng dụng; không phải báo cáo thử nghiệm trên mọi nền tảng.
Compose v1 Python đã ngừng hỗ trợ. Dùng plugin với docker compose, kiểm tra docker compose version; Compose Specification không đồng nhất với version trên đầu YAML.
Docker Compose được viết lại hoàn toàn bằng ngôn ngữ Golang, tích hợp trực tiếp vào nhân của Docker CLI dưới dạng plugin cấp một (First-class plugin), thực thi bằng cú pháp có dấu cách:
# Cú pháp chuẩn hiện đại (Compose hiện hành)
docker compose up -d
# Lệnh cũ (v1) đã ngừng hỗ trợ: docker-compose up -d (Không nên dùng)
Compose hiện hành dùng Compose Specification. Tính năng cụ thể phụ thuộc plugin; kiểm tra release notes và docker compose config trước thuộc tính mới.

Theo tiêu chuẩn Compose Specification mới nhất của Docker:
compose.yaml (hoặc compose.yml) thay vì docker-compose.yml cũ.version: '3.8' trên đầu file đã bị đánh dấu DEPRECATED và trở nên dư thừa. Compose hiện hành tự động nhận diện tính năng mà không cần bạn phải khai báo phiên bản chuỗi số..env hỗ trợ nội suy, không phải kho bí mật mã hóa và không tự chuyển mọi biến vào container. Shell, --env-file, environment và env_file có phạm vi khác nhau. Không commit .env thật.
File .env:
PROJECT_NAME=ecommerce
POSTGRES_DB=shop_db
POSTGRES_USER=db_admin
DB_PASSWORD_FILE=/srv/secrets/db_password
APP_PORT=8080
Trong compose.yaml, bạn tham chiếu biến theo cú pháp ${BIEN:-gia_tri_mac_dinh} để dự phòng giá trị nếu file .env chưa được cung cấp.
Một sai lầm rất phổ biến là dùng depends_on thông thường. Khi đó, Docker chỉ chờ container database vừa khởi động tiến trình là bật ngay container ứng dụng. Tuy nhiên, lúc này database vẫn đang trong giai đoạn khởi tạo bảng, khiến backend bị lỗi mất kết nối.
Giải pháp chuẩn Production: Kết hợp healthcheck với condition: service_healthy:
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
timeout: 5s
retries: 5
api:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "127.0.0.1:${APP_PORT:-8080}:3000"
depends_on:
db:
condition: service_healthy
environment:
DB_HOST: db
DB_NAME: ${POSTGRES_DB}
DB_USER: ${POSTGRES_USER}
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ${DB_PASSWORD_FILE:?Can chi dinh file secret}
volumes:
db_data:
Nhờ cấu hình này, Docker Compose chỉ cho phép api khởi chạy sau khi cơ sở dữ liệu đã vượt qua bài kiểm tra sức khỏe và sẵn sàng tiếp nhận kết nối SQL.
Khi bạn chạy một project Compose, một dải mạng bridge riêng biệt tự động được khởi tạo cho project đó. Các service có thể giao tiếp với nhau trực tiếp thông qua chính tên của service (ví dụ service api kết nối tới hostname db).
volumes:
db_data:
name: ${PROJECT_NAME}_postgres_volume
networks:
default:
name: ${PROJECT_NAME}_network
Thay vì phải duy trì nhiều file yaml khác nhau (như docker-compose.dev.yml, docker-compose.prod.yml), Compose hiện hành cung cấp tính năng Profiles giúp gộp chung cấu hình nhưng kích hoạt có chọn lọc:
services:
app:
image: my-app:prod
ports:
- "80:80"
# Dich vu chi can khi debug hoac test local
adminer:
image: adminer:latest
ports:
- "127.0.0.1:8081:8080"
profiles: ["debug"]
mock_server:
image: wiremock/wiremock:latest
profiles: ["test"]
Khi bạn gõ docker compose up -d thông thường, chỉ có service app được chạy. Khi cần bật thêm công cụ giao diện cơ sở dữ liệu để debug, bạn chỉ cần gõ:
docker compose --profile debug up -d
# 1. Khoi chay toan bo he thong o che do nen va tu dong build lai neu co thay doi
docker compose up -d --build
# 2. Xem trang thai cac container trong project kem ket qua healthcheck
docker compose ps
# 3. Theo doi nhat ky tap trung cua toan bo cac service
docker compose logs -f --tail 100
# 4. Thuc thi mot cau lenh ben trong mot service dang chay
docker compose config --quiet
# Migration can backup va ke hoach rieng.
# 5. Dung va giai phong toan bo container va mang
docker compose down
# 6. Dung va xoa luon ca volume du lieu (Than trong khi dung tren Prod)
# docker compose down -v # Xoa volume; khong dung de restart.
pg_isready kiểm tra PostgreSQL tiếp nhận kết nối, không kiểm chứng schema hoặc nghiệp vụ. service_healthy điều khiển khởi động, không tự restart app mỗi khi dependency unhealthy; ứng dụng cần retry/backoff. DB_PASSWORD_FILE đòi hỏi API của bạn thực sự hỗ trợ đọc file đó.
Secret file Compose cục bộ vẫn nằm trên host, không có cam kết mã hóa như secret manager. Profiles chọn service, không phải ranh giới bảo mật hay thay thế mọi override file. Down dừng stack; down -v xóa named volume khai báo và anonymous volume liên quan, trừ external volume. Backup và phục hồi thử trước khi xóa.

Đọc đúng tài liệu theo phiên bản. Địa chỉ, tên và đường dẫn trong ví dụ cần thay theo môi trường. Sơ đồ là khái niệm, không phải screenshot hay benchmark.
Lưu cấu hình và digest cũ, kiểm tra backup phục hồi được, xác nhận endpoint và log sau thay đổi. Rollback phải tính đến dữ liệu đã ghi mới; đổi image không tự phục hồi database.
Đoạn networks/volumes ở phần 5 là phần thay thế hoặc hợp nhất vào các khóa top-level đã có, không nối thành khóa YAML trùng. Mẫu healthcheck chỉ áp dụng cho Docker Compose; đừng suy ra docker stack deploy hoặc orchestrator khác có cùng ngữ nghĩa.

Tách builder khỏi runtime, kiểm tra tương thích libc và native module; giảm thành phần không cần thiết mà không cam kết tỷ lệ dung lượng chưa đo.

Cài Docker Engine từ kho phù hợp, kiểm tra phiên bản và quyền truy cập; phân biệt lưu trữ containerd mới với overlay2 trên máy nâng cấp.

Tra trạng thái, đọc log, kiểm tra OOM và giới hạn tài nguyên; hiểu tác động của stop, restart và prune trước khi thao tác trên máy production.

Phân biệt tag và digest, save/load với export; chuẩn bị TLS, xác thực và quy trình garbage collection trước khi vận hành private registry.