Docker networking: bridge, host, overlay khác nhau thế nào

SSH vào VPS, chạy docker run -d nginx xong, container có IP riêng và chạy ngon lành. Nhưng thử expose port thì sao? Nối nhiều container với nhau? Kết nối container qua nhiều máy chủ? Đó là lúc bạn cần hiểu về mạng Docker. Bridge, host, overlay là ba chế độ mạng chính. Dùng sai kiểu là performance tụt, bảo mật lỏng, hoặc container không nói chuyện được với nhau. Bài này mình phân tích cụ thể từng loại, kèm lệnh cấu hình, benchmark và lỗi hay gặp. Làm trên VPS cả thảy, nên kiểu gì bạn cũng dùng được.
Yêu cầu trước khi bắt đầu
- VPS chạy Linux (Ubuntu 24.04 LTS hoặc Debian 12). Hướng dẫn này dùng Ubuntu.
- Docker CE đã cài đặt. Nếu chưa:
apt update && apt install docker.io -yrồisystemctl start docker && systemctl enable docker. - Quyền
sudohoặc root. Tài khoản hiện tại nằm trong groupdocker(nếu không:sudo usermod -aG docker $USERrồi logout/login lại). - Có ít nhất 2 VPS hoặc node trong Docker Swarm nếu muốn test overlay, nếu chỉ có 1 VPS thì dùng bridge và host vẫn được.
Vì sao container cần network?
Container là tiến trình cô lập. Mặc định không thấy nhau, không thấy host. Docker cung cấp lớp mạng ảo (network driver) để container có thể giao tiếp, giữa container với nhau, container với host, hoặc container với mạng bên ngoài. Mỗi driver có cách xử lý khác nhau về cô lập, hiệu năng, và phạm vi kết nối. Bridge là mặc định cho container đơn lẻ. Host dùng khi cần tốc độ tối đa. Overlay dùng khi chạy container trên nhiều máy chủ. Xoay quanh ba driver này, bạn giải quyết gần như mọi bài toán mạng Docker.
Bước 1, Bridge network: chế độ mặc định, cô lập từng container
Bridge là driver mặc định. Khi bạn chạy docker run không thêm --network, container sẽ nối vào mạng bridge tên bridge (thường là docker0 trên host). Mỗi container được cấp một IP thuộc dải 172.17.0.0/16 (mặc định). Container trên cùng bridge có thể giao tiếp qua IP. Không cùng bridge thì không thấy nhau, đó là cô lập cơ bản.
Kiểm tra bridge mặc định:
docker network ls
# Kết quả: NETWORK ID NAME DRIVER SCOPE
# ... bridge bridge local
docker network inspect bridge | grep -E '"Subnet"|"Gateway"'
# Output mẫu:
# "Subnet": "172.17.0.0/16",
# "Gateway": "172.17.0.1"
Chạy hai container và kiểm tra kết nối:
docker run -d --name c1 alpine sleep 3600
docker run -d --name c2 alpine sleep 3600
docker exec c1 ping -c 2 c2
# Lỗi: ping: bad address 'c2', vì DNS không resolve tên container trên bridge mặc định
docker exec c1 ping -c 2 172.17.0.3
# OK, ping thành công nếu bạn biết IP của c2
Nhược điểm của bridge mặc định: không có DNS name resolution cho tên container. Để giải quyết, tạo bridge riêng (user-defined bridge):
docker network create mybridge
docker run -d --name c3 --network mybridge alpine sleep 3600
docker run -d --name c4 --network mybridge alpine sleep 3600
docker exec c3 ping -c 2 c4
# OK, giờ c3 có thể ping c4 bằng tên container
Expose port ra ngoài: bridge mặc định không expose port. Phải dùng -p:
docker run -d --name web -p 8080:80 nginx:alpine
curl http://localhost:8080
# Trả về HTML của Nginx, port 8080 host ánh xạ vào port 80 container
Khi nào dùng bridge: hầu hết container đơn lẻ hoặc nhóm container giao tiếp nội bộ trên cùng một VPS (ví dụ web + database). Cô lập tốt, NAT qua host khi cần ra ngoài. Thích hợp cho dev, staging, và cả production với ứng dụng ít container.
Bước 2, Host network: bỏ lớp ảo hóa, dùng trực tiếp mạng host
Host network loại bỏ hoàn toàn lớp mạng ảo. Container dùng thẳng network stack của máy chủ. Nghĩa là container thấy tất cả interface mạng của host, không có NAT, không có IP riêng. Port container mở là port host. -p bị vô hiệu hóa, không cần và cũng không dùng được.
Chạy container với host network:
docker run -d --name nginx-host --network host nginx:alpine
curl http://localhost:80
# Nginx chạy trực tiếp trên port 80 host, không cần -p
docker exec nginx-host ip addr show
# Bạn sẽ thấy địa chỉ của host, không có địa chỉ 172.17.x.x
Hiệu năng: vì không qua bridge NAT, host network cho latency thấp hơn và throughput cao hơn. Tuy nhiên mức chênh thường không đáng kể với ứng dụng web thông thường. Bạn chỉ thấy rõ khi chạy ứng dụng network-heavy như streaming, game server, proxy với throughput cực lớn.
Hạn chế lớn: không thể chạy hai container cùng port trên host network, vì cùng dùng một port host. Mất cô lập. Container có thể quét và gắn vào bất kỳ socket nào của host. Về bảo mật, host network là lựa chọn rủi ro hơn bridge.
Khi nào dùng host: ứng dụng cần performance mạng tối đa (benchmark, real-time, proxy tốc độ cao), hoặc container cần bind vào địa chỉ IP cụ thể của host (ví dụ chạy MetalLB trong Kubernetes). Dùng trên VPS chạy một service riêng biệt. Nếu bạn chạy nhiều service trên cùng một VPS (ví dụ Nginx + database + cache), host network gây xung đột port, bridge vẫn là lựa chọn an toàn hơn.
Bước 3, Overlay network: kết nối container qua nhiều máy chủ
Overlay network dùng cho multi-host, container trên VPS này nói chuyện với container trên VPS khác như thể cùng mạng nội bộ. Docker Swarm hoặc Kubernetes dùng overlay làm xương sống. Dưới hood, Docker dùng VXLAN tunnel để đóng gói packet và gửi qua mạng vật lý. Mỗi container được cấp IP riêng trong dải overlay, bất kể container chạy trên node nào.
Yêu cầu: cần Docker Swarm hoặc Kubernetes. Với Docker thuần, overlay chỉ hoạt động trong Swarm mode. Nếu chưa có Swarm:
# Trên node manager
docker swarm init --advertise-addr 203.0.113.10
# Output: Swarm initialized ... docker swarm join --token ...
# Trên node worker (chạy token lấy từ lệnh trên)
docker swarm join --token SWMTKN-1-xxxxxxxxx 203.0.113.10:2377
Tạo overlay network và chạy service:
docker network create --driver overlay --attachable myoverlay
docker service create --name web --network myoverlay --replicas 3 nginx:alpine
# Service này chạy 3 replicas rải trên các node Swarm, tất cả nối vào myoverlay
docker service ps web
# Xem container đang chạy trên node nào
Kiểm tra kết nối cross-node: exec vào container trên node manager, ping container trên node worker.
docker exec -it $(docker ps -q --filter name=web.1) sh
/ # ping web.2
# Thành công, container trên node manager nói chuyện với container trên node worker
Hiệu năng overlay: thấp hơn bridge và host vì packet phải đóng gói VXLAN (thêm ~50-100 byte overhead) và đi qua mạng vật lý giữa các node. Latency tăng. Trên VPS Việt Nam với băng thông trong nước 100 Mbps và latency nội địa thấp, overlay vẫn dùng tốt cho web service và microservices. Nếu bạn chạy ứng dụng sensitive với latency (gaming, trading), cân nhắc bridge + kết nối qua IP public thay vì overlay.
Khi nào dùng overlay: khi bạn cần multi-host, orchestration (Swarm, Kubernetes), microservices phân tán, hoặc muốn container di chuyển giữa các VPS mà không đổi IP. Overlay cũng cho phép service discovery bằng DNS tích hợp.
Bảng so sánh ba driver mạng Docker
| Tiêu chí | Bridge | Host | Overlay |
|---|---|---|---|
| Cô lập mạng | Cao, mỗi container có IP riêng | Không, dùng chung stack host | Cao, IP riêng trong mạng ảo |
| DNS nội bộ theo tên | Có (user-defined bridge) | Không | Có |
| Expose port từ container | -p host:container | Tự động dùng port host | --publish trong service |
| Hiệu năng mạng | Trung bình (qua NAT bridge) | Cao nhất | Thấp hơn bridge (VXLAN overhead) |
| Multi-host | Không | Không | Có |
| Swarm / Kubernetes | Hỗ trợ cục bộ | Không khuyến nghị | Mặc định cho Swarm service |
| Dùng khi nào | Single host, nhóm container | Performance tối đa, 1 service | Multi-host, microservices |
Xử lý lỗi thường gặp với Docker network
1. Container không ping được container khác trên bridge mặc định
Nguyên nhân: bridge mặc định không có DNS name resolution. Giải pháp: tạo user-defined bridge. docker network create mynet rồi chạy container với --network mynet. Kiểm tra: docker exec -it container1 ping container2.
2. Port conflict trên host network
Error: starting container: failed to create endpoint on network host: bind: address already in use. Nguyên nhân: hai container cùng port. Giải pháp: dùng bridge thay host, hoặc gán container khác port (dùng -p 8081:80).
3. Overlay không kết nối được cross-node
Kiểm tra Docker Swarm đang hoạt động: docker node ls. Nếu node worker không join được, kiểm tra port 2377 TCP (Swarm management), 7946 TCP/UDP (gossip), 4789 UDP (VXLAN). Trên VPS, nếu dùng ufw: ufw allow 2377/tcp && ufw allow 7946/tcp && ufw allow 7946/udp && ufw allow 4789/udp && ufw reload. Nếu dùng firewalld: firewall-cmd --add-port={2377/tcp,7946/tcp,7946/udp,4789/udp} --permanent && firewall-cmd --reload.
4. Container mất kết nối internet sau khi gắn vào user-defined bridge
Kiểm tra docker network inspect mynet có thấy gateway không. Nếu gateway là 172.x.x.1 và container vẫn không ra internet, kiểm tra IP forwarding trên host: sysctl net.ipv4.ip_forward. Nếu bằng 0: echo 'net.ipv4.ip_forward=1' >> /etc/sysctl.conf && sysctl -p.
Kết luận thực tế
Ba driver mạng Docker, bridge, host, overlay, không thay thế nhau. Mỗi loại giải quyết một bài toán khác nhau. Với hầu hết ứng dụng trên một VPS Linux, bridge là lựa chọn mặc định hàng đầu: cô lập, dễ expose port, dễ debug. Dùng host chỉ khi bạn thực sự cần từng Mbps và chỉ chạy một service. Dùng overlay khi bạn chạy ứng dụng trên nhiều VPS và muốn có mạng ảo trong suốt. Lời khuyên: bắt đầu với bridge, đừng vội dùng host trừ khi bạn đo được bridge đang là bottleneck. Và nếu bạn đã có máy chủ riêng với nhiều VPS ảo hóa, overlay cho phép bạn xây dựng cụm Swarm mà container có thể chạy bất kỳ đâu, rất tiện cho microservices và CI/CD.
Câu hỏi thường gặp
Có nên dùng host network cho web server production không?
Nếu bạn chỉ chạy một container web riêng biệt trên VPS và cần latency thấp nhất, host network là option. Nhưng nếu có nhiều service (web + api + cache), bridge an toàn hơn vì tránh conflict port và có cô lập. Benchmark thử trước khi quyết định.
Overlay network có chạy được nếu không dùng Swarm không?
Có thể, nhưng không đơn giản. Bạn phải cấu hình thủ công key-value store (Consul, etcd) và dùng docker network create --driver overlay --attachable, nhưng Docker không khuyến nghị cho production. Thực tế overlay gắn liền với Swarm hoặc Kubernetes.
Bridge network ảnh hưởng đến bảo mật không?
Bridge cô lập container ở layer 3. Container trên cùng bridge thấy nhau. Nếu cần cách ly rất cao, dùng bridge riêng cho từng nhóm container. Trong user-defined bridge, nếu không attach container vào, nó không tự động thấy.
Macvlan và ipvlan có nằm trong ba loại này không?
Không. Macvlan và ipvlan là driver riêng, cho phép container có MAC/IP thật trên mạng vật lý. Dùng khi cần tích hợp trực tiếp vào hạ tầng mạng hiện có, ví dụ legacy network policy. Hiệu năng cao hơn bridge nhưng phức tạp hơn khi cấu hình.
Làm sao kiểm tra network driver nào container đang dùng?
Chạy docker inspect <container_name> | jq '.[].HostConfig.NetworkMode'. Kết quả trả về bridge, host, overlay, hoặc tên network custom.
Bài viết liên quan
- Cách cài Docker trên VPS Ubuntu chi tiết từ A đến Z
- Cài đặt và tối ưu Nginx làm reverse proxy trên Ubuntu 24.04
- VPS là gì? So sánh VPS với Hosting và Dedicated Server


