Community
0
HostiServer
2026-09-21 11:18

Docker Compose: více služeb dohromady

⏱️ Doba čtení: ~15 minut | 📅 Aktualizováno: září 2026

Docker Compose: více služeb dohromady

V první části série jsme se naučili spustit jeden kontejner příkazem docker run. Reálná aplikace zřídka žije sama: přidává se k ní databáze, cache, a často i fronta zpráv. Tři služby jsou už tři samostatné příkazy docker run, v každém až desítka přepínačů, plus síť, kterou je třeba vytvořit ručně předem: docker network create app-net. Na pořadí spuštění přitom záleží, ale nic ho nezaručuje.

Problém je zvlášť patrný po restartu serveru. Kontejnery s restart: unless-stopped naběhnou samy, ale Docker neví, která služba má startovat první. Pokud aplikace naběhne dřív než databáze, první požadavek spadne s ECONNREFUSED — a je třeba aplikaci ručně restartovat, až je databáze připravená.

Docker Compose to řeší změnou samotného způsobu uvažování. Místo sekvence příkazů popisujete požadovaný stav v souboru docker-compose.yml: jaké služby mají existovat, jak jsou propojené, co na čem závisí. Pořadí spuštění, sítě a volumes bere na sebe Compose.

Jednu technickou věc je dobré vyřešit hned na začátku. Moderní příkaz je docker compose (dvě slova, plugin v Go, vestavěný do Docker Engine od verze 20.10+). Starý docker-compose (s pomlčkou, samostatný nástroj v Pythonu, větev v1) byl oficiálně vyřazen z podpory v květnu 2023. Ověřit, jaká verze je nainstalovaná:

docker compose version

Očekávaný výstup je něco jako Docker Compose version v2.x.x. Pokud příkaz nenajde, plugin se instaluje samostatně: apt install docker-compose-plugin.

2. Struktura docker-compose.yml

2.1 K řádku version:

Většina starších tutoriálů začíná soubor řádkem version: "3.8". V Compose v2 je tento řádek ignorován s varováním o zastaralosti — lze ho klidně odstranit, soubor bude kratší a bez zbytečného šumu v logách.

2.2 services: — klíč, jméno a DNS zároveň

Název každé služby pod klíčem services: plní dvojí roli: ve výchozím stavu z něj vzniká jméno kontejneru (<projekt>-<služba>-1) a zároveň je to DNS jméno, pod kterým je služba vidět ostatním kontejnerům ve stejné síti. Pokud nastavíte container_name: my-app explicitně, jméno bude předvídatelné, ale pak službu nelze škálovat příkazem docker compose up --scale app=3 — Compose nemůže vytvořit víc kontejnerů se stejným pevným jménem.

2.3 image: nebo build:

image: postgres:16-alpine stáhne hotový image z registru. build: . sestaví image z Dockerfile v aktuálním adresáři. Pokud Dockerfile neleží v kořeni projektu, uvede se explicitně:

build:
  context: ./app
  dockerfile: Dockerfile.prod

2.4 environment: — dva formáty zápisu

Proměnné prostředí lze psát jako mapu (DATABASE_URL: postgres://...) nebo jako seznam (- DATABASE_URL=postgres://...). Formát mapy se čte lépe při velkém počtu proměnných. Výraz ${VAR} se v obou formátech dosazuje z hodnoty v souboru .env nebo ze shell prostředí v okamžiku spuštění Compose.

2.5 ports: — jen to, co skutečně potřebuje být venku

Formát "3000:3000" znamená port hostu : port kontejneru. Bez sekce ports: zůstává služba nedostupná zvenčí, ale dostupná ostatním službám ve stejné síti Compose. Pro databázi v produkci ports: zpravidla není potřeba a je nežádoucí — otevírat port SŘBD do internetu bez naprosté nutnosti se nevyplatí.

2.6 volumes: u služby

Krátká forma je pgdata:/var/lib/postgresql/data. Dlouhá forma umožňuje explicitně uvést typ — type: volume pro named volume nebo type: bind pro bind mount. Named volume použitý ve službě musí mít odpovídající blok na horní úrovni souboru: volumes: pgdata: — právě tady Compose přebírá řízení jeho životního cyklu.

2.7 networks: — vlastní výchozí síť

Bez explicitní deklarace Compose vytvoří síť s názvem <projekt>_default a připojí do ní všechny služby. Vlastní síť se nastaví takto: u služby networks: [app-net], a dole v souboru networks: app-net: (prázdný blok znamená bridge síť s výchozím nastavením).

2.8 restart: — čtyři varianty

Hodnota Chování
no Výchozí — vůbec se nerestartuje
always Restartuje se vždy, i po docker compose stop
unless-stopped Restartuje se, kromě případu, kdy byl zastaven ručně
on-failure Jen pokud proces skončil s nenulovým kódem

Pro produkci se jako výchozí vyplatí zvolit unless-stopped: služba přežije restart hostu, ale nebude se snažit naběhnout znovu, pokud jste ji zastavili vědomě.

2.9 command: a entrypoint:

Obě direktivy přepisují to, co je nastaveno v Dockerfile přes CMD nebo ENTRYPOINT. Typické použití je samostatný dev režim: command: npm run dev místo produkčního spouštěcího příkazu, bez nutnosti udržovat dva různé Dockerfile.

3. Reálný stack: Node.js + PostgreSQL + Redis

Dáme to všechno dohromady do jednoho funkčního příkladu — aplikace na Node.js, databáze PostgreSQL a cache Redis:

services:
  app:
    build: .
    ports: ["3000:3000"]
    env_file: .env
    environment:
      DATABASE_URL: postgres://user:${DB_PASSWORD}@db:5432/mydb
      REDIS_URL: redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    networks: [app-net]
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: mydb
    volumes: [pgdata:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
      interval: 5s
      timeout: 5s
      retries: 10
    networks: [app-net]
    restart: unless-stopped

  cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru
    networks: [app-net]
    restart: unless-stopped

volumes:
  pgdata:

networks:
  app-net:

Stack Docker Compose: app, db a cache v jedné síti app-net s named volume pgdata

3.1 Proměnné POSTGRES_*

Oficiální image postgres čte POSTGRES_USER, POSTGRES_PASSWORD a POSTGRES_DB jen jednou — při první inicializaci clusteru na prázdném volume. Při dalších spuštěních, kdy volume už existuje, se tyto proměnné ignorují. Heslo pozdější změnou proměnné nezměníte — bude třeba provést ALTER USER uvnitř už běžící databáze.

3.2 depends_on s podmínkou service_healthy

Sekce depends_on: db: condition: service_healthy znamená, že app nezačne startovat, dokud healthcheck databáze nevrátí úspěch. Prostý zápis depends_on: [db], bez podmínky, čeká jen na start samotného procesu kontejneru — a PostgreSQL v tu chvíli ještě může inicializovat cluster a nepřijímat spojení. Přesně to způsobuje ECONNREFUSED při prvním požadavku po startu stacku.

3.3 Proč retries: 10, ne 5

Při interval: 5s a retries: 10 je Compose ochoten čekat na healthy stav databáze až 50 sekund celkem. To není s rezervou: první inicializace clusteru PostgreSQL sama o sobě může trvat 10-20 sekund, a při retries: 5 (25 sekund) může Compose označit databázi jako unhealthy ještě předtím, než skutečně naběhla.

Pořadí spuštění stacku Docker Compose: app čeká na healthy stav db, než začne startovat

3.4 redis:7-alpine a limit paměti

Tag redis:latest znamená, že obsah image se může kdykoli změnit; redis:7-alpine fixuje hlavní verzi a váží zhruba 40 MB. Přepínač --maxmemory 128mb v command: je v produkci kriticky důležitý: bez explicitního limitu se Redis ve výchozím stavu snaží využít veškerou dostupnou paměť hostu, a při aktivním cachování to může vést k OOM zabití sousedních kontejnerů.

3.5 Jak služby najdou jedna druhou podle jména

Řádek @db:5432 v DATABASE_URL funguje díky vestavěnému DNS Compose: jméno služby db se přeloží na interní IP adresu odpovídajícího kontejneru. To funguje jen pro služby ve stejné sekci networks: a nefunguje z hostu — z terminálu serveru jméno db nic neznamená.

4. .env — proměnné a secrets

4.1 Automatické načtení

Soubor .env ve stejném adresáři jako docker-compose.yml Compose načte automaticky, bez dalšího nastavení:

DB_PASSWORD=supersecret123
NODE_ENV=production

4.2 Dva různé mechanismy — nezaměňovat

Tady se snadno spletou dva podobné, ale odlišné způsoby, jak se hodnoty dostanou do kontejneru:

  • ${DB_PASSWORD} přímo v compose souboru — dosazení proběhne během parsování YAML samotným Compose; hodnota se dostane do konfigurace, ale ne automaticky do proměnných prostředí kontejneru.
  • env_file: .env v sekci služby — soubor se celý předá dovnitř kontejneru jako proměnné prostředí, dostupné aplikaci přes, například, process.env.DB_PASSWORD.

4.3 Ověření dosazení

docker compose config

Tento příkaz vypíše finální compose soubor už po dosazení všech ${VAR} — pohodlný způsob, jak se ujistit, že hodnoty z .env se skutečně načetly, ještě před spuštěním stacku.

4.4 Priorita zdrojů hodnot

Od nejvyšší priority po nejnižší: proměnná shell prostředí → hodnota ze souboru .env → výchozí hodnota přímo ve výrazu, pokud je zadaná jako ${VAR:-default}.

4.5 .gitignore

Soubor .env se musí přidat do .gitignore. Rozumný vzor je *.env a .env*, což zároveň vyloučí .env.local a .env.production, které se často přidávají později.

4.6 .dockerignore taky

.env musí být i v .dockerignore — jinak COPY . . v Dockerfile zkopíruje secrets přímo dovnitř image. Snadno se to ověří:

docker run --rm my-app cat /app/.env

Pokud příkaz vypíše obsah souboru, secret je už „zapečený" v image, a problém nevyřeší smazání souboru v dalším commitu: předchozí vrstva image ho stále obsahuje.

4.7 Přístupová práva k souboru

chmod 600 .env omezí čtení souboru jen na vlastníka — pro jeden VPS to stačí. Pro scénáře náročnější než jeden server (Swarm, víc týmů s různou úrovní důvěry) se vyplatí podívat se po Docker Secrets nebo HashiCorp Vault.

5. Sítě: jak služby najdou jedna druhou

5.1 Izolace podle projektů

Každý Compose projekt — obvykle samostatný adresář — dostane vlastní izolovanou síť. Služba app z jednoho projektu nevidí db jiného projektu, i když oba běží na stejném hostu.

5.2 Jméno projektu

Ve výchozím stavu se jméno projektu bere z názvu adresáře. Lze ho nastavit explicitně přepínačem docker compose -p myproject up nebo řádkem name: myproject na horní úrovni compose souboru — to ovlivňuje jména kontejnerů a sítí, a tedy i to, zda se dva stacky navzájem „uvidí".

5.3 Minimum otevřených portů

Pravidlo je jednoduché: ports: se píše jen u služeb, které skutečně potřebují přístup zvenčí. V příkladu výše je to app (3000:3000); db a cache takový blok nemají. Zbytečný řádek "5432:5432" v sekci databáze otevře PostgreSQL celému internetu — to je jedna z nejčastějších příčin kompromitace databáze na VPS.

5.4 Komunikace mezi různými stacky

Pokud spolu mají komunikovat dva nezávislé Compose projekty — například samostatný monitorovací stack, který potřebuje vidět metriky aplikace — použije se připojení k už existující síti:

networks:
  monitoring-net:
    external: true

6. Klíčové příkazy

Příkaz Co dělá
docker compose up -d Spustí všechny služby na pozadí; při prvním spuštění vytvoří sítě, volumes, stáhne image a sestaví build:; při opakovaném restartuje jen změněné služby
docker compose up -d --build Vynutí přesestavení image před spuštěním — potřeba po změnách v Dockerfile nebo kódu, jinak Compose vezme cachovaný image
docker compose up -d --no-deps app Restartuje jen app, aniž by se dotkl db a cache — pohodlné při nasazení nové verze aplikace
docker compose down Zastaví a smaže kontejnery a sítě; named volumes zůstávají — data v pgdata jsou zachována
docker compose down -v Totéž, plus smazání named volumes — v produkci nevratné: pgdata zmizí spolu se všemi daty databáze
docker compose stop / start Zastavit nebo spustit bez mazání kontejnerů — rychlejší než down+up, volumes a sítě zůstávají
docker compose restart app Restartovat konkrétní službu; compose soubor se přitom znovu nenačítá — pro použití změn konfigurace je potřeba up -d
docker compose ps Stav všech služeb: jméno, image, stav, porty, health
docker compose logs -f app Follow logy konkrétní služby; bez jména služby logy všech najednou s barevnými prefixy; --tail=100 omezí výstup na poslední řádky
docker compose exec db psql -U user -d mydb Otevřít psql uvnitř kontejneru databáze pro debug
docker compose run --rm app npm run migrate Spustit jednorázový příkaz v novém kontejneru služby app a hned po dokončení ho smazat — typické pro migrace DB
docker compose pull && docker compose up -d Aktualizovat image z registru a restartovat — základní vzor deploye v CI/CD (článek 4 série)

7. Závěr

Teď je celý stack — aplikace, databáze, cache — popsaný v jednom souboru. git clone plus docker compose up -d vytvoří identické prostředí na jakémkoli serveru s Dockerem za minutu až dvě, bez jediného ručního kroku a bez otázky „v jakém pořadí to spustit".

Zůstává pár věcí, které docker-compose.yml sám o sobě neřeší. HTTPS a SSL certifikáty — stack potřebuje před sebou reverse proxy jako Nginx nebo Traefik. Víc domén na jedné IP adrese se také řeší na úrovni proxy, ne Compose. Limity zdrojů (mem_limit: 512m, cpus: "0.5") zatím chybí — a bez nich může jedna služba, která se vymkne kontrole, vzít veškerou paměť serveru ostatním. A logy jsou zatím dostupné jen přes docker compose logs, bez rotace a bez uchování po smazání kontejneru.

Přesně tyto mezery jsou tématem dalšího článku: před stack se postaví Nginx nebo Traefik, objeví se certifikát Let's Encrypt a automatické spuštění se přesune z ručního docker compose up -d na systemd jednotku, která stack po restartu serveru naběhne sama, bez účasti člověka.

📚 Navigace v sérii:
Čtete část 2 z 5 „Docker Compose: více služeb dohromady".
Předchozí: Část 1. Docker na VPS: instalace a první kontejner ←
Dál: Část 3. Docker v produkci →

🚀 VPS pro váš Compose stack

Víc kontejnerů najednou už není „jedno dvě jádra pro jistotu": aplikace, databáze a cache běží paralelně a každá drží vlastní paměť. Hostiserver dává zdroje počítané přesně pro takový stack.

🖥️ Dedikované servery

  • Od $90/měsíc, plná kontrola nad hardwarem pro náročnější produkční stacky
  • Bez sousedů o zdroje: healthcheck databáze nezávisí na cizí zátěži
  • Podpora 24/7: pomůžeme se sítěmi, volumes a systémovým automatickým spuštěním stacku

💻 Cloud (VPS) hosting

  • Od $19.95/měsíc, KVM izolace, vyhrazené vCPU a RAM
  • NVMe disky: PostgreSQL a Redis s diskem, který se nestane úzkým hrdlem
  • Dost RAM už od prvního tarifu: app + db + cache najednou bez swapování
  • Snadné škálování: víc paměti pro novou službu ve stejném compose souboru

💬 Nejste si jistí, kterou variantu potřebujete?
💬 Napište nám — pomůžeme s výběrem!

Časté dotazy

Čím se docker compose (v2) liší od docker-compose (v1)?

docker-compose (s pomlčkou) je samostatný nástroj v Pythonu, větev v1, oficiálně vyřazená z podpory v květnu 2023. docker compose (dvě slova) je plugin v Go, vestavěný do Docker Engine od verze 20.10+, a právě ten se teď vyvíjí. Syntaxe compose souboru se prakticky nezměnila, rozdíl je hlavně v samotném příkazu spuštění a rychlosti.

Aplikace hned po startu spadne s ECONNREFUSED — co je špatně?

Nejčastější příčina je prostý depends_on: [db] bez podmínky: Compose čeká jen na start procesu kontejneru databáze, ne na její připravenost přijímat spojení. Řešení je depends_on: db: condition: service_healthy spolu s nastaveným healthcheck: přímo u služby databáze.

Potřebuje moderní compose soubor řádek version:?

Ne. V Compose v2 je ignorován s varováním o zastaralosti a nemá vliv na fungování souboru. Lze ho odstranit z jakéhokoli projektu bez následků — soubor bude jen kratší.

docker compose down vs down -v — jaký je rozdíl?

down smaže kontejnery a sítě, ale nechá named volumes na místě — data databáze jsou zachována. down -v navíc smaže i volumes a s nimi všechna data uvnitř. Na produkčním serveru se -v vyplatí použít jen vědomě a po ověření, že záloha skutečně existuje.

Jak předat heslo k databázi, aniž bych ho ukládal do gitu?

Heslo se vyčlení do souboru .env vedle docker-compose.yml, a samotný soubor se přidá do .gitignore (a do .dockerignore, aby se nedostal do image). V compose souboru se hodnota dosazuje přes ${DB_PASSWORD}. Pro scénáře s víc servery nebo týmy se vyplatí zvážit Docker Secrets nebo externí úložiště jako HashiCorp Vault.

Lze otevřít port databáze ven kvůli debugu?

Technicky ano, přidáním ports: ["5432:5432"], ale v produkci to není žádoucí — port se stane dostupným celému internetu. Bezpečnější cesta pro debug je docker compose exec db psql -U user -d mydb, který otevře session psql přímo uvnitř kontejneru bez otevření portu ven, nebo dočasný SSH tunel na dobu práce.

Kolik paměti přidělit každé službě?

V základním docker-compose.yml bez explicitních limitů může každá služba využít veškerou dostupnou paměť hostu — přesně proto Redis v příkladu výše běží s --maxmemory 128mb. Pro systémové limity na úrovni Compose se používají mem_limit a cpus u každé služby; víc o tom v dalším článku série, věnovaném produkčnímu nastavení.

Contents

Sdílejte tento článek

MANAGED VPS STARTING AT

$19 95 / mo

NEW INTEL XEON BASED SERVERS

$80 / mo

CDN STARTING AT

$0 / mo

 

Tento web používá cookies. Používáním tohoto webu souhlasíte s politikou ochrany osobních údajů.