Networking & Volumes
Docker networks, port mapping, service discovery, volumes và data persistence
Kiến trúc Network
Hệ thống sử dụng 3 Docker networks riêng biệt để cô lập traffic theo nguyên tắc least privilege — mỗi service chỉ truy cập được những gì nó cần:
data-net được đánh dấu internal: true nghĩa là các container trong network này
không có internet access. PostgreSQL và Redis hoàn toàn cô lập — chỉ có API mới kết nối
được.
Service Discovery
Docker Compose tự động tạo DNS entries cho mỗi service. Các container giao tiếp với nhau bằng tên service thay vì IP address:
# Từ container Nginx, kết nối đến React: proxy_pass http://frontend:80; # Từ container Nginx, kết nối đến API: proxy_pass http://backend:8080; # Từ container API, kết nối đến PostgreSQL: Host=postgres;Port=5432;Database=myapp_db # Từ container API, kết nối đến Redis: redis:6379,password=xxx
docker-compose.yml chính là hostname. Khi bạn đặt service tên
postgres, các container khác (cùng network) có thể dùng postgres như hostname để kết
nối. Docker DNS tự resolve thành container IP.
expose vs ports
Hai directive quan trọng nhưng thường bị nhầm lẫn:
expose
- Mở port cho containers khác trong cùng network
- Không accessible từ host machine
- Không accessible từ internet
- Dùng cho: database, cache, internal services
ports
- Syntax:
"host:container" - Accessible từ bên ngoài host
- Cần thiết cho entry points (Nginx)
- Giảm thiểu số ports expose ra ngoài
nginx: ports: - "80:80" # Host port 80 → Container port 80 (PUBLIC) - "443:443" # Host port 443 → Container port 443 (PUBLIC) backend: expose: - "8080" # Chỉ visible trong Docker network (INTERNAL) postgres: expose: - "5432" # Chỉ API mới kết nối được (INTERNAL) redis: expose: - "6379" # Chỉ API mới kết nối được (INTERNAL)
ports cho PostgreSQL hay Redis trong production. Việc expose port
5432 hoặc 6379 ra internet là lỗ hổng bảo mật nghiêm trọng — kẻ tấn công sẽ
brute-force password hoặc khai thác vulnerability.
Docker Volumes
Containers là ephemeral — khi bị xóa, dữ liệu bên trong mất theo. Volumes giúp lưu trữ dữ liệu bền vững bên ngoài container lifecycle.
Named Volumes vs Bind Mounts
Named Volumes
- Docker tự tạo và quản lý vị trí lưu trữ
- Portable giữa các host
- Performance tốt hơn trên Linux
- Dùng cho: database data, cache data
- Syntax:
pgdata:/var/lib/postgresql/data
Bind Mounts
- Map trực tiếp path trên host machine
- Dễ truy cập và chỉnh sửa từ host
- Phụ thuộc vào filesystem của host
- Dùng cho: config files, SSL certs, logs
- Syntax:
./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
:ro (read-only) ở cuối bind mount nghĩa là container chỉ được đọc file, không
được ghi. Luôn dùng :ro cho config files và SSL certs để tránh container vô tình sửa đổi.
Data Persistence theo Service
Volume: pgdata:/var/lib/postgresql/data
Toàn bộ database files (tables, indexes, WAL logs) nằm trong thư mục
/var/lib/postgresql/data. Named volume đảm bảo dữ liệu tồn tại ngay cả khi container bị xóa
và tạo lại.
Lưu ý: Khi thay đổi POSTGRES_USER hoặc POSTGRES_PASSWORD sau
lần chạy đầu tiên, giá trị mới sẽ bị bỏ qua vì PostgreSQL chỉ init database khi volume trống. Để
đổi password, dùng SQL: ALTER USER myuser PASSWORD 'newpass';
Volume: redisdata:/data
Redis mặc định lưu RDB snapshots vào /data/dump.rdb. Khi container restart, Redis tự load
snapshot này để khôi phục dữ liệu.
Persistence modes:
- RDB (mặc định): Snapshot theo interval. Nhanh nhưng có thể mất vài phút dữ liệu gần nhất.
- AOF: Log mọi write operation. An toàn hơn nhưng file lớn hơn. Bật bằng:
--appendonly yes
Config: ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
SSL: ./nginx/ssl:/etc/nginx/ssl:ro
Dùng bind mount (không phải volume) vì bạn cần chỉnh sửa config file từ host machine. Flag
:ro ngăn container ghi vào file.
Reload config: Sau khi sửa nginx.conf, không cần restart container:
docker compose exec nginx nginx -s reload
React và ASP.NET API là stateless — không lưu dữ liệu trong container. Mọi state đều nằm ở PostgreSQL (persistent) hoặc Redis (cache).
Khi cần update code, chỉ cần build lại image và recreate container — không lo mất dữ liệu.
Quản lý Volumes
# Liệt kê tất cả volumes docker volume ls # Xem chi tiết volume (vị trí lưu trữ trên host) docker volume inspect myapp_pgdata # Xem dung lượng volumes docker system df -v # Xóa volumes không sử dụng (CẢNH BÁO!) docker volume prune # Backup volume PostgreSQL docker compose exec postgres pg_dump -U myapp_user myapp_db > backup.sql # Restore từ backup docker compose exec -T postgres psql -U myapp_user myapp_db < backup.sql
docker volume prune xóa tất cả volumes không được sử dụng bởi container nào.
Nếu stack đang dừng (docker compose down), volumes sẽ bị coi là "unused" và bị xóa. Hãy cực kỳ cẩn
thận!
Docker DNS Resolution
Khi một container cần kết nối đến container khác, quá trình DNS diễn ra như sau:
127.0.0.11) được tự động inject vào mỗi container. Bạn không cần cấu hình gì
— chỉ cần dùng service name làm hostname. Nếu container được scale
(docker compose up --scale backend=3), DNS sẽ round-robin giữa các instances.