Modul 7 — Virtualizace a kontejnery: Docker

32. Docker networking a persistentní data (volumes)

Jak spolu kontejnery komunikují přes Docker sítě a jak řešit persistentní data pomocí volumes a bind mountů.

Odhadovaná délka studia: 55 minut · Stav: nehotovo

Technologie: Docker

Úvod a kontext

Kontejner je z principu efemérní — když ho smažete, zmizí s ním i
všechna data zapsaná do jeho zapisovatelné vrstvy. To je v pořádku pro
bezstavové aplikace, ale prakticky každá reálná aplikace potřebuje buď
komunikovat s jinými kontejnery (databáze, cache, další služby), nebo
si někde trvale uchovávat data (databázové soubory, nahrané soubory
uživatelů, logy). Docker řeší obojí: sítě (networking) pro
komunikaci mezi kontejnery a volumes pro persistentní data, která
přežijí i smazání kontejneru.

Teorie

Docker networking

Docker při instalaci vytvoří několik výchozích sítí, které lze zobrazit
příkazem docker network ls:

  • bridge — výchozí síť pro kontejnery spuštěné bez explicitního
    --network. Kontejnery v ní vidí jeden na druhého jen přes IP adresu,
    ne přes jméno (DNS resolution zde nefunguje).
  • host — kontejner sdílí síťový stack přímo s hostitelským strojem,
    žádná izolace, žádný port mapping (-p) není potřeba, ale ztrácí se
    síťová izolace.
  • none — kontejner nemá žádné síťové rozhraní kromě loopbacku.

Pro reálné multi-kontejnerové aplikace se v praxi téměř vždy vytváří
vlastní bridge síť (docker network create). Uvnitř takové sítě
funguje automatický DNS resolving podle jména kontejneru — kontejner
web se může připojit ke kontejneru db prostě pod hostname db, bez
znalosti jeho IP adresy. Toto je zásadní rozdíl oproti výchozí bridge
síti a je to hlavní důvod, proč se vlastní sítě používají.

docker network create app-net
docker run -d --name db --network app-net postgres:16
docker run -d --name web --network app-net -p 8000:8000 mojeaplikace
# uvnitř kontejneru web funguje: psql -h db -U postgres

Kontejner může být připojen i k více sítím současně (docker network connect), což se hodí například pro reverzní proxy, která musí vidět
jak "frontend" síť, tak "backend" síť s aplikačními servery.

Persistentní data: volumes vs. bind mounty vs. tmpfs

Docker nabízí tři způsoby, jak dostat data mimo efemérní vrstvu
kontejneru:

  1. Named volumes (docker volume create) — Docker spravuje
    úložiště sám, typicky pod /var/lib/docker/volumes/. Toto je
    doporučený způsob pro perzistentní data aplikací (databáze,
    uploady) — je přenosný mezi kontejnery, nezávisí na struktuře
    hostitelského systému a Docker o něj umí pečovat (zálohovat,
    migrovat pomocí volume driverů).
  2. Bind mounty (-v /host/cesta:/kontejner/cesta) — namapují
    konkrétní adresář z hostitele přímo do kontejneru. Hodí se pro vývoj
    (živé mapování zdrojového kódu) nebo když potřebujete přesnou
    kontrolu nad umístěním na disku, ale váží aplikaci na konkrétní
    hostitelský souborový systém.
  3. tmpfs mounty — data existují pouze v paměti hostitele, nikdy se
    nezapisují na disk; zmizí při zastavení kontejneru. Hodí se pro
    citlivá dočasná data (např. dešifrovací klíče za běhu).
# named volume — Docker spravuje úložiště
docker volume create pgdata
docker run -d --name db \
  -v pgdata:/var/lib/postgresql/data \
  postgres:16

# bind mount — konkrétní adresář z hostitele
docker run -d --name web \
  -v /home/petr/app/src:/app/src \
  mojeaplikace

# tmpfs — jen v paměti
docker run -d --name cache --tmpfs /app/tmp mojeaplikace

Volume přežije docker rm kontejneru — data zmizí jen explicitním
docker volume rm. To je klíčové: pokud databázový kontejner
restartujete, updatujete na novou verzi image nebo znovu vytvoříte,
data v named volume zůstávají netknutá, protože nejsou součástí
kontejneru, jen jsou do něj při běhu připojena (mountnuta).

Přehled volumes

docker volume ls                 # seznam volumes
docker volume inspect pgdata     # detail včetně cesty na disku
docker volume rm pgdata          # smazání (jen pokud není použit)
docker volume prune              # smazání všech nepoužívaných volumes

Praktický příklad

Kompletní ukázka: aplikace s vlastní sítí a perzistentní databází.

# 1. vytvoření izolované sítě pro tuto aplikaci
docker network create shop-net

# 2. named volume pro databázová data
docker volume create shop-db-data

# 3. databáze v této síti, s daty ve volume
docker run -d \
  --name shop-db \
  --network shop-net \
  -v shop-db-data:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=tajneheslo \
  postgres:16

# 4. aplikace ve stejné síti, komunikuje s db podle jména
docker run -d \
  --name shop-web \
  --network shop-net \
  -p 8000:8000 \
  -e DATABASE_HOST=shop-db \
  mojeaplikace

# 5. ověření, že web vidí db
docker exec shop-web ping -c 1 shop-db

Pokud teď kontejner shop-db smažeme a znovu vytvoříme se stejným
-v shop-db-data:..., databázová data přežijí, protože žijí ve
volume, ne v kontejneru:

docker rm -f shop-db
docker run -d --name shop-db --network shop-net \
  -v shop-db-data:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=tajneheslo postgres:16
# data z původního běhu jsou stále v databázi

Shrnutí

Vlastní bridge sítě umožňují kontejnerům komunikovat přes DNS jméno
místo IP adresy a izolují skupiny kontejnerů od sebe. Data, která mají
přežít restart nebo smazání kontejneru, patří do named volumes (obecné
doporučení), bind mounty se hodí pro vývoj nebo přesnou kontrolu nad
umístěním na disku a tmpfs pro dočasná citlivá data jen v paměti.
Klíčový princip: kontejner je efemérní, volume je trvalé.

Kontrolní otázky

  1. Proč se ve výchozí bridge síti nedá spolehnout na DNS resolving
    podle jména kontejneru a jak to obejít?
  2. Jaký je rozdíl mezi named volume a bind mountem a kdy použijete
    který?
  3. Co se stane s daty v named volume, když kontejner, který ho
    používal, smažete příkazem docker rm?
  4. Mini cvičení: vytvořte vlastní síť test-net, spusťte v ní dva
    kontejnery (nginx a alpine) a z kontejneru alpine ověřte
    příkazem ping nebo wget, že vidíte nginx podle jména.

Lekce na sebe nejsou zamčené — libovolnou lekci můžete otevřít i označit jako hotovou v jakémkoliv pořadí.