Modul 9 · 9.3
Docker compose og brannmuren
Modul 9: Docker og docker compose · Lesetid: 12 minutter
Læringsmål: Etter denne leksjonen kan du beskrive tjenester i en compose-fil og starte, oppdatere og stoppe dem. Du kan også forklare hvorfor publiserte porter fra Docker går forbi ufw, og hvordan du hindrer det.
Nøkkelbegreper: compose.yaml, services, image, ports, volumes, environment, .env, restart, networks, depends_on, healthcheck, docker compose up -d, pull, logs, down, utgått version:, Docker og ufw, DOCKER-USER, publisering på 127.0.0.1, hemmeligheter, docker.sock
Hvorfor compose?
Med docker run (leksjon 9.2) starter du én container med en lang linje med valg. En ekte applikasjon består ofte av flere containere: et program, en database, en omvendt proxy. Å huske de linjene og skrive dem inn på nytt etter en omstart eller oppdatering går galt før eller siden.
Docker Compose beskriver alle containerne i en applikasjon i én fil: compose.yaml. Du legger filen i en egen mappe, for eksempel /srv/status/compose.yaml, og styrer alt med docker compose. Filen er samtidig dokumentasjonen din: hva som kjører, hvilket image, hvilke porter og hvor dataene ligger. Ta med mappen i sikkerhetskopien din (leksjon 8.1), så kan du gjenopprette applikasjonen på en ny server på noen minutter.
Programtillegget heter docker compose (med mellomrom, versjon 2). Det gamle frittstående programmet docker-compose (med bindestrek) er erstattet, men du ser det fortsatt i gamle veiledninger. Feltet version: "3.8" øverst i gamle filer er også utgått: Compose bruker alltid det nyeste skjemaet og gir bare en advarsel ved version:.
Lese en compose-fil
Et eksempel med et program og en PostgreSQL-database:
# /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:Steg for steg:
- services: hver tjeneste blir en container. Navnet (
app,db) er også vertsnavnet containerne bruker for å finne hverandre. Compose lager et eget nettverk for applikasjonen, såappkobler seg til databasen pådb:5432. - image: alltid med en versjonstagg (leksjon 9.1).
- restart: hva Docker gjør når containeren stopper eller serveren starter på nytt.
unless-stoppedstarter den igjen, med mindre du stoppet den med vilje. Uten en restart-policy kommer ikke applikasjonen din tilbake etter en omstart (leksjon 4.2). - ports: bare appen publiserer en port, og bare på
127.0.0.1. Databasen publiserer ingenting: appen når den via det interne nettverket. En database medports: - "5432:5432"er en av de vanligste feilene (se nedenfor). - environment: innstillinger for programmet. Passordet står ikke der i klartekst, men som
${DB_PASSWORD}. - volumes: det navngitte volumet
db-datatar vare på databasen når containeren byttes ut. - depends_on med healthcheck: appen starter først når databasen faktisk er klar, ikke bare startet.
Hemmeligheter i en .env-fil
Compose leser variabler som ${DB_PASSWORD} fra en fil .env i samme mappe:
# /srv/notities/.env
DB_PASSWORD=Kies-hier-een-lang-willekeurig-wachtwoordanna@web1:/srv/notities$ sudo chmod 600 .envSlik står ikke passordet i compose-filen, som du kanskje lagrer i Git eller limer inn på et forum når du ber om hjelp. Legg .env i .gitignore. Lag passordet med en passordbehandler eller med openssl rand -base64 24.
Daglig bruk
Alle kommandoene kjører du i mappen med compose-filen:
anna@web1:/srv/notities$ sudo docker compose config # kontroller filen, variabler fylt inn
anna@web1:/srv/notities$ sudo docker compose up -d # start alt (eller oppdater i tråd med filen)
anna@web1:/srv/notities$ sudo docker compose ps # status per tjeneste
anna@web1:/srv/notities$ sudo docker compose logs -f app
anna@web1:/srv/notities$ sudo docker compose pull # hent nye images
anna@web1:/srv/notities$ sudo docker compose up -d # erstatt containerne med de nye imagene
anna@web1:/srv/notities$ sudo docker compose down # stopp og fjern containernedown lar volumene dine stå. down -v sletter også volumene til applikasjonen, og dermed databasen din. Skriv det bare når du virkelig vil begynne på nytt.
docker compose config tilsvarer nginx -t og sshd -t: den viser hvordan Compose forstår filen din, med alle variabler fylt inn, før du starter noe. Pass på at du ikke limer inn utdataene noe sted, for passordene står i dem.
Docker går forbi ufw
Nå kommer det viktigste sikkerhetspunktet i denne modulen. I leksjon 5.2 satte du ufw til "avvis alt unntatt SSH, 80 og 443". Du skulle tro at en container med ports: - "5432:5432" da ikke er tilgjengelig. Det stemmer ikke.
Docker-dokumentasjonen sier det rett ut: Docker og ufw bruker brannmurregler på måter som ikke passer sammen. Når du publiserer en port, legger Docker selv inn regler i kjernens brannmur. Disse reglene sender trafikken videre til containeren (adresseoversettelse, DNAT) før reglene i ufw blir brukt. Pakken går altså utenom ufw. ufw status viser ingenting spesielt, mens porten er tilgjengelig fra hele internett. Det samme gjelder firewalld.
I tillegg publiserer Docker uten adresse på 0.0.0.0 og [::], altså på både IPv4 og IPv6 (leksjon 9.1).
Tre måter å gjøre det riktig på, fra enkel til avansert:
- Ikke publiser noe som ikke må være offentlig. Databaser, cacher og interne tjenester får ingen
ports:. Containere i samme compose-applikasjon når hverandre via det interne nettverket. - Publiser på loopback.
"127.0.0.1:8081:8080". Da er det bare serveren selv som når den, og du setter en omvendt proxy (nginx eller Caddy, modul 7) foran som lytter på 443. Docker kan også få dette som standard: en daemon-innstilling sørger for at alle publiserte porter uten adresse havner på127.0.0.1. - Regler i kjeden DOCKER-USER. Docker lager en tom kjede
DOCKER-USERsom gås gjennom før Dockers egne regler. Der kan du legge inn egne regler, for eksempel "bare denne IP-adressen får nå de publiserte portene". Det er avansert arbeid med iptables eller nftables, og lett å gjøre feil. For de fleste små servere holder 1 og 2.
Kontroller alltid utenfra, som i leksjon 5.1: nc -vz -w 3 <ip> 5432 fra den bærbare maskinen din, eller kurskontrollen i oppgave Z5.1 og Z10.4.
To ting til du ikke gjør
- Ikke monter
/var/run/docker.socki en container med mindre du vet nøyaktig hvorfor. En container med tilgang til Docker-socketen kan selv starte containere, også en med hele disken til verten (leksjon 9.2). Noen hjelpeprogrammer (dashbord, automatiske oppdaterere) ber om det. I praksis gir du da root til det programmet. - Ikke bruk
privileged: trueellernetwork_mode: hostbare fordi en veiledning sier det. Begge fjerner det meste av isolasjonen rundt containeren. Bruk dem bare når utvikleren forklarer hvorfor det trengs.
Oppsummering
- En compose-fil (
compose.yaml) beskriver alle containerne i en applikasjon. Den er samtidig dokumentasjon og hører hjemme i sikkerhetskopien din. - Bruk versjonstagger, en restart-policy, navngitte volumer, en healthcheck der det går, og hemmeligheter i en
.envmed rettigheter 600. docker compose config,up -d,ps,logs,pull,down.down -vsletter også volumene.- Publiserte porter går forbi ufw og firewalld. Publiser bare det som må være offentlig, og ellers på
127.0.0.1med en omvendt proxy foran. - Ingen docker.sock,
privilegedellernetwork_mode: hostuten god grunn.
Quiz
Oppgave
Oppgave Z9.3: Gå gjennom en compose-fil. Eksempelfilen compose-nakijken.txt inneholder (som tekstfil) compose-filen til en liten nettbutikk med en app, en database, en cache og et administrasjonsverktøy. Den har seks feil som er gjennomgått i denne leksjonen eller i leksjon 9.1 og 9.2. Angi for hver nummererte linjeblokk om den er riktig eller feil, og velg riktig rettelse for hver feil. Programmet sammenligner med fasiten. Har du en egen compose-fil, går du gjennom den etterpå etter de samme punktene.
Les mer
- Docker-dokumentasjonen, How Compose works (compose.yaml): https://docs.docker.com/compose/intro/compose-application-model/
- Docker-dokumentasjonen, Version and name top-level elements: https://docs.docker.com/reference/compose-file/version-and-name/
- Docker-dokumentasjonen, Packet filtering and firewalls (Docker and ufw): https://docs.docker.com/engine/network/packet-filtering-firewalls/
- Docker-dokumentasjonen, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Docker-dokumentasjonen, Interpolation (variabler og .env): https://docs.docker.com/reference/compose-file/interpolation/
