Moduuli 9 · 9.3
Docker compose ja palomuuri
Moduuli 9: Docker ja docker compose · Lukuaika: 12 minuuttia
Tavoite: Tämän oppitunnin jälkeen osaat kuvata palvelut compose-tiedostossa, käynnistää, päivittää ja pysäyttää ne. Osaat myös selittää, miksi Dockerin julkaisemat portit ohittavat ufw:n ja miten sen voi estää.
Keskeiset käsitteet: compose.yaml, services, image, ports, volumes, environment, .env, restart, networks, depends_on, healthcheck, docker compose up -d, pull, logs, down, vanhentunut version:, Docker ja ufw, DOCKER-USER, julkaiseminen osoitteeseen 127.0.0.1, salaisuudet, docker.sock
Miksi compose?
Komennolla docker run (oppitunti 9.2) käynnistät yhden kontin pitkällä rivillä valitsimia. Oikea sovellus koostuu usein useasta kontista: ohjelmasta, tietokannasta ja käänteisestä välityspalvelimesta. Jos nuo rivit pitää muistaa ja kirjoittaa uudelleen jokaisen uudelleenkäynnistyksen tai päivityksen jälkeen, jossain vaiheessa jokin menee pieleen.
Docker Compose kuvaa sovelluksen kaikki kontit yhdessä tiedostossa: compose.yaml. Laitat tiedoston omaan kansioonsa, esimerkiksi /srv/status/compose.yaml, ja hallitset kaikkea komennolla docker compose. Tiedosto toimii samalla dokumentaationa: mitä on käynnissä, mikä image, mitkä portit ja missä tiedot ovat. Kun otat kansion mukaan varmuuskopioon (oppitunti 8.1), voit palauttaa sovelluksen uudelle palvelimelle muutamassa minuutissa.
Liitännäisen nimi on docker compose (välilyönnillä, versio 2). Vanha erillinen ohjelma docker-compose (yhdysmerkillä) on korvattu, mutta näet sen yhä vanhoissa ohjeissa. Myös vanhojen tiedostojen alussa ollut kenttä version: "3.8" on vanhentunut: Compose käyttää aina uusinta skeemaa ja antaa kentästä version: vain varoituksen.
Compose-tiedoston lukeminen
Esimerkki, jossa on ohjelma ja PostgreSQL-tietokanta:
# /srv/muistiinpanot/compose.yaml
services:
app:
image: ghcr.io/example/muistiinpanot:1.4
restart: unless-stopped
ports:
- "127.0.0.1:8081:8080"
environment:
DB_HOST: db
DB_USER: muistiinpanot
DB_PASSWORD: ${DB_PASSWORD}
depends_on:
db:
condition: service_healthy
db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_USER: muistiinpanot
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U muistiinpanot"]
interval: 10s
retries: 5
volumes:
db-data:Vaihe vaiheelta:
- services: jokaisesta palvelusta tulee kontti. Nimi (
app,db) on myös isäntänimi, jolla kontit löytävät toisensa. Compose luo sovellukselle oman verkon, jotenappyhdistää tietokantaan osoitteessadb:5432. - image: aina versiotagilla (oppitunti 9.1).
- restart: mitä Docker tekee, kun kontti pysähtyy tai palvelin käynnistyy uudelleen.
unless-stoppedkäynnistää sen uudelleen, paitsi jos pysäytit sen itse tarkoituksella. Ilman restart-käytäntöä sovelluksesi ei palaa uudelleenkäynnistyksen (oppitunti 4.2) jälkeen. - ports: vain sovellus julkaisee portin, ja vain osoitteeseen
127.0.0.1. Tietokanta ei julkaise mitään: sovellus tavoittaa sen sisäisen verkon kautta. Tietokanta, jolla onports: - "5432:5432", on yksi yleisimmistä virheistä (katso alempaa). - environment: ohjelman asetukset. Salasana ei ole tiedostossa sellaisenaan vaan muodossa
${DB_PASSWORD}. - volumes: nimetty volyymi
db-datasäilyttää tietokannan, kun kontti vaihdetaan. - depends_on yhdessä healthcheckin kanssa: sovellus käynnistyy vasta, kun tietokanta on oikeasti valmis eikä vain käynnistynyt.
Salaisuudet .env-tiedostossa
Compose lukee muuttujat, kuten ${DB_PASSWORD}, samassa kansiossa olevasta tiedostosta .env:
# /srv/muistiinpanot/.env
DB_PASSWORD=Valitse-tahan-pitka-satunnainen-salasanaanna@web1:/srv/muistiinpanot$ sudo chmod 600 .envNäin salasana ei ole compose-tiedostossa, jota ehkä säilytät Gitissä tai liität foorumille avunpyyntöön. Lisää .env tiedostoon .gitignore. Luo salasana salasanojen hallintaohjelmalla tai komennolla openssl rand -base64 24.
Päivittäinen käyttö
Kaikki komennot ajetaan kansiossa, jossa compose-tiedosto on:
anna@web1:/srv/muistiinpanot$ sudo docker compose config # tarkista tiedosto, muuttujat täytettyinä
anna@web1:/srv/muistiinpanot$ sudo docker compose up -d # käynnistä kaikki (tai päivitä tiedoston mukaiseksi)
anna@web1:/srv/muistiinpanot$ sudo docker compose ps # tila palveluittain
anna@web1:/srv/muistiinpanot$ sudo docker compose logs -f app
anna@web1:/srv/muistiinpanot$ sudo docker compose pull # hae uudet imaget
anna@web1:/srv/muistiinpanot$ sudo docker compose up -d # korvaa kontit uusilla imageilla
anna@web1:/srv/muistiinpanot$ sudo docker compose down # pysäytä ja poista kontitdown jättää volyymit paikalleen. down -v poistaa myös sovelluksen volyymit ja samalla tietokantasi. Kirjoita se vain, jos haluat todella aloittaa alusta.
docker compose config vastaa komentoja nginx -t ja sshd -t: se näyttää, miten Compose ymmärtää tiedostosi kaikkine muuttujineen, ennen kuin käynnistät mitään. Älä liitä tulostetta mihinkään, sillä salasanat näkyvät siinä.
Docker ohittaa ufw:n
Nyt tämän moduulin tärkein tietoturva-asia. Oppitunnilla 5.2 määritit ufw:n asetukseksi "estä kaikki paitsi SSH, 80 ja 443". Voisi olettaa, että kontti, jolla on ports: - "5432:5432", ei silloin ole tavoitettavissa. Näin ei ole.
Dockerin dokumentaatio sanoo sen suoraan: Docker ja ufw käyttävät palomuurisääntöjä tavalla, joka ei sovi yhteen. Kun julkaiset portin, Docker lisää itse sääntöjä ytimen palomuuriin. Nämä säännöt ohjaavat liikenteen konttiin (osoitteenmuunnos, DNAT) ennen kuin ufw:n sääntöjä sovelletaan. Paketti siis kiertää ufw:n. ufw status ei näytä mitään erikoista, vaikka portti on koko internetin tavoitettavissa. Sama koskee firewalld:tä.
Lisäksi Docker julkaisee ilman osoitetta osoitteisiin 0.0.0.0 ja [::], eli sekä IPv4:ssä että IPv6:ssa (oppitunti 9.1).
Kolme tapaa tehdä se oikein, helpoimmasta vaikeimpaan:
- Älä julkaise mitään, minkä ei tarvitse olla julkista. Tietokannat, välimuistit ja sisäiset palvelut eivät saa riviä
ports:. Saman compose-sovelluksen kontit tavoittavat toisensa sisäisen verkon kautta. - Julkaise loopback-osoitteeseen.
"127.0.0.1:8081:8080". Silloin vain palvelin itse pääsee siihen käsiksi, ja eteen laitetaan käänteinen välityspalvelin (nginx tai Caddy, moduuli 7), joka kuuntelee porttia 443. Tämän voi myös asettaa Dockerin oletukseksi: daemonin asetus ohjaa kaikki ilman osoitetta julkaistut portit osoitteeseen127.0.0.1. - Säännöt DOCKER-USER-ketjuun. Docker luo tyhjän ketjun
DOCKER-USER, joka käydään läpi ennen sen omia sääntöjä. Sinne voit lisätä omia sääntöjä, esimerkiksi "vain tämä IP-osoite pääsee julkaistuihin portteihin". Se on edistynyttä työtä iptablesilla tai nftablesilla, ja siinä on helppo tehdä virheitä. Useimmille pienille palvelimille vaihtoehdot 1 ja 2 riittävät.
Tarkista aina ulkopuolelta, kuten oppitunnilla 5.1: nc -vz -w 3 <ip> 5432 kannettavalta koneeltasi tai kurssin tarkistuksella tehtävissä Z5.1 ja Z10.4.
Kaksi muuta asiaa, joita et tee
- Älä liitä
/var/run/docker.sockkonttiin, ellet tiedä tarkalleen miksi. Kontti, jolla on pääsy Docker-sokettiin, voi itse käynnistää kontteja, myös sellaisen, jolla on käytössään isännän koko levy (oppitunti 9.2). Jotkin apuohjelmat (kojelaudat, automaattiset päivittäjät) pyytävät sitä. Käytännössä se tarkoittaa root-oikeuksien antamista ohjelmalle. - Älä käytä
privileged: truetainetwork_mode: hostvain siksi, että ohje käskee. Molemmat poistavat suurimman osan kontin eristyksestä. Käytä niitä vain, jos tekijä selittää, miksi se on tarpeen.
Yhteenveto
- Compose-tiedosto (
compose.yaml) kuvaa sovelluksen kaikki kontit. Se on samalla dokumentaatiota ja kuuluu varmuuskopioon. - Käytä versiotageja, restart-käytäntöä, nimettyjä volyymejä, healthcheckiä aina kun mahdollista ja säilytä salaisuudet tiedostossa
.env, jonka oikeudet ovat 600. docker compose config,up -d,ps,logs,pull,down;down -vpoistaa myös volyymit.- Julkaistut portit ohittavat ufw:n ja firewalld:n. Julkaise vain se, minkä täytyy olla julkista, ja muuten osoitteeseen
127.0.0.1käänteisen välityspalvelimen taakse. - Ei docker.sockia,
privilegedtainetwork_mode: hostilman hyvää syytä.
Tietovisa (quiz)
Tehtävä
Tehtävä Z9.3: Compose-tiedoston tarkistaminen. Esimerkkitiedostossa compose-nakijken.txt on (tekstitiedostona) pienen verkkokaupan compose-tiedosto, jossa on sovellus, tietokanta, välimuisti ja hallintatyökalu. Siinä on kuusi virhettä, joita on käsitelty tällä oppitunnilla tai oppitunneilla 9.1 ja 9.2. Merkitse jokaisesta numeroidusta rivilohkosta, onko se oikein vai väärin, ja valitse jokaiseen virheeseen oikea korjaus. Ohjelma vertaa vastauksiasi kiinteään avaimeen. Jos sinulla on oma compose-tiedosto, käy se sen jälkeen läpi samojen kohtien avulla.
Lue lisää
- Dockerin dokumentaatio, How Compose works (compose.yaml): https://docs.docker.com/compose/intro/compose-application-model/
- Dockerin dokumentaatio, Version and name top-level elements: https://docs.docker.com/reference/compose-file/version-and-name/
- Dockerin dokumentaatio, Packet filtering and firewalls (Docker and ufw): https://docs.docker.com/engine/network/packet-filtering-firewalls/
- Dockerin dokumentaatio, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Dockerin dokumentaatio, Interpolation (muuttujat ja .env): https://docs.docker.com/reference/compose-file/interpolation/
- VPS: ensimmäisestä kirjautumisesta turvalliseen palvelimeen 6.2: Työhakemisto: compose.yaml, .env ja Caddy
- VPS: ensimmäisestä kirjautumisesta turvalliseen palvelimeen 6.3: Docker ja palomuuri: porttien turvallinen julkaiseminen
