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

```bash
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](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.

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

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

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

```yaml
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í.

```yaml
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

```bash
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ů](Nastroje).

Odposlech provozu kontejneru z hostitele:

```bash
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](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"] }
```
