Podstawy Docker #4: Docker Compose w praktyce

Docker Compose pozwala uruchamiać wiele kontenerów jednocześnie za pomocą jednego pliku konfiguracyjnego. Zamiast wpisywać długie komendy docker run, definiujesz wszystko w pliku docker-compose.yml. W praktyce to narzędzie, którego będziesz używać najczęściej.

Kiedy Compose, kiedy sam Docker?

Sam docker run wystarczy gdy:

  • Uruchamiasz jeden kontener (np. szybki test)
  • Robisz coś jednorazowo

Docker Compose gdy:

  • Masz więcej niż jeden kontener (np. aplikacja + baza danych)
  • Chcesz mieć powtarzalną konfigurację zapisaną w pliku
  • Potrzebujesz wolumenów, sieci, zmiennych środowiskowych
  • Pracujesz na serwerze produkcyjnym

💡 Praktyka

W praktyce prawie zawsze używasz Docker Compose — nawet dla jednego kontenera. Dlaczego? Bo masz konfigurację zapisaną w pliku, a nie w historii terminala. Łatwiej wrócić, zmodyfikować, przenieść na inny serwer.

Struktura pliku docker-compose.yml

⚠️ YAML wymaga wcięć spacjami

Pliki .yml wymagają wcięć spacjami (nie tabulatorami). Użyj 2 spacji na każdy poziom zagnieżdżenia. Jeden zły tabulator i plik nie zadziała.

Minimalny przykład:

services:
  web:
    image: caddy:2
    ports:
      - "8080:80"

To jest odpowiednik komendy:

docker run -d -p 8080:80 --name web caddy:2

Pełniejszy przykład

services:
  app:
    image: n8nio/n8n:latest
    ports:
      - "5678:5678"
    environment:
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=admin
      - N8N_BASIC_AUTH_PASSWORD=tajnehaslo
    volumes:
      - n8n_data:/home/node/.n8n
    restart: unless-stopped

volumes:
  n8n_data:

Kluczowe sekcje

Sekcja Co robi
services Definicje kontenerów (każdy serwis = jeden kontener)
image Jaki obraz użyć
ports Mapowanie portów (host:kontener)
environment Zmienne środowiskowe
volumes Dane trwałe
restart Polityka restartu
networks Sieci

Polityki restartu

Wartość Znaczenie
no Nie restartuj (domyślne)
always Restartuj zawsze (nawet po ręcznym stopie)
unless-stopped Restartuj chyba że ręcznie zatrzymany
on-failure Restartuj tylko po błędzie

💡 Rekomendacja

Na serwerze produkcyjnym używaj restart: unless-stopped — kontener automatycznie wstanie po restarcie serwera, ale nie będzie się restartował jeśli go ręcznie zatrzymasz.

Komendy Docker Compose

Wszystkie komendy uruchamiaj z katalogu, w którym jest plik docker-compose.yml:

docker compose up -d                 # uruchom wszystkie serwisy w tle
docker compose down                  # zatrzymaj i usuń kontenery
docker compose ps                    # lista serwisów i ich status
docker compose logs                  # logi wszystkich serwisów
docker compose logs -f app           # śledź logi konkretnego serwisu
docker compose restart               # restart wszystkich serwisów
docker compose restart app           # restart jednego serwisu
docker compose pull                  # pobierz najnowsze obrazy
docker compose up -d --pull always   # pobierz obrazy i uruchom

Workflow aktualizacji

docker compose pull                  # pobierz nowe wersje obrazów
docker compose up -d                 # uruchom ponownie (podmieni kontenery)

💡 Aktualizacja bez downtime

docker compose up -d po pull automatycznie podmieni tylko te kontenery, których obraz się zmienił. Reszta zostaje nietknięta.

Przykład: Caddy z własną stroną

Utwórz katalog projektu:

mkdir -p ~/caddy-test && cd ~/caddy-test

Utwórz plik docker-compose.yml:

services:
  web:
    image: caddy:2
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/caddy:ro
    restart: unless-stopped

Utwórz prostą stronę:

mkdir html
echo "<h1>Działa!</h1>" > html/index.html

Uruchom:

docker compose up -d

Wejdź na http://IP-SERWERA:8080 — zobaczysz „Działa!”.

Przykład: n8n + PostgreSQL + Redis + Caddy

Bardziej realistyczny przykład — n8n z bazą danych, cache i reverse proxy:

services:
  n8n:
    image: n8nio/n8n:latest
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=db
      - DB_POSTGRESDB_PORT=5432
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=tajnehaslo
      - EXECUTIONS_MODE=queue
      - QUEUE_BULL_REDIS_HOST=redis
    volumes:
      - n8n_data:/home/node/.n8n
    restart: unless-stopped
    depends_on:
      - db
      - redis

  db:
    image: postgres:16
    environment:
      - POSTGRES_DB=n8n
      - POSTGRES_USER=n8n
      - POSTGRES_PASSWORD=tajnehaslo
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    restart: unless-stopped

  caddy:
    image: caddy:2
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
    restart: unless-stopped

volumes:
  n8n_data:
  postgres_data:
  caddy_data:

Zwróć uwagę na kilka ważnych rzeczy:

  • depends_on: db, redis — n8n startuje po bazie i Redis (uwaga: czeka aż kontener się uruchomi, ale NIE czeka aż baza będzie gotowa do połączeń)
  • DB_POSTGRESDB_HOST: db — n8n łączy się z PostgreSQL po nazwie serwisu (db), nie po IP
  • Tylko Caddy ma ports — reszta serwisów jest dostępna tylko wewnętrznie (bezpieczniejsze)
  • Każdy serwis ma wolumen — dane przetrwają restart kontenerów

💡 Scenariusz: n8n nie startuje

docker compose ps                   # czy wszystkie kontenery działają?
docker compose logs n8n             # logi n8n
docker compose logs db              # logi PostgreSQL — może hasło nie pasuje?
docker compose logs caddy           # logi Caddy — może błąd w Caddyfile?

Plik .env — zmienne środowiskowe

Zamiast trzymać hasła w docker-compose.yml, utwórz plik .env w tym samym katalogu:

MYSQL_ROOT_PASSWORD=super_tajne_haslo
MYSQL_USER=wp_user
MYSQL_PASSWORD=inne_tajne_haslo

I w docker-compose.yml użyj zmiennych:

environment:
  MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
  MYSQL_USER: ${MYSQL_USER}
  MYSQL_PASSWORD: ${MYSQL_PASSWORD}

Zapis ${NAZWA} to zmienna — Docker podmieni ją na wartość z pliku .env. Dzięki temu hasła trzymasz w jednym pliku zamiast rozrzucać po konfiguracji.

⚠️ Bezpieczeństwo

Plik .env z hasłami nie powinien trafić do gita. Dodaj go do .gitignore.

Podsumowanie

Komenda Co robi
docker compose up -d Uruchom serwisy w tle
docker compose down Zatrzymaj i usuń kontenery
docker compose ps Status serwisów
docker compose logs -f Śledź logi
docker compose pull Pobierz nowe obrazy
docker compose restart Restart serwisów

📚 Podstawy Docker — przewodnik

Podstawy Docker #3: Komendy | Następny → Podstawy Docker #5: Wolumeny i sieci

Roman Rozenberger
Roman Rozenberger

Jestem digital marketerem ze specjalizacją w marketingu w wyszukiwarkach internetowych. Wdrażam automatyzacje z wykorzystaniem narzędzi LowCode, NoCode i AI. Identyfikuje procesy i rozwiązuję problemy.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *