2 giờ sáng và sự cố đứt kết nối đa Cloud
Màn hình PagerDuty sáng rực lúc 2:15 sáng. Worker đồng bộ dữ liệu đặt trên Hetzner VPS liên tục ném lỗi connection timed out khi ghi vào cụm PostgreSQL trên AWS EC2. Cả hai phía đều chạy Docker. Trước đó, team chọn cách kết nối qua Public IP rồi cấu hình whitelist trong Security Group để tiết kiệm thời gian.
Sự cố ập đến khi Hetzner gán lại dải IP sau một đợt bảo trì mạng. Whitelist trên AWS vô hiệu ngay lập tức. Toàn bộ pipeline xử lý đơn hàng tê liệt suốt 45 phút. Mở toang port 5432 ra ngoài Internet thì rủi ro bị bot quét qua Shodan sau chưa đầy 15 phút. Dựng AWS NAT Gateway và Direct Connect thì đội chi phí thêm ít nhất 32 USD mỗi tháng cho từng cụm. Đây là lúc mô hình mạng nội bộ dạng mesh trở thành bắt buộc.
Ba hướng tiếp cận khi nối Docker container liên server
Khi các cụm container nằm rải rác ở AWS, DigitalOcean, Hetzner hay máy chủ văn phòng, bạn thường có 3 lựa chọn:
- Cách 1: Mở Port Public và Whitelist IP (Tạm bợ)
Map port container ra IP public (-p 5432:5432) rồi dùng UFW hoặc Security Group chặn IP. Triển khai trong 2 phút nhưng bảo trì rất cực khi IP thay đổi liên tục. - Cách 2: Cài WireGuard trực tiếp lên Host OS (Hạ tầng truyền thống)
Dựng WireGuard trên từng máy chủ, tạo filewg0.confrồi cấu hình iptables để đẩy traffic từ Docker bridge sang VPN. Hiệu năng cao nhưng dễ xung đột network stack của Docker khi cập nhật OS. - Cách 3: Chạy Tailscale Sidecar trong Docker (Container-level Mesh)
Mỗi stack dịch vụ có riêng một container Tailscale. Container ứng dụng gắn trực tiếp vào network stack của Tailscale thông qua chỉ thịnetwork_mode: "service:...".
So sánh chi tiết ba giải pháp
| Tiêu chí | Public Port + Whitelist | WireGuard trên Host OS | Tailscale Sidecar Container |
|---|---|---|---|
| Độ an toàn | Thấp, dễ lộ port nếu firewall lỗi | Rất cao | Rất cao (Zero Trust) |
| Bảo trì khi mở rộng | Ác mộng khi có trên 5 server | Tốn công quản lý key và NAT | Tự động 100% qua Control Plane |
| Tác động đến máy chủ Host | Mở port trực tiếp trên Host | Can thiệp sâu vào kernel/iptables | Cô lập hoàn toàn trong Docker |
| Độ phức tạp cấu hình | Rất thấp | Trung bình đến cao | Chỉ 1 file docker-compose.yml |
Tại sao Tailscale Sidecar tối ưu hơn cài trên Host?
Trong một đợt nâng cấp Ubuntu 20.04 lên 22.04 trước đây, bảng iptables của máy chủ bị reset. Các rule chuyển tiếp giữa Docker bridge và wg0 biến mất sạch sẽ, làm sập toàn bộ kết nối giữa 3 microservice. Team mất 3 tiếng mò log giữa đêm chỉ để debug iptables.
Mô hình Sidecar giải quyết triệt để vấn đề này. Mạng được đóng gói đi kèm ứng dụng. Khi bạn dọn container sang một VPS mới hoặc chuyển giữa các nhà cung cấp Cloud, bạn chỉ cần gõ docker compose up -d là mọi thứ thông mạng ngay lập tức, không phụ thuộc vào cấu hình của máy chủ bên dưới.
Hướng dẫn cấu hình Tailscale Sidecar với Docker Compose
Giả sử chúng ta có 2 dịch vụ cần giao tiếp an toàn:
- Server A (AWS EC2): Chạy database PostgreSQL.
- Server B (Hetzner VPS): Chạy Worker service cần query dữ liệu từ Server A.
Bước 1: Tạo Tailscale Auth Key
Truy cập vào trang quản trị Tailscale, chọn Settings > Keys > Generate auth key. Bật tùy chọn Reusable và gắn tag (ví dụ tag:server). Việc gắn tag giúp key không bị hết hạn sau 90 ngày và tự động cấp quyền theo ACL định trước.
Bước 2: Cấu hình cụm Database trên Server A
Tạo file docker-compose.yml trên Server A với nội dung:
services:
tailscale-db:
image: tailscale/tailscale:v1.64.0
container_name: tailscale-db
hostname: db-node
environment:
- TS_AUTHKEY=tskey-auth-kXXXXX-XXXXXXXXXXXX
- TS_STATE_DIR=/var/lib/tailscale
- TS_EXTRA_ARGS=--accept-routes=false
volumes:
- ./tailscale-state:/var/lib/tailscale
- /dev/net/tun:/dev/net/tun
cap_add:
- NET_ADMIN
- NET_RAW
restart: unless-stopped
postgres:
image: postgres:15-alpine
container_name: production-postgres
network_mode: "service:tailscale-db"
environment:
POSTGRES_USER: admin
POSTGRES_PASSWORD: SecretPassword123!
POSTGRES_DB: app_db
volumes:
- pgdata:/var/lib/postgresql/data
restart: unless-stopped
depends_on:
- tailscale-db
volumes:
pgdata:
3 chi tiết kỹ thuật quan trọng:
- Không khai báo
ports:Container PostgreSQL không expose port ra host, vô hình trước mọi máy quét bên ngoài. - Chung Network Namespace: Dòng
network_mode: "service:tailscale-db"khiến PostgreSQL lắng nghe trực tiếp trên IP nội bộ của Tailscale. - Mount thư mục state: Volume
./tailscale-statelưu giữ identity của node. Nếu thiếu volume này, mỗi lần chạy lại container hệ thống sẽ sinh ra một node mới trên Tailscale Admin.
Bước 3: Khởi chạy và kiểm tra node
Khởi động stack trên Server A:
docker compose up -d
docker compose logs -f tailscale-db
Khi thấy log xuất hiện dòng Boot: ... Success; node is db-node (100.x.y.z), cụm database đã gia nhập mạng mesh an toàn.
Bước 4: Kết nối từ Server B
Trên Server B (đã tham gia cùng mạng Tailscale), bạn có thể kiểm tra đường truyền và latency trực tiếp:
# Ping trực tiếp qua MagicDNS, độ trễ thường chỉ dao động từ 20-35ms giữa các datacenter EU
tailscale ping db-node
# Kiểm tra port PostgreSQL qua mạng riêng WireGuard
nc -zv db-node 5432
Màn hình hiển thị Connection to db-node 5432 port [tcp/*] succeeded!. Chuỗi kết nối của Worker giờ đây chỉ cần trỏ về postgres://admin:SecretPassword123!@db-node:5432/app_db.
Lưu ý thực chiến trên môi trường Production
- Cấp quyền tối thiểu: Chỉ dùng
cap_add: [NET_ADMIN, NET_RAW]. Tránh dùngprivileged: trueđể giảm nguy cơ container breakout. - Khai thác MagicDNS: Dùng hostname
db-nodethay vì hardcode dải IP100.x.y.zđể tránh phải sửa file config khi node tái cấp phát IP. - Giám sát DERP Relay: Lệnh
tailscale statuscho bạn biết kết nối làdirect(P2P WireGuard) hay đi quarelay(DERP). Nếu thấy relay, hãy mở UDP port 41641 ở chiều Outbound để đạt throughput cao nhất.
