Docker Compose Cơ Bản: Chạy Multi-Container App Với Một Lệnh

Ở bài trước, bạn đã học cách viết Dockerfile và build image của riêng mình. Nhưng app thực tế không chạy một mình — nó cần database, cache, có thể cả background worker. Chạy từng cái bằng một lệnh docker run riêng biệt nhanh chóng trở nên cực kỳ rườm rà.
Đó là lúc Docker Compose phát huy tác dụng.
Docker Compose là gì?
Docker Compose là tool để định nghĩa và chạy multi-container Docker application. Thay vì gõ những lệnh docker run dài dòng cho từng service, bạn khai báo tất cả trong một file docker-compose.yml — rồi khởi động toàn bộ stack bằng một lệnh duy nhất:
docker compose upXong. App, database, cache — tất cả chạy cùng nhau.
Docker Compose đặc biệt phù hợp cho môi trường development và testing. Commit file docker-compose.yml vào git là mọi người trong team có thể chạy full stack mà không cần cài PostgreSQL, Redis hay bất cứ thứ gì khác trên máy.
Cấu Trúc File docker-compose.yml
Đây là một Compose file điển hình:
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=development
depends_on:
- db
volumes:
- .:/app
db:
image: postgres:16
ports:
- "5432:5432"
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:Hai service: app (Node.js application) và db (PostgreSQL). Một named volume để giữ data database. Hãy breakdown từng field.
Các Field Quan Trọng
services
Block cấp cao nhất liệt kê tất cả container cần chạy. Mỗi key dưới services là tên của container — tên này cũng trở thành hostname của nó trên internal Docker network.
image
Dùng image có sẵn từ Docker Hub (hoặc local registry) thay vì build từ source.
image: postgres:16
image: redis:alpine
image: nginx:latestbuild
Bảo Docker build image từ Dockerfile thay vì pull về. Trỏ đến thư mục chứa Dockerfile.
build: . # Dùng Dockerfile ở thư mục hiện tại
build: ./backend # Dùng Dockerfile trong thư mục backend/ports
Map port của container ra máy host. Format: "host:container".
ports:
- "3000:3000" # localhost:3000 → container port 3000
- "5432:5432"environment
Đặt environment variable bên trong container. Hỗ trợ cả dạng list lẫn map:
# Dạng list
environment:
- NODE_ENV=production
- PORT=3000
# Dạng map
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secretvolumes
Có hai loại volume mount:
volumes:
- .:/app # Bind mount — sync code local vào container
- db_data:/var/lib/postgresql/data # Named volume — persist data kể cả khi container bị xóaBind mount (.:/app) liên kết thư mục trên host trực tiếp vào container. Thay đổi file ở local — container thấy ngay lập tức. Không cần rebuild. Hoàn hảo cho development.
Named volume (db_data:...) được Docker quản lý và tồn tại ngay cả khi container bị xóa. Không thể thiếu cho data database mà bạn không muốn mất.
depends_on
Kiểm soát thứ tự khởi động — service này start sau các service được liệt kê.
depends_on:
- db
- redisLưu ý: depends_on chỉ chờ container start, không chờ service bên trong sẵn sàng. Với database, app có thể start trước khi PostgreSQL khởi tạo xong. Với production, dùng health check hoặc retry loop trong app của bạn.
Các Lệnh Thường Dùng
# Khởi động toàn bộ stack (chạy nền)
docker compose up -d
# Xem log của tất cả service
docker compose logs -f
# Xem log của một service cụ thể
docker compose logs -f app
# Dừng tất cả container
docker compose down
# Dừng và xóa toàn bộ: container, volume, image
docker compose down -v --rmi all
# Rebuild image rồi mới start (dùng sau khi thay đổi Dockerfile)
docker compose up -d --build
# Chạy lệnh bên trong container đang chạy
docker compose exec app sh
# Xem trạng thái các service
docker compose psVí Dụ Thực Tế: Node.js + PostgreSQL
Đây là setup hoàn chỉnh cho một Node.js app kết nối với PostgreSQL:
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://admin:secret@db:5432/mydb
depends_on:
- db
volumes:
- .:/app
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: secret
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:docker compose up -d
# App chạy tại http://localhost:3000
# PostgreSQL chạy tại localhost:5432Một chi tiết quan trọng: các service trong cùng một docker-compose.yml có thể kết nối với nhau qua tên service như hostname. Để ý DATABASE_URL dùng @db:5432 — không phải @localhost:5432. App container kết nối tới service db qua tên của nó, vì Docker Compose tự động đặt tất cả service vào một internal network chung.
Tóm Lại
✅ Docker Compose quản lý multi-container app từ một file docker-compose.yml
✅ docker compose up -d khởi động toàn bộ stack; docker compose down dọn dẹp
✅ Dùng build: để build từ Dockerfile, image: để pull image có sẵn
✅ Bind mount (.:/app) sync code local vào container — không cần rebuild khi thay đổi code
✅ Named volume persist data qua các lần restart container — không thể thiếu cho database
✅ Service kết nối với nhau qua tên service như hostname, không phải localhost
Series: Lộ Trình Học Docker & Kubernetes
Previous: Viết Dockerfile: Tự Build Docker Image Của Bạn
Next: Docker Networking & Volumes
Tiếp theo: tìm hiểu sâu hơn về Docker networking và volumes hoạt động như thế nào bên dưới.
📬 Đăng ký nhận bản tin
Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.
Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.
💬 Comments
Đăng nhập để bình luận
Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.