Tech Handbook Null Yard

Docker

Docker pozwala uruchamiać aplikacje w powtarzalnych, izolowanych kontenerach. Najważniejszy model mentalny jest prosty: image jest szablonem, container jego uruchomioną instancją, volume przechowuje dane trwałe, a Compose opisuje zestaw współpracujących usług.

Kiedy ten materiał jest przydatny: przy uruchamianiu gotowego projektu, budowaniu własnego obrazu, lokalnym developmentcie, wdrażaniu małej aplikacji na VPS-ie, przenoszeniu obrazów oraz diagnozowaniu problemów z portami, siecią, storage i logami.

Kompendium używa współczesnego polecenia docker compose dostarczanego jako plugin Compose. Nie opiera się na starym, osobnym poleceniu docker-compose.

Powiązane tematy: Debian - desktop i serwer, systemd, cron i schedulery, Linux permissions i bezpieczeństwo serwera oraz nginx i reverse proxy.

Mapa kompendium


1. Czym jest Docker

Docker uruchamia aplikacje w kontenerach.

Kontener to odizolowane środowisko procesu, które korzysta z kernela hosta, ale może mieć własne:

  • system plików,
  • biblioteki,
  • konfigurację,
  • zmienne środowiskowe,
  • porty,
  • sieć,
  • limity zasobów.

To nie jest pełna maszyna wirtualna.

Schemat:

Linux host
│
├── Docker Engine
│
├── kontener aplikacji A
│   ├── program
│   ├── biblioteki
│   └── filesystem
│
├── kontener aplikacji B
│
└── kontener bazy danych

Najważniejsze pojęcia:

Pojęcie Znaczenie
image gotowy szablon aplikacji
container uruchomiona instancja obrazu
Dockerfile instrukcja budowania obrazu
volume trwałe dane poza kontenerem
network sieć łącząca kontenery
registry magazyn obrazów, np. Docker Hub
Compose opis wielu kontenerów w jednym pliku

2. Docker a maszyna wirtualna

Maszyna wirtualna:

Host
└── Hypervisor
    └── VM
        ├── Kernel
        ├── OS
        └── aplikacja

Docker:

Host Linux
└── Docker
    ├── aplikacja
    ├── aplikacja
    └── aplikacja

Kontenery:

  • uruchamiają się szybciej,
  • zajmują mniej miejsca,
  • łatwo je usuwać i odtwarzać,
  • łatwo je przenosić,
  • dobrze nadają się do backendów, usług i aplikacji webowych.

3. Ważna uwaga o systemach

Docker działa natywnie przede wszystkim na Linuxie.

Na:

  • Debianie,
  • Ubuntu,
  • Fedora,
  • Arch Linux,
  • Rocky Linux,
  • AlmaLinux

działa bezpośrednio.

Na Windows i macOS Docker Desktop uruchamia pod spodem środowisko linuksowe.

Na FreeBSD Docker nie jest natywną technologią systemową. FreeBSD ma własne rozwiązanie kontenerowe: jails.


4. Sprawdzenie instalacji

docker --version

Przykładowy wynik:

Docker version 28.x.x

Więcej informacji:

docker info

Pokazuje m.in.:

  • wersję serwera,
  • liczbę kontenerów,
  • liczbę obrazów,
  • sterownik storage,
  • dostępne sieci,
  • konfigurację runtime.

5. Uruchamianie i zatrzymywanie Dockera

Na Debianie z systemd:

sudo systemctl start docker

Zatrzymanie:

sudo systemctl stop docker

Restart:

sudo systemctl restart docker

Status:

sudo systemctl status docker

Automatyczny start przy bootowaniu:

sudo systemctl enable docker

Start od razu + włączenie autostartu:

sudo systemctl enable --now docker

6. Docker bez sudo

Domyślnie Docker często wymaga:

sudo docker ...

Można dodać użytkownika do grupy docker:

sudo usermod -aG docker "$USER"

Następnie:

newgrp docker

albo wylogować się i zalogować ponownie.

Test:

docker ps

Uwaga bezpieczeństwa

Użytkownik należący do grupy docker ma praktycznie uprawnienia równoważne rootowi.

Na prywatnym serwerze jest to często akceptowalne, ale warto wiedzieć, co to oznacza.


7. Pierwszy kontener

Najprostszy test:

docker run hello-world

Docker:

  1. sprawdzi, czy obraz istnieje lokalnie,
  2. jeśli nie - pobierze go,
  3. utworzy kontener,
  4. uruchomi program,
  5. program zakończy działanie.

8. Obrazy

Lista lokalnych obrazów:

docker images

lub:

docker image ls

Przykład:

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    abcdef123456   2 weeks ago   190MB

9. Pobieranie obrazu

docker pull nginx

Konkretny tag:

docker pull nginx:1.28

Inny przykład:

docker pull postgres:17

10. Usuwanie obrazu

docker rmi nginx

lub:

docker image rm nginx

Po ID:

docker rmi abcdef123456

Wymuszenie:

docker rmi -f nginx

11. Uruchamianie kontenera

Podstawowa składnia:

docker run IMAGE

Przykład:

docker run nginx

Kontener działa wtedy w terminalu na pierwszym planie.

Najczęściej używa się trybu detached:

docker run -d nginx

-d = detached, czyli działanie w tle.


12. Nadawanie nazwy kontenerowi

Bez nazwy Docker wygeneruje losową.

Lepiej użyć:

docker run -d --name web nginx

Teraz można pisać:

docker stop web
docker start web
docker logs web

zamiast używać ID.


13. Lista kontenerów

Tylko działające:

docker ps

Wszystkie:

docker ps -a

Alternatywnie:

docker container ls
docker container ls -a

14. Start, stop, restart

docker start web
docker stop web
docker restart web

15. Usuwanie kontenera

docker rm web

Działający kontener trzeba najpierw zatrzymać.

Albo:

docker rm -f web

16. Porty

Kontener ma własną przestrzeń sieciową.

Jeżeli nginx słucha wewnątrz kontenera na:

80

to nie oznacza jeszcze, że port jest dostępny z hosta.

Trzeba go opublikować:

docker run -d \
  --name web \
  -p 8080:80 \
  nginx

Znaczenie:

HOST:KONTENER
8080:80

Czyli:

http://localhost:8080

trafia do portu 80 w kontenerze.

Uwaga: zapis -p 8080:80 publikuje port na interfejsach hosta zgodnie z konfiguracją Dockera. Jeżeli usługa nie ma być dostępna z sieci, bezpieczniej jawnie związać ją z 127.0.0.1, jak w następnym przykładzie. Docker tworzy własne reguły filtrowania/NAT, więc zachowanie firewalla hosta trzeba sprawdzać razem z konfiguracją Dockera.


17. Port tylko na localhost

Jeżeli usługa ma być dostępna wyłącznie lokalnie:

docker run -d \
  -p 127.0.0.1:8080:80 \
  nginx

To bardzo przydatne, gdy przed Dockerem stoi nginx jako reverse proxy.


18. Sprawdzanie mapowania portów

docker port web

lub:

docker ps

19. Logi kontenera

docker logs web

Ostatnie 50 linii:

docker logs --tail 50 web

Śledzenie logów na żywo:

docker logs -f web

Ostatnie 100 linii + dalsze śledzenie:

docker logs --tail 100 -f web

20. Wejście do kontenera

Jeśli obraz ma bash:

docker exec -it web bash

Jeżeli bash nie istnieje:

docker exec -it web sh

-i:

interactive

-t:

pseudo-terminal

Po wejściu można np.:

ls
cd /app
ps aux
cat /etc/os-release

21. Uruchomienie pojedynczego polecenia

Nie trzeba wchodzić do shella.

docker exec web ls /etc

Przykład:

docker exec postgres pg_isready

22. Zmienne środowiskowe

Można przekazywać wartości przez:

-e

Przykład:

docker run -d \
  -e APP_ENV=production \
  -e PORT=8080 \
  myapp

W kontenerze będą dostępne:

echo "$APP_ENV"

23. Plik .env

Przykład:

APP_ENV=production
DATABASE_URL=postgres://app:secret@db/app
PORT=8080

Uruchomienie:

docker run --env-file .env myapp

Nie należy wrzucać pliku .env z hasłami do publicznego repozytorium.

Typowy .gitignore:

.env
.env.*

24. System plików kontenera

Zmiany wykonane bezpośrednio w filesystemie kontenera są nietrwałe w sensie infrastruktury.

Można np.:

docker exec -it web sh

i utworzyć:

echo test > /tmp/test.txt

Plik będzie istniał, dopóki istnieje dany kontener.

Po usunięciu kontenera:

docker rm -f web

dane z jego zapisywalnej warstwy znikną.

Dlatego trwałe dane przechowujemy w:

  • volumes,
  • bind mounts,
  • zewnętrznych bazach danych,
  • object storage.

25. Bind mount

Bind mount podłącza katalog hosta do kontenera.

Przykład:

docker run -d \
  -p 8080:80 \
  -v "$PWD/html:/usr/share/nginx/html" \
  nginx

Znaczenie:

HOST                          KONTENER
./html        ->              /usr/share/nginx/html

Zmiana pliku na hoście jest natychmiast widoczna w kontenerze.


26. Składnia --mount

Bardziej czytelna wersja:

docker run -d \
  --mount type=bind,source="$PWD/html",target=/usr/share/nginx/html \
  nginx

27. Volumes

Volume jest zarządzany przez Dockera.

Lista:

docker volume ls

Utworzenie:

docker volume create postgres-data

Użycie:

docker run -d \
  --name db \
  -v postgres-data:/var/lib/postgresql/data \
  postgres:17

28. Gdzie Docker trzyma volume

Na Linuksie zazwyczaj:

/var/lib/docker/volumes/

Nie należy jednak budować workflow na bezpośrednim grzebaniu w tym katalogu.

Do obsługi używamy:

docker volume ...

29. Informacje o volume

docker volume inspect postgres-data

30. Usuwanie volume

docker volume rm postgres-data

Usunięcie volume oznacza utratę zapisanych tam danych.


31. Sieci Dockera

Lista:

docker network ls

Standardowo Docker tworzy m.in.:

bridge
host
none

Najczęściej używana jest własna sieć bridge.


32. Tworzenie sieci

docker network create app-network

33. Uruchamianie kontenerów w jednej sieci

Baza:

docker run -d \
  --name db \
  --network app-network \
  postgres:17

Backend:

docker run -d \
  --name app \
  --network app-network \
  myapp

Backend może odwoływać się do bazy po nazwie:

db

np.:

postgres://user:password@db:5432/app

Nie trzeba znać adresu IP kontenera.


34. Inspect

Jedno z najważniejszych poleceń diagnostycznych:

docker inspect web

Pokazuje ogrom informacji:

  • konfigurację,
  • IP,
  • sieci,
  • mounty,
  • zmienne środowiskowe,
  • porty,
  • stan,
  • obraz,
  • entrypoint,
  • command.

Można użyć formatu:

docker inspect -f '{{.State.Status}}' web

35. Statystyki kontenerów

docker stats

Pokazuje:

  • CPU,
  • RAM,
  • sieć,
  • I/O,
  • liczbę procesów.

36. Procesy w kontenerze

docker top web

37. Dockerfile

Dockerfile opisuje, jak zbudować obraz.

Przykład prostego projektu Go:

FROM golang:1.25 AS build

WORKDIR /src

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN CGO_ENABLED=0 go build -o app ./cmd/server

FROM debian:13-slim

WORKDIR /app

COPY --from=build /src/app /app/app

EXPOSE 8080

CMD ["/app/app"]

38. Jak czytać Dockerfile

FROM

FROM golang:1.25

Obraz bazowy.


WORKDIR

WORKDIR /app

Ustawia bieżący katalog.


COPY

COPY . .

Kopiuje pliki z hosta do obrazu.


RUN

RUN go build -o app

Uruchamia polecenie podczas budowania obrazu.


ENV

ENV PORT=8080

Definiuje zmienną środowiskową.


EXPOSE

EXPOSE 8080

Dokumentuje port używany przez aplikację.

Nie publikuje portu automatycznie.


CMD

CMD ["./app"]

Domyślne polecenie uruchamiane po starcie kontenera.


ENTRYPOINT

Przykład:

ENTRYPOINT ["/app/app"]

Definiuje główny program kontenera.


39. Budowanie obrazu

Będąc w katalogu zawierającym Dockerfile:

docker build -t myapp .

-t oznacza tag/nazwę.

myapp

a kropka:

.

oznacza bieżący katalog jako build context.


40. Tagowanie obrazu

docker tag myapp myapp:1.0

Przykładowe wersje:

myapp:1.0
myapp:1.1
myapp:latest

41. Uruchomienie własnego obrazu

docker run -d \
  --name myapp \
  -p 8080:8080 \
  myapp:1.0

42. .dockerignore

Docker podczas builda wysyła build context.

Nie warto wysyłać rzeczy zbędnych.

Przykład:

.git
.gitignore
.env
node_modules
tmp
dist
*.log

Działa podobnie jak .gitignore.


43. Multi-stage build

Bardzo ważna technika.

Zamiast wrzucać do końcowego obrazu:

  • kompilator Go,
  • source code,
  • cache,
  • narzędzia buildowe,

można użyć pierwszego obrazu tylko do kompilacji.

Przykład:

FROM golang:1.25 AS builder

WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o app

FROM debian:13-slim

WORKDIR /app
COPY --from=builder /src/app /app/app

CMD ["/app/app"]

Końcowy obraz jest dużo mniejszy.


44. Jeszcze mniejszy obraz Go

Dla statycznie skompilowanego programu:

FROM golang:1.25 AS builder

WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o app

FROM scratch

COPY --from=builder /src/app /app

ENTRYPOINT ["/app"]

scratch to praktycznie pusty obraz.

Nie ma w nim shella.

Dlatego:

docker exec -it app sh

nie zadziała.


45. Docker Compose

Compose pozwala opisać cały zestaw usług w jednym pliku.

Najczęściej:

compose.yaml

Przykład:

services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/app
    depends_on:
      - db

  db:
    image: postgres:17
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app
    volumes:
      - postgres-data:/var/lib/postgresql/data

volumes:
  postgres-data:

46. Start Compose

docker compose up

W tle:

docker compose up -d

47. Budowanie i uruchamianie

docker compose up -d --build

To jedno z najczęściej używanych poleceń podczas developmentu i deployu.


48. Status Compose

docker compose ps

49. Logi Compose

Wszystkie:

docker compose logs

Na żywo:

docker compose logs -f

Tylko aplikacja:

docker compose logs -f app

50. Zatrzymanie Compose

docker compose stop

Kontenery pozostają.

Ponowny start:

docker compose start

51. Usunięcie kontenerów Compose

docker compose down

Usuwa m.in.:

  • kontenery,
  • automatycznie utworzone sieci.

Domyślnie nie usuwa nazwanych volumes.


52. Usunięcie Compose razem z volume

docker compose down -v

Uwaga:

To może usunąć bazę danych.


53. Restart pojedynczej usługi

docker compose restart app

54. Shell w kontenerze Compose

docker compose exec app sh

Jeśli jest bash:

docker compose exec app bash

55. Uruchomienie jednorazowego polecenia

docker compose exec app ./app migrate

Przykład Node:

docker compose exec app npm test

Przykład Django:

docker compose exec app python manage.py migrate

56. Sprawdzanie poprawności Compose

docker compose config

To bardzo przydatne.

Pokazuje finalną konfigurację po:

  • interpolacji zmiennych,
  • merge,
  • odczycie .env.

57. Nazwy projektów Compose

Compose tworzy nazwy np.:

example-site-app-1
example-site-db-1

Nazwa projektu zwykle pochodzi z nazwy katalogu.

Można ustawić ją ręcznie:

docker compose -p example-site up -d

58. Restart policy

Dla usług serwerowych warto ustawić:

services:
  app:
    image: myapp
    restart: unless-stopped

Najczęstsze wartości:

no
always
on-failure
unless-stopped

Dla VPS często najlepsze:

unless-stopped

Kontener uruchomi się ponownie po restarcie Dockera/serwera, chyba że został ręcznie zatrzymany.


59. Healthcheck

Kontener może mieć test zdrowia.

Przykład:

services:
  app:
    image: myapp
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 5s
      retries: 3

Status:

docker ps

może wtedy pokazać:

healthy
unhealthy

60. Limity pamięci

Przykład docker run:

docker run \
  --memory=512m \
  myapp

CPU:

docker run \
  --cpus=1.0 \
  myapp

61. Kopiowanie plików do i z kontenera

Host → kontener:

docker cp config.json web:/app/config.json

Kontener → host:

docker cp web:/app/report.txt ./report.txt

62. Eksport obrazu - docker save

To właściwy sposób przenoszenia gotowego obrazu Dockera jako pliku.

docker save myapp:1.0 -o myapp.tar

Powstanie:

myapp.tar

Na innym komputerze:

docker load -i myapp.tar

Po imporcie:

docker images

63. Kompresowanie obrazu

Można zrobić:

docker save myapp:1.0 | gzip > myapp.tar.gz

Import:

gunzip -c myapp.tar.gz | docker load

Albo:

gzip -dc myapp.tar.gz | docker load

64. docker save vs docker export

To bardzo ważne.

docker save

Eksportuje image.

Zachowuje:

  • warstwy obrazu,
  • tagi,
  • historię,
  • metadata.

Najlepsze do przenoszenia obrazów.

docker save myapp:1.0 -o myapp.tar

Import:

docker load -i myapp.tar

docker export

Eksportuje filesystem kontenera.

docker export web -o web.tar

Import:

docker import web.tar myweb

Nie zachowuje pełnej historii obrazu ani konfiguracji w taki sposób jak save.

W praktyce dużo rzadziej potrzebujesz docker export.


65. Zasada

Do przenoszenia aplikacji:

docker save
docker load

Do zrzutu samego filesystemu kontenera:

docker export
docker import

66. Registry

Zamiast kopiować pliki .tar, można przechowywać obraz w registry.

Schemat:

komputer lokalny
     │
     │ docker push
     ▼
Docker Registry
     │
     │ docker pull
     ▼
serwer

Przykłady:

  • Docker Hub,
  • GitHub Container Registry,
  • GitLab Container Registry,
  • prywatne registry.

67. Logowanie do registry

docker login

Lub do konkretnego:

docker login ghcr.io

68. Push obrazu

Najpierw tag:

docker tag myapp:1.0 username/myapp:1.0

Push:

docker push username/myapp:1.0

Na serwerze:

docker pull username/myapp:1.0

69. Typowy deploy przez registry

Lokalnie:

docker build -t ghcr.io/user/myapp:1.2.0 .
docker push ghcr.io/user/myapp:1.2.0

Na VPS:

docker pull ghcr.io/user/myapp:1.2.0
docker compose up -d

70. Typowy deploy bez registry

Lokalnie:

docker build -t myapp:1.0 .
docker save myapp:1.0 | gzip > myapp.tar.gz

Kopiowanie:

scp myapp.tar.gz user@server:/tmp/

Na serwerze:

gzip -dc /tmp/myapp.tar.gz | docker load

Potem:

docker compose up -d

71. Najlepszy model dla małych projektów

Dla własnych małych aplikacji sensowny układ to:

GitHub
  │
  ├── source code
  ├── Dockerfile
  └── compose.yaml

VPS
  │
  ├── nginx
  ├── Docker
  └── aplikacje

Możliwe są dwa workflow.

Wariant A - build na serwerze

git pull
docker compose up -d --build

Najprostszy.

Wariant B - gotowe obrazy

CI albo komputer lokalny:

build → registry

VPS:

pull → restart

Lepsze przy większych projektach.


72. Docker + nginx reverse proxy

Przykład aplikacji:

services:
  app:
    build: .
    ports:
      - "127.0.0.1:8080:8080"
    restart: unless-stopped

Nginx hosta:

server {
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Dzięki temu:

Internet
   │
   ▼
nginx :443
   │
   ▼
127.0.0.1:8080
   │
   ▼
Docker
   │
   ▼
aplikacja

73. Aktualizacja aplikacji

Dla projektu budowanego lokalnie na VPS:

cd /srv/myapp
git pull
docker compose up -d --build

Compose przebuduje obraz i wymieni kontener.


74. Aktualizacja obrazu z registry

docker compose pull
docker compose up -d

75. Sprawdzanie logów po deployu

docker compose logs --tail 100 -f

Jeżeli wszystko działa:

Ctrl+C

nie zatrzymuje kontenera - tylko kończy śledzenie logów.


76. Backup volume

Przykład volume:

postgres-data

Backup:

docker run --rm \
  -v postgres-data:/data \
  -v "$PWD:/backup" \
  alpine \
  tar czf /backup/postgres-data.tar.gz -C /data .

77. Restore volume

Najpierw utwórz volume:

docker volume create postgres-data

Potem:

docker run --rm \
  -v postgres-data:/data \
  -v "$PWD:/backup" \
  alpine \
  sh -c 'cd /data && tar xzf /backup/postgres-data.tar.gz'

78. Backup bazy danych

W przypadku bazy danych często lepiej robić backup logiczny niż kopiować jej filesystem.

PostgreSQL:

docker exec db \
  pg_dump -U app app > backup.sql

Restore:

cat backup.sql | docker exec -i db \
  psql -U app app

79. Prune - sprzątanie

Docker zostawia:

  • stare obrazy,
  • cache,
  • nieużywane sieci,
  • zatrzymane kontenery.

Podstawowe:

docker system df

Pokazuje zajęte miejsce.


80. Usuwanie nieużywanych rzeczy

docker system prune

Bardziej agresywnie:

docker system prune -a

Uwaga:

-a usuwa wszystkie nieużywane obrazy, nie tylko dangling images.


81. Volume prune

docker volume prune

Uwaga:

volumes mogą zawierać dane.


82. Build cache

Sprawdzenie:

docker builder du

Sprzątanie:

docker builder prune

83. Najczęstsze problemy

Port już zajęty

Błąd podobny do:

bind: address already in use

Sprawdzenie:

sudo ss -lntp

albo:

sudo ss -lntp | grep ':8080'

Rozwiązanie:

  • zatrzymać konfliktującą usługę,
  • użyć innego portu.

84. Kontener natychmiast się zatrzymuje

Sprawdź:

docker ps -a

Potem:

docker logs NAZWA

Kontener działa tylko tak długo, jak działa jego główny proces.


85. Nie mogę wejść przez bash

Spróbuj:

docker exec -it app sh

Minimalne obrazy mogą nie mieć bash.

Obrazy scratch mogą nie mieć nawet sh.


86. Zmieniłem kod, ale aplikacja jest stara

Jeżeli kod został skopiowany do obrazu podczas docker build, trzeba przebudować obraz:

docker compose up -d --build

87. Docker używa starego cache

Wymuszenie pełnego rebuilda:

docker build --no-cache -t myapp .

Compose:

docker compose build --no-cache
docker compose up -d

88. Nie działa komunikacja między kontenerami

Nie używaj:

localhost

do połączenia z innym kontenerem.

localhost wewnątrz kontenera oznacza ten sam kontener.

Jeżeli Compose ma:

services:
  app:
  db:

aplikacja powinna łączyć się do:

db

czyli np.:

db:5432

89. localhost - ważna zasada

Host:

localhost → host

W kontenerze:

localhost → ten kontener

Inny kontener:

nazwa-usługi → inny kontener

90. Kontener nie widzi usługi hosta

Na Linuksie sytuacja jest bardziej złożona niż w Docker Desktop.

Często lepiej:

  • wystawić usługę przez konkretny interfejs,
  • użyć wspólnej sieci,
  • przenieść zależność również do Compose.

91. Debugowanie krok po kroku

Jeżeli aplikacja nie działa:

docker ps -a

Potem:

docker logs app

Potem:

docker inspect app

Potem:

docker exec -it app sh

Sprawdź:

env
ps aux
ls -la

Jeżeli problem sieciowy:

docker network ls
docker network inspect NAZWA

92. Debugowanie Compose

docker compose ps
docker compose logs
docker compose config
docker compose exec app sh

To cztery najważniejsze komendy.


93. Bezpieczeństwo

Kilka praktycznych zasad.

Nie wkładaj haseł do Dockerfile:

ENV DB_PASSWORD=sekret

to zły pomysł.

Lepiej:

.env

albo system secrets.


94. Nie używaj latest w krytycznych usługach

Zamiast:

image: postgres:latest

lepiej:

image: postgres:17

Jeszcze dokładniej:

image: postgres:17.6

Zapobiega niespodziewanym zmianom.


95. Nie wystawiaj bez potrzeby baz danych do Internetu

Złe:

ports:
  - "5432:5432"

jeżeli tylko aplikacja ma korzystać z PostgreSQL.

Jeżeli app i db są w Compose, PostgreSQL nie potrzebuje ports.

Kontenery mogą się komunikować przez wewnętrzną sieć.


96. Uruchamianie jako non-root

Dobrze przygotowany obraz powinien uruchamiać aplikację jako zwykły użytkownik.

Przykład:

RUN useradd -r -u 10001 appuser

USER appuser

CMD ["/app/app"]

97. Read-only filesystem

Dla niektórych usług można użyć:

docker run --read-only myapp

Albo Compose:

read_only: true

Jeżeli aplikacja musi pisać np. do /tmp, można podłączyć tmpfs.


98. docker run --rm

Bardzo przydatne dla narzędzi jednorazowych:

docker run --rm alpine echo hello

Po zakończeniu kontener zostanie automatycznie usunięty.


99. Tymczasowy shell Linuxa

Docker może służyć jako szybkie środowisko testowe.

docker run --rm -it debian:13 bash

Masz czystego Debiana.

Po:

exit

kontener znika.


100. Testowanie różnych wersji oprogramowania

Node:

docker run --rm -it node:24 bash

Python:

docker run --rm -it python:3.14 bash

Go:

docker run --rm -it golang:1.25 bash

PostgreSQL:

docker run --rm postgres:17

101. Przegląd najważniejszych komend

Kontenery

docker ps
docker ps -a
docker run IMAGE
docker run -d IMAGE
docker start NAME
docker stop NAME
docker restart NAME
docker rm NAME
docker logs NAME
docker exec -it NAME sh
docker inspect NAME
docker stats

Obrazy

docker images
docker pull IMAGE
docker build -t NAME .
docker rmi IMAGE
docker tag SOURCE TARGET
docker save IMAGE -o image.tar
docker load -i image.tar

Volumes

docker volume ls
docker volume create NAME
docker volume inspect NAME
docker volume rm NAME
docker volume prune

Sieci

docker network ls
docker network create NAME
docker network inspect NAME
docker network rm NAME

Compose

docker compose up
docker compose up -d
docker compose up -d --build
docker compose down
docker compose ps
docker compose logs
docker compose logs -f
docker compose pull
docker compose build
docker compose restart
docker compose exec SERVICE sh
docker compose config

102. Typowy projekt Go + Docker

Struktura:

myapp/
├── cmd/
│   └── server/
│       └── main.go
├── internal/
├── static/
├── templates/
├── go.mod
├── go.sum
├── Dockerfile
├── compose.yaml
└── .dockerignore

Dockerfile:

FROM golang:1.25 AS build

WORKDIR /src

COPY go.mod go.sum ./
RUN go mod download

COPY . .

RUN CGO_ENABLED=0 GOOS=linux go build \
    -o /out/myapp ./cmd/server

FROM debian:13-slim

WORKDIR /app

COPY --from=build /out/myapp /app/myapp
COPY static /app/static
COPY templates /app/templates

EXPOSE 8080

CMD ["/app/myapp"]

103. Compose dla aplikacji Go

services:
  app:
    build: .
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      APP_ENV: production

Start:

docker compose up -d --build

104. Go + PostgreSQL

services:
  app:
    build: .
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      DATABASE_URL: postgres://app:secret@db:5432/app
    depends_on:
      - db

  db:
    image: postgres:17
    restart: unless-stopped
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app
    volumes:
      - db-data:/var/lib/postgresql/data

volumes:
  db-data:

105. Co powinno być w Git

Najczęściej:

Dockerfile
compose.yaml
.dockerignore
.env.example
kod aplikacji

Nie:

.env
sekrety
backupy bazy
obrazy .tar

106. .env.example

Można utrzymywać:

APP_ENV=production
DATABASE_URL=
OPENROUTER_API_KEY=

Użytkownik kopiuje:

cp .env.example .env

i wypełnia wartości.


107. Typowy workflow lokalny

Kodujesz:

vim main.go

Budujesz:

docker compose build

Uruchamiasz:

docker compose up -d

Sprawdzasz:

docker compose logs -f app

Po zmianach:

docker compose up -d --build

108. Typowy workflow lokalnie → VPS

Na komputerze:

git add .
git commit -m "Add feature"
git push

Na VPS:

cd /srv/myapp
git pull
docker compose up -d --build
docker compose logs --tail 100

To bardzo dobry model na początek.


109. Typowy workflow z registry

Lokalnie/CI:

docker build -t ghcr.io/user/myapp:1.5.0 .
docker push ghcr.io/user/myapp:1.5.0

VPS:

docker compose pull
docker compose up -d

110. Jak aktualizować bez długiego downtime

Compose zwykle:

  1. tworzy nowy kontener,
  2. zatrzymuje stary,
  3. uruchamia nowy.

Przy pojedynczej instancji może wystąpić krótka przerwa.

Dla małych prywatnych projektów zwykle jest to całkowicie akceptowalne.

Zero-downtime wymaga bardziej rozbudowanego deploymentu.


111. Jak zobaczyć ile Docker zajmuje miejsca

docker system df

Dokładniej:

docker system df -v

112. Gdzie Docker trzyma dane

Typowy root:

/var/lib/docker

Sprawdzenie:

docker info | grep "Docker Root Dir"

113. Nie kopiuj ręcznie /var/lib/docker

To nie jest dobry sposób migracji.

Lepsze są:

  • docker save,
  • registry,
  • backup volumes,
  • backup baz danych,
  • Git dla kodu i konfiguracji.

114. Migracja aplikacji między serwerami

Najbezpieczniejszy model:

  1. skopiować repozytorium,
  2. przenieść .env,
  3. przenieść backup danych,
  4. odbudować/pobrać obrazy,
  5. odtworzyć volumes,
  6. uruchomić Compose.

Przykład:

git clone ...
cd app
cp /secure-backup/.env .
docker compose pull
docker compose up -d

Potem przywrócić bazę.


115. Co naprawdę warto eksportować

Dla aplikacji:

kod źródłowy → Git
Dockerfile → Git
compose.yaml → Git
obrazy → registry lub docker save
sekrety → osobny bezpieczny backup
database → dump
volumes → backup

Nie traktuj kontenera jako miejsca, w którym „mieszka aplikacja”.

Kontener powinien być odtwarzalny.


116. Najważniejsza filozofia Dockera

Kontener powinien być:

disposable

czyli możliwy do wyrzucenia.

Powinieneś móc zrobić:

docker rm -f app

a następnie:

docker compose up -d

i odzyskać działającą aplikację.

Jeżeli ważne dane giną po usunięciu kontenera, projekt jest źle skonfigurowany.


117. Przykład kompletnego małego deploymentu

Struktura:

/srv/myapp/
├── compose.yaml
├── Dockerfile
├── .env
└── source/

Compose:

services:
  app:
    build: .
    restart: unless-stopped
    env_file:
      - .env
    ports:
      - "127.0.0.1:8080:8080"

Nginx:

https://myapp.example.com
        │
        ▼
      nginx
        │
        ▼
127.0.0.1:8080
        │
        ▼
 Docker container

Deploy:

cd /srv/myapp
git pull
docker compose up -d --build

Kontrola:

docker compose ps
docker compose logs --tail 100

118. Przydatne aliasy

Można dodać do:

~/.bashrc

np.:

alias dps='docker ps'
alias dpa='docker ps -a'
alias di='docker images'
alias dc='docker compose'
alias dcl='docker compose logs -f'
alias dcu='docker compose up -d'
alias dcd='docker compose down'

Po zmianie:

source ~/.bashrc

119. Pomoc

Docker:

docker --help

Polecenie:

docker run --help

Compose:

docker compose --help

Konkretne polecenie:

docker compose up --help

120. Minimalny zestaw poleceń do zapamiętania

Jeżeli chcesz pamiętać tylko kilkanaście:

docker ps
docker ps -a
docker images

docker run
docker stop
docker start
docker rm

docker logs
docker exec -it NAME sh
docker inspect

docker build -t NAME .
docker pull

docker compose up -d
docker compose up -d --build
docker compose down
docker compose logs -f

docker system df
docker system prune

121. Minimalny workflow projektu

Pierwsze uruchomienie

git clone REPO
cd PROJECT
cp .env.example .env
vim .env

docker compose up -d --build

Sprawdzenie

docker compose ps
docker compose logs --tail 100

Aktualizacja

git pull
docker compose up -d --build

Debug

docker compose logs -f app

lub:

docker compose exec app sh

Zatrzymanie

docker compose down

122. Przykłady z prawdziwego życia

Przykład 1 - szybki nginx

docker run -d \
  --name nginx-test \
  -p 8080:80 \
  nginx

Wejdź:

http://localhost:8080

Logi:

docker logs nginx-test

Usuń:

docker rm -f nginx-test

Przykład 2 - tymczasowy Debian

docker run --rm -it debian:13 bash

W środku:

apt update
apt install curl
curl https://example.com

Wyjście:

exit

Kontener znika.


Przykład 3 - PostgreSQL

docker volume create pgdata
docker run -d \
  --name postgres \
  -e POSTGRES_PASSWORD=secret \
  -v pgdata:/var/lib/postgresql/data \
  postgres:17

Logi:

docker logs postgres

Shell:

docker exec -it postgres bash

Przykład 4 - eksport obrazu na drugi komputer

Komputer A:

docker build -t web-monitor:1.0 .
docker save web-monitor:1.0 | gzip > web-monitor.tar.gz

Kopiowanie:

scp web-monitor.tar.gz server:/tmp/

Serwer:

gzip -dc /tmp/web-monitor.tar.gz | docker load

Sprawdzenie:

docker images

Przykład 5 - aplikacja Go na VPS

Repo:

git clone git@github.com:user/app.git
cd app
docker compose up -d --build

Sprawdzenie:

docker compose ps

Logi:

docker compose logs -f app

Aktualizacja tydzień później:

git pull
docker compose up -d --build

123. Docker - mapa mentalna

Dockerfile
    │
    │ docker build
    ▼
  IMAGE
    │
    │ docker run
    ▼
CONTAINER
    │
    ├── porty
    ├── env
    ├── networks
    └── volumes

Dla wielu usług:

compose.yaml
    │
    ▼
docker compose up
    │
    ├── app
    ├── database
    ├── redis
    └── inne usługi

124. Co powinieneś umieć po przeczytaniu tego kompendium

Powinieneś rozumieć:

  • czym różni się image od container,
  • jak uruchomić i zatrzymać Docker Engine,
  • jak uruchamiać kontenery,
  • jak publikować porty,
  • jak wejść do kontenera,
  • jak czytać logi,
  • jak używać volumes,
  • jak łączyć kontenery przez sieć,
  • jak czytać Dockerfile,
  • jak budować własny image,
  • jak korzystać z Docker Compose,
  • jak aktualizować aplikację,
  • jak przenosić obrazy,
  • czym różni się save/load od export/import,
  • jak backupować dane,
  • jak diagnozować typowe problemy,
  • jak wdrażać mały projekt na VPS.

125. Ściąga - jednoekranowa

# status
docker ps
docker ps -a
docker images

# run
docker run -d --name app -p 8080:8080 image

# logi
docker logs -f app

# shell
docker exec -it app sh

# stop/start
docker stop app
docker start app
docker restart app

# usuń
docker rm -f app
docker rmi image

# build
docker build -t app:1.0 .

# eksport obrazu
docker save app:1.0 -o app.tar

# import obrazu
docker load -i app.tar

# compose
docker compose up -d
docker compose up -d --build
docker compose ps
docker compose logs -f
docker compose down

# miejsce
docker system df

# sprzątanie
docker system prune

126. Najważniejsze rzeczy do zapamiętania

  1. Image to szablon, container to uruchomiona instancja.
  2. Kontener powinien być odtwarzalny i możliwy do wyrzucenia.
  3. Trwałe dane trzymaj w volumes lub poza Dockerem.
  4. Kod i konfigurację infrastruktury trzymaj w Git.
  5. Do wielu usług używaj Compose.
  6. docker logs to pierwsza komenda przy problemach.
  7. docker inspect pokazuje prawie wszystko o kontenerze.
  8. docker save/load służy do przenoszenia obrazów.
  9. docker export/import służy do zrzutu filesystemu kontenera i jest potrzebne znacznie rzadziej.
  10. Na małym VPS wystarczy zwykle: Git + Docker + Compose + nginx + backup.

127. Dokumentacja i źródła

Oficjalna dokumentacja Dockera jest źródłem nadrzędnym dla składni i zachowania Engine, Build oraz Compose:

  • Docker Engine
    https://docs.docker.com/engine/
  • Instalacja Docker Engine na Debianie
    https://docs.docker.com/engine/install/debian/
  • Docker Compose
    https://docs.docker.com/compose/
  • Docker Build
    https://docs.docker.com/build/
  • Storage
    https://docs.docker.com/engine/storage/
  • Linux post-installation i uprawnienia grupy docker
    https://docs.docker.com/engine/install/linux-postinstall/

Koniec

Dla małych prywatnych projektów nie trzeba od razu wdrażać Kubernetes, Swarm ani rozbudowanego CI/CD.

Bardzo rozsądny stos to:

Debian
+
Git
+
Docker
+
Docker Compose
+
nginx
+
Let's Encrypt
+
regularny backup

Taki zestaw spokojnie wystarcza do hostowania wielu własnych backendów, stron i małych usług na jednym VPS.