ťařina
Obsah Soubory
Virtualizace a kontejnery

Sítě v Dockeru

Aktualizováno 3 min čtení 555 slov

Sítě v Dockeru

Docker vytváří virtuální sítě a většina zmatků kolem něj pramení z toho, že si člověk neuvědomí, že kontejner je vlastní stroj s vlastním síťovým prostorem.

Souvislost s bezpečností je v Docker a firewall — přečti si to, i když tě sítě jinak nezajímají.

Režimy

Režim Co dělá Kdy použít
bridge vlastní privátní síť, NAT ven výchozí, skoro vždy
host kontejner sdílí síť hostitele když potřebuješ výkon nebo broadcast
macvlan kontejner má vlastní MAC a IP ve tvé LAN když má vypadat jako fyzické zařízení
none žádná síť izolované výpočty

bridge

Výchozí. Docker udělá virtuální switch docker0, kontejnery dostanou adresy z 172.17.0.0/16 a ven jdou přes NAT.

Zásadní rozdíl proti výchozí síti: v uživatelsky vytvořené síti funguje DNS podle jmen kontejnerů, ve výchozí bridge ne. Proto vždycky vytvářej vlastní síť, nebo používej Compose, který to dělá sám.

docker network create moje-sit
docker run -d --network moje-sit --name db postgres
docker run -d --network moje-sit --name app mojeapp
# app se na databázi připojí přes hostname "db"

host

Kontejner nemá vlastní síť, používá přímo hostitelovu. Žádný NAT, žádné mapování portů — co kontejner otevře, je otevřené na stroji.

Použij pro věci, které potřebují vidět broadcast nebo mDNS: Home Assistant, Pi-hole, monitorovací sondy.

Cenou je ztráta izolace a to, že -p přestane fungovat (a nedává smysl).

macvlan

Kontejner dostane vlastní MAC adresu a IP přímo z tvé LAN. Z pohledu sítě je to samostatné zařízení a můžeš mu dát vlastní VLANu i firewallová pravidla.

docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 \
  lan-sit

Jedna past, která překvapí každého: hostitel se na macvlan kontejnery nedostane. Je to omezení jádra, ne chyba konfigurace. Obchází se to vytvořením pomocného macvlan rozhraní na hostiteli, ale je to otrava. Když potřebuješ komunikaci hostitel–kontejner, macvlan není správná volba.

Co dělá -p doopravdy

docker run -p 8080:80 nginx

Levé číslo je port na hostiteli, pravé v kontejneru. Docker k tomu vytvoří DNAT pravidlo v netfilteru.

Vazba na rozhraní je klíčová pro bezpečnost:

-p 8080:80              # 0.0.0.0, tedy všude včetně internetu
-p 127.0.0.1:8080:80    # jen z hostitele
-p 192.168.1.5:8080:80  # jen přes konkrétní adresu

Podrobně v Docker a firewall.

localhost v kontejneru není hostitel

Nejčastější chyba začátečníků. Když v kontejneru napíšeš localhost nebo 127.0.0.1, míníš tím ten kontejner, ne hostitele ani jiný kontejner.

Jak se dostat kam:

Odkud kam Adresa
kontejner → jiný kontejner ve stejné síti jméno kontejneru, třeba db
kontejner → hostitel host.docker.internal (Docker Desktop) nebo IP mostu
kontejner → internet normálně, přes NAT
hostitel → kontejner localhost:publikovaný-port

Na Linuxu host.docker.internal ve výchozím stavu nefunguje. Přidej:

extra_hosts:
  - "host.docker.internal:host-gateway"

Compose

Compose vytvoří pro každý projekt vlastní síť a kontejnery se v ní vidí podle jmen služeb. To je obvykle přesně to, co chceš.

Rozumný vzor pro self-hosting: jediná služba s publikovanými porty je proxy, ostatní jsou vnitřní.

services:
  caddy:
    image: caddy:2
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
    networks: [web]

  app:
    image: mojeapp
    expose: ["3000"]
    networks: [web, backend]

  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_heslo
    networks: [backend]
    volumes:
      - db_data:/var/lib/postgresql/data

networks:
  web:
  backend:
    internal: true

volumes:
  caddy_data:
  db_data:

Dvě věci, které stojí za povšimnutí:

internal: true znamená, že síť backend nemá cestu ven. Databáze se nedostane na internet ani kdyby chtěla. Užitečné proti exfiltraci a proti tomu, aby si image samo něco stahovalo.

Aplikace je ve dvou sítích. Vidí proxy i databázi, ale proxy databázi nevidí. Minimální propojení.

Diagnostika

docker network ls
docker network inspect moje-sit
docker ps --format "table {{.Names}}\t{{.Ports}}"

# z kontejneru, i když v něm nejsou nástroje
docker run --rm -it --network moje-sit nicolaka/netshoot bash

Ten poslední trik je zlatý. netshoot je image plný síťových nástrojů — připojíš ho do stejné sítě jako problémový kontejner a máš k dispozici dig, tcpdump, curl, nmap a všechno ostatní z nástrojů.

Odposlech provozu kontejneru z hostitele:

docker network inspect moje-sit -f '{{.Id}}' | cut -c1-12   # zjistí id
tcpdump -i br-<id> -n

Časté potíže

Kontejnery se nevidí podle jména → jsi ve výchozí síti bridge. Vytvoř vlastní.

Kontejner se nedostane na internet → chybí forwarding (net.ipv4.ip_forward=1), nebo ti do toho mluví vlastní firewall. Viz Docker a firewall.

Kolize adresního rozsahu s LAN → Docker používá 172.17.0.0/16, což se občas potká s firemní VPN. Změň v /etc/docker/daemon.json:

{ "default-address-pools": [{"base": "10.200.0.0/16", "size": 24}] }

DNS v kontejneru nefunguje → kontejner dědí resolver z hostitele. Když máš systemd-resolved s 127.0.0.53, kontejner na to nedosáhne. Nastav v daemon.json konkrétní servery:

{ "dns": ["192.168.1.1", "1.1.1.1"] }