Як troubleshoot мережеві проблеми між контейнерами?
Network-troubleshooting в Docker значить йти від DNS вниз до packet-інспекції, поки не знайдеш, де connection ламається. Більшість issue у верхніх трьох layer-ах (неправильна мережа, немає DNS, заблокований port). Тягнись до tcpdump і iptables лише, коли ці провалюються.
Теорія
TL;DR
- Container'и доходять один до одного, лише якщо на тій самій мережі.
- Дефолтний
bridgeбез DNS між container'ами; user-defined bridge мають. - Host-firewall (UFW, firewalld, custom iptables) часто заважає docker0-bridge.
--network=hostшарить host network-namespace; без isolation.- Overlay-мережі (Swarm) потребують UDP 4789 (VXLAN) і MTU нижчий за host.
- Порядок діагностики: layer-by-layer від name-resolution вниз до packet'ів.
Diagnostic checklist
- На якій мережі кожен container?
- Чи DNS resolve'ить peer's name?
- Чи peer's IP reachable (ping)?
- Чи target-port відкритий (nc, telnet)?
- Чи target-сервіс реально слухає на тому port і bind'иться до правильного interface?
- Чи firewall (host або in-container) дропає packet?
- Чи щось не так на layer 2/3 (MTU, MAC-address конфлікт)?
Типи мереж і їхні gotcha
Дефолтний bridge (без імені)
- Auto-присвоюється container'ам без
--network. - Без DNS між container'ами. Імена не resolve'ляться. Треба
--link(deprecated) або IP. - Уникай для всього, крім toy-use.
User-defined bridge (docker network create mynet)
- DNS працює: container'и доходять один до одного за container-ім'ям.
- Isolated від default-bridge.
- Дефолт для Compose-проєктів (один bridge per project).
host-мережа (--network=host)
- Container шарить host network-namespace.
- Port-mapping не потрібен; без isolation.
- Корисно для performance-sensitive випадків або system-tool.
- Linux-only поведінка; на Docker Desktop (Mac/Windows) це не значить host-networking, значить host VM.
Overlay (Swarm)
- Простягається через кілька Docker-host через VXLAN.
- Потребує UDP 4789 між host-ами для VXLAN-трафіку, TCP/UDP 7946 для control-plane.
- MTU mismatch це класичний overlay-bug: VXLAN-encapsulation додає 50 bytes; якщо host-MTU 1500, container-MTU має бути ≤ 1450.
none (--network=none)
- Лише loopback. Використовується для sandbox.
Приклади
Крок 1: підтверди, що обидва container'и на тій самій мережі
docker inspect app --format '{{json .NetworkSettings.Networks}}' | jq
# {
# "my-app-default": {
# "IPAddress": "172.18.0.3",
# "Aliases": ["app", "abc123"]
# }
# }
docker inspect db --format '{{json .NetworkSettings.Networks}}' | jq
# {
# "some-other-network": {
# "IPAddress": "172.19.0.5"
# }
# }Різні мережі: з'єднай їх або перенеси один container.
docker network connect my-app-default db
# тепер db на обох мережахКрок 2: DNS
docker exec app sh -c 'getent hosts db'
# 172.18.0.5 dbЯкщо нічого не resolve'иться: ти ймовірно на default bridge. Перейди на user-defined-мережу.
docker exec app cat /etc/resolv.conf
# nameserver 127.0.0.11 ← embedded Docker-DNS127.0.0.11 це embedded resolver, який Docker injects у user-defined-мережі. Відсутність значить default-bridge issue.
Крок 3: IP-рівень reachability
docker exec app ping -c 3 db
# PING db (172.18.0.5): 56 data bytes
# 64 bytes from 172.18.0.5: seq=0 ttl=64 time=0.080 msБез відповіді: networking-layer зламаний. Перевір iptables:
sudo iptables -L DOCKER-USER -nv
sudo iptables -L DOCKER -nvUFW часто скидає ці chain'и; додай explicit allow або вимкни UFW-втручання.
Крок 4: port-рівень reachability
docker exec app nc -vz db 5432
# Connection to db 5432 port [tcp/postgresql] succeeded!Connection refused: сервіс не слухає на тому port.
Operation timed out: firewall (host або in-container) дропає packet.
# Всередині db-container
docker exec db ss -tlnp
# State Recv-Q Send-Q Local Address:Port
# LISTEN 0 128 127.0.0.1:5432 ← bind на localhost, не на container-interface!Класична помилка: Postgres bind на 127.0.0.1 замість 0.0.0.0 недосяжний з peer-container'ів. Фіксь сервіс-config: listen_addresses = '*' для Postgres.
Крок 5: packet-capture (коли нічого інше не допомагає)
Знайди ім'я bridge:
docker network inspect my-app-default --format '{{.Id}}'
# 4f7c9... (перші 12 chars стають суфіксом bridge-interface name)
ip link show | grep br-
# br-4f7c9...Capture:
sudo tcpdump -i br-4f7c9 -nn 'host 172.18.0.5 and port 5432'Запусти запит з app, дивися flow-packet'ів. SYN без SYN-ACK = firewall drop або сервіс не слухає. Reset = сервіс відмовив.
Крок 6: container-level firewall
Деякі images shipping iptables-rules (security-hardened distro):
docker exec db iptables -L -nv
# Chain INPUT (policy DROP 0 packets, 0 bytes)policy DROP блокує все, що явно не дозволено. Або фікс in-container-rules, або base-image без них.
Типові сценарії і фікс
«Не дотягається до db з app», Compose-проєкт
services:
app:
image: myorg/app
db:
image: postgres:16Compose auto-створює <project>_default-мережу. Обидва сервіси на ній. app дотягається до db за іменем. Має просто працювати.
Якщо ламається: підтверди, що обидва піднялися (docker compose ps), потім:
docker compose exec app ping db
docker compose exec app nc -vz db 5432«Host не може дотягтися до published port container»
docker run -d -p 8080:80 nginx
curl localhost:8080 # працює
curl 192.168.1.5:8080 # не працює з іншої машиниПеревір host-firewall: ufw status, firewall-cmd --list-all, або iptables -L. Відкрий port 8080.
«Container може дотягтися до зовнішнього інтернету, але не до іншого container»
Ймовірно на default bridge (без DNS) або на різних мережах. Перейди на user-defined bridge:
docker network create mynet
docker run --network=mynet --name=app myorg/app
docker run --network=mynet --name=db postgres:16«Випадкові connection-drop або повільний Swarm-overlay»
MTU mismatch. Перевір host-MTU:
ip link show eth0 | grep mtu
# mtu 1500VXLAN-overhead = 50 bytes. Container'и в overlay мають крутитися на MTU 1450 (або 1400 для безпеки через cloud-NAT). Set per-network:
docker network create -d overlay \
--opt com.docker.network.driver.mtu=1450 \
swarm-net«--network=host працює на Linux, fail на Mac»
Docker Desktop крутить Linux у VM. host-networking таргетить VM, не твій Mac. Щоб дотягтися до localhost на Mac з container, бери host.docker.internal.
Корисні tools
nicolaka/netshoot: debug-image зdig,nc,tcpdump,iperf,mtr,tshark. Запускай у тій самій мережі, що misbehaving container:
docker run --rm -it --network=container:app nicolaka/netshoot
# Тепер маєш повний diagnostic-toolkit у network-namespace appdocker logs <container>для логу сервісу; часто failure на listening-стороні.docker exec <container> cat /etc/hosts, щоб побачити, що container бачить як власне ім'я.
Реальне застосування
- «App не дотягається до DB»: 90% часу, мережі misaligned або DNS відсутній. Застосуй кроки 1-2.
- Intermittent-failure: зазвичай MTU на overlay або DNS-TTL з restarting-container'ами.
- Production-outage: tcpdump на bridge, потім iptables. Зроби packet-capture перед тим, як щось перезапускати.
Типові помилки
Ставити сервіси на default-bridge
Без DNS. Завжди створюй user-defined-мережу або покладайся на Compose-auto-network.
Bind сервісу на 127.0.0.1 всередині container
Досяжно лише з того container. Bind на 0.0.0.0, щоб інші container'и могли дотягтися через bridge.
Модифікація host-iptables вручну
Docker переписує iptables на кожному restart. Custom-rules належать у DOCKER-USER-chain (Docker його не чіпає).
Використання --link
Deprecated. Setup'ить /etc/hosts-entries, без DNS. Бери user-defined-мережі.
Питання для поглиблення
Q: Чому default-bridge без DNS?
A: Історично. Default-bridge передує embedded Docker-DNS-server. User-defined-bridge додав DNS, але старий behavior зберегли для compatibility.
Q: Що таке 127.0.0.11?
A: Embedded Docker DNS-resolver. Кожен container у user-defined-мережі має його як nameserver, і запити resolve'ляться у IP інших container'ів.
Q: Як побачити, які packet'и дропаються на host-firewall?
A: Додай logging-rule перед DROP-rule: iptables -I DOCKER-USER -j LOG --log-prefix 'docker-drop: '. Потім dmesg -w показує drop у real time.
Q: (Senior) Як debug'ити overlay-мережу, що працює локально, але втрачає packet'и через host'и?
A: Підтверди, що UDP 4789 (VXLAN) дозволений між host'ами (cloud-security-group часто блокує). Запусти tcpdump -i any port 4789 на обох host'ах під час failing-request. Перевір MTU; знизь до 1400, якщо VXLAN йде через якийсь tunnel, що додає overhead. Інспектуй docker network inspect <overlay> для peer-counts; mismatched-peers значить Swarm-gossip нездоровий.
Q: (Senior) Як детектити MAC-address конфлікти на custom-bridge?
A: docker network inspect <net> перелічує MAC кожного container. Конфлікти приходять з manual --mac-address. Kernel логує bridge: received packet on br0 with own address as source address при конфліктах. Фікс через прибирання manual-MAC-assignment.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів