Sổ tay kỹ thuật

Docker networking – container không ra mạng, DNS, port, MTU

troubleshooting#docker#linux#troubleshooting· cập nhật 2026-11-06

Khoanh vùng khi container không ra internet, không resolve DNS, port publish không truy cập được hoặc kết nối treo do MTU.

Sửa trang này
Mục lục

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"]
  1. 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).
  2. Kiểm tra trên host: route, NAT, forwarding. Bắt gói trên docker0 hoặc br-<id> bằng tcpdump, xem tcpdump cheatsheet.
  3. So MTU giữa uplink của host và interface trong container.
  4. Hiểu bản chất veth/bridge/netns: Linux namespaces và cgroups.

Cấu hình đúng

/etc/docker/daemon.json
{
  "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 }
  ]
}
  • mtu trong daemon.json chỉ áp dụng cho bridge mặc định docker0. Network do người dùng/Compose tạo cần đặt riêng:
compose.yaml
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/null

DNS 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.