Triệu chứng chính: trong container ping 1.1.1.1 hoặc curl https://example.com timeout, Temporary failure in name resolution, curl http://<host>:8080 từ máy khác bị Connection refused, hoặc TLS handshake/git clone/apt treo giữa chừng trong khi gói nhỏ vẫn đi được.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
| Container không ra internet, host vẫn ra được | net.ipv4.ip_forward=0 hoặc rule MASQUERADE của Docker bị xoá (firewalld/nftables reload, iptables -F) |
sysctl -w net.ipv4.ip_forward=1, rồi systemctl restart docker để Docker tạo lại rule |
| Ping IP được nhưng không resolve tên | Host chỉ có nameserver loopback (dnsmasq local, 127.0.0.1...). Container không dùng được loopback của host nên Docker bỏ đi và fallback về 8.8.8.8/8.8.4.4, bị firewall công ty chặn |
Đặt "dns": ["192.0.2.53"] trong daemon.json hoặc --dns khi run |
| Container A không gọi được container B bằng tên | Cả hai nằm trên bridge mặc định docker0 (không có DNS nội bộ) |
Tạo network riêng docker network create appnet, Compose tự làm việc này |
Connection refused khi gọi port đã publish |
App trong container listen 127.0.0.1 |
App phải listen 0.0.0.0 (hoặc ::) |
| Publish port bỏ qua ufw/firewalld | Docker chèn rule NAT/DOCKER chain trước rule của ufw |
Publish 127.0.0.1:8080:80 nếu chỉ cần local, hoặc thêm rule vào chain DOCKER-USER |
| Port chỉ truy cập được từ host, máy khác không vào được | Publish dạng 127.0.0.1:8080:80 |
Bỏ IP hoặc dùng IP interface ngoài |
--network host mà -p không có tác dụng |
Chế độ host dùng chung stack mạng host, không có NAT | Bỏ -p, app listen trực tiếp port trên host |
HTTPS/git clone/apt treo, request nhỏ vẫn qua |
MTU đường ra nhỏ hơn 1500 (VPN, VXLAN, PPPoE), PMTUD bị chặn | Đặt MTU network Docker nhỏ hơn uplink (xem dưới) |
| Mạng nội bộ công ty không tới được từ container | Subnet bridge Docker (mặc định 172.17.0.0/16, network mới lấy từ 172.18+) trùng subnet thật |
Đổi bip và default-address-pools trong daemon.json |
Sau khi đổi daemon.json, Docker không start |
JSON sai cú pháp hoặc trùng tuỳ chọn với flag trong unit systemd | dockerd --validate và journalctl -u docker -n 50 |
Các bước khoanh vùng
flowchart TD A["Container lỗi mạng"] --> B{"ping IP ngoài được?"} B -->|Không| C["ip_forward, iptables/nft MASQUERADE"] B -->|Có| D{"Resolve DNS được?"} D -->|Không| E["resolv.conf trong container, dns trong daemon.json"] D -->|Có| F{"Gói lớn/TLS treo?"} F -->|Có| G["MTU"] F -->|Không| H["Port publish, listen address, firewall"]
- Kiểm tra từ trong container bằng image có đủ công cụ:
docker run --rm -it --network container:<c> nicolaka/netshoot(dùng chung network namespace với container lỗi). - Kiểm tra trên host: route, NAT, forwarding. Bắt gói trên
docker0hoặcbr-<id>bằng tcpdump, xem tcpdump cheatsheet. - So MTU giữa uplink của host và interface trong container.
- Hiểu bản chất veth/bridge/netns: Linux namespaces và cgroups.
Cấu hình đúng
{
"dns": ["192.0.2.53", "198.51.100.53"],
"mtu": 1400,
"bip": "198.18.0.1/24",
"default-address-pools": [
{ "base": "198.18.64.0/18", "size": 24 }
]
}mtutrongdaemon.jsonchỉ áp dụng cho bridge mặc địnhdocker0. Network do người dùng/Compose tạo cần đặt riêng:
networks:
default:
driver_opts:
com.docker.network.driver.mtu: "1400"docker network create -o com.docker.network.driver.mtu=1400 appnet- Chặn truy cập port publish từ ngoài, chỉ cho subnet quản trị:
iptables -I DOCKER-USER -i eth0 ! -s 203.0.113.0/24 -j DROPĐổi bip/default-address-pools cần restart Docker và tạo lại network (docker compose down && docker compose up -d). Network cũ giữ nguyên subnet cũ.
Kiểm tra nhanh
# Trên host
sysctl net.ipv4.ip_forward
ip -br addr show docker0; ip route
iptables -t nat -S POSTROUTING | grep MASQUERADE # hoặc: nft list ruleset | grep -i masq
docker network ls
docker network inspect bridge -f '{{json .IPAM.Config}}'
ss -ltnp | grep 8080
ip link show eth0 | grep -o 'mtu [0-9]*'
# Trong container (netshoot)
cat /etc/resolv.conf
ip -br addr; ip route
ping -c2 1.1.1.1 && dig example.com
ping -c2 -M do -s 1472 1.1.1.1 # fail mà -s 1372 qua => MTU đường ra < 1500
curl -sv https://example.com -o /dev/nullDNS nội bộ của user-defined network là 127.0.0.11 trong /etc/resolv.conf của container. Thấy địa chỉ này là bình thường, Docker sẽ forward ra DNS của host.