Bối cảnh thực tế: Khi Docker Bridge trở thành nút thắt cổ chai
Hơn nửa năm trước, cụm server nội bộ bên mình (quản lý khoảng 50 nhân sự và 12 node datacenter) bắt đầu xuất hiện tình trạng rớt gói kỳ lạ. Bình thường, Docker bridge mặc định với iptables NAT (masquerading) vận hành rất mượt cho các cụm API hay web app. Bạn chỉ cần -p 8080:80 là xong.
Mọi chuyện vỡ vụn khi mình migrate hệ thống voice Asterisk (SIP/RTP), 30 camera RTSP và bộ agent SNMP giám sát hạ tầng vào container. Lúc này, tầng NAT bộc lộ ba điểm yếu chí mạng:
- Cháy bảng conntrack: Mỗi cuộc gọi SIP/RTP mở hàng nghìn port UDP ngẫu nhiên. Bảng
nf_conntrackcủa kernel liên tục chạm ngưỡng 262.144 sessions. CPU host tăng vọt từ 15% lên 75% chỉ để duyệt rule iptables. - Mất dấu IP gốc: Mọi request ra ngoài đều mang IP của host Docker. Muốn phân quyền firewall pfSense cho từng container theo IP riêng là điều bất khả thi.
- Điếc broadcast/multicast: Docker bridge cô lập broadcast domain. Kết quả là các dịch vụ tự discovery như mDNS, BACnet hay camera ONVIF không thể nhìn thấy container.
Để xử lý triệt để, mình chuyển sang kéo container ra thẳng mạng LAN vật lý thông qua hai driver Linux kernel: Macvlan và IPVlan.
Chọn Macvlan hay IPVlan?
Sau nhiều tháng vận hành song song trên production, mình rút ra bảng so sánh nhanh:
- Macvlan: Kernel sinh riêng một địa chỉ MAC ảo cho mỗi container. Switch coi container như máy vật lý cắm trực tiếp vào port. Điểm trừ: Dễ đụng tính năng Port Security trên switch Cisco/Aruba (mặc định chỉ cho học 1–2 MAC/port). Trên hạ tầng VMware ESXi hoặc AWS/GCP, gói tin sẽ bị drop ngay do cơ chế chặn MAC spoofing.
- IPVlan (L2 mode): Tất cả container dùng chung địa chỉ MAC của card mạng vật lý, nhưng giữ IP riêng biệt. Switch chỉ thấy duy nhất một MAC của host. Nhờ đó, bạn vượt qua rào cản Port Security dễ dàng. IPVlan là lựa chọn hoàn hảo cho môi trường máy ảo hoặc cloud nội bộ.
Chuẩn bị môi trường mạng host
Trước tiên, hãy xác định card mạng chính (ở đây mình dùng eth0) và dải subnet hiện hành:
ip -br addr show eth0
Bật IP forwarding trên Linux host để gói tin trung chuyển thông suốt:
sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.d/99-docker-network.conf
Lưu ý hạ tầng: Nếu dùng Macvlan trên VMware ESXi, bạn phải vào vSwitch hoặc Port Group và bật Accept cho cả hai mục Promiscuous Mode và MAC Address Changes.
Thực hành cấu hình chi tiết
1. Triển khai Macvlan
Giả sử mạng văn phòng là 192.168.1.0/24, gateway 192.168.1.1. Hãy trích riêng một dải nhỏ (ví dụ 192.168.1.192/27, gồm 30 IP) cấp cho Docker để tránh xung đột với DHCP pool:
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--ip-range=192.168.1.192/27 \
--gateway=192.168.1.1 \
-o parent=eth0 \
macvlan_lan
Khởi chạy container với IP tĩnh mong muốn:
docker run -d --name legacy-app \
--net=macvlan_lan \
--ip=192.168.1.200 \
--restart=always \
nginx:alpine
Xử lý lỗi kinh điển: Host không ping được Container
Theo thiết kế bảo mật của Linux kernel, card mạng vật lý sẽ drop toàn bộ lưu lượng định tuyến trực tiếp giữa host và child Macvlan interface. Bạn ping từ host sang 192.168.1.200 sẽ time out 100%, dù máy tính khác trong phòng vẫn mở web vù vù.
Giải pháp là tạo thêm một sub-interface macvlan ngay trên host:
# 1. Tạo macvlan interface ảo trên host
sudo ip link add mac0 link eth0 type macvlan mode bridge
# 2. Gán IP riêng và kích hoạt (chọn 1 IP chưa dùng trong subnet)
sudo ip addr add 192.168.1.220/32 dev mac0
sudo ip link set mac0 up
# 3. Trỏ route dải IP container qua interface vừa tạo
sudo ip route add 192.168.1.192/27 dev mac0
Giờ đây host và container đã có thể trao đổi dữ liệu mượt mà.
2. Triển khai IPVlan (Chế độ L2)
Trên máy ảo Proxmox hoặc cloud chặn MAC spoofing, IPVlan L2 là lựa chọn tối ưu. Cú pháp khởi tạo rất quen thuộc:
docker network create -d ipvlan \
--subnet=192.168.1.0/24 \
--ip-range=192.168.1.224/28 \
--gateway=192.168.1.1 \
-o ipvlan_mode=l2 \
-o parent=eth0 \
ipvlan_lan
Gán container vào network IPVlan:
docker run -d --name voip-service \
--net=ipvlan_lan \
--ip=192.168.1.225 \
alpine sleep 3600
Kiểm tra và xác thực cấu hình
Sau khi dựng xong, bạn nên kiểm tra bảng ARP và packet flow để chắc chắn mọi thứ chuẩn xác.
Xác nhận IP và gateway trong container
# Kiểm tra IP thực tế container nhận được
docker exec -it legacy-app ip -br addr show
# Ping ra gateway kiểm tra kết nối L2
docker exec -it legacy-app ping -c 3 192.168.1.1
Bắt gói tin kiểm tra địa chỉ MAC
Đứng từ một máy khác trong mạng LAN, ping liên tục vào container (192.168.1.200). Đồng thời, mở terminal host và chạy tcpdump:
sudo tcpdump -i eth0 icmp and host 192.168.1.200 -n -e
Nếu là Macvlan, MAC đích trên log tcpdump sẽ là địa chỉ MAC ảo riêng của container. Nếu là IPVlan, MAC đích sẽ trùng khớp hoàn toàn với MAC của card mạng eth0 trên host.
Đúc kết
Nếu chỉ chạy web API hay microservice thông thường, bridge network vẫn là phương án tiện nhất nhờ tính cơ động. Ngược lại, khi gặp bài toán VoIP, RTSP camera hay dịch vụ L2 discovery, việc đưa container ra thẳng LAN bằng Macvlan hoặc IPVlan sẽ giảm tải CPU ngoạn mục, gỡ bỏ nút thắt NAT và giúp quy hoạch firewall mạng chuẩn chỉ hơn.

