Part 11 · Docker · 11.1.07

Docker Compose: service graph và local environments

Compose khai báo một ứng dụng nhiều container bằng một application model chung. Nó giúp dựng môi trường dev/integration lặp lại được, nhưng thứ tự dependency không đồng nghĩa dependency đã thật sự sẵn sàng phục vụ request.

1. Compose

Một Compose application thường được mô tả trong compose.yaml. File này gom các service và các tài nguyên liên quan như network, volume, config và secret thành một project. Khi chạy docker compose up, Compose resolve model rồi tạo các resource/container cần thiết cho project đó.

compose.yaml │ ├── services │ ├── web │ ├── api │ └── db ├── networks ├── volumes ├── configs └── secrets │ └── docker compose up → project-scoped resources
Mental model: Compose là declarative application model trên Docker Engine, không phải một scheduler HA. Hãy nghĩ “một graph service + cấu hình runtime”, không phải “Kubernetes thu nhỏ”.

2. Model

Mỗi service có thể định nghĩa image hoặc build, command, environment, port publishing, network, volume, healthcheck và resource-related configuration. Project name tạo namespace để nhiều stack tương tự có thể cùng tồn tại mà không trùng tên resource.

Trên cùng một Compose network, service name đóng vai trò tên DNS ổn định cho service discovery. Vì vậy container ứng dụng nên kết nối tới db:5432 hoặc redis:6379 thay vì hard-code IP container, vì IP có thể đổi sau recreate.

Ví dụ model tối thiểu

services:
  api:
    build: .
    environment:
      DB_HOST: db
    depends_on:
      db:
        condition: service_healthy
    networks: [backend]

  db:
    image: postgres:18
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s
    volumes:
      - db-data:/var/lib/postgresql/data
    networks: [backend]

networks:
  backend:

volumes:
  db-data:

Compose hỗ trợ merge nhiều file và profiles để tạo biến thể môi trường. Đây là công cụ hữu ích cho dev/test, nhưng nếu YAML có quá nhiều lớp override, anchor và profile, cấu hình thực tế trở nên khó review. Trước khi chạy, dùng docker compose config để render model cuối cùng mà Docker Compose sẽ áp dụng.

3. Startup

depends_on mô tả dependency graph và điều khiển thứ tự create/remove. Với short syntax, dependency chỉ cần được start trước; container đang chạy chưa chắc application bên trong đã ready. Long syntax cho phép condition: service_healthy hoặc service_completed_successfully.

Startup order ≠ runtime availability. Ngay cả khi Compose chờ dependency healthy lúc startup, dependency vẫn có thể restart hoặc mất kết nối sau đó. Application phải có timeout, bounded retry/backoff và xử lý reconnect phù hợp.

Healthcheck phải đo readiness có ý nghĩa

Healthcheck nên kiểm tra đúng khả năng mà consumer cần: database chấp nhận connection/query tối thiểu, HTTP service trả lời endpoint readiness, hoặc broker nhận được protocol handshake. Tránh check giả kiểu echo ok hoặc chỉ kiểm tra process tồn tại nếu điều đó không chứng minh service phục vụ được traffic.

Tình huốngRủi roThiết kế tốt hơn
App start ngay sau DB containerDB process còn recovery/migration nên connection failservice_healthy + app retry/backoff
Dependency restart giữa runtimeConnection cũ chết, request failReconnect, timeout, idempotency khi retry
Healthcheck quá nặngTạo tải hoặc tự làm service unhealthyProbe rẻ, bounded timeout, đúng readiness contract
Healthcheck luôn xanhFalse-ready che lỗi thậtProbe resource tối thiểu mà downstream thật sự cần

4. Configuration

Interpolation và environment

.env chủ yếu là nguồn giá trị cho Compose interpolation; nó không phải secret store. Giá trị có thể đến từ shell, --env-file hoặc file .env và có precedence. Dùng biểu thức required như ${DB_HOST:?DB_HOST is required} để fail sớm thay vì chạy stack với giá trị rỗng ngoài ý muốn.

# .env
APP_PORT=8080

# compose.yaml
services:
  api:
    image: example/api:${API_TAG:-local}
    ports:
      - "${APP_PORT}:8080"

Có thể kiểm tra model đã resolve bằng docker compose config, và kiểm tra environment dùng cho interpolation bằng docker compose config --environment. Đừng đưa output này vào log công khai nếu có khả năng chứa giá trị nhạy cảm.

Secrets

Không commit password, token hay private key vào Compose file hoặc .env. Compose có top-level secrets; service chỉ nhận secret nếu được cấp rõ ràng và secret được mount vào container dưới dạng file. Với production, nguồn secret thực tế còn phụ thuộc platform và secret-management system của tổ chức.

services:
  api:
    image: example/api:1.4.2
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt

Images, networks và volumes

5. Use and limits

Compose rất phù hợp cho development, integration test, demo, CI job hoặc deployment single-host có failure model chấp nhận được. Nó giúp giữ parity ở application contract — cùng image, environment contract, ports, healthchecks và dependency topology — nhưng không tạo ra cùng infrastructure semantics với orchestrator nhiều node.

Compose phù hợpCần thận trọng / cần platform khác
Developer chạy nhiều service localHigh availability qua nhiều node/AZ
Integration test reproducibleAutomatic rescheduling khi host chết
Demo, workshop, ephemeral stackProgressive rollout, autoscaling, cluster policy phức tạp
Single-host internal workloadRPO/RTO yêu cầu orchestration/replication ngoài một host

Failure window và recovery

Trên single-host Compose, host failure có thể làm toàn bộ stack mất cùng lúc. Restart policy có thể giúp container quay lại sau process/daemon restart, nhưng không thay thế multi-node failover. Với stateful service, phải xác định dữ liệu nằm ở đâu, backup/restore thế nào, và điều gì xảy ra nếu volume hoặc host bị mất.

Khi thay image/config, hãy render config trước, pull/build image trước nếu phù hợp, sau đó rollout trong maintenance window hoặc với reverse proxy/draining do hệ thống bên ngoài kiểm soát. Rollback phải chỉ rõ image/config version trước đó và migration database có backward-compatible hay không.

Capacity và operational signals

Operational rule: nếu môi trường Compose được dùng lâu dài thay vì disposable dev stack, hãy có backup/restore test cho dữ liệu, limit log growth, pin/version images, least-privilege network exposure và runbook cho host/volume failure.

6. Practical workflow

  1. Viết compose.yaml với service/network/volume tối thiểu cần thiết.
  2. Đặt biến local vào .env hoặc --env-file; đưa secret ra cơ chế secret phù hợp.
  3. Chạy docker compose config để xem model sau merge/interpolation.
  4. Chạy docker compose up -d; kiểm tra docker compose ps và health status.
  5. Kiểm tra log bằng docker compose logs --tail=200 <service> khi startup thất bại.
  6. Inject failure: restart dependency, dừng một service hoặc làm healthcheck fail; xác nhận client retry/reconnect đúng kỳ vọng.
  7. Dùng docker compose down để dừng/xóa containers và networks; chỉ dùng -v khi thật sự muốn xóa named volumes.
docker compose config

docker compose up -d
docker compose ps
docker compose logs --tail=200 api

docker compose restart db
# Verify: api reconnects/retries without corrupting work

docker compose down
# Destructive for project named volumes:
# docker compose down -v

7. Checklist

Tài liệu: Docker Compose · Compose Specification · Startup order · Variable interpolation · Compose secrets · docker compose config