Zaawansowany Docker w moment
Wprowadzenie
Docker od lat stanowi fundament współczesnej inżynierii oprogramowania. W świecie, w którym aplikacje muszą być uruchamiane szybko, bezpiecznie i w sposób powtarzalny, konteneryzacja zrewolucjonizowała sposób myślenia o wdrażaniu, testowaniu i utrzymywaniu systemów. Dziś Docker to nie tylko narzędzie dla programistów — to pełnoprawny ekosystem obejmujący procesy CI/CD, środowiska produkcyjne, chmurę, orkiestrację i automatyzację infrastruktury.
Książka „Zaawansowany Docker w moment” została napisana z myślą o osobach, które znają już podstawy Dockera — wiedzą, jak tworzyć obrazy, uruchamiać kontenery i korzystać z prostych konfiguracji docker-compose. Celem tej książki nie jest powtórzenie fundamentów, lecz głębokie zrozumienie mechanizmów, które stoją za Dockerem. Zamiast powierzchownego użycia poleceń, tutaj skupimy się na tym, dlaczego Docker działa tak, jak działa, oraz jak wykorzystać jego pełen potencjał w praktyce.
Po co sięgać po zaawansowany Docker?
Docker w swojej prostocie pozwala każdemu uruchomić aplikację w izolowanym środowisku jednym poleceniem. Ale wraz z rosnącą skalą projektów i wymogami biznesowymi pojawiają się pytania:
— Jak optymalizować obrazy, aby skrócić czas budowania i wdrażania?
— Jak zabezpieczyć kontenery przed atakami i nieautoryzowanym dostępem?
— Jak utrzymać setki kontenerów w środowisku produkcyjnym?
— Jak zautomatyzować cykl życia aplikacji — od kodu po wdrożenie w chmurze?
Na te i wiele innych pytań odpowiada ta książka. Omawia ona Docker nie jako narzędzie programistyczne, lecz jako element pełnego środowiska inżynieryjnego, które łączy aspekty programowania, administracji systemów, bezpieczeństwa i orkiestracji.
Dla kogo jest ta książka
Ta książka została napisana dla:
— programistów, którzy chcą lepiej zrozumieć, co dzieje się „pod maską” kontenerów;
— DevOpsów, którzy potrzebują zoptymalizować i zautomatyzować infrastrukturę;
— administratorów systemów, którzy wdrażają Dockera w środowiskach produkcyjnych;
— architektów systemów, którzy projektują skalowalne aplikacje mikroserwisowe;
— osób, które znają Dockera, ale czują, że używają tylko 20% jego możliwości.
Nie będziemy tłumaczyć podstawowych pojęć jak container, image czy volume. Zamiast tego skupimy się na praktycznych aspektach zarządzania, bezpieczeństwa i optymalizacji Dockera w zaawansowanych środowiskach.
Czego się nauczysz
Po przeczytaniu tej książki będziesz w stanie:
— w pełni zrozumieć architekturę Dockera — od jądra Linuksa po warstwy obrazu;
— budować zoptymalizowane, bezpieczne i wieloetapowe obrazy;
— zarządzać setkami kontenerów i usług z użyciem Docker Compose, Swarm lub Kubernetes;
— wdrażać kontenery w środowiskach chmurowych (AWS, Azure, GCP);
— automatyzować cykl życia kontenerów w pipeline’ach CI/CD;
— pisać własne pluginy, integrować Dockera z API i tworzyć narzędzia wspomagające pracę zespołów DevOps;
— diagnozować problemy z wydajnością, bezpieczeństwem i siecią w czasie rzeczywistym.
Każdy rozdział został zaprojektowany tak, aby można go było czytać niezależnie, ale razem tworzą spójną i logiczną całość — przewodnik po zaawansowanym Dockerze w praktyce.
Jak czytać tę książkę
Nie jest to podręcznik akademicki. Każdy rozdział łączy teorię z praktyką — z rzeczywistymi przykładami, konfiguracjami i przypadkami użycia. Znajdziesz tu konkretne polecenia, fragmenty kodu i konfiguracje, które możesz natychmiast zastosować w swoim środowisku.
W niektórych rozdziałach znajdziesz sekcje oznaczone jako:
— „W praktyce” — pokazujące realne scenariusze użycia;
— „Najczęstsze błędy” — opisujące typowe problemy i ich rozwiązania;
— „Optymalizacja” — praktyczne wskazówki dotyczące wydajności, bezpieczeństwa i zarządzania.
Warto traktować tę książkę nie tylko jako źródło wiedzy, ale także jako kompendium technicznych wskazówek i dobrych praktyk.
Dlaczego „w moment”?
Tytuł tej serii ma w sobie przewrotność — chodzi o to, by złożone zagadnienia wyjaśnić w sposób przystępny i zrozumiały, bez zbędnej teorii i lania wody. Choć książka jest obszerna i technicznie zaawansowana, jej treść została napisana w sposób przejrzysty, logiczny i nastawiony na efektywne przyswajanie wiedzy.
Celem nie jest nauczenie Cię każdej komendy Dockera, lecz przekazanie praktycznej wiedzy inżynierskiej, dzięki której Docker przestanie być narzędziem, a stanie się Twoim sprzymierzeńcem w budowie nowoczesnych, skalowalnych i bezpiecznych systemów.
Docker dzisiaj i jutro
Docker to już nie tylko kontenery. To filozofia pracy — szybkość, automatyzacja, izolacja i niezawodność. Dziś Docker jest obecny w każdej dużej firmie technologicznej, w centrach danych, w chmurach publicznych i prywatnych, a także w środowiskach deweloperskich. Jego wpływ na rozwój DevOps, mikroserwisów i chmury jest nie do przecenienia.
Jednocześnie świat Dockera nieustannie się zmienia: coraz większą rolę odgrywają alternatywne runtime’y (containerd, CRI-O), narzędzia orkiestracji (Kubernetes), nowe modele bezpieczeństwa (rootless containers) i technologie wydajnościowe (Firecracker, Wasm).
Dlatego ta książka nie tylko pokazuje, jak używać Dockera dziś, ale także jak przygotować się na przyszłość konteneryzacji.
Podsumowanie
Zaawansowany Docker w moment to książka dla tych, którzy chcą przekroczyć granicę podstaw i zrozumieć Dockera od strony inżynieryjnej, systemowej i architektonicznej. To podróż od pojedynczego kontenera do całego ekosystemu mikroserwisów w produkcji — od teorii po praktykę, od optymalizacji po bezpieczeństwo.
Docker nie jest już tylko narzędziem — to sposób myślenia o oprogramowaniu. Jeśli chcesz w pełni wykorzystać jego możliwości, ta książka jest Twoim przewodnikiem.
1. Architektura Dockera od podszewki
Docker to nie tylko narzędzie do uruchamiania kontenerów. To złożony system, który wykorzystuje zaawansowane mechanizmy jądra Linux, własne komponenty sieciowe, warstwy przechowywania danych i procesy zarządzające. Zrozumienie tego, jak Docker działa od środka, jest kluczowe, jeśli chcesz tworzyć niezawodne, bezpieczne i wydajne środowiska produkcyjne.
W tym rozdziale zagłębimy się w wewnętrzną architekturę Dockera — od komponentów wysokiego poziomu, takich jak Docker Engine, po mechanizmy niskopoziomowe, jak cgroups, namespaces i union file systems.
1.1. Ogólny model działania Dockera
Docker działa w architekturze klient-serwer, co oznacza, że każda komenda, którą wpisujesz w terminalu (docker run, docker ps itd.), jest w rzeczywistości żądaniem wysyłanym do działającego w tle procesu — Docker Daemon.
[ Docker CLI ] — -> [ Docker Daemon (dockerd) ] — -> [ containerd / runc / kernel ]
Główne komponenty:
— Docker CLI — interfejs wiersza poleceń, z którego korzysta użytkownik.
— Wysyła żądania przez REST API do demona Dockera.
— Docker Daemon (dockerd) — proces zarządzający kontenerami, obrazami, siecią i wolumenami.
— Container Runtime (containerd, runc) — wykonuje rzeczywiste uruchomienie i zarządzanie kontenerami.
— Docker Engine API — REST API, które umożliwia komunikację między CLI, daemonem i aplikacjami zewnętrznymi.
— Plugins / Drivers — rozszerzenia umożliwiające integrację z systemami sieci, storage, logowania itp.
1.2. Docker Engine — serce systemu
Docker Engine to centralny komponent odpowiedzialny za tworzenie, uruchamianie i zarządzanie kontenerami.
W skład silnika wchodzą trzy główne warstwy:
— Docker Daemon (dockerd) — główny proces serwera.
— Zarządza kontenerami, obrazami, sieciami, wtyczkami i innymi zasobami.
— Container Runtime (containerd) — niskopoziomowy demon odpowiedzialny za uruchamianie i zarządzanie kontenerami w imieniu dockerd.
— runc — właściwy silnik wykonawczy, który komunikuje się z jądrem systemu Linux i tworzy izolowane procesy.
Kiedy uruchamiasz kontener, Docker przechodzi przez następujące etapy:
— Docker CLI wysyła polecenie docker run do Docker Daemon.
— Daemon tworzy nowy kontener, wykorzystując obraz z lokalnego cache lub pobrany z rejestru.
— Daemon przekazuje proces do containerd, który wywołuje runc.
— runc konfiguruje przestrzenie nazw (namespaces) i grupy kontrolne (cgroups), a następnie uruchamia proces kontenera.
1.3. Container Runtime — czyli jak naprawdę powstaje kontener
Od wersji Dockera 1.11 wprowadzono rozdzielenie na dwie warstwy wykonawcze:
— containerd — zarządza cyklem życia kontenera (tworzenie, start, zatrzymanie, usunięcie),
— runc — faktycznie uruchamia proces kontenera w izolowanym środowisku
To podejście zgodne ze standardem OCI (Open Container Initiative), który definiuje, jak powinny wyglądać obrazy i środowiska wykonawcze kontenerów.
Każdy kontener to w rzeczywistości jeden proces systemowy, który działa w izolowanych przestrzeniach nazw (namespaces) oraz z ograniczonymi zasobami (cgroups).
1.4. Namespaces — izolacja procesów
Namespaces to mechanizm jądra Linux, który izoluje różne aspekty środowiska kontenera. Dzięki nim kontener „myśli”, że działa w swoim własnym systemie.
Najważniejsze typy namespaces:
Możesz zobaczyć namespaces kontenera za pomocą polecenia:
# Znajdź PID głównego procesu kontenera
docker inspect -f '{{.State. Pid}}” <nazwa_kontenera>
# Wyświetl przypisane przestrzenie nazw
lsns -p <PID>
1.5. Cgroups — kontrola zasobów
Cgroups (control groups) to drugi filar izolacji w Dockerze. Pozwalają ograniczać i monitorować zużycie zasobów (CPU, RAM, I/O, sieć) przez kontenery.
Dzięki cgroups można np. przydzielić kontenerowi tylko 1 rdzeń procesora i 512 MB RAM:
docker run -d \
— cpus=1.0 \
— memory=512m \
nginx
Możesz podejrzeć konfigurację cgroups dla uruchomionego kontenera:
cat /sys/fs/cgroup/memory/docker/<ID_KONTENERA>/memory.limit_in_bytes
Cgroups umożliwiają także śledzenie statystyk i egzekwowanie limitów, dzięki czemu żaden kontener nie zdominuje zasobów hosta.
1.6. Union File Systems — jak Docker zarządza warstwami
Każdy obraz Dockera składa się z wielu warstw (layers), które są nakładane jedna na drugą, tworząc tzw. Union File System.
Każda warstwa jest tylko-do-odczytu (read-only), a kontener ma dodatkową warstwę zapisu (read-write), w której przechowywane są zmiany.
Najczęściej wykorzystywane systemy plików:
— OverlayFS — domyślny w większości nowoczesnych dystrybucji Linuksa, szybki i efektywny.
— AUFS — starszy, ale nadal spotykany w niektórych konfiguracjach.
— btrfs / ZFS — systemy z własnym mechanizmem snapshotów i kompresji.
Aby zobaczyć strukturę warstw obrazu:
docker history nginx: latest
Przykładowy wynik:
IMAGE CREATED CREATED BY SIZE
a1b2c3d4e5f6 2 days ago /bin/sh -c apt-get install -y nginx 35.6MB
b7c8d9e0f1g2 3 days ago /bin/sh -c apt-get update 22.3MB
<missing> 4 days ago /bin/sh -c #(nop) ADD file: abc123 in / 54.7MB
Każda warstwa to oddzielny krok w Dockerfile — dzięki temu Docker może efektywnie wykorzystywać cache.
1.7. Docker Networking — komunikacja między kontenerami
Docker tworzy domyślnie sieć typu bridge, która łączy wszystkie kontenery uruchamiane bez jawnie zdefiniowanej sieci.
Możesz zobaczyć istniejące sieci:
docker network ls
Przykład utworzenia niestandardowej sieci i podłączenia kontenera:
docker network create — driver bridge moja_siec
docker run -d — name web — network moja_siec nginx
docker run -d — name db — network moja_siec mysql
Dzięki sieciom Docker zapewnia izolację ruchu, wirtualne DNS-y i możliwość komunikacji między kontenerami przez nazwy usług.
1.8. Docker Storage — trwałość danych
Domyślnie dane w kontenerze znikają po jego usunięciu. Aby temu zapobiec, Docker korzysta z wolumenów (volumes) i mountów.
Przykład użycia wolumenu:
docker volume create moja_dane
docker run -d \
— v moja_dane:/var/lib/mysql \
mysql
Możesz też zamontować katalog z hosta:
docker run -v /data/logs:/var/log/nginx nginx
Wolumeny są niezależne od cyklu życia kontenera, co umożliwia trwałe przechowywanie danych aplikacji.
1.9. Docker API — jak komunikują się komponenty
Docker udostępnia interfejs REST API, który umożliwia zewnętrznym narzędziom i aplikacjom zarządzanie kontenerami.
Domyślnie API nasłuchuje na gnieździe UNIX:
/var/run/docker.sock
Możesz np. sprawdzić listę kontenerów za pomocą curl:
curl — unix-socket /var/run/docker.sock http://localhost/containers/json
Wynik to dane w formacie JSON opisujące wszystkie uruchomione kontenery.
Wiele narzędzi DevOps (np. Portainer, Rancher, Jenkins) komunikuje się z Dockerem właśnie przez to API.
1.10. Docker Plugins i modularna architektura
Docker został zaprojektowany w sposób modularny. Wiele funkcji (np. sieć, storage, logowanie) można rozszerzać za pomocą pluginów.
Przykłady typów pluginów:
— Volume plugins — integracja z zewnętrznymi systemami plików (NFS, GlusterFS, Amazon EBS).
— Network plugins — integracja z sieciami SDN, np. Weave, Calico, Flannel.
— Logging plugins — wysyłanie logów do systemów zewnętrznych (syslog, Fluentd, AWS CloudWatch).
Przykład instalacji pluginu:
docker plugin install vieux/sshfs
docker volume create -d vieux/sshfs user@host:/path
1.11. Przepływ życia kontenera
— Użytkownik wpisuje:
— docker run nginx
— Docker CLI wysyła żądanie POST do API Dockera.
— Daemon sprawdza, czy obraz istnieje lokalnie. Jeśli nie — pobiera go z rejestru (Docker Hub, ECR, Harbor itd.).
— Tworzony jest nowy kontener:
— inicjalizowane są namespaces i cgroups,
— montowany jest system plików warstwowy,
— konfiguracja sieci i zmiennych środowiskowych.
— containerd wywołuje runc, który uruchamia proces główny kontenera.
— Docker monitoruje stan kontenera i reaguje na zdarzenia (start, stop, restart, kill).
1.12. Podsumowanie
Architektura Dockera to złożony, lecz elegancki system oparty na zasadzie separacji obowiązków.
Każdy komponent — od dockerd, przez containerd, po runc — odpowiada za konkretny etap w cyklu życia kontenera.
Zrozumienie tej architektury pozwala:
— skuteczniej diagnozować błędy,
— precyzyjnie konfigurować zasoby,
— lepiej zabezpieczać środowisko,
— oraz optymalizować wydajność aplikacji.
W kolejnych rozdziałach przejdziemy do szczegółowych aspektów praktycznych: budowania obrazów, zarządzania siecią, bezpieczeństwa i automatyzacji. Ale zanim tam dotrzemy, warto pamiętać — Docker to nie tylko narzędzie do uruchamiania aplikacji, lecz kompletna warstwa abstrakcji nad jądrem systemu operacyjnego.
2. Zaawansowane budowanie obrazów
Budowanie obrazów to jedno z kluczowych zadań w pracy z Dockerem. Na pierwszy rzut oka wydaje się proste — wystarczy plik Dockerfile i polecenie docker build. Jednak w praktyce budowanie obrazów dla dużych projektów, złożonych aplikacji i środowisk produkcyjnych wymaga głębokiego zrozumienia mechanizmów działania Dockera, efektywnego zarządzania warstwami oraz optymalizacji czasu budowy i rozmiaru końcowych obrazów.
W tym rozdziale zagłębimy się w proces budowania obrazów Dockera od strony inżynieryjnej. Poznasz zasady działania cache’a, różnice między builderami, sposoby minimalizacji rozmiaru obrazów, a także zaawansowane techniki, takie jak multi-stage builds, BuildKit, secret management i custom build context.
2.1. Jak Docker buduje obrazy
Kiedy uruchamiasz polecenie:
docker build -t myapp: latest.
Docker wykonuje serię kroków opisanych w pliku Dockerfile. Każdy krok (FROM, RUN, COPY, CMD, itd.) tworzy nową warstwę (layer). Warstwy te są cache’owane i współdzielone między obrazami, co pozwala skrócić czas kolejnych budowań.
Struktura procesu budowania:
— Parsowanie Dockerfile — Docker analizuje wszystkie instrukcje i przygotowuje plan budowania.
— Tworzenie warstw — każda instrukcja generuje nową warstwę w systemie plików typu overlay (np. overlay2 na Linuksie).
— Zastosowanie cache’a — jeśli dany krok nie uległ zmianie, Docker ponownie używa poprzednio zbudowanej warstwy.
— Tworzenie obrazu końcowego — po zakończeniu wszystkich kroków warstwy są scalane w jeden obraz.
2.2. Zrozumienie cache’a budowania
Cache w Dockerze to potężne narzędzie, które potrafi znacznie przyspieszyć proces budowy. Jednak jego niewłaściwe użycie może prowadzić do nieaktualnych zależności lub błędów w obrazie.
Docker przechowuje hash każdej instrukcji i danych wejściowych (np. plików z kontekstu budowy). Jeśli hash się nie zmienia, warstwa zostaje użyta ponownie.
Przykład:
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3
COPY. /app
RUN pip install -r /app/requirements. txt
CMD [„python3”, "/app/app.py”]
Jeśli zmienisz tylko kod aplikacji (COPY. /app), wszystkie wcześniejsze warstwy zostaną użyte z cache’a — co znacząco skraca czas budowania.
Kluczowa zasada:
Docker używa cache’a do momentu, aż natrafi na krok, w którym coś się zmieniło. Od tego miejsca cache jest przerywany i wszystkie kolejne warstwy są budowane od nowa.
2.3. Optymalizacja warstw i kolejności poleceń
Kolejność instrukcji w Dockerfile ma ogromne znaczenie. Nie tylko wpływa na cache, ale także na końcowy rozmiar obrazu.
Zły przykład:
FROM python:3.11
COPY. /app
RUN pip install -r /app/requirements. txt
Tutaj każda zmiana w kodzie aplikacji (COPY. /app) unieważnia cache dla instalacji zależności Pythona.
Lepszy przykład:
FROM python:3.11
WORKDIR /app
COPY requirements. txt.
RUN pip install -r requirements. txt
COPY..
Teraz cache dla zależności Pythona działa efektywnie, bo requirements. txt rzadko się zmienia, a kod aplikacji jest kopiowany dopiero później.
2.4. Multi-stage builds — obrazy wieloetapowe
Jednym z najważniejszych usprawnień w Dockerze jest możliwość budowania obrazów wieloetapowych (multi-stage builds). Pozwala to na stworzenie obrazu, który zawiera tylko to, co niezbędne do uruchomienia aplikacji — bez zbędnych narzędzi kompilacyjnych.
Przykład:
# Etap 1: budowanie aplikacji
FROM golang:1.22 AS builder
WORKDIR /app
COPY..
RUN go build -o main.
# Etap 2: minimalny obraz produkcyjny
FROM alpine: latest
WORKDIR /app
COPY — from=builder /app/main.
CMD [”. /main”]
Pierwszy etap buduje aplikację w pełnym środowisku Go, natomiast drugi etap kopiuje tylko wynik kompilacji do lekkiego obrazu produkcyjnego (alpine).
Dzięki temu obraz końcowy może być nawet 10 razy mniejszy.
2.5. Używanie BuildKit
BuildKit to nowy silnik budowania w Dockerze, zaprojektowany dla wydajności i równoległości. Obsługuje równoległe budowanie warstw, lepszy cache, sekrety i bardziej zaawansowane funkcje.
Aby włączyć BuildKit:
export DOCKER_BUILDKIT=1
docker build -t myapp.
Przykład BuildKit z sekretem:
# syntax=docker/dockerfile:1.3
FROM ubuntu:22.04
RUN — mount=type=secret, id=sshkey \
mkdir /root/.ssh && \
cp /run/secrets/sshkey /root/.ssh/id_rsa && \
chmod 600 /root/.ssh/id_rsa && \
echo „Secret key loaded!”
Aby przekazać sekret do BuildKita:
docker build — secret id=sshkey, src=~/.ssh/id_rsa.
Sekret nie zostanie zapisany w obrazie — dostępny jest tylko podczas budowy. To ogromny krok w kierunku bezpiecznego zarządzania danymi podczas builda.
2.6. Zaawansowane kopie i kontekst budowy
Domyślnie Docker buduje obraz w kontekście katalogu, w którym znajduje się Dockerfile. Wszystko, co zostanie skopiowane do kontenera (COPY. /app), pochodzi właśnie z tego kontekstu.
Aby ograniczyć wielkość kontekstu:
— Używaj. dockerignore, aby wykluczyć pliki niepotrzebne (np..git, node_modules, pliki tymczasowe).
— Używaj wielu kontekstów (docker buildx bake lub — build-context).
Przykład. dockerignore:
.git
__pycache__
*.log
node_modules
Dzięki temu budowa jest szybsza i bezpieczniejsza.
2.7. Minimalizacja rozmiaru obrazu
Rozmiar obrazu wpływa na:
— czas budowania,
— szybkość wdrożenia,
— ilość przesyłanych danych do rejestru.
Sposoby redukcji rozmiaru:
— Używaj lżejszych bazowych obrazów (alpine, distroless, scratch).
— Łącz komendy RUN:
— RUN apt-get update && apt-get install -y curl git && rm -rf /var/lib/apt/lists/*
— Czyść niepotrzebne zależności i pliki tymczasowe.
— Wykorzystuj multi-stage builds.
— Stosuj BuildKit cache mounts, aby nie powielać zależności w każdej warstwie.
2.8. Własne build argumenty i zmienne środowiskowe
Możesz przekazywać argumenty do Dockerfile podczas budowy:
ARG VERSION=latest
FROM ubuntu:${VERSION}
Uruchomienie:
docker build — build-arg VERSION=22.04 -t myubuntu.
Warto jednak pamiętać, że ARG działa tylko podczas budowy, natomiast ENV ustawia zmienne w obrazie wynikowym.
2.9. Zaawansowane tagowanie i wersjonowanie
W środowiskach produkcyjnych stosuje się różne tagi, aby śledzić wersje obrazów.
Przykład:
docker build -t myapp:1.2.0 -t myapp: latest.
Dzięki temu jeden obraz ma wiele etykiet — ułatwia to automatyzację wdrożeń i rollback.
2.10. Diagnostyka procesu budowy
Aby debugować proces budowania:
docker build — progress=plain — no-cache.
Lub sprawdzić szczegóły obrazu:
docker history myapp: latest
docker inspect myapp: latest
2.11. Podsumowanie
Zaawansowane budowanie obrazów to sztuka łączenia wydajności, bezpieczeństwa i powtarzalności. Zrozumienie cache’a, warstw i kontekstu budowy pozwala tworzyć obrazy szybciej, taniej i bardziej niezawodnie.
W praktyce:
— Optymalizuj Dockerfile — każda linijka ma znaczenie.
— Używaj BuildKit — nowoczesny, bezpieczny i szybki silnik budowy.
— Wdrażaj multi-stage builds — oddzielaj build-time od runtime.
— Dbaj o rozmiar — mniej znaczy szybciej.
W kolejnym rozdziale przejdziemy do zagadnień związanych z zarządzaniem kontenerami w środowiskach złożonych i produkcyjnych, gdzie wiedza o obrazach stanie się fundamentem dla skalowalności i automatyzacji wdrożeń.
3. Praca z rejestrami i zarządzanie obrazami
Rejestry Docker (Docker registries) stanowią kluczowy element ekosystemu konteneryzacji. To właśnie one przechowują obrazy, które są budowane, testowane, dystrybuowane i wdrażane w środowiskach produkcyjnych. Zrozumienie mechanizmów działania rejestrów, sposobu zarządzania obrazami oraz zasad bezpieczeństwa i wersjonowania to fundament efektywnego zarządzania cyklem życia kontenerów w złożonych projektach.
W tym rozdziale szczegółowo omówimy:
— rodzaje rejestrów (publiczne i prywatne),
— logowanie i autoryzację,
— publikowanie i pobieranie obrazów,
— wersjonowanie i tagowanie,
— skanowanie bezpieczeństwa,
— zarządzanie obrazami lokalnymi i w chmurze,
— najlepsze praktyki pracy z rejestrami w środowiskach DevOps i CI/CD.
3.1. Czym jest rejestr Docker
Rejestr Docker to zdalny (lub lokalny) magazyn, w którym przechowywane są obrazy Dockera w postaci zestawów warstw. Każdy obraz posiada unikalny identyfikator (digest) oraz jeden lub więcej tagów, które ułatwiają jego identyfikację.
Schemat nazewnictwa obrazu:
[rejestr]/[nazwa_użytkownika lub organizacja]/[repozytorium]:[tag]
Przykłady:
— nginx: latest — obraz z oficjalnego rejestru Docker Hub
— myregistry. local:5000/app/backend:1.0.0 — obraz z prywatnego rejestru
— ghcr.io/org/frontend: prod — obraz przechowywany w GitHub Container Registry
3.2. Docker Hub i inne rejestry publiczne
Najbardziej znanym rejestrem jest Docker Hub — domyślny rejestr, z którego Docker pobiera obrazy, jeśli nie podano innego źródła.
Pobranie obrazu:
docker pull nginx: latest
Wysłanie obrazu:
docker login
docker tag myapp: latest username/myapp: latest
docker push username/myapp: latest
Oprócz Docker Hub istnieje wiele alternatyw:
— GitHub Container Registry (GHCR) — zintegrowany z repozytoriami GitHub, umożliwia automatyczne publikowanie obrazów w pipeline’ach CI/CD,
— GitLab Container Registry — wbudowany w GitLab, wspiera autoryzację przez tokeny,
— Google Artifact Registry, AWS Elastic Container Registry (ECR), Azure Container Registry (ACR) — rejestry chmurowe dla środowisk produkcyjnych.
3.3. Prywatne rejestry Docker
Prywatne rejestry są niezbędne w firmach i organizacjach, które nie chcą przechowywać obrazów w publicznej chmurze. Pozwalają na pełną kontrolę nad bezpieczeństwem, dostępem i polityką wersjonowania.
Uruchomienie własnego rejestru lokalnie:
docker run -d -p 5000:5000 — name registry registry:2
Rejestr jest dostępny pod adresem http://localhost:5000.
Wysłanie obrazu do prywatnego rejestru:
docker tag myapp: latest localhost:5000/myapp:1.0
docker push localhost:5000/myapp:1.0
Pobranie obrazu z prywatnego rejestru:
docker pull localhost:5000/myapp:1.0
Usunięcie obrazu z rejestru:
Lokalny rejestr nie udostępnia prostego API do usuwania obrazów, ale można to zrobić przez REST API:
curl -X DELETE http://localhost:5000/v2/myapp/manifests/<digest>
3.4. Logowanie i autoryzacja
Aby uzyskać dostęp do prywatnych rejestrów, należy się zalogować.
Logowanie do Docker Hub:
docker login
Logowanie do prywatnego rejestru:
docker login myregistry. local:5000
Docker zapisuje dane uwierzytelniające w pliku:
~/.docker/config. json
Przykład zawartości pliku:
{
„auths”: {
„myregistry. local:5000”: {
„auth”: „bXl1c2VyOm15cGFzc3dvcmQ=”
}
}
}
W środowiskach CI/CD dane te są zwykle przechowywane w postaci tokenów dostępu lub zmiennych środowiskowych, a nie jawnych haseł.
3.5. Wersjonowanie i tagowanie obrazów
Wersjonowanie obrazów to kluczowy element utrzymania porządku w środowiskach produkcyjnych. Tagi umożliwiają jednoznaczne wskazanie wersji aplikacji.
Typowe strategie tagowania:
— Semantyczna wersja — np. 1.0.0, 1.1.2, 2.0.0-rc1
— Tag dynamiczny — np. latest, dev, prod
— Tag z datą lub commit SHA — np. 2025-10-09, sha-3e4f2c
Przykład:
docker build -t registry. local:5000/myapp:1.2.3.
docker tag registry. local:5000/myapp:1.2.3 registry. local:5000/myapp: latest
docker push registry. local:5000/myapp — all-tags
W praktyce w środowiskach CI/CD warto automatycznie generować tagi, np. z numeru builda lub hasha commit’u.
3.6. Przeglądanie i zarządzanie obrazami lokalnymi
Docker pozwala zarządzać obrazami przechowywanymi lokalnie na hoście.
Lista obrazów:
docker images
Szczegóły obrazu:
docker inspect myapp: latest
Historia warstw obrazu:
docker history myapp: latest
Usuwanie obrazów:
docker rmi myapp: latest
Usuwanie nieużywanych obrazów:
docker image prune -a
Oznaczanie obrazów do ponownego użycia:
docker tag oldimage:1.0 newimage: stable
3.7. Skanowanie bezpieczeństwa obrazów
Bezpieczeństwo kontenerów zaczyna się od bezpieczeństwa obrazów. Warto regularnie skanować je pod kątem znanych luk (CVE).
Wbudowane narzędzie w Docker Hub:
Docker Hub automatycznie skanuje obrazy po przesłaniu ich do rejestru.
Narzędzie CLI — docker scan (powered by Snyk):
docker scan myapp: latest
Przykład raportu:
✗ Medium severity vulnerability found in glibc
Description: CVE-2024-0001
Remediation: Upgrade to version 2.35 or later
Alternatywy:
— Trivy (Aqua Security)
— Clair (CoreOS)
— Anchore Engine
3.8. Zarządzanie dostępem i bezpieczeństwem rejestrów
W środowiskach produkcyjnych należy stosować zasadę least privilege — dostęp tylko dla osób lub systemów, które go rzeczywiście potrzebują.
Najlepsze praktyki:
— Używaj tokenów dostępu zamiast haseł,
— Ograniczaj prawa użytkowników (tylko „read” lub „write”),
— Stosuj TLS (HTTPS) nawet dla lokalnych rejestrów,
— Regularnie usuwaj nieużywane obrazy i tagi,
— Włącz automatyczne skanowanie i alerty bezpieczeństwa.
Konfiguracja TLS dla lokalnego rejestru:
— Wygeneruj certyfikat:
openssl req -newkey rsa:4096 -nodes -sha256 -keyout domain.key -x509 -days 365 -out domain.crt
— Uruchom rejestr z TLS:
docker run -d \ -p 443:5000 \ — name registry \ -v $(pwd)/certs:/certs \ -e REGISTRY_HTTP_ADDR=0.0.0.0:5000 \ -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \ -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \ registry:2
3.9. Integracja rejestrów z CI/CD
Automatyzacja publikacji i pobierania obrazów jest nieodzowna w cyklu DevOps.
Przykład (GitLab CI/CD):
stages:
— build
— deploy
build_image:
stage: build
script:
— docker build -t registry. local:5000/myapp:$CI_COMMIT_SHORT_SHA.
— docker push registry. local:5000/myapp:$CI_COMMIT_SHORT_SHA
Przykład (GitHub Actions):
jobs:
build:
runs-on: ubuntu-latest
steps:
— uses: actions/checkout@v4
— name: Build and Push
run: |
echo $CR_PAT | docker login ghcr.io -u $GITHUB_ACTOR — password-stdin
docker build -t ghcr.io/myorg/myapp:${{ github.sha }}.
docker push ghcr.io/myorg/myapp:${{ github.sha }}
3.10. Czyszczenie i utrzymywanie rejestrów
Z czasem rejestry mogą się rozrastać, zajmując setki gigabajtów danych. Regularne utrzymanie jest kluczowe.
Praktyki konserwacyjne:
— Automatyczne usuwanie starych tagów po określonym czasie,
— Usuwanie „dangling” warstw (bez przypisanego taga),
— Archiwizacja obrazów z poprzednich wersji,
— Limitowanie liczby wersji w rejestrze.
Przykład skryptu usuwającego stare obrazy:
docker image prune -a — filter „until=240h”
3.11. Podsumowanie
Praca z rejestrami i zarządzanie obrazami to nie tylko umiejętność techniczna — to element strategii bezpieczeństwa, automatyzacji i ciągłości działania w świecie kontenerów. Znajomość narzędzi, dobrych praktyk i architektury rejestrów pozwala uniknąć chaosu, zwiększyć bezpieczeństwo i przyspieszyć wdrażanie aplikacji.
Najważniejsze wnioski:
— Traktuj obrazy jak artefakty — wersjonuj, skanuj i utrzymuj porządek.
— Używaj prywatnych rejestrów do środowisk produkcyjnych.
— Automatyzuj publikację i pobieranie obrazów w pipeline’ach CI/CD.
— Dbaj o bezpieczeństwo — stosuj TLS, tokeny i skanowanie CVE.
W kolejnym rozdziale przejdziemy do pracy z zaawansowaną siecią kontenerową, w której omówimy komunikację między usługami, konfigurację wirtualnych sieci oraz izolację kontenerów w złożonych środowiskach produkcyjnych.
4. Docker Compose i orkiestracja lokalna
Docker Compose to narzędzie, które pozwala definiować, konfigurować i uruchamiać wielokontenerowe aplikacje przy użyciu jednego pliku YAML. Choć w porównaniu do zaawansowanych systemów orkiestracji, takich jak Kubernetes czy Docker Swarm, Compose wydaje się prostszy, jego rola w środowiskach deweloperskich, testowych i integracyjnych jest nie do przecenienia.
W tym rozdziale szczegółowo poznamy mechanizmy działania Docker Compose, nauczymy się tworzyć złożone pliki docker-compose. yml, zarządzać sieciami, wolumenami, zależnościami między usługami oraz wdrażać aplikacje lokalnie w sposób powtarzalny i automatyczny.
4.1. Czym jest Docker Compose
Docker Compose to narzędzie, które umożliwia zdefiniowanie całego środowiska aplikacji w jednym pliku YAML. Dzięki temu można w prosty sposób uruchamiać wiele kontenerów współpracujących ze sobą — np. aplikację webową, bazę danych, cache i system kolejkowania.
Zamiast ręcznie uruchamiać każdy kontener poleceniem docker run, wystarczy jedno polecenie:
docker compose up
Compose zajmuje się automatycznie:
— tworzeniem sieci między kontenerami,
— budowaniem obrazów,
— tworzeniem i podłączaniem wolumenów,
— uruchamianiem usług w odpowiedniej kolejności.
4.2. Instalacja i podstawy
Docker Compose jest zintegrowany z nowszymi wersjami Dockera (CLI docker compose zamiast docker-compose).