Modul 9 · 9.3
Docker compose og firewallen
Modul 9: Docker og docker compose · Læsetid: 12 minutter
Læringsmål: Efter denne lektion kan du beskrive tjenester i en compose-fil, starte, opdatere og stoppe dem, og du kan forklare hvorfor publicerede porte fra Docker går uden om ufw, og hvordan du forhindrer det.
Centrale begreber: compose.yaml, services, image, ports, volumes, environment, .env, restart, networks, depends_on, healthcheck, docker compose up -d, pull, logs, down, forældet version:, Docker og ufw, DOCKER-USER, publicering på 127.0.0.1, hemmeligheder, docker.sock
Hvorfor compose?
Med docker run (lektion 9.2) starter du én container med en lang linje af indstillinger. Et rigtigt program består ofte af flere containere: selve programmet, en database, en reverse proxy. Hvis du skal huske de linjer og skrive dem igen efter en genstart eller opdatering, går det galt på et tidspunkt.
Docker Compose beskriver alle containere i et program i én fil: compose.yaml. Du lægger filen i sin egen mappe, for eksempel /srv/status/compose.yaml, og styrer det hele med docker compose. Filen er samtidig din dokumentation: hvad kører der, hvilket image, hvilke porte, hvor ligger dataene. Tag mappen med i din backup (lektion 8.1), så kan du genskabe programmet på en ny server på få minutter.
Pluginnet hedder docker compose (med mellemrum, version 2). Det gamle selvstændige program docker-compose (med bindestreg) er erstattet; du ser det stadig i gamle vejledninger. Feltet version: "3.8" øverst i gamle filer er også forældet: Compose bruger altid det nyeste skema og giver kun en advarsel ved version:.
Læs 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:Trin for trin:
- services: hver tjeneste bliver en container. Navnet (
app,db) er også det hostnavn, containerne finder hinanden med. Compose opretter et eget netværk til programmet, såappforbinder til databasen pådb:5432. - image: altid med et versionstag (lektion 9.1).
- restart: hvad Docker gør, når containeren stopper, eller serveren genstarter.
unless-stoppedstarter den igen, medmindre du selv har stoppet den med vilje. Uden en restart-politik kommer dit program ikke tilbage efter en genstart (lektion 4.2). - ports: kun appen publicerer en port, og kun på
127.0.0.1. Databasen publicerer ingenting: appen når den via det interne netværk. En database medports: - "5432:5432"er en af de mest almindelige fejl (se nedenfor). - environment: indstillinger til programmet. Adgangskoden står ikke direkte i filen, men som
${DB_PASSWORD}. - volumes: det navngivne volume
db-databevarer databasen, når containeren bliver udskiftet. - depends_on med healthcheck: appen starter først, når databasen faktisk er klar, ikke bare startet.
Hemmeligheder i en .env-fil
Compose læser 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 .envSå står adgangskoden ikke i compose-filen, som du måske gemmer i Git eller indsætter på et forum for at få hjælp. Tilføj .env til .gitignore. Lav adgangskoden med en adgangskodeadministrator eller med openssl rand -base64 24.
Daglig brug
Alle kommandoer kører du i mappen med compose-filen:
anna@web1:/srv/notities$ sudo docker compose config # tjek filen, variabler udfyldt
anna@web1:/srv/notities$ sudo docker compose up -d # start alt (eller opdater til filen)
anna@web1:/srv/notities$ sudo docker compose ps # status pr. 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 # erstat containere med de nye images
anna@web1:/srv/notities$ sudo docker compose down # stop og fjern containeredown lader dine volumes være. down -v sletter også programmets volumes, og dermed din database. Skriv det kun, hvis du virkelig vil starte forfra.
docker compose config svarer til nginx -t og sshd -t: den viser, hvordan Compose forstår din fil, med alle variabler udfyldt, før du starter noget. Pas på ikke at indsætte outputtet nogen steder, for adgangskoderne står i det.
Docker går uden om ufw
Nu kommer det vigtigste sikkerhedspunkt i dette modul. I lektion 5.2 satte du ufw til "afvis alt undtagen SSH, 80 og 443". Du ville forvente, at en container med ports: - "5432:5432" så ikke kan nås. Sådan er det ikke.
Docker-dokumentationen siger det direkte: Docker og ufw bruger firewallregler på en måde, der ikke passer sammen. Når du publicerer en port, skriver Docker selv regler i kernens firewall. De regler sender trafikken videre til containeren (adresseoversættelse, DNAT), før ufw-reglerne bliver anvendt. Pakken går altså uden om ufw. ufw status viser intet særligt, mens porten kan nås fra hele internettet. Det samme gælder firewalld.
Desuden publicerer Docker uden adresse på 0.0.0.0 og [::], altså på både IPv4 og IPv6 (lektion 9.1).
Tre måder at gøre det rigtigt på, fra enkel til avanceret:
- Publicér ikke noget, der ikke behøver at være offentligt. Databaser, caches og interne tjenester får ingen
ports:. Containere i samme compose-program når hinanden via det interne netværk. - Publicér på loopback.
"127.0.0.1:8081:8080". Så kan kun serveren selv komme til, og du sætter en reverse proxy (nginx eller Caddy, modul 7) foran, som lytter på 443. Docker kan også få det som standard: en daemon-indstilling får alle publicerede porte uden adresse til at lande på127.0.0.1. - Regler i kæden DOCKER-USER. Docker opretter en tom kæde
DOCKER-USER, som bliver gennemløbet før Dockers egne regler. Der kan du selv tilføje regler, for eksempel "kun denne IP-adresse må nå de publicerede porte". Det er avanceret arbejde med iptables eller nftables og nemt at gøre forkert. For de fleste små servere er 1 og 2 nok.
Kontrollér altid udefra, som i lektion 5.1: nc -vz -w 3 <ip> 5432 fra din bærbare, eller kursuskontrollen i opgave Z5.1 og Z10.4.
To ting mere, du ikke gør
- Montér ikke
/var/run/docker.socki en container, medmindre du ved præcis hvorfor. En container med adgang til Docker-socketten kan selv starte containere, også en med hele værtens disk (lektion 9.2). Nogle hjælpeprogrammer (dashboards, automatiske opdateringsværktøjer) beder om det; det svarer reelt til at give programmet root. - Ingen
privileged: trueellernetwork_mode: host, bare fordi en vejledning siger det. Begge fjerner størstedelen af containerens afskærmning. Brug dem kun, hvis udvikleren forklarer, hvorfor det er nødvendigt.
Opsummering
- En compose-fil (
compose.yaml) beskriver alle containere i et program; den er samtidig dokumentation og hører hjemme i din backup. - Brug versionstags, en restart-politik, navngivne volumes, et healthcheck hvor det er muligt, og hemmeligheder i en
.envmed rettigheder 600. docker compose config,up -d,ps,logs,pull,down;down -vsletter også volumes.- Publicerede porte går uden om ufw og firewalld. Publicér kun det, der skal være offentligt, og ellers på
127.0.0.1med en reverse proxy foran. - Ingen docker.sock,
privilegedellernetwork_mode: hostuden en god grund.
Quiz
Opgave
Opgave Z9.3: Gennemgå en compose-fil. Eksempelfilen compose-nakijken.txt indeholder (som tekstfil) compose-filen til en lille webshop med en app, en database, en cache og et administrationsværktøj. Der er seks fejl i den, som er gennemgået i denne lektion eller i lektion 9.1 og 9.2. Angiv for hver nummereret blok af linjer, om den er rigtig eller forkert, og vælg for hver fejl den rigtige rettelse. Programmet sammenligner med den faste nøgle. Har du selv en compose-fil, så gennemgå den bagefter efter de samme punkter.
Læs mere
- Docker-dokumentationen, How Compose works (compose.yaml): https://docs.docker.com/compose/intro/compose-application-model/
- Docker-dokumentationen, Version and name top-level elements: https://docs.docker.com/reference/compose-file/version-and-name/
- Docker-dokumentationen, Packet filtering and firewalls (Docker and ufw): https://docs.docker.com/engine/network/packet-filtering-firewalls/
- Docker-dokumentationen, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Docker-dokumentationen, Interpolation (variabler og .env): https://docs.docker.com/reference/compose-file/interpolation/
- VPS: fra første login til sikker server 6.2: Din arbejdsmappe med compose.yaml, .env og Caddy
- VPS: fra første login til sikker server 6.3: Docker og firewallen: udgiv porte sikkert
