Docker Compose là gì? Kết nối Node.js với PostgreSQL hoặc MongoDB
Hướng dẫn Docker Compose cho Node.js với hai cấu hình docker-compose.yml hoàn chỉnh: PostgreSQL và MongoDB, kèm healthcheck, service discovery, volume, bảo mật và debug.
ShanverseCập nhật 9 phút đọc— lượt xemĐang tải lượt xem
Docker
Docker Compose
PostgreSQL
Node.js
Docker Compose là gì?
Một ứng dụng backend thường không chỉ có một Container:
Node.js API.
PostgreSQL hoặc MongoDB.
Redis, queue hoặc reverse proxy.
Network để các service giao tiếp.
Volume để dữ liệu tồn tại sau khi Container bị xóa.
Compose biến toàn bộ topology này thành cấu hình có thể review và tái sử dụng.
Mermaid
Loading diagram…
Các khái niệm chính:
Bình luận
Service: định nghĩa cách chạy một loại Container.
Image / build: dùng Image có sẵn hoặc build từ Dockerfile.
Network: cho phép service tìm nhau qua DNS nội bộ.
Volume: lưu dữ liệu bền vững.
Environment: truyền cấu hình vào Container.
Healthcheck: xác định service đã thực sự sẵn sàng.
Cấu trúc dự án mẫu
Dockerfile cho Node.js
.dockerignore tối thiểu:
package.json ví dụ:
Trong dự án thật, hãy commit lockfile được tạo bởi package manager thay vì tự viết version thủ công.
Quy tắc quan trọng: không dùng localhost giữa các Container
Từ Node.js Container:
Vì vậy:
PostgreSQL host là postgres, không phải localhost.
MongoDB host là mongodb, không phải localhost.
Port dùng giữa các service là port Container: 5432 hoặc 27017.
Compose tự tạo default network và DNS theo tên service.
Phương án 1: Node.js + PostgreSQL
Tạo .env dùng cho local development:
Đảm bảo .env nằm trong .gitignore và .dockerignore.
docker-compose.yml
Vì sao dùng $${POSTGRES_USER} trong healthcheck?
Compose dùng ${VAR} để interpolate biến trên host. Hai dấu $ giữ biểu thức cho shell bên trong Container, nơi biến POSTGRES_USER tồn tại.
Kết nối PostgreSQL bằng pg
Phải bind 0.0.0.0; bind 127.0.0.1 chỉ cho phép truy cập từ bên trong Container.
Phương án 2: Node.js + MongoDB
.env:
docker-compose.yml
Kết nối MongoDB bằng Mongoose
authSource=admin cần thiết vì root user được tạo trong database admin, dù application database là app.
Khởi động stack
Kiểm tra YAML và kết quả interpolation trước:
Build và chạy:
Xem trạng thái:
Theo dõi log API:
Mở health endpoint:
Truy cập database từ CLI
PostgreSQL:
Lệnh trên phụ thuộc shell host có export biến. Cách rõ ràng cho giá trị mẫu:
MongoDB:
Không đưa mật khẩu thật vào shell history trong môi trường chia sẻ hoặc production.
ports và expose khác gì?
publish PostgreSQL ra host nhưng chỉ bind loopback. Node.js service không cần mapping này để kết nối; nó dùng network nội bộ.
Nếu không cần dùng database GUI/CLI từ host, bỏ hoàn toàn ports của database để giảm bề mặt truy cập.
Volume giúp dữ liệu tồn tại
Container có thể được recreate nhưng named volume vẫn tồn tại.
Dừng stack:
Dừng và xóa cả volume:
depends_on không thay thế retry trong ứng dụng
condition: service_healthy giúp Compose đợi healthcheck, nhưng database vẫn có thể restart hoặc mất kết nối sau khi API chạy.
Ứng dụng cần:
Connection timeout.
Retry với exponential backoff khi khởi động.
Reconnect behavior phù hợp driver.
Health/readiness endpoint.
Graceful shutdown.
Compose điều phối startup; application vẫn chịu trách nhiệm về resilience.
Hot reload và node_modules
Bind mount source giúp hot reload. Anonymous volume /app/node_modules ngăn bind mount host che dependency Linux đã cài trong Image.
Cấu hình này phù hợp development. Production nên chạy immutable Image, không bind mount source.
Chạy đồng thời cả PostgreSQL và MongoDB
Nếu ứng dụng thật sự dùng cả hai, gộp hai database service vào cùng file và truyền cả:
Đồng thời khai báo cả hai dependency:
Không chạy thêm database nếu application không sử dụng; nó làm tốn tài nguyên và tăng độ phức tạp.
Biến môi trường và secret
File .env cạnh Compose thường được dùng để interpolation. env_file hoặc environment đưa giá trị vào Container. Cả hai đều không phải secret manager.
Development:
Commit .env.example, không commit .env.
Dùng credential local riêng, không tái sử dụng production password.
Bind database port vào 127.0.0.1 hoặc không publish.
Production:
Dùng Docker secrets hoặc secret manager của platform.
Không publish database ra Internet.
Dùng application user với quyền tối thiểu thay vì root/superuser.
Mã hóa kết nối khi database nằm ngoài private network.
Scan Image và pin version/digest theo chính sách cập nhật.
Lưu ý khi thay đổi credential khởi tạo
POSTGRES_* và MONGO_INITDB_* chủ yếu được áp dụng khi data directory còn trống. Nếu named volume đã tồn tại, sửa .env không tự đổi user/password trong database.
Để cập nhật an toàn:
Đổi credential bằng lệnh SQL/database administration.
Cập nhật secret của application.
Restart service.
Chỉ dùng docker compose down -v để khởi tạo lại khi chấp nhận xóa dữ liệu.
Debug các lỗi phổ biến
ECONNREFUSED 127.0.0.1:5432
API đang dùng localhost. Đổi host thành postgres.
getaddrinfo ENOTFOUND postgres
Kiểm tra tên service, network và API có chạy trong cùng Compose project không.
API chạy trước database
Thêm healthcheck, depends_on với service_healthy và retry trong code.
Password authentication failed
Kiểm tra interpolation bằng:
Không dán output này công khai vì có thể chứa secret.
Đổi password nhưng vẫn dùng password cũ
Named volume đã được initialize. Đổi credential trong database hoặc reset volume nếu là dữ liệu local có thể xóa.
Port đã được sử dụng
Đổi host port, ví dụ 5433:5432, hoặc bỏ mapping database.
Permission hoặc dependency sai khi bind mount
Giữ /app/node_modules trong volume riêng và tránh copy node_modules từ host.
Compose có phù hợp production không?
Compose rất tốt cho:
Local development.
Integration test.
Demo và môi trường một host đơn giản.
CI stack tạm thời.
Với yêu cầu multi-host, autoscaling, rolling deployment, self-healing phức tạp hoặc policy nâng cao, cần cân nhắc Kubernetes, managed container platform hoặc orchestrator phù hợp.
Checklist hoàn chỉnh
Không có top-level version: không cần thiết.
Node.js bind 0.0.0.0.
API dùng postgres hoặc mongodb, không dùng localhost.
Database có healthcheck.
API vẫn có retry/reconnect.
Dữ liệu database nằm trong named volume.
Database port không public ngoài nhu cầu.
.env nằm trong .gitignore và .dockerignore.
Production không dùng root/superuser cho application.
docker compose config chạy thành công.
docker compose down -v chỉ được dùng khi chấp nhận mất dữ liệu.
Có backup và quy trình nâng cấp database.
Tổng kết
Docker Compose biến một nhóm lệnh rời rạc thành mô hình ứng dụng có thể tái tạo:
Docker Compose khi nào không còn đủ? So sánh Kubernetes và Docker Swarm về multi-host, self-healing, scaling, rolling update, networking, secrets và lộ trình migration production.
Hướng dẫn Live Reload và Hot Reload với Docker Compose cho Node.js, TypeScript, Vite và Next.js: bind mounts, Compose Watch, node_modules, polling, quyền file và debug.