Docker Compose to narzędzie do uruchamiania aplikacji złożonych z wielu kontenerów na jednej maszynie za pomocą jednego pliku YAML (docker-compose.yml). Zamiast wielu poleceń docker run opisujesz cały stack deklaratywnie i startujesz komendą docker compose up -d - przy self-hostingu AI składasz tak Ollama i interfejs w jeden działający zestaw.
W skrócie: Compose działa świetnie lokalnie na laptopie, ale produkcyjny stack AI musi chodzić 24/7 - wtedy potrzebujesz VPS pod n8n i lokalne LLM
W skrócie: Docker to silnik, który uruchamia pojedynczy kontener, a Docker Compose to nakładka, która zarządza wieloma kontenerami naraz na jednej maszynie. Compose nie zastępuje Dockera - opakowuje go. Zamiast ręcznie odpalać osobno kontener z bazą, osobno z aplikacją i osobno z interfejsem, opisujesz je wszystkie w jednym pliku i uruchamiasz razem.
Konkret: Compose to nie Kubernetes. Kubernetes orkiestruje kontenery na klastrze wielu maszyn (węzłów), a Compose pracuje na jednej maszynie. Dla domowego serwera, homelaba czy pojedynczego VPS to dokładnie to, czego potrzebujesz - bez narzutu i bez nadmiarowej złożoności. Sam Docker Compose to narzędzie stworzone przez Docker, Inc., a do definiowania środowiska używa formatu YAML.
Dla porządku: Compose nie ma też nic wspólnego z Docker Swarm, czyli starszą warstwą do orkiestracji w klastrze, która korzystała z dawnego formatu pliku Compose. Po przejęciu Swarma przez Mirantis nie jest on już rozwijany przez Docker, Inc. - dla pojedynczej maszyny i tak interesuje Cię Compose, a nie Swarm.
W klasycznych poradnikach Compose najczęściej widać usługi typu redis, nginx czy postgres - to typowy zestaw aplikacji webowej (cache, serwer WWW, baza danych). My zbudujemy zamiast tego stack AI, ale mechanika pliku jest dokładnie taka sama: jedna usługa to jeden kontener, niezależnie od tego, czy w środku siedzi baza, serwer WWW, czy silnik LLM.
Compose V2 (docker compose) vs V1 (docker-compose)
To częste źródło zamieszania, bo w sieci krążą obie formy zapisu. Różnica jest konkretna:
docker compose(ze spacją) to wersja V2 - wtyczka zintegrowana z Docker CLI. To wersja aktualna i tej powinieneś używać.docker-compose(z myślnikiem) to stara wersja V1, napisana w Pythonie i dostępna w gałęzi v1. Jest uznana za przestarzałą.
Pro tip admina: składnia samego pliku docker-compose.yml jest w obu wariantach praktycznie taka sama, więc starsze poradniki z komendą docker-compose up nadal działają koncepcyjnie - po prostu zamień myślnik na spację. Obie formy krążą w starszych tutorialach i wpisach, ale realnie pracujesz dziś na V2.
Kiedy Compose, a kiedy docker run
Trade-off jest prosty:
- Jeden kontener bez zależności (np. szybki test obrazu) -
docker runwystarczy. - Stack z dwóch lub więcej kontenerów, które muszą się widzieć (np. Ollama plus interfejs) - Compose. Masz wtedy całą konfigurację w pliku pod kontrolą wersji, zamiast w historii terminala.
Instalacja Docker Compose
Krok po kroku (Linux, np. Ubuntu albo Debian na VPS): w wersji V2 Compose instaluje się jako wtyczka razem z silnikiem Dockera. W oficjalnym repozytorium Dockera odpowiada za to pakiet docker-compose-plugin, który zwykle dociągasz przy instalacji Docker Engine.
Sprawdź instalację:
docker compose version
Jeśli polecenie zwraca numer wersji, masz V2 gotowe do pracy. Na Windowsie i macOS nie musisz instalować nic osobno - Docker Compose jest dołączony do pakietu Docker Desktop.
Dokładne polecenia instalacji bywają aktualizowane wraz z wersjami systemu i repozytoriów - aktualną procedurę dla swojej dystrybucji sprawdź w aktualnej dokumentacji Dockera (docs.docker.com).
Błąd "docker: 'compose' is not a docker command"
Objaw: po wpisaniu docker compose version terminal zwraca komunikat, że compose nie jest poleceniem Dockera. Przyczyna: masz silnik Dockera, ale brakuje wtyczki Compose V2. Rozwiązanie: doinstaluj pakiet docker-compose-plugin z repozytorium Dockera i ponów weryfikację. Jeśli dopiero stawiasz Ollama w kontenerze, cały proces od zera opisuję w osobnym wpisie - jak postawić Ollama w kontenerze to jeden kontener. Podajesz obraz (image), nazwę kontenera (container_name) i politykę restartu (restart).
services:
ollama:
image: ollama/ollama
container_name: ollama
restart: unless-stopped
Konkret: restart: unless-stopped sprawia, że kontener wstaje sam po restarcie serwera - kluczowe dla stacku, który ma działać 24/7.
ports - mapowanie portów
Port to brama do kontenera z zewnątrz. Składnia to host:kontener.
ports:
- "11434:11434"
Lewa liczba to port na maszynie-hoście, prawa to port wewnątrz kontenera. Trade-off: ports wystawia usługę na zewnątrz, a expose udostępnia port tylko innym kontenerom w tej samej sieci, bez otwierania go na świat.
volumes - trwałość danych
Pułapka, na którą nabiera się każdy początkujący: bez wolumenu dane z kontenera znikają po jego usunięciu. Wolumen to trwały magazyn poza cyklem życia kontenera.
volumes:
- ollama_data:/root/.ollama
volumes:
ollama_data:
Dwa typy: named volume (zarządzany przez Dockera, jak wyżej) oraz bind mount (mapowanie konkretnej ścieżki z hosta, np. ./dane:/root/.ollama). Konkret: pobrane modele Ollama trzymaj na named volume, żeby kilkugigabajtowe pliki nie znikały po każdym docker compose down.
environment - zmienne środowiskowe
Konfigurację kontenera podajesz przez zmienne środowiskowe - bezpośrednio albo z pliku .env.
environment:
- OLLAMA_HOST=0.0.0.0
Pro tip admina: hasła i klucze trzymaj w pliku .env (dodanym do .gitignore), a nie na sztywno w docker-compose.yml. Dzięki temu nie wrzucisz przypadkiem hasła do repozytorium.
networks - komunikacja między kontenerami
To zaskakuje wielu początkujących: Compose automatycznie tworzy wspólną sieć dla wszystkich usług z jednego pliku. Kontenery widzą się po nazwie usługi - nie po adresie IP.
Konkret: interfejs Open WebUI łączy się z Ollama nie przez localhost, tylko przez nazwę usługi - http://ollama:11434. Wewnątrz sieci Compose ollama to poprawna nazwa hosta wskazująca na węzeł z modelem.
depends_on i healthcheck - kolejność startu
depends_on ustala kolejność uruchamiania - np. interfejs ma wstać po silniku.
depends_on:
- ollama
Trade-off: depends_on czeka, aż kontener wystartuje, ale niekoniecznie aż usługa w środku będzie gotowa przyjmować połączenia. Do tego dochodzi healthcheck, który sprawdza realną gotowość usługi, zanim ruszą zależne kontenery.
Kompletny plik Ollama + Open WebUI
Złóżmy to w całość. Poniższy docker-compose.yml stawia lokalny stack AI: silnik Ollama plus webowy interfejs Open WebUI, połączone wspólną siecią Compose.
services:
ollama:
image: ollama/ollama
container_name: ollama
restart: unless-stopped
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
# silnik LLM - tu pobierają się i działają modele
open-webui:
image: ghcr.io/open-webui/open-webui:main
container_name: open-webui
restart: unless-stopped
ports:
- "3000:8080"
volumes:
- open_webui_data:/app/backend/data
environment:
# interfejs łączy się z silnikiem po nazwie usługi, nie po localhost
- OLLAMA_BASE_URL=http://ollama:11434
depends_on:
- ollama
volumes:
ollama_data:
open_webui_data:
Krok po kroku: zapisz plik jako docker-compose.yml, w tym samym katalogu uruchom docker compose up -d, a po chwili wejdź w przeglądarce na http://localhost:3000. Interfejs Open WebUI sam połączy się z Ollama po wspólnej sieci. Więcej o samym interfejsie znajdziesz we wpisie Open WebUI - interfejs do Ollama.
Podstawowe komendy Compose
Wszystkie polecenia uruchamiasz w katalogu z plikiem docker-compose.yml. Oto zestaw, który pokrywa codzienną pracę:
| Polecenie | Co robi |
|---|---|
docker compose up -d |
Tworzy i uruchamia cały stack w tle (detached) |
docker compose down |
Zatrzymuje i usuwa kontenery (dane na named volume zostają) |
docker compose ps |
Pokazuje status uruchomionych usług |
docker compose logs -f |
Wyświetla logi na żywo (-f = follow) |
docker compose restart |
Restartuje usługi bez przebudowy obrazów |
docker compose pull |
Pobiera nowsze wersje obrazów |
docker compose build |
Buduje obrazy z lokalnego Dockerfile |
Konkret: różnica między up a start. up tworzy kontenery od zera i je startuje, a start jedynie uruchamia kontenery, które już istnieją, ale zostały zatrzymane. Na co dzień używasz up -d.
Pułapka: docker compose down -v. Flaga -v kasuje także named volumes, czyli Twoje dane, łącznie z pobranymi modelami. Używaj down bez -v, chyba że naprawdę chcesz wyczyścić wszystko do zera.
Częste błędy i pułapki
Większość problemów z Compose to nie awarie, tylko powtarzalne potknięcia. Oto te, które łapią najczęściej.
port is already allocated- port na hoście jest już zajęty przez inny proces (np. 11434 trzyma lokalnie zainstalowana Ollama). Rozwiązanie: zmień port po lewej stronie mapowania, np."11435:11434", albo zatrzymaj proces zajmujący port.- Dane znikają po
down- prawie zawsze oznacza brak named volume albo użyciedown -v. Sprawdź, czy usługa ma podpięty wolumen i czy nie kasujesz go flagą. - Kontenery się nie widzą - zwykle literówka w nazwie usługi albo odwołanie do
localhostzamiast nazwy usługi. Pamiętaj: wewnątrz sieci Compose łączysz się po nazwie (ollama), nie polocalhost. - Ostrzeżenie o
version- starsze pliki zaczynają się od polaversion: "3". W Compose V2 to pole jest już zbędne i bywa zgłaszane jako przestarzałe - możesz je po prostu usunąć. permission deniedprzy bind mount - kontener nie ma prawa zapisu do zamapowanej ścieżki hosta. Przyczyna to najczęściej niezgodność UID albo GID użytkownika w kontenerze i na hoście.
Sprawdź: jeśli błąd dotyczy konkretnie Ollama (modele się nie pobierają, GPU niewidoczne), więcej rozwiązań zebrałem w osobnym wpisie - jak postawić Ollama w kontenerze to wersja V2 - wtyczka zintegrowana z Docker CLI, której powinieneś używać dzisiaj. docker-compose (z myślnikiem) to stara wersja V1 napisana w Pythonie, uznana za przestarzałą. Składnia pliku jest praktycznie identyczna, więc starsze poradniki nadal działają - zamień tylko myślnik na spację w poleceniu.
Jak zainstalować Docker Compose na Ubuntu lub VPS?
W wersji V2 Compose instaluje się jako wtyczka razem z silnikiem Dockera - w repozytorium Dockera odpowiada za to pakiet docker-compose-plugin. Po instalacji zweryfikuj wszystko poleceniem docker compose version. Jeśli zwróci numer wersji, masz gotowe środowisko. Dokładną procedurę dla swojej dystrybucji sprawdź w aktualnej dokumentacji Dockera.
Gdzie Docker Compose przechowuje dane?
W wolumenach. Named volume jest zarządzany przez Dockera i przeżywa usunięcie kontenera, a bind mount mapuje konkretną ścieżkę z hosta do kontenera. Dla stacku AI trzymaj pobrane modele na named volume - dzięki temu kilkugigabajtowe pliki nie znikają po docker compose down i nie pobierasz ich od nowa.
Jak zatrzymać stack bez utraty danych?
Użyj docker compose down, bez flagi -v. Polecenie zatrzymuje i usuwa kontenery, ale named volumes z danymi pozostają nietknięte. Pułapka: docker compose down -v kasuje także wolumeny, czyli Twoje dane i pobrane modele. Flagi -v używaj wyłącznie, gdy świadomie chcesz wyczyścić stack do zera.
Jak kontenery komunikują się między sobą?
Compose automatycznie tworzy wspólną sieć dla wszystkich usług z jednego pliku. Kontenery łączą się po nazwie usługi, nie po adresie IP ani localhost. Przykład: interfejs łączy się z silnikiem przez http://ollama:11434, gdzie ollama to nazwa usługi. To wbudowane DNS Compose wskazuje na właściwy węzeł stacku.
Czy Docker Compose nadaje się na produkcję?
Tak, Compose działa produkcyjnie na pojedynczej maszynie i świetnie sprawdza się dla jednego serwera czy homelaba. Ograniczenie: to nie orkiestrator klastra jak Kubernetes. Stack AI działający 24/7 potrzebuje serwera z zapasem RAM, a często też GPU - lokalny laptop nie wystarczy do stałej pracy pod obciążeniem.
Co dalej
Teraz rozumiesz, z czego składa się docker-compose.yml i potrafisz jednym poleceniem postawić stack Ollama plus Open WebUI. Konkret: Compose świetnie sprawdza się lokalnie, ale produkcyjny zestaw AI musi chodzić bez przerwy, a do tego laptop nie wystarczy.
Trade-off: stały stack AI (silnik LLM, interfejs i automatyzacja w stylu n8n) potrzebuje serwera z zapasem RAM, a często też GPU dla sensownej prędkości generowania. Jeśli planujesz uruchomić go na stałe, sprawdź VPS pod n8n i lokalne LLM.