Docker Compose: Orkiestracja wielokontenerowa
Wskazówka pomocnicza
Jeśli masz trudności z rozwiązaniem zadań z Docker Compose, możesz znaleźć pomocnicze materiały w repozytorium: Docker Lab 02
Czym jest Docker Compose?
Docker Compose to narzędzie do definiowania i uruchamiania wielokontenerowych aplikacji Docker. Za pomocą jednego pliku konfiguracyjnego w formacie YAML oraz prostych komend możesz utworzyć i uruchomić wszystkie usługi swojej aplikacji.
Główne zalety Docker Compose: - Definiowanie całego środowiska aplikacji w jednym pliku - Uruchamianie wszystkich kontenerów jedną komendą - Automatyczne tworzenie sieci między kontenerami - Współdzielenie wolumenów między kontenerami - Łatwe zarządzanie zależnościami między usługami
Podstawy Docker Compose
Plik docker-compose.yml
Centralnym elementem Docker Compose jest plik
docker-compose.yml. Definiuje on wszystkie
usługi, sieci i wolumeny potrzebne do uruchomienia
aplikacji.
Podstawowa struktura pliku docker-compose.yml:
version: '3.8'
services:
service1:
image: nginx:alpine
ports:
- "8080:80"
service2:
build: ./app
volumes:
- ./app:/code
depends_on:
- service1
volumes:
data-volume:
networks:
app-network:Główne sekcje docker-compose.yml
- version: Określa wersję składni Docker Compose (obecnie rekomendowana jest ‘3.x’)
- services: Definicje wszystkich usług (kontenerów) aplikacji
- volumes: Definicje współdzielonych wolumenów
- networks: Definicje sieci używanych przez usługi
Konfiguracja usług (services)
Dla każdej usługi można zdefiniować wiele opcji konfiguracyjnych:
- image: Obraz Docker, na podstawie którego ma być utworzony kontener
- build: Alternatywa dla
image, wskazuje na katalog z Dockerfile - ports: Mapowanie portów między hostem a kontenerem (host:kontener)
- volumes: Wolumeny montowane w kontenerze
- environment: Zmienne środowiskowe
- env_file: Plik zawierający zmienne środowiskowe
- depends_on: Zależności od innych usług (kolejność uruchamiania)
- restart: Polityka restartu (no, always, on-failure, unless-stopped)
- networks: Sieci, do których ma być podłączony kontener
Podstawowe komendy Docker Compose
# Uruchomienie wszystkich usług
docker-compose up
# Uruchomienie w tle (detached mode)
docker-compose up -d
# Zatrzymanie usług
docker-compose down
# Zatrzymanie i usunięcie wolumenów
docker-compose down -v
# Przebudowanie obrazów
docker-compose build
# Przebudowanie i uruchomienie
docker-compose up -d --build
# Wyświetlenie statusu kontenerów
docker-compose ps
# Wyświetlenie logów
docker-compose logs
# Wyświetlenie logów w trybie ciągłym
docker-compose logs -f
# Wyświetlenie logów konkretnej usługi
docker-compose logs service_name
# Uruchomienie polecenia w kontenerze
docker-compose exec service_name command
# Uruchomienie powłoki w kontenerze
docker-compose exec service_name sh
# Zatrzymanie pojedynczej usługi
docker-compose stop service_name
# Uruchomienie pojedynczej usługi
docker-compose start service_name
# Restart usługi
docker-compose restart service_namePrzykłady zastosowań Docker Compose
Prosta aplikacja webowa z bazą danych
version: '3.8'
services:
web:
build: ./app
ports:
- "5000:5000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/mydatabase
depends_on:
- db
db:
image: postgres:13
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydatabase
volumes:
postgres-data:Aplikacja MERN stack (MongoDB, Express, React, Node.js)
version: '3.8'
services:
frontend:
build: ./frontend
ports:
- "3000:80"
environment:
- API_URL=http://backend:3000
depends_on:
- backend
backend:
build: ./backend
ports:
- "3001:3000"
environment:
- MONGODB_URI=mongodb://db:27017/myapp
- PORT=3000
- CORS_ORIGIN=http://localhost:3000
depends_on:
- db
db:
image: mongo:5
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db
volumes:
mongo-data:Zarządzanie zależnościami między usługami
Definiowanie zależności z depends_on
services:
web:
depends_on:
- db
- redisWażne jest, by zrozumieć, że depends_on
tylko określa kolejność uruchamiania, ale nie czeka aż
usługa będzie “gotowa”. Na przykład, kontener bazy danych
może być uruchomiony, ale sama baza danych może nie być
jeszcze gotowa na przyjmowanie połączeń.
Czekanie na gotowość usługi
Dla bardziej zaawansowanych zależności, można użyć skryptów typu wait-for-it lub healthcheck:
services:
web:
depends_on:
db:
condition: service_healthy
db:
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
timeout: 5s
retries: 5Sieci w Docker Compose
Docker Compose automatycznie tworzy sieć dla wszystkich usług, dzięki czemu mogą one komunikować się ze sobą używając nazw usług jako nazw hostów.
Definiowanie własnych sieci
services:
frontend:
networks:
- frontend-network
backend:
networks:
- frontend-network
- backend-network
db:
networks:
- backend-network
networks:
frontend-network:
backend-network:
internal: true # Sieć bez dostępu do InternetuWolumeny i trwałość danych
Wolumeny pozwalają na przechowywanie danych nawet po zatrzymaniu kontenerów.
Typy wolumenów
Nazwane wolumeny: Zarządzane przez Docker
volumes: - postgres-data:/var/lib/postgresql/dataMapowanie ścieżek (bind mounts): Mapuje ścieżki z hosta do kontenera
volumes: - ./app:/codeWolumeny tymczasowe (tmpfs): Przechowuje dane w pamięci
volumes: - type: tmpfs target: /tmp
Deklarowanie nazwanych wolumenów
services:
db:
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:
# Opcjonalne konfiguracje wolumenuZmienne środowiskowe
Zmienne środowiskowe są kluczem do konfiguracji usług w Docker Compose.
Bezpośrednie definiowanie zmiennych
services:
web:
environment:
- NODE_ENV=production
- PORT=3000Używanie plików .env
services:
web:
env_file:
- .env
- .env.productionFormat pliku .env:
NODE_ENV=production
PORT=3000
Używanie zmiennych z środowiska hosta
services:
web:
environment:
- NODE_ENV=${NODE_ENV:-development}Złożone aplikacje i wzorce użycia
Środowisko deweloperskie z hot reload
version: '3.8'
services:
frontend:
build:
context: ./frontend
dockerfile: Dockerfile.dev
volumes:
- ./frontend:/app
- /app/node_modules
ports:
- "3000:3000"
environment:
- CHOKIDAR_USEPOLLING=trueRóżne konfiguracje dla różnych środowisk
Docker Compose pozwala na używanie wielu plików konfiguracyjnych i nakładanie ich na siebie:
- docker-compose.yml: Podstawowa konfiguracja
- docker-compose.override.yml: Automatycznie nakładany, zwykle dla środowiska deweloperskiego
- docker-compose.prod.yml: Konfiguracja produkcyjna
# Uruchomienie ze specyficznym plikiem
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -dPraktyczne przykłady
Przykład 1: Aplikacja web + API + baza danych
version: '3.8'
services:
frontend:
build: ./frontend
ports:
- "80:80"
environment:
- API_URL=http://backend:3000
depends_on:
- backend
backend:
build: ./backend
ports:
- "3000:3000"
environment:
- DB_HOST=db
- DB_PORT=5432
- DB_USER=postgres
- DB_PASSWORD=password
- DB_NAME=myapp
depends_on:
- db
db:
image: postgres:13
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
postgres-data:Przykład 2: Środowisko deweloperskie dla aplikacji Node.js
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
environment:
- NODE_ENV=development
command: npm run devĆwiczenia praktyczne
Ćwiczenie 1: Podstawowy docker-compose.yml
Utwórz plik docker-compose.yml dla prostej
aplikacji składającej się z frontendu (nginx) i backendu
(node.js).
version: '3.8'
services:
frontend:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./frontend:/usr/share/nginx/html
backend:
image: node:18-alpine
working_dir: /app
volumes:
- ./backend:/app
command: node app.js
ports:
- "3000:3000"Ćwiczenie 2: Dodanie bazy danych
Rozszerz poprzedni przykład o bazę danych MongoDB.
version: '3.8'
services:
# frontend i backend jak poprzednio
db:
image: mongo:5
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db
volumes:
mongo-data:Ćwiczenie 3: Środowisko z hot reload
Zmodyfikuj docker-compose.yml, aby umożliwić hot reload dla aplikacji frontendowej i backendowej.
version: '3.8'
services:
frontend:
build: ./frontend
volumes:
- ./frontend:/app
- /app/node_modules
ports:
- "3000:3000"
environment:
- CHOKIDAR_USEPOLLING=true
command: npm start
backend:
build: ./backend
volumes:
- ./backend:/app
- /app/node_modules
ports:
- "3001:3000"
environment:
- MONGO_URI=mongodb://db:27017/myapp
command: npm run dev
depends_on:
- db
db:
image: mongo:5
volumes:
- mongo-data:/data/db
volumes:
mongo-data:Rozwiązywanie problemów
Problem 1: Kontener nie uruchamia się
Sprawdź logi kontenera:
docker-compose logs service_nameProblem 2: Problemy z zależnościami
Sprawdź, czy wszystkie zależne serwisy są uruchomione:
docker-compose psUżyj healthcheck dla krytycznych usług:
services:
db:
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 5Problem 3: Problemy z wolumenami
Sprawdź, czy wolumeny istnieją i mają poprawne uprawnienia:
docker volume lsDobre praktyki
- Używaj wersji w plikach
docker-compose.yml:
version: '3.8' - Definiuj wolumeny dla danych które muszą być trwałe
- Używaj zmiennych środowiskowych do konfiguracji
- Używaj healthchecków dla krytycznych usług
- Nadawaj nazwy sieciom i wolumenom, aby uniknąć konfliktów
- Minimalizuj ekspozycję portów na hoście (tylko te które są naprawdę potrzebne)
- Używaj restart policy odpowiedniego do potrzeb aplikacji
- Organizuj różne konfiguracje środowisk w osobnych plikach