Michał Walendowski

Zaawansowany Docker w moment

Książka stworzona przy pomocy AI

© Michał Walendowski, 2025

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. Książka stworzona przy pomocy AI

ISBN 978-83-8431-652-8

Książka powstała w inteligentnym systemie wydawniczym Ridero

Spis treści

Zaawansowany Docker w moment

Wprowadzenie

Po co sięgać po zaawansowany Docker?

Dla kogo jest ta książka

Czego się nauczysz

Jak czytać tę książkę

Dlaczego „w moment”?

Docker dzisiaj i jutro

Podsumowanie

1. Architektura Dockera od podszewki

1.1. Ogólny model działania Dockera

1.2. Docker Engine — serce systemu

1.3. Container Runtime — czyli jak naprawdę powstaje kontener

1.4. Namespaces — izolacja procesów

1.5. Cgroups — kontrola zasobów

1.6. Union File Systems — jak Docker zarządza warstwami

1.7. Docker Networking — komunikacja między kontenerami

1.8. Docker Storage — trwałość danych

1.9. Docker API — jak komunikują się komponenty

1.10. Docker Plugins i modularna architektura

1.11. Przepływ życia kontenera

1.12. Podsumowanie

2. Zaawansowane budowanie obrazów

2.1. Jak Docker buduje obrazy

2.2. Zrozumienie cache’a budowania

2.3. Optymalizacja warstw i kolejności poleceń

2.4. Multi-stage builds — obrazy wieloetapowe

2.5. Używanie BuildKit

2.6. Zaawansowane kopie i kontekst budowy

2.7. Minimalizacja rozmiaru obrazu

2.8. Własne build argumenty i zmienne środowiskowe

2.9. Zaawansowane tagowanie i wersjonowanie

2.10. Diagnostyka procesu budowy

2.11. Podsumowanie

3. Praca z rejestrami i zarządzanie obrazami

3.1. Czym jest rejestr Docker

3.2. Docker Hub i inne rejestry publiczne

3.3. Prywatne rejestry Docker

3.4. Logowanie i autoryzacja

3.5. Wersjonowanie i tagowanie obrazów

3.6. Przeglądanie i zarządzanie obrazami lokalnymi

3.7. Skanowanie bezpieczeństwa obrazów

3.8. Zarządzanie dostępem i bezpieczeństwem rejestrów

3.9. Integracja rejestrów z CI/CD

3.10. Czyszczenie i utrzymywanie rejestrów

3.11. Podsumowanie

4. Docker Compose i orkiestracja lokalna

4.1. Czym jest Docker Compose

4.2. Instalacja i podstawy

4.3. Architektura Docker Compose

4.4. Budowanie i uruchamianie usług

4.5. Zależności między usługami — depends_on

4.6. Sieci w Docker Compose

4.7. Wolumeny i trwałość danych

4.8. Zmienne środowiskowe i pliki. env

4.9. Profile usług (profiles)

4.10. Skalowanie usług

4.11. Docker Compose override

4.12. Inspekcja i debugowanie usług

4.13. Integracja Docker Compose z CI/CD

4.14. Docker Compose v2 i BuildKit

4.15. Przykład kompletnego środowiska z Compose

4.16. Podsumowanie

5. Networking — sieci kontenerów w praktyce

5.1. Wprowadzenie do sieci Dockera

5.2. Architektura sieci Dockera

5.3. Typy sieci w Dockerze

5.4. Sieć typu bridge — lokalna komunikacja

5.5. Sieć typu host — bezpośredni dostęp do hosta

5.6. Sieć typu none — pełna izolacja

5.7. Sieć typu overlay — multi-host i orkiestracja

5.8. Sieć typu macvlan — kontenery z własnym adresem MAC

5.9. Inspekcja sieci

5.10. Przypisywanie statycznych adresów IP

5.11. DNS w Dockerze

5.12. Komunikacja między sieciami

5.13. Diagnostyka sieci kontenerowych

5.14. Praktyczny przykład — aplikacja wielowarstwowa

5.15. Sieci użytkownika w trybie produkcyjnym

5.16. Integracja z zewnętrznymi systemami

5.17. Podsumowanie

6. Storage i trwałość danych

6.1. Trwałość danych — podstawowe pojęcia

6.2. Wolumeny (Volumes)

6.3. Bind mounts — powiązanie katalogu hosta

6.4. tmpfs — dane tylko w pamięci

6.5. Różnice między wolumenami, bind mounts i tmpfs

6.6. Montowanie za pomocą — mount

6.7. Użycie wolumenów w Docker Compose

6.8. Wolumeny anonimowe i nazwane

6.9. Backup i przywracanie danych z wolumenów

6.10. Współdzielenie wolumenów między kontenerami

6.11. Wolumeny tylko do odczytu

6.12. Wtyczki do wolumenów (Volume Drivers)

6.13. Tworzenie snapshotów danych

6.14. Rozproszone systemy plików

6.15. Zarządzanie wolumenami

6.16. Optymalizacja wydajności I/O

6.17. Przykład kompleksowej konfiguracji

6.18. Podsumowanie

7. Bezpieczeństwo kontenerów

7.1. Dlaczego bezpieczeństwo w Dockerze jest inne?

7.2. Model bezpieczeństwa Dockera

7.3. Namespaces — izolacja procesów

7.4. Cgroups — ograniczanie zasobów

7.5. Capabilities — redukcja uprawnień root

7.6. User namespaces — odseparowanie użytkowników

7.7. AppArmor i SELinux — kontrola dostępu

7.8. Seccomp — filtracja syscalli

7.9. Uruchamianie kontenerów jako nie-root

7.10. Skanowanie obrazów pod kątem podatności

7.11. Podpisywanie i weryfikacja obrazów

7.12. Ograniczenie dostępu do socka Dockera

7.13. Rootless Docker — Docker bez roota

7.14. Ochrona sieci kontenerowej

7.15. Ochrona danych i tajemnic (Secrets)

7.16. Audyt i logowanie

7.17. Narzędzia do testowania bezpieczeństwa kontenerów

7.18. Przykład bezpiecznej konfiguracji Compose

7.19. Najlepsze praktyki bezpieczeństwa Dockera

7.20. Podsumowanie

8. Debugowanie i monitorowanie

8.1. Podejście do debugowania kontenerów

8.2. Analiza logów kontenerów

8.3. Zmiana sterownika logowania

8.4. Wejście do wnętrza kontenera

8.5. Analiza nieuruchomionych kontenerów

8.6. Debugowanie poprzez kontenery narzędziowe

8.7. Analiza sieci kontenerów

8.8. Monitorowanie zasobów kontenerów

8.9. Zbieranie metryk za pomocą cAdvisor

8.10. Integracja z Prometheus i Grafana

8.11. Monitorowanie logów — ELK stack

8.12. Profilowanie kontenerów

8.13. Debugowanie sieci i DNS

8.14. Diagnostyka problemów z wolumenami

8.15. Analiza stanu kontenerów i systemu

8.16. Diagnostyka demonów Dockera

8.17. Automatyzacja monitorowania

8.18. Przykładowy scenariusz diagnostyki

8.19. Najlepsze praktyki debugowania i monitorowania

8.20. Podsumowanie

9. Docker Swarm — produkcyjna orkiestracja (zaawansowana konfiguracja)

9.1. Inicjalizacja klastra Swarm

9.2. Dodawanie węzłów do klastra

9.3. Tworzenie usług w Swarm

9.4. Zaawansowane opcje usług

9.5. Sieci Overlay

9.6. Load balancing i routing w Swarm

9.7. Trwałe dane i wolumeny

9.8. Secrets i konfiguracje

9.9. Monitorowanie klastra Swarm

9.10. Diagnostyka problemów w Swarm

9.11. Skalowanie i aktualizacja w produkcji

9.12. Najlepsze praktyki w produkcyjnym Swarm

9.13. Podsumowanie

10. Kubernetes dla zaawansowanych dockerowców

10.1. Dlaczego Kubernetes?

10.2. Podstawowe komponenty Kubernetes

10.3. Instalacja klastra lokalnego

10.4. Tworzenie pierwszego poda

10.5. Deployment — deklaratywne zarządzanie replikami

10.6. StatefulSet — aplikacje z trwałym stanem

10.7. Service — stabilny dostęp do podów

10.8. ConfigMap i Secret

10.9. PersistentVolume i PersistentVolumeClaim

10.10. Networking — Ingress i NetworkPolicy

10.11. Horizontal Pod Autoscaler (HPA)

10.12. Integracja z Dockerem

10.13. Debugowanie w Kubernetes

10.14. Najlepsze praktyki dla dockerowców w Kubernetes

10.15. Podsumowanie

11. CI/CD z Dockerem w praktyce

11.1. Podstawy CI/CD z Dockerem

11.2. GitLab CI/CD z Dockerem

11.3. Jenkins i Docker

11.4. Automatyczne budowanie i publikowanie obrazów

11.5. Testowanie kontenerów

11.6. Wdrażanie na Swarm i Kubernetes

11.7. Najlepsze praktyki CI/CD z Dockerem

11.8. Podsumowanie

12. Docker w środowiskach chmurowych

12.1. Dlaczego Docker w chmurze?

12.2. Docker w AWS

12.3. Docker w Azure

12.4. Docker w Google Cloud Platform (GCP)

12.5. Praktyczne przykłady

12.6. Skalowanie kontenerów w chmurze

12.7. Monitoring i logowanie

12.8. Najlepsze praktyki Dockera w chmurze

12.9. Podsumowanie

13. Automatyzacja i DevOps z Dockerem

13.1. Docker w kontekście DevOps

13.2. Automatyzacja za pomocą Docker Compose

13.3. Skrypty automatyzujące

13.4. Integracja z narzędziami DevOps

13.5. Infrastruktura jako kod (IaC) z Dockerem

13.6. Automatyczne skalowanie i self-healing

13.7. Monitoring i alerty

13.8. Najlepsze praktyki DevOps z Dockerem

13.9. Podsumowanie

14. Tworzenie i rozwijanie własnych pluginów Dockera

14.1. Architektura pluginów Dockera

14.2. Tworzenie prostego pluginu — przykład Volume plugin

14.3. Instalacja i włączenie pluginu

14.4. Tworzenie Network plugin

14.5. Rozwijanie pluginu i integracja z Docker Engine

14.6. Publikowanie pluginu

14.7. Najlepsze praktyki przy tworzeniu pluginów

14.8. Podsumowanie

15. Case studies — Realne scenariusze użycia Dockera

15.1. Case study 1 — Aplikacja webowa z bazą danych

15.2. Case study 2 — Microservices w Docker Swarm

15.3. Case study 3 — CI/CD z Dockerem

15.4. Case study 4 — Migracja aplikacji legacy do Dockera

15.5. Case study 5 — Skalowanie aplikacji w chmurze

15.6. Podsumowanie

16. Przyszłość Dockera i konteneryzacji

16.1. Ewolucja konteneryzacji

16.2. Trendy i nowe technologie

16.3. Integracja z AI/ML

16.4. Konteneryzacja w edge computing

16.5. Automatyzacja i zarządzanie cyklem życia

16.6. Bezpieczeństwo i compliance

16.7. Ekosystem i standaryzacja

16.8. Podsumowanie

Bibliografia

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).

Aby sprawdzić, czy Compose jest dostępny:

docker compose version

Przykładowy plik docker-compose. yml:

version: „3.9”

services:

web:

build:.

ports:

— „8080:80”

depends_on:

— db

db:

image: postgres:16

environment:

POSTGRES_USER: admin

POSTGRES_PASSWORD: secret

POSTGRES_DB: appdb

Uruchomienie całego środowiska:

docker compose up

Zatrzymanie i usunięcie:

docker compose down

4.3. Architektura Docker Compose

Docker Compose składa się z trzech głównych elementów:

— Plik definicyjny (docker-compose. yml) — opis usług, wolumenów, sieci i konfiguracji.

— Kontekst roboczy — katalog, z którego uruchamiane jest polecenie docker compose.

— CLI Compose — interfejs do zarządzania cyklem życia aplikacji.

Compose działa lokalnie, ale jego definicje są kompatybilne z Docker Swarm oraz częściowo z Kubernetes (poprzez kompose).

4.4. Budowanie i uruchamianie usług

Każda usługa w Compose może bazować na istniejącym obrazie (image) lub być zbudowana lokalnie z pliku Dockerfile (build).

Przykład:

services:

app:

build:

context:.

dockerfile: Dockerfile

image: myapp: latest

Polecenie:

docker compose build

zbuduje wszystkie obrazy zdefiniowane w pliku YAML.

4.5. Zależności między usługami — depends_on

Koniec darmowego fragmentu książki.

Zachęcamy do zakupu pełnej wersji.