Docker compose a firewall
Modul 9: Docker a docker compose · Doba čtení: 12 min.
Cíl lekce: Po této lekci dokážete popsat služby v souboru compose, spustit je, aktualizovat a zastavit. Také vysvětlíte, proč publikované porty Dockeru obcházejí ufw a jak tomu zabránit.
Klíčové pojmy: compose.yaml, services, image, ports, volumes, environment, .env, restart, networks, depends_on, healthcheck, docker compose up -d, pull, logs, down, zastaralé version:, Docker a ufw, DOCKER-USER, publikování na 127.0.0.1, tajné údaje, docker.sock
Proč compose?
Pomocí docker run (lekce 9.2) spustíte jeden kontejner s dlouhým řádkem voleb. Skutečná aplikace se ale často skládá z více kontejnerů: programu, databáze a reverzní proxy. Pamatovat si tyto řádky a po restartu nebo aktualizaci je znovu psát se jednou nepovede.
Docker Compose popisuje všechny kontejnery aplikace v jednom souboru: compose.yaml. Tento soubor uložíte do vlastní složky, například /srv/status/compose.yaml, a vše spravujete pomocí docker compose. Soubor je zároveň Vaší dokumentací: co běží, jaký image, jaké porty, kde jsou uložena data. Zahrňte tuto složku do zálohy (lekce 8.1) a aplikaci pak obnovíte na novém serveru za pár minut.
Plugin se jmenuje docker compose (s mezerou, verze 2). Starý samostatný program docker-compose (se spojovníkem) byl nahrazen; uvidíte ho ještě ve starých návodech. Zastaralé je i pole version: "3.8" na začátku starých souborů: Compose vždy používá nejnovější schéma a u version: zobrazí jen varování.
Jak číst soubor compose
Příklad s programem a databází PostgreSQL:
# /srv/notities/compose.yaml
services:
app:
image: ghcr.io/example/notities:1.4
restart: unless-stopped
ports:
- "127.0.0.1:8081:8080"
environment:
DB_HOST: db
DB_USER: notities
DB_PASSWORD: ${DB_PASSWORD}
depends_on:
db:
condition: service_healthy
db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_USER: notities
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U notities"]
interval: 10s
retries: 5
volumes:
db-data:Krok za krokem:
- services: každá služba se stane kontejnerem. Název (
app,db) je zároveň názvem hostitele, podle kterého se kontejnery navzájem najdou. Compose vytvoří pro aplikaci vlastní síť, takžeappse připojí k databázi nadb:5432. - image: vždy s tagem verze (lekce 9.1).
- restart: co Docker udělá, když se kontejner zastaví nebo se server restartuje.
unless-stoppedho znovu spustí, pokud jste ho sami vědomě nezastavili. Bez pravidla pro restart se Vaše aplikace po restartu (lekce 4.2) nevrátí. - ports: port publikuje jen aplikace, a to pouze na
127.0.0.1. Databáze nepublikuje nic: aplikace se k ní dostane přes interní síť. Databáze sports: - "5432:5432"je jednou z nejčastějších chyb (viz níže). - environment: nastavení pro program. Heslo v něm není doslovně, ale jako
${DB_PASSWORD}. - volumes: pojmenovaný svazek
db-datauchová databázi, i když je kontejner nahrazen. - depends_on s healthcheck: aplikace se spustí, až když je databáze opravdu připravená, ne jen spuštěná.
Tajné údaje v souboru .env
Compose načítá proměnné jako ${DB_PASSWORD} ze souboru .env ve stejné složce:
# /srv/notities/.env
DB_PASSWORD=Kies-hier-een-lang-willekeurig-wachtwoordanna@web1:/srv/notities$ sudo chmod 600 .envHeslo tak není v souboru compose, který možná uchováváte v Gitu nebo vkládáte na fórum, když žádáte o pomoc. Přidejte .env do .gitignore. Heslo vytvořte ve správci hesel nebo pomocí openssl rand -base64 24.
Každodenní používání
Všechny příkazy spouštějte ve složce se souborem compose:
anna@web1:/srv/notities$ sudo docker compose config # zkontrolovat soubor, proměnné doplněny
anna@web1:/srv/notities$ sudo docker compose up -d # spustit vše (nebo aktualizovat podle souboru)
anna@web1:/srv/notities$ sudo docker compose ps # stav jednotlivých služeb
anna@web1:/srv/notities$ sudo docker compose logs -f app
anna@web1:/srv/notities$ sudo docker compose pull # stáhnout nové images
anna@web1:/srv/notities$ sudo docker compose up -d # nahradit kontejnery novými images
anna@web1:/srv/notities$ sudo docker compose down # zastavit a odstranit kontejnerydown ponechá Vaše svazky. down -v odstraní i svazky aplikace, a tím i Vaši databázi. Zadejte to jen tehdy, když opravdu chcete začít znovu.
docker compose config je obdobou nginx -t a sshd -t: ukáže, jak Compose rozumí Vašemu souboru, se všemi dosazenými proměnnými, ještě než cokoli spustíte. Dejte pozor, abyste výstup nikam nevkládali, protože obsahuje hesla.
Docker obchází ufw
Nyní nejdůležitější bezpečnostní bod tohoto modulu. V lekci 5.2 jste nastavili ufw na "vše zakázat kromě SSH, 80 a 443". Čekali byste, že kontejner s ports: - "5432:5432" pak nebude dostupný. Není tomu tak.
Dokumentace Dockeru to říká doslova: Docker a ufw používají pravidla firewallu způsobem, který se navzájem nesnáší. Když publikujete port, Docker sám vloží pravidla do firewallu jádra. Tato pravidla přesměrují provoz do kontejneru (překlad adres, DNAT) dříve, než se uplatní pravidla ufw. Paket tedy ufw obejde. ufw status neukáže nic zvláštního, přestože je port dostupný z celého internetu. Totéž platí pro firewalld.
Navíc Docker bez uvedené adresy publikuje na 0.0.0.0 a [::], tedy na IPv4 i IPv6 (lekce 9.1).
Tři způsoby, jak to udělat správně, od jednoduchého po složitý:
- Nepublikujte nic, co nemusí být veřejné. Databáze, cache a interní služby nedostanou
ports:. Kontejnery ve stejné aplikaci compose se navzájem dosáhnou přes interní síť. - Publikujte na loopback.
"127.0.0.1:8081:8080". Pak se k nim dostane jen samotný server a před ně postavíte reverzní proxy (nginx nebo Caddy, modul 7), která naslouchá na 443. Docker to může mít i jako výchozí nastavení: nastavení démona zajistí, že všechny publikované porty bez adresy skončí na127.0.0.1. - Pravidla v řetězci DOCKER-USER. Docker vytvoří prázdný řetězec
DOCKER-USER, který se prochází před jeho vlastními pravidly. Tam můžete vložit vlastní pravidla, například "na publikované porty smí jen tato IP adresa". Jde o pokročilou práci s iptables nebo nftables, ve které se snadno udělá chyba. Pro většinu malých serverů stačí způsoby 1 a 2.
Vždy kontrolujte zvenku, jako v lekci 5.1: nc -vz -w 3 <ip> 5432 z Vašeho notebooku, nebo kontrolou kurzu v úkolu Z5.1 a Z10.4.
Ještě dvě věci, které nedělejte
- Nepřipojujte
/var/run/docker.sockdo kontejneru, pokud přesně nevíte proč. Kontejner s přístupem k socketu Dockeru může sám spouštět kontejnery, i takový, který má celý disk hostitele (lekce 9.2). Některé nástroje (dashboardy, automatické aktualizátory) to vyžadují; v podstatě tím danému programu dáváte práva roota. - Nepoužívejte
privileged: trueaninetwork_mode: hostjen proto, že to říká návod. Obojí z velké části ruší izolaci kontejneru. Používejte to jen tehdy, když autor vysvětlí, proč je to nutné.
Shrnutí
- Soubor compose (
compose.yaml) popisuje všechny kontejnery aplikace; je zároveň dokumentací a patří do Vaší zálohy. - Používejte tagy verzí, pravidlo pro restart, pojmenované svazky, healthcheck tam, kde to jde, a tajné údaje v
.envs oprávněním 600. docker compose config,up -d,ps,logs,pull,down;down -vodstraní i svazky.- Publikované porty obcházejí ufw i firewalld. Publikujte jen to, co musí být veřejné, a jinak na
127.0.0.1s reverzní proxy před tím. - Žádný docker.sock,
privilegedaninetwork_mode: hostbez dobrého důvodu.
Kvíz
Úkol
Úkol Z9.3: Kontrola souboru compose. Ve vzorovém souboru compose-nakijken.txt je (jako textový soubor) soubor compose malého e-shopu s aplikací, databází, cache a nástrojem pro správu. Obsahuje šest chyb, které byly probrány v této lekci nebo v lekcích 9.1 a 9.2. U každého očíslovaného bloku řádků uveďte, zda je správně, nebo chybně, a u každé chyby zvolte správnou opravu. Program Vaše odpovědi porovná s pevným klíčem. Máte-li vlastní soubor compose, projděte ho potom podle stejných bodů.
Doporučujeme k přečtení
- Dokumentace Dockeru, How Compose works (compose.yaml): https://docs.docker.com/compose/intro/compose-application-model/
- Dokumentace Dockeru, Version and name top-level elements: https://docs.docker.com/reference/compose-file/version-and-name/
- Dokumentace Dockeru, Packet filtering and firewalls (Docker and ufw): https://docs.docker.com/engine/network/packet-filtering-firewalls/
- Dokumentace Dockeru, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Dokumentace Dockeru, Interpolation (proměnné a .env): https://docs.docker.com/reference/compose-file/interpolation/
