Zrozumienie kontenerów
Moduł 9: Docker i docker compose · Czas czytania: 10 min
Cel lekcji: Po tej lekcji potrafią Państwo wyjaśnić, czym jest kontener, czym różni się od maszyny wirtualnej, gdzie zostają dane kontenera i kiedy Docker ma sens na Państwa serwerze.
Kluczowe pojęcia: obraz (image), kontener, warstwa, rejestr (Docker Hub), tag, digest, namespaces, cgroups, współdzielone jądro, ulotny system plików, wolumen (volume), bind mount, publikowanie portu, oficjalny obraz
Dlaczego kontenery?
Załóżmy, że chcą Państwo uruchomić na swoim VPS stronę statusu, która pokazuje, czy Państwa witryna działa. Program jest napisany w Node.js, wymaga określonej wersji Node.js oraz około dwustu bibliotek. Bez kontenerów instalują Państwo to wszystko na serwerze, obok serwera WWW i bazy danych. Rok później potrzebują Państwo drugiego programu, który wymaga innej wersji Node.js. Wtedy zaczyna się układanie łamigłówki.
Kontener rozwiązuje ten problem. Twórca programu dostarcza program razem ze wszystkim, czego on potrzebuje, w jednej paczce: obrazie (image). Na serwerze uruchamiają Państwo ten obraz jako kontener. Program widzi własne pliki, własny Node.js, własne biblioteki i nie wchodzi w konflikt z resztą serwera. Chcą się go Państwo pozbyć? Usuwają Państwo kontener i obraz, a w /usr ani w /etc nic nie zostaje.
Docker to najbardziej znane narzędzie do pobierania obrazów i uruchamiania kontenerów. Istnieją alternatywy (Podman, sam containerd), ale pojęcia są wszędzie takie same.
Obraz, kontener i rejestr
Trzy słowa, które będą Państwo stale spotykać:
- Obraz (image): szablon tylko do odczytu, zawierający system plików (program, biblioteki, ustawienia) oraz polecenie, które ma zostać uruchomione. Obraz składa się z warstw: warstwy bazowej (na przykład czystego Debiana), nad nią warstwy z Node.js, a nad nią samego programu. Dwa obrazy z tą samą warstwą bazową współdzielą ją na dysku.
- Kontener: działający (lub zatrzymany) egzemplarz obrazu. Na wierzchu warstw tylko do odczytu kontener otrzymuje własną cienką warstwę zapisu. Z jednego obrazu można uruchomić dziesięć kontenerów.
- Rejestr (registry): miejsce, w którym przechowywane są obrazy, na przykład Docker Hub (
docker.io) lub rejestr GitHuba (ghcr.io). Docker pobiera obraz poleceniemdocker pull.
Nazwa obrazu wygląda tak:
louislam/uptime-kuma:2
caddy:2
vaultwarden/server:latestCzęść po dwukropku to tag: etykieta wersji. Tag może się zmieniać: caddy:2 wskazuje dziś na inną kompilację niż za trzy miesiące, gdy tylko pojawi się nowa wersja 2.x. Jeśli chcą Państwo dokładnie ustalić, który obraz działa, prosimy użyć digestu: odcisku zawartości, na przykład caddy@sha256:.... Ten nigdy się nie zmienia. Tag latest to po prostu nazwa wybrana przez twórcę; nie oznacza automatycznie "najnowszej stabilnej wersji", dlatego jest złym wyborem, jeśli chcą Państwo wiedzieć, co działa.
To nie maszyna wirtualna
Kontener przypomina małą maszynę wirtualną, ale nią nie jest. Ta różnica ma znaczenie dla bezpieczeństwa.
| Maszyna wirtualna (jak Państwa VPS) | Kontener | |
|---|---|---|
| Jądro | Własne jądro | Współdzieli jądro hosta |
| Uruchamianie | Od sekund do minut, cały system operacyjny | Zwykle w sekundę, tylko program |
| Izolacja | Przez hypervisor, na poziomie sprzętu | Przez jądro: namespaces i cgroups |
| Rozmiar | Gigabajty | Często od kilkudziesięciu do kilkuset megabajtów |
Kontener to w rzeczywistości zwykły proces na serwerze, który jądro umieszcza w odizolowanym środowisku:
- namespaces sprawiają, że proces ma własny widok plików, procesów, sieci i użytkowników. W kontenerze program wydaje się być procesem numer 1 i nie widzi reszty serwera;
- cgroups ograniczają, ile procesora i pamięci może on wykorzystać.
Ponieważ wszystkie kontenery współdzielą to samo jądro, izolacja jest słabsza niż między dwoma serwerami VPS. Luka w jądrze lub kontener z nadmiernymi uprawnieniami może zagrozić hostowi. Stąd zasady z tego modułu: prosimy uruchamiać wyłącznie zaufane obrazy, nie nadawać kontenerom większych uprawnień niż to konieczne i nigdy nie montować w kontenerze /var/run/docker.sock ani / (lekcja 9.3 i 10.2).
Gdzie zostają Państwa dane?
To klasyczna pułapka dla początkujących. Warstwa zapisu kontenera jest ulotna: jeśli usuną Państwo kontener (na przykład podczas aktualizacji, lekcja 9.4), wszystko, co program w niej zapisał, przepada. Dane, które mają przetrwać, należy więc przechowywać poza kontenerem:
- Wolumen (volume): miejsce na dane, którym zarządza sam Docker (w
/var/lib/docker/volumes/). Nadają mu Państwo nazwę, na przykładuptime-kuma, i podłączają go do katalogu w kontenerze:-v uptime-kuma:/app/data. - Bind mount: zwykły katalog na serwerze, który podłączają Państwo do kontenera:
-v /srv/vaultwarden:/data. Wygodne, bo pliki widać bezpośrednio i łatwo uwzględnić je w kopii zapasowej (moduł 8).
Kontener z dobrze skonfigurowanymi wolumenami można usunąć i utworzyć od nowa bez utraty danych. Dokładnie tak działa aktualizacja: pobranie nowego obrazu, usunięcie starego kontenera, nowy kontener na tych samych wolumenach. Dlatego prosimy uwzględnić wolumeny w planie kopii zapasowych (lekcja 8.1).
Publikowanie portów
Kontener ma własną sieć. Program webowy, który w kontenerze nasłuchuje na porcie 3001, nie jest dostępny spoza serwera, dopóki nie opublikują Państwo tego portu: -p 3001:3001 (port hosta:port kontenera). Uwaga: bez podania adresu Docker publikuje port na wszystkich adresach serwera, czyli 0.0.0.0 i [::]. Oznacza to dostępność z całego internetu, a Docker ustawia to z pominięciem ufw (lekcja 9.3). Bezpieczny nawyk to publikowanie na loopbacku, -p 127.0.0.1:3001:3001, i umieszczenie przed kontenerem reverse proxy z https (lekcja 9.4).
Kto tworzy obraz?
Obraz to oprogramowanie innej osoby, które może działać na Państwa serwerze jako root. Dlatego prosimy sprawdzić, kto jest jego twórcą:
- Docker Official Images (na przykład
caddy,nginx,postgres) są utrzymywane przez Dockera wspólnie z twórcami; - obrazy samego twórcy (na przykład
louislam/uptime-kumaivaultwarden/server), rozpoznawalne po nazwie podanej na stronie projektu; - obrazy nieznanych autorów o podobnie brzmiących nazwach: nie używać.
Prosimy zawsze używać nazwy podanej na oficjalnej stronie projektu, a nie pierwszej, którą zwróci wyszukiwarka.
Kiedy tak, kiedy nie?
Docker przydaje się do programów, które twórca dostarcza jako obraz, do usług, które chcą Państwo szybko usunąć lub przenieść, oraz do uruchamiania obok siebie kilku programów o różnych wymaganiach. Do podstaw serwera (SSH, zapora, aktualizacje) nie używa się kontenerów. Pojedyncza strona z nginx i PHP z repozytorium pakietów (lekcja 7.2) działa świetnie bez Dockera. Kontener dodaje warstwę, którą trzeba rozumieć i aktualizować; warto go używać, gdy coś to daje.
Podsumowanie
- Obraz to szablon tylko do odczytu złożony z warstw; kontener to działający egzemplarz z własną warstwą zapisu.
- Kontenery współdzielą jądro hosta i są izolowane za pomocą namespaces i cgroups: są lżejsze niż VM, ale słabiej odseparowane.
- Warstwa zapisu jest ulotna: trwałe dane należy trzymać w wolumenie lub bind mount, a te powinny trafić do kopii zapasowej.
- Tag może się zmienić, digest nie;
latestmówi niewiele. - Prosimy publikować porty na 127.0.0.1 i używać wyłącznie obrazów twórcy lub obrazów oficjalnych.
Quiz
Zadanie
Zadanie O9.1: Kontener czy nie? Prosimy wybrać dwa programy, które chcą Państwo uruchomić na swoim serwerze (lub użyć jako przykładu Uptime Kuma i strony WordPress). Dla każdego programu prosimy sprawdzić, czy twórca dostarcza oficjalny obraz i pod jaką nazwą, jaki tag by Państwo wybrali, który katalog zawiera trwałe dane i na jakim porcie program nasłuchuje. Następnie prosimy wyjaśnić, czy uruchomiliby go Państwo w kontenerze, czy z repozytorium pakietów, i dlaczego.
Zadanie O9.1: Kontener czy nie?
To zadanie wykonuje się samodzielnie, nikt go nie sprawdza. Prosimy zaznaczyć wykonane punkty i oznaczyć zadanie jako wykonane.
Uptime Kuma: louislam/uptime-kuma z tagiem wersji, dane w /app/data, port 3001, publikowanie na 127.0.0.1 za reverse proxy. Prosimy wybrać obraz od twórcy lub Official Image, z tagiem wersji i nazwanym katalogiem danych.
Zaznaczenia i notatki pozostają tylko w tej przeglądarce; nie są nigdzie wysyłane. Po zalogowaniu w Moje kursy zapisywana jest jedynie informacja, że zadanie zostało wykonane.
Przeczytaj więcej
- Dokumentacja Dockera, What is a container?: https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/
- Dokumentacja Dockera, Volumes: https://docs.docker.com/engine/storage/volumes/
- Dokumentacja Dockera, Port publishing and mapping: https://docs.docker.com/engine/network/port-publishing/
- Docker Official Images: https://docs.docker.com/docker-hub/repos/manage/trusted-content/official-images/
