Polecenia z tego poradnika zostały uruchomione 6 października 2026 w czystym systemie (Ubuntu 24.04.5 LTS, Node.js 24.21.0, Python 3.12.3). Wyniki pod poleceniami pochodzą z tego uruchomienia.

Docker pozwala uruchamiać aplikacje w kontenerach, czyli odizolowanych procesach z potrzebnymi plikami i zależnościami. Obraz jest pakietem, z którego powstaje kontener, a Docker Compose opisuje współpracujące usługi w jednym pliku. Ten docker tutorial przeprowadzi cię od instalacji do aplikacji z licznikiem odwiedzin, bez konieczności samodzielnego instalowania jej bibliotek na komputerze. Te podstawowe role opisuje dokumentacja Dockera.

Zacznij od rozróżnienia obrazu i kontenera, uruchom test, a następnie przygotuj własny obraz oraz compose.yaml. Po ćwiczeniu będziesz mieć działającą stronę, zapis danych poza kontenerem i zestaw poleceń do diagnozowania problemów.

W skrócie

  • Obraz traktuj jak gotowy pakiet aplikacji, a kontener jak jego uruchomiony egzemplarz.
  • Do konfiguracji aplikacji i bazy wybierz Docker Compose.
  • Dane, które chcesz zachować, zapisuj w wolumenie.
  • Na początek polecam udostępniać stronę tylko na własnym komputerze.
  • Przed usuwaniem zasobów sprawdzaj znaczenie opcji, szczególnie -v.

Obraz, kontener i Docker Compose: różnice

Obraz kontenera zawiera pliki, biblioteki i konfigurację potrzebne do uruchomienia programu. Jest niezmienny: aktualizując aplikację, tworzysz nowy obraz. Warstwy obrazu to kolejne zestawy zmian w jego plikach.

Kontener jest odizolowanym procesem z własnym środowiskiem plików. Maszyna wirtualna uruchamia cały system z własnym jądrem, czyli podstawową częścią zarządzającą sprzętem i procesami. Kontenery współdzielą jądro środowiska, w którym pracują.

Docker Engine to silnik zarządzający kontenerami, obrazami, sieciami i wolumenami. Polecenie docker jest klientem, który przekazuje mu zadania. Taką architekturę klienta i silnika opisuje producent.

Docker Compose pozwala zapisać konfigurację wielu usług i zarządzać nimi razem. Usługa oznacza tutaj część aplikacji opisaną w pliku, na przykład stronę albo bazę.

Element Jak go rozumieć Przykład w ćwiczeniu
Obraz Pakiet do tworzenia kontenerów Obraz aplikacji z Pythonem
Kontener Uruchomiony egzemplarz obrazu Działająca strona
Dockerfile Przepis budowania obrazu Instalacja bibliotek i kopiowanie kodu
Compose Opis współpracujących usług web oraz redis
Wolumen Dane zarządzane przez Dockera poza życiem kontenera Zapis licznika

Role Dockerfile i wolumenu opisują odpowiednio instrukcje budowania obrazu oraz dokumentacja trwałego przechowywania danych. Dla początkującego najważniejsza jest granica: kod trafia do obrazu, uruchomienie tworzy kontener, a potrzebne dane przechowujesz osobno.

Docker tutorial: instalacja na Ubuntu

Wymagania i wybór środowiska

Pełną ścieżkę poniżej przygotowano dla lokalnego Ubuntu 24.04 LTS w wersji 64-bitowej, które znajduje się na liście wspieranych systemów Docker Engine. Przygotuj terminal, edytor tekstu, przeglądarkę, dostęp do internetu i konto z uprawnieniami sudo, czyli możliwością wykonywania poleceń administracyjnych.

Na Windows i macOS zacznij od instalacji Docker Desktop według instrukcji dla swojego systemu. Docker Desktop zawiera Engine, klienta i Compose. Poleceń instalacyjnych Ubuntu nie wklejaj do PowerShella; dalsze ćwiczenie opisano dla terminala Ubuntu.

Nie musisz wcześniej uczyć się Flaska ani Redis. Flask pomaga tworzyć aplikację internetową w Pythonie, a Redis przechowuje licznik w oficjalnym przykładzie Compose, na którym oparto ćwiczenie. Tutaj skupiamy się na pakowaniu i uruchamianiu programu.

1. Dodaj repozytorium i zainstaluj pakiety

Najpierw utwórz katalog projektu i wejdź do niego. Wszystkie kolejne polecenia wykonuj z tego katalogu:

terminal
mkdir compose-demo
cd compose-demo

Repozytorium pakietów to miejsce, z którego system pobiera oprogramowanie. Poniższe polecenia dodają klucz do weryfikacji pakietów oraz repozytorium Dockera, a następnie instalują silnik i wtyczkę Compose zgodnie z instrukcją instalacji przez apt.

Zakładamy czyste Ubuntu bez wcześniejszego Dockera. Jeżeli masz starszą instalację, najpierw sprawdź w tej instrukcji listę konfliktujących pakietów. Nie usuwaj ich bez ustalenia, czy korzystają z nich inne projekty.

terminal
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Wynik w czystym systemie:
sudo: unable to send audit message: Operation not permitted

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

Hit:1 https://download.docker.com/linux/ubuntu noble InRelease
Hit:2 https://deb.nodesource.com/node_24.x nodistro InRelease
Hit:3 http://archive.ubuntu.com/ubuntu noble InRelease
Hit:4 https://cli.github.com/packages stable InRelease
Hit:5 http://archive.ubuntu.com/ubuntu noble-updates InRelease
Hit:6 http://security.ubuntu.com/ubuntu noble-security InRelease
…
Processing triggers for libc-bin (2.39-0ubuntu8.9) ...

Polecenia zmieniają konfigurację systemu i instalują pakiety. Opcja -y automatycznie odpowiada „tak” na pytania APT o potwierdzenie instalacji. Oczekiwany wynik to zakończona instalacja bez błędów pobierania lub zależności.

2. Sprawdź silnik i uruchom pierwszy kontener

Sprawdź usługę, a następnie wykonaj test hello-world opisany w dokumentacji instalacyjnej:

terminal
sudo systemctl status docker

Oczekiwany stan to active (running). Jeśli widok zajmuje terminal, wyjdź klawiszem q. Gdy usługa nie działa, uruchom ją:

terminal
sudo systemctl start docker

Teraz sprawdź kontener testowy oraz wersję wtyczki Compose:

terminal
sudo docker run hello-world
sudo docker compose version

Pierwsze polecenie pobiera obraz testowy, uruchamia go i wyświetla potwierdzenie, po czym kontener kończy pracę. Drugie powinno wypisać wersję Compose; nie musi być identyczna z wersją z innego poradnika.

W całym ćwiczeniu używamy sudo. Dodanie użytkownika do grupy docker pozwala pracować bez tego prefiksu, ale przyznaje uprawnienia na poziomie administratora. Polecam pozostać przy pokazanej ścieżce podczas pierwszej nauki.

3. Zobacz osobno kontenery i obrazy

docker ps -a pokazuje także zakończone kontenery, natomiast docker image ls wyświetla lokalne obrazy:

terminal
sudo docker ps -a
sudo docker image ls

W pierwszym zestawieniu znajdź zakończony hello-world, a w drugim jego obraz. To praktyczny przykład różnicy: program już nie pracuje, lecz obraz pozostaje dostępny. Sam widok zakończonego kontenera testowego nie oznacza awarii.

Własny obraz: aplikacja i Dockerfile

4. Przygotuj kod aplikacji

Pracuj w utworzonym katalogu compose-demo. Każdy podany dalej plik zapisz bezpośrednio w nim.

Zgodnie z przykładem Flask i Redis aplikacja będzie zwiększać licznik przy każdym wejściu na stronę. Utwórz plik app.py:

python
import os
import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(
    host=os.getenv("REDIS_HOST", "redis"),
    port=int(os.getenv("REDIS_PORT", "6379")),
)

@app.route("/")
def hello():
    count = cache.incr("hits")
    return f"Witaj w Dockerze! Liczba odwiedzin: {count}\n"

Kod odczytuje adres Redis z konfiguracji i zwiększa wartość hits poleceniem INCR. Na razie zapisujesz plik; wynik w przeglądarce zobaczysz po uruchomieniu kontenerów.

Biblioteki potrzebne aplikacji wymienia requirements.txt. Utwórz plik requirements.txt:

polecenie dla Claude
flask
redis

5. Opisz budowanie obrazu

Dockerfile jest plikiem tekstowym z instrukcjami budowania. FROM wybiera obraz bazowy, WORKDIR katalog roboczy, COPY kopiuje pliki, RUN wykonuje polecenia podczas budowania, a CMD ustala domyślne uruchomienie.

Utwórz plik bez rozszerzenia Dockerfile:

dockerfile
#syntax=docker/dockerfile:1
FROM python:3.12-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["flask", "run", "--debug"]

Baza python:3.12-alpine i zestaw pakietów pochodzą z przykładu producenta. Python będzie częścią obrazu; nie instalujesz tych bibliotek w swoim systemie Ubuntu.

EXPOSE 5000 opisuje port aplikacji, ale samo nie publikuje go na komputerze. Port to numer, pod którym program odbiera połączenia; przekierowanie przygotujesz w Compose.

Kontekst budowania to pliki dostępne dla procesu tworzącego obraz. .dockerignore wyklucza wskazane pliki z tego kontekstu. Utwórz plik .dockerignore:

polecenie dla Claude
.env
.git
*.pyc
__pycache__
redis-data

Dzięki temu później utworzony .env nie trafi do obrazu przez COPY . .. Polecam również nie umieszczać prywatnych plików ani kluczy w katalogu tego ćwiczenia.

Docker Compose: dwie usługi w jednym pliku

6. Zapisz konfigurację i zależności

Zmienna środowiskowa to nazwana wartość konfiguracji. Compose może podstawiać wartości z .env do compose.yaml. Utwórz plik .env:

dotenv
APP_PORT=8000
REDIS_HOST=redis
REDIS_PORT=6379

Tutaj nie ma haseł. Port strony możesz później zmienić, edytując APP_PORT, zamiast poprawiać cały opis usług.

Plik Compose używa YAML, formatu konfiguracji opartego na kluczach i wcięciach. Definicje usług określają między innymi obraz, porty, zmienne i zależności. Utwórz plik compose.yaml:

yaml
services:
  web:
    build: .
    ports:
      - "127.0.0.1:${APP_PORT}:5000"
    environment:
      REDIS_HOST: ${REDIS_HOST}
      REDIS_PORT: ${REDIS_PORT}
    depends_on:
      redis:
        condition: service_healthy
  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5
      start_period: 10s

volumes:
  redis-data:

build: . wskazuje budowanie aplikacji z bieżącego katalogu, a image: redis:alpine gotowy obraz drugiej usługi. redis-data:/data podłącza nazwany wolumen do katalogu danych Redis, zgodnie z przykładem trwałego zapisu.

Healthcheck to test stanu usługi. W połączeniu z condition: service_healthy sprawia, że Compose czeka na pozytywny test zależności przed uruchomieniem aplikacji. Samo uruchomienie procesu bazy nie oznacza jeszcze gotowości do obsługi połączeń.

7. Sprawdź konfigurację i uruchom projekt

Najpierw użyj docker compose config, który podstawia zmienne i pokazuje wynikową konfigurację:

terminal
sudo docker compose config

Sprawdź obecność usług web oraz redis i portu 8000. Oczekiwany wynik to konfiguracja bez błędów składni; nie publikuj jej zawartości, jeśli w innym projekcie zawiera poufne wartości.

Następnie zbuduj obrazy i uruchom kontenery w tle:

terminal
sudo docker compose up -d --build

Opcja --build zleca budowanie, a -d pozostawia działające kontenery w tle. Pierwsze uruchomienie obejmuje pobieranie obrazów i instalowanie bibliotek.

Sprawdź stan usług poleceniem ps:

terminal
sudo docker compose ps

Obie usługi powinny działać, a Redis uzyskać stan healthy. Otwórz http://127.0.0.1:8000. Oczekiwany tekst to „Witaj w Dockerze! Liczba odwiedzin: 1”; po odświeżeniu liczba wzrośnie.

Porty i sieć: jak kontenery się odnajdują?

Mapowanie 127.0.0.1:8000:5000 oznacza adres komputera, jego port i port aplikacji w kontenerze. Przy aktualnej instalacji z powyższych kroków podanie 127.0.0.1 ogranicza dostęp do opublikowanego portu do hosta, czyli komputera uruchamiającego Dockera. To ustawienie wybrano do lokalnej nauki.

Compose tworzy domyślną sieć, a usługi znajdują się po swoich nazwach. Dlatego aplikacja używa redis:6379. Do komunikacji między usługami nie potrzebujesz publikować portu Redis na komputerze.

Poniższy diagram pokazuje przepływ w tym projekcie: przeglądarka łączy się ze stroną, strona aktualizuje licznik, a pliki danych są zapisane w wolumenie.

flowchart TD
    A[Przeglądarka] --> B[Port komputera 8000]
    B --> C[Kontener web]
    C --> D[Kontener Redis]
    D --> E[Wolumen danych]

Logi i polecenia wewnątrz kontenera

8. Zobacz, co robi aplikacja

Logi to komunikaty programu, pomocne podczas szukania błędów. docker compose logs -f śledzi nowe komunikaty:

terminal
sudo docker compose logs -f web

Odśwież stronę i poszukaj wpisu dotyczącego żądania. Zakończ podgląd klawiszami Ctrl+C; kontenery pozostaną uruchomione.

docker compose exec wykonuje polecenie w działającym kontenerze. Sprawdź Redis:

terminal
sudo docker compose exec redis redis-cli ping

Oczekiwany wynik to PONG, odpowiedź na polecenie PING. Jeśli go nie widzisz, polecam sprawdzić najpierw stan i logi tej usługi.

Wolumeny, zatrzymywanie i usuwanie danych

9. Sprawdź zachowanie licznika

Wolumen jest magazynem zarządzanym przez Dockera, którego zawartość istnieje niezależnie od kontenera. Zatrzymanie, usunięcie kontenera i usunięcie wolumenu to różne operacje.

Po kilku odświeżeniach zanotuj licznik. docker compose down zatrzymuje i usuwa kontenery oraz sieć projektu, domyślnie zachowując nazwane wolumeny. Wykonaj:

terminal
sudo docker compose down
sudo docker compose up -d

Otwórz stronę ponownie. Przy poprawnym zapisie danych licznik powinien kontynuować poprzednią wartość, jak w ćwiczeniu z wolumenem Redis.

Jeśli chcesz tylko zrobić przerwę, stop zatrzymuje kontenery bez ich usuwania, a start uruchamia je ponownie:

terminal
sudo docker compose stop
sudo docker compose start

Polecam nie traktować wolumenu jako kopii zapasowej. Przed eksperymentami z ważnymi danymi przygotuj osobny backup, czyli kopię pozwalającą je odtworzyć.

Typowe błędy i rozwiązania

Brak uprawnień lub niedziałający silnik

Przy permission denied sprawdź, czy używasz sudo. Dostęp użytkownika do silnika opisuje instrukcja uprawnień na Linuksie.

Przy Cannot connect to the Docker daemon wróć do sudo systemctl status docker i sprawdź usługę. Jeśli nie działa, użyj sudo systemctl start docker z instrukcji instalacyjnej.

Brak Compose albo błędny plik

Jeżeli docker compose version nie działa, sprawdź instalację docker-compose-plugin. Używamy wtyczki uruchamianej jako docker compose, ze spacją.

Przy błędzie konfiguracji polecam sprawdzić wcięcia w compose.yaml oraz uruchomić sudo docker compose config. Przy braku Dockerfile upewnij się, że edytor nie zapisał pliku jako Dockerfile.txt, przed czym ostrzega oficjalny przykład.

Port jest zajęty lub nie widać zmian

Jeśli port 8000 jest zajęty, polecam zmienić APP_PORT w .env na 8001 i ponownie wykonać sudo docker compose up -d. Otwórz wtedy http://127.0.0.1:8001. Compose odtwarza kontenery po zmianie ich konfiguracji, zachowując podłączone wolumeny.

Po zmianie kodu użyj sudo docker compose up -d --build. W tym przykładzie kod został skopiowany do obrazu, więc jego aktualizacja wymaga ponownego budowania.

Obrazy, aktualizacje i prywatne sekrety

Tag to etykieta obrazu, na przykład 3.12-alpine. Tag może wskazywać z czasem inny obraz; nie oznacza niezmiennej zawartości. Digest, czyli identyfikator treści obrazu, pozwala wskazać konkretną zawartość zamiast zmiennej etykiety.

W ćwiczeniu zachowano prosty wybór obrazów i bibliotek z dokumentacji. Do projektu, który inni mają odtwarzać, polecam zapisywać dokładne zależności i planować aktualizacje świadomie.

Sekret to poufna wartość, na przykład hasło lub klucz do usługi. Polecam nie wpisywać sekretów w Dockerfile i nie publikować .env. Mechanizm Compose secrets udostępnia sekret jako plik tylko wskazanym usługom; aplikacja musi potrafić go odczytać.

FAQ

Czy Docker to maszyna wirtualna?

Kontener jest odizolowanym procesem, a maszyna wirtualna obejmuje własny system i jądro. Dokumentacja porównuje oba rozwiązania. Docker i maszyny wirtualne mogą być używane razem.

Czym różni się Dockerfile od Docker Compose?

Dockerfile opisuje tworzenie obrazu aplikacji. Docker Compose opisuje usługi i ich uruchomienie: obrazy, porty, sieci oraz wolumeny. W tym projekcie potrzebujesz obu plików.

Czy usunięcie kontenera usuwa dane?

Usunięcie kontenera usuwa jego zapisywalną warstwę plików. Dane w nazwanym wolumenie pozostają, dopóki nie usuniesz samego wolumenu. Dlatego licznik przechowujemy poza kontenerem.

Czy muszę znać Pythona, aby zacząć?

Do tego ćwiczenia wystarczy zapisać podane pliki i rozumieć ich rolę. Polecam najpierw uruchomić przykład bez zmian, a następnie zmienić komunikat na stronie i przebudować obraz. Nauka kontenerów i nauka programowania mogą być osobnymi krokami.

Co dalej

Polecam teraz zmienić komunikat, przebudować obraz i sprawdzić, czy licznik zachował dane. Kolejnym tematem Dockera jest Compose Watch, który potrafi synchronizować zmiany plików lub przebudowywać usługę podczas pracy.

Jeśli chcesz samodzielnie rozwijać kod przykładu, przejdź do poradnika Pythona od zera. Wracaj do tego przewodnika, gdy potrzebujesz odróżnić zmianę kodu, obrazu, konfiguracji kontenera i danych.

Co dalej?

Źródła

  1. Install Docker Engine on Ubuntu
  2. apt-get - APT package handling utility - command-line interface
  3. apt - command-line interface
  4. What is Docker?
  5. What is an image?
  6. What is a container?
  7. What is Docker Compose?
  8. Dockerfile reference
  9. Volumes
  10. Overview of installing Docker Compose
  11. Docker Compose Quickstart
  12. Install the Docker Compose plugin
  13. Linux post-installation steps for Docker Engine
  14. docker container ls
  15. docker image ls
  16. INCR
  17. Quickstart | Flask Documentation
  18. Build context
  19. Set, use, and manage variables in a Compose file with interpolation
  20. Define services in Docker Compose
  21. Control startup and shutdown order in Compose
  22. docker compose config
  23. docker compose up
  24. docker compose ps
  25. Port publishing and mapping
  26. Networking in Compose
  27. docker compose logs
  28. docker compose exec
  29. PING
  30. docker compose down
  31. docker compose stop
  32. Building best practices
  33. Manage secrets securely in Docker Compose
  34. Use Compose Watch