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ů.
Ú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:
- 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ů). - 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. - 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
- Proč se ve výchozí
bridgesíti nedá spolehnout na DNS resolving
podle jména kontejneru a jak to obejít? - Jaký je rozdíl mezi named volume a bind mountem a kdy použijete
který? - Co se stane s daty v named volume, když kontejner, který ho
používal, smažete příkazemdocker rm? - Mini cvičení: vytvořte vlastní síť
test-net, spusťte v ní dva
kontejnery (nginxaalpine) a z kontejnerualpineověřte
příkazempingnebowget, že vidítenginxpodle jména.
Lekce na sebe nejsou zamčené — libovolnou lekci můžete otevřít i označit jako hotovou v jakémkoliv pořadí.