Skip to main content

Як 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

  1. На якій мережі кожен container?
  2. Чи DNS resolve'ить peer's name?
  3. Чи peer's IP reachable (ping)?
  4. Чи target-port відкритий (nc, telnet)?
  5. Чи target-сервіс реально слухає на тому port і bind'иться до правильного interface?
  6. Чи firewall (host або in-container) дропає packet?
  7. Чи щось не так на 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'и на тій самій мережі

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

bash
docker network connect my-app-default db # тепер db на обох мережах

Крок 2: DNS

bash
docker exec app sh -c 'getent hosts db' # 172.18.0.5 db

Якщо нічого не resolve'иться: ти ймовірно на default bridge. Перейди на user-defined-мережу.

bash
docker exec app cat /etc/resolv.conf # nameserver 127.0.0.11 ← embedded Docker-DNS

127.0.0.11 це embedded resolver, який Docker injects у user-defined-мережі. Відсутність значить default-bridge issue.

Крок 3: IP-рівень reachability

bash
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:

bash
sudo iptables -L DOCKER-USER -nv sudo iptables -L DOCKER -nv

UFW часто скидає ці chain'и; додай explicit allow або вимкни UFW-втручання.

Крок 4: port-рівень reachability

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

bash
# Всередині 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:

bash
docker network inspect my-app-default --format '{{.Id}}' # 4f7c9... (перші 12 chars стають суфіксом bridge-interface name) ip link show | grep br- # br-4f7c9...

Capture:

bash
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):

bash
docker exec db iptables -L -nv # Chain INPUT (policy DROP 0 packets, 0 bytes)

policy DROP блокує все, що явно не дозволено. Або фікс in-container-rules, або base-image без них.

Типові сценарії і фікс

«Не дотягається до db з app», Compose-проєкт

yaml
services: app: image: myorg/app db: image: postgres:16

Compose auto-створює <project>_default-мережу. Обидва сервіси на ній. app дотягається до db за іменем. Має просто працювати.

Якщо ламається: підтверди, що обидва піднялися (docker compose ps), потім:

bash
docker compose exec app ping db docker compose exec app nc -vz db 5432

«Host не може дотягтися до published port container»

bash
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:

bash
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:

bash
ip link show eth0 | grep mtu # mtu 1500

VXLAN-overhead = 50 bytes. Container'и в overlay мають крутитися на MTU 1450 (або 1400 для безпеки через cloud-NAT). Set per-network:

bash
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:
bash
docker run --rm -it --network=container:app nicolaka/netshoot # Тепер маєш повний diagnostic-toolkit у network-namespace app
  • docker 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.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Коментарі

Ще немає коментарів