Modul 9 · 9.3
Docker compose i vatrozid
Modul 9: Docker i docker compose · Vrijeme čitanja: 12 minuta
Cilj učenja: Nakon ove lekcije moći ćete opisati usluge u compose datoteci, pokrenuti ih, ažurirati i zaustaviti te objasniti zašto objavljeni Docker priključci zaobilaze ufw i kako to spriječiti.
Ključni pojmovi: compose.yaml, services, image, ports, volumes, environment, .env, restart, networks, depends_on, healthcheck, docker compose up -d, pull, logs, down, zastarjeli version:, Docker i ufw, DOCKER-USER, objava na 127.0.0.1, tajne, docker.sock
Zašto compose?
Naredbom docker run (lekcija 9.2) pokrećete jedan kontejner s dugim retkom opcija. Prava aplikacija često se sastoji od više kontejnera: programa, baze podataka i obrnutog proxyja (reverse proxy). Pamtiti te retke i ponovno ih upisivati nakon ponovnog pokretanja ili ažuriranja jednom će poći po zlu.
Docker Compose opisuje sve kontejnere jedne aplikacije u jednoj datoteci: compose.yaml. Tu datoteku stavite u zasebnu mapu, primjerice /srv/status/compose.yaml, i svime upravljate naredbom docker compose. Datoteka je ujedno i Vaša dokumentacija: što radi, koji image, koji priključci, gdje se nalaze podaci. Uključite tu mapu u sigurnosnu kopiju (lekcija 8.1) i aplikaciju ćete na novom poslužitelju moći vratiti za nekoliko minuta.
Dodatak se zove docker compose (s razmakom, verzija 2). Stari zasebni program docker-compose (s crticom) je zamijenjen; još ćete ga vidjeti u starim uputama. I polje version: "3.8" na vrhu starih datoteka je zastarjelo: Compose uvijek koristi najnoviju shemu i za version: daje samo upozorenje.
Čitanje compose datoteke
Primjer s programom i bazom podataka 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:Korak po korak:
- services: svaka usluga postaje kontejner. Naziv (
app,db) ujedno je i naziv hosta po kojem se kontejneri međusobno pronalaze. Compose za aplikaciju stvara zasebnu mrežu, pa seappspaja na bazu podataka nadb:5432. - image: uvijek s oznakom verzije (lekcija 9.1).
- restart: što Docker radi kada se kontejner zaustavi ili se poslužitelj ponovno pokrene.
unless-stoppedga ponovno pokreće, osim ako ste ga Vi namjerno zaustavili. Bez pravila za ponovno pokretanje Vaša se aplikacija nakon ponovnog pokretanja poslužitelja (lekcija 4.2) neće vratiti. - ports: samo aplikacija objavljuje priključak, i to samo na
127.0.0.1. Baza podataka ne objavljuje ništa: aplikacija joj pristupa preko interne mreže. Baza podataka sports: - "5432:5432"jedna je od najčešćih pogrešaka (vidi u nastavku). - environment: postavke programa. Lozinka nije upisana doslovno, nego kao
${DB_PASSWORD}. - volumes: imenovani volumen
db-datačuva bazu podataka kada se kontejner zamijeni. - depends_on s healthcheck: aplikacija se pokreće tek kada je baza podataka stvarno spremna, a ne samo pokrenuta.
Tajne u datoteci .env
Compose čita varijable poput ${DB_PASSWORD} iz datoteke .env u istoj mapi:
# /srv/notities/.env
DB_PASSWORD=Kies-hier-een-lang-willekeurig-wachtwoordanna@web1:/srv/notities$ sudo chmod 600 .envTako lozinka nije u compose datoteci koju možda čuvate u Gitu ili zalijepite na forum kada tražite pomoć. Dodajte .env u .gitignore. Lozinku izradite upraviteljem lozinki ili naredbom openssl rand -base64 24.
Svakodnevna upotreba
Sve naredbe izvršavate u mapi s compose datotekom:
anna@web1:/srv/notities$ sudo docker compose config # provjera datoteke, varijable popunjene
anna@web1:/srv/notities$ sudo docker compose up -d # pokreni sve (ili ažuriraj prema datoteci)
anna@web1:/srv/notities$ sudo docker compose ps # status po servisu
anna@web1:/srv/notities$ sudo docker compose logs -f app
anna@web1:/srv/notities$ sudo docker compose pull # dohvati nove imageove
anna@web1:/srv/notities$ sudo docker compose up -d # zamijeni kontejnere novim imageovima
anna@web1:/srv/notities$ sudo docker compose down # zaustavi i ukloni kontejneredown ostavlja Vaše volumene. down -v briše i volumene aplikacije, a time i Vašu bazu podataka. To upišite samo ako zaista želite početi ispočetka.
docker compose config ekvivalent je naredbi nginx -t i sshd -t: prikazuje kako Compose razumije Vašu datoteku, sa svim popunjenim varijablama, prije nego što išta pokrenete. Pazite da taj ispis tada nigdje ne zalijepite, jer sadrži lozinke.
Docker zaobilazi ufw
Sada najvažnija sigurnosna točka ovog modula. U lekciji 5.2 postavili ste ufw na "odbij sve, osim SSH, 80 i 443". Očekivali biste da kontejner s ports: - "5432:5432" tada nije dostupan. To nije tako.
Docker dokumentacija to kaže doslovno: Docker i ufw koriste pravila vatrozida na način koji nije međusobno kompatibilan. Kada objavite priključak, Docker sam postavlja pravila u vatrozid jezgre. Ta pravila prosljeđuju promet kontejneru (prevođenje adresa, DNAT) prije nego što se primijene pravila ufw-a. Paket dakle zaobilazi ufw. ufw status ne prikazuje ništa neobično, dok je priključak dostupan s cijelog interneta. Isto vrijedi i za firewalld.
Osim toga, Docker bez navedene adrese objavljuje na 0.0.0.0 i [::], dakle na IPv4 i na IPv6 (lekcija 9.1).
Tri načina da to napravite ispravno, od jednostavnog prema složenom:
- Ne objavljujte ništa što ne mora biti javno. Baze podataka, predmemorije (cache) i interne usluge ne dobivaju
ports:. Kontejneri u istoj compose aplikaciji dostupni su jedni drugima preko interne mreže. - Objavljujte na loopback.
"127.0.0.1:8081:8080". Tada mu može pristupiti samo sam poslužitelj, a ispred postavite obrnuti proxy (nginx ili Caddy, modul 7) koji sluša na 443. Docker to može dobiti i kao zadanu postavku: postavka daemona usmjerava sve objavljene priključke bez adrese na127.0.0.1. - Pravila u lancu DOCKER-USER. Docker stvara prazan lanac
DOCKER-USERkoji se prolazi prije njegovih vlastitih pravila. Ondje možete sami postaviti pravila, primjerice "samo ova IP adresa smije pristupati objavljenim priključcima". To je napredan posao s iptables ili nftables, u kojem je lako pogriješiti. Za većinu malih poslužitelja dovoljni su načini 1 i 2.
Uvijek provjeravajte izvana, kao u lekciji 5.1: nc -vz -w 3 <ip> 5432 s Vašeg prijenosnog računala ili provjerom tečaja iz zadataka Z5.1 i Z10.4.
Još dvije stvari koje ne radite
- Ne montirajte
/var/run/docker.socku kontejner, osim ako točno znate zašto. Kontejner s pristupom Docker socketu može sam pokretati kontejnere, pa i onaj s cijelim diskom hosta (lekcija 9.2). Neki pomoćni programi (nadzorne ploče, automatski alati za ažuriranje) to traže; to u biti znači davanje root ovlasti tom programu. - Nema
privileged: trueninetwork_mode: hostsamo zato što tako piše u uputama. Oboje u velikoj mjeri uklanja izolaciju kontejnera. Koristite ih samo ako autor objasni zašto je to potrebno.
Sažetak
- Compose datoteka (
compose.yaml) opisuje sve kontejnere jedne aplikacije; ujedno je dokumentacija i treba biti u Vašoj sigurnosnoj kopiji. - Koristite oznake verzija, pravilo za ponovno pokretanje, imenovane volumene, healthcheck gdje je moguće te tajne u
.envs pravima 600. docker compose config,up -d,ps,logs,pull,down;down -vbriše i volumene.- Objavljeni priključci zaobilaze ufw i firewalld. Objavljujte samo ono što mora biti javno, a inače na
127.0.0.1s obrnutim proxyjem ispred. - Nema docker.sock,
privilegedninetwork_mode: hostbez dobrog razloga.
Kviz
Zadatak
Zadatak Z9.3: Provjera compose datoteke. U primjeru datoteke compose-nakijken.txt nalazi se (kao tekstualna datoteka) compose datoteka male web trgovine s aplikacijom, bazom podataka, predmemorijom i alatom za upravljanje. U njoj je šest pogrešaka obrađenih u ovoj lekciji ili u lekcijama 9.1 i 9.2. Za svaki numerirani blok redaka navedite je li ispravan ili pogrešan, a za svaku pogrešku odaberite ispravan popravak. Program uspoređuje s fiksnim ključem. Ako imate vlastitu compose datoteku, nakon toga je provjerite prema istim točkama.
Dodatno štivo
- Docker dokumentacija, How Compose works (compose.yaml): https://docs.docker.com/compose/intro/compose-application-model/
- Docker dokumentacija, Version and name top-level elements: https://docs.docker.com/reference/compose-file/version-and-name/
- Docker dokumentacija, Packet filtering and firewalls (Docker and ufw): https://docs.docker.com/engine/network/packet-filtering-firewalls/
- Docker dokumentacija, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Docker dokumentacija, Interpolation (varijable i .env): https://docs.docker.com/reference/compose-file/interpolation/
