markdown
Site-v-Dockeru.md
markdown
# 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](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](NAT-a-port-forwarding). 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. ```bashdocker network create moje-sitdocker run -d --network moje-sit --name db postgresdocker 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](MAC-ARP-a-prepinani) a IP přímo z tvé LAN. Z pohledu sítě je to samostatné zařízení a můžeš mu dát vlastní [VLANu](VLANy) i firewallová pravidla. ```bashdocker 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 ```bashdocker 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: ```bash-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](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: ```yamlextra_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í. ```yamlservices: 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 ```bashdocker network lsdocker network inspect moje-sitdocker ps --format "table {{.Names}}\t{{.Ports}}" # z kontejneru, i když v něm nejsou nástrojedocker 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ů](Nastroje). Odposlech provozu kontejneru z hostitele: ```bashdocker network inspect moje-sit -f '{{.Id}}' | cut -c1-12 # zjistí idtcpdump -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](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`: ```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: ```json{ "dns": ["192.168.1.1", "1.1.1.1"] }```