Twoja aplikacja to już nie jeden proces. Jest API, jest MongoDB, jest Redis - i żeby uruchomić całość lokalnie, trzeba wywołać trzy razy
docker run z długą listą flag, w odpowiedniej kolejności, pamiętając o sieci i o tym, że baza potrzebuje chwili na start. Przy każdym nowym członku zespołu ta instrukcja jest przekazywana ustnie i za każdym razem trochę inaczej.Legion nie wymaszerowywał na podstawie ustnych ustaleń. Miał rozkaz dzienny: spisaną listę oddziałów, ich kolejność i to, co każdy ze sobą zabiera. Docker Compose jest takim rozkazem - służy do zarządzania wieloma kontenerami jednocześnie.
Nie myl go z sąsiednimi narzędziami: budowaniem obrazów z kodu źródłowego zajmuje się
docker build i Dockerfile, testowaniem - Twój pipeline, a monitorowaniem zużycia zasobów - narzędzia, które poznałeś przy obserwowalności.Cała konfiguracja mieści się w jednym pliku
docker-compose.yml:1services:
2 mongodb:
3 image: mongo:7
4 volumes:
5 - mongo-data:/data/db
6 healthcheck:
7 test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
8 interval: 10s
9 retries: 5
10
11 redis:
12 image: redis:7-alpine
13
14 api:
15 build: .
16 ports:
17 - "3000:3000"
18 environment:
19 DATABASE_URL: mongodb://mongodb:27017/legions
20 REDIS_HOST: redis
21 depends_on:
22 mongodb:
23 condition: service_healthy
24 redis:
25 condition: service_started
26
27volumes:
28 mongo-data:Każdy wpis pod
services to jeden kontener. image bierze gotowy obraz, build: . każe zbudować go z Dockerfile'a w tym katalogu.Pole
zapewnia kolejność uruchamiania serwisów. Nasze trzy serwisy wstają więc tak: najpierw MongoDB, potem Redis, na końcu API, które czeka na oba.depends_on
Ale tu jest pułapka, o którą rozbija się większość pierwszych konfiguracji: samo
depends_on czeka tylko na uruchomienie kontenera, nie na jego gotowość. MongoDB potrzebuje kilku sekund na wczytanie danych - kontener już działa, a baza jeszcze nie przyjmuje połączeń. API startuje, próbuje się połączyć i pada.Dlatego przy bazie stoi
healthcheck, a w depends_on warunek condition: service_healthy. Teraz Compose czeka, aż polecenie z healthcheck zacznie kończyć się powodzeniem. Redis wstaje szybko i wystarcza mu service_started - domyślne zachowanie, czyli „kontener ruszył".Zapamiętaj tę różnicę, @name: uruchomiony to nie to samo co gotowy. Zdecydowana większość błędów „connection refused" przy starcie środowiska bierze się właśnie stąd.
Zwróć uwagę na adres bazy:
mongodb://mongodb:27017/legions. Nie ma tam localhost ani żadnego adresu IP - jest nazwa serwisu.Compose tworzy dla wszystkich serwisów wspólną sieć i rejestruje w niej każdy pod jego nazwą. Kontener
api łączy się z bazą, pisząc po prostu mongodb - reszta dzieje się sama. Nie musisz znać adresów IP ani niczego konfigurować.Zauważ też, czego nie ma w naszym pliku: MongoDB i Redis nie mają sekcji
ports. To celowe. Bez niej usługa jest widoczna tylko wewnątrz sieci Compose - API do niej dosięgnie, ale nikt z zewnątrz już nie. Port wystawiamy wyłącznie tam, gdzie naprawdę trzeba, czyli przy API.Kontener jest z założenia nietrwały: usuwasz go i znika wszystko, co zapisał. Dla bazy danych to katastrofa, więc wolumeny służą do przechowywania danych trwałych poza kontenerem.
Wpis
mongo-data:/data/db mówi: to, co MongoDB zapisuje w katalogu /data/db, trzymaj w wolumenie o nazwie mongo-data, żyjącym niezależnie od kontenera. Usunięcie i odtworzenie kontenera nie tknie tych danych.Wolumeny nie ograniczają zużycia procesora, nie szyfrują komunikacji i nie skalują niczego - przechowują dane, i tyle.
Cały rozkaz wykonuje jedno polecenie:
1docker compose up --build -dTrzy człony po
up warto rozdzielić. --build przebudowuje obrazy przed startem - bez tego Compose użyje poprzednio zbudowanego, choćbyś zmienił kod. -d (od detached) puszcza wszystko w tle i oddaje Ci terminal.Zatrzymanie ma dwa warianty i różnica między nimi bywa kosztowna.
docker compose down usuwa kontenery i sieć, zostawiając wolumeny. docker compose down -v usuwa także wolumeny - czyli dane bazy. Pierwsze robisz codziennie, drugie wtedy, gdy naprawdę chcesz zacząć od pustej bazy.Rozkaz dzienny spisany, oddziały wyruszają w kolejności:
docker-compose.yml, a każdy wpis pod services to jeden kontener,depends_on zapewnia kolejność uruchamiania serwisów,depends_on czeka na start kontenera, a nie na gotowość usługi,healthcheck plus condition: service_healthy każe czekać na faktyczną gotowość; service_started wystarcza dla szybkich usług,mongodb://mongodb:27017, bez adresów IP i bez konfiguracji sieci,ports znaczy, że usługa jest widoczna tylko wewnątrz sieci Compose,docker compose up --build -d, gdzie --build przebudowuje obrazy, a -d puszcza w tle,down zostawia wolumeny, down -v usuwa je razem z danymi.W następnej lekcji zajmiemy się sekretami - hasłami i kluczami, które w tym pliku wpisaliśmy jeszcze wprost. A na razie zapamiętaj: Compose to rozkaz dzienny - jeden plik zastępuje ustną instrukcję, którą każdy zapamiętał inaczej.