Docker Compose nije rezerviran samo za lokalni development. Za male timove i SMB stackove na jednom ili nekoliko VPS-ova često je najbrži način da se aplikacija, baza i reverse proxy drže u jednoj deklarativnoj datoteci. Problem nastaje kad se development Compose kopira u produkciju bez restart policyja, healthcheckova, limita resursa i bez kontrole tajni.
Ovaj članak pokriva što mora biti na mjestu prije nego što Compose stack smatrate produkcijskim. Ako tek krećete s kontejnerima na malom hardveru, koristan je i vodič Raspberry Pi i Docker. Za ulazni TLS sloj na VPS-u pogledajte Traefik kao reverse proxy.
Compose, Swarm ili Kubernetes za male timove
Compose opisuje stack: servise, mreže, volumene, ovisnosti. Pokreće se na jednom Docker hostu naredbom docker compose up -d (Compose V2 plugin, ne stari binarni docker-compose v1).
Compose na jednom hostu dovoljan je za većinu Django/Node aplikacija, bazu, Redis i Traefik. Operativni model je jednostavan. Swarm donosi isti Compose-sličan model, ali s orkestracijom preko više nodova; ima smisla ako već imate Swarm i trebate rolling update ili više replika. Kubernetes je smislen kad imate više timova, stroge SLA-ove, horizontalno skaliranje i ljude koji znaju održavati klaster. Za jedan VPS i jednu aplikaciju često je prevelik operativni trošak.
Tradeoff: Compose je brz za deploy i čitljiv. Nema ugrađenog multi-node failovera. Ako host padne, stack pada. To je prihvatljivo ako imate snapshot/backup i RTO koji to dopušta.
Compose V2: bez zastarjelog version: ključa
U modernom Compose Specification ključ version: više nije potreban i Compose V2 ga ignorira. Koristite docker compose (plugin u Docker Engineu), ne docker-compose v1 paket iz starih Debian/Ubuntu repozitorija.
docker compose version
docker compose config
docker compose up -d --pull missing
Pinani image tagovi
nginx:latest ili postgres:alpine bez verzije znači da sutrašnji pull može donijeti lomljivu nadogradnju. U produkciji pinajte major.minor (ili digest):
services:
web:
image: ghcr.io/example/app:1.4.2
db:
image: postgres:16.6-alpine
Digest (image@sha256:...) daje maksimalnu reproduktivnost, ali otežava čitljive bumpove. Za SMB stackove često je dovoljan eksplicitni semver tag plus changelog prije upgradea.
Restart policy
Bez restart policyja kontejner ostaje mrtav nakon crasha ili reboota hosta. Za produkcijske servise tipično:
services:
web:
restart: unless-stopped
no ostavite za jednokratne jobove. always restarta i nakon ručnog stop (nakon reboota). unless-stopped restarta nakon crasha ili reboota, ali poštuje ručni stop; to je najčešći izbor. on-failure radi samo pri non-zero exitu i koristan je za workere uz max_attempts.
Healthcheck i ovisnosti
depends_on sam po sebi čeka samo start kontejnera, ne spremnost aplikacije. Kombinirajte healthcheck s condition: service_healthy:
services:
db:
image: postgres:16.6-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 10s
timeout: 5s
retries: 5
start_period: 20s
web:
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:8000/healthz"]
interval: 15s
timeout: 3s
retries: 3
Healthcheck mora biti lagan i lokalni. Ne udarajte vanjski CDN iz healthchecka. Ako endpoint ovisi o bazi, odvojite liveness (proces živi) od readiness (spreman za promet). Compose ima jedan healthcheck, pa dizajnirajte endpoint namjerno.
Tajne: što ne stavljati u compose.yml
Environment varijable u plain YAML-u završe u gitu. Za mali host bolje ide env_file: .env izvan gita (.gitignore) s permisijama 600, ili Docker Compose secrets (file-based) mountani kao datoteke u kontejneru. Vanjske tajne (Vault, cloud secret manager) imaju smisla kad stack naraste.
services:
web:
env_file:
- .env
secrets:
- db_password
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
file: ./secrets/db_password.txt
Ne logirajte cijeli environment u entrypoint skriptama. Ne commitajte .env. Rotirajte credentiale nakon curenja, ne samo "promijeni u Composeu".
Resource limits
Jedan runaway proces (memory leak, fork bomb u buildu) može ubiti cijeli VPS. Postavite granice:
services:
web:
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
reservations:
memory: 256M
Na Composeu bez Swarma deploy.resources Compose V2 mapira na container limits na Docker Engineu (provjerite docker compose config i stvarne limite s docker inspect). Testirajte ponašanje pod OOM-om: bolje kontrolirani restart nego host freeze.
Logging
Default json-file driver može napuniti disk. Ograničite rotaciju:
services:
web:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
Za centralizirani pregled (Loki, journald, cloud log sink) odvojite shipping od aplikacije. Ne oslanjajte se na docker logs kao jedini audit trail.
Bind mount vs named volume
Named volume pogodan je za Postgres data i Redis persistence. Docker upravlja lokacijom; backup ide preko volume alata ili host patha ispod /var/lib/docker/volumes (pazite na format). Bind mount pogodan je za certifikate, .env, Traefik dynamic config i upload direktorije koje backupirate rsync-om s poznate putanje. Path je jasniji, ali ovisi o layoutu hosta.
Ne mountajte cijeli source tree aplikacije u produkciju "radi bržeg deploja". Image treba sadržavati artefakt; mountajte samo mutable podatke.
Mreža i portovi
Ne publishajte bazu na 0.0.0.0:5432 ako joj pristupa samo drugi kontejner. Držite DB na internal Compose mreži; publishajte samo reverse proxy (80/443).
services:
db:
expose:
- "5432"
proxy:
ports:
- "80:80"
- "443:443"
Česte greške
Najčešće vidim stari docker-compose v1 plus version: "3" copy-paste iz tutorijala iz 2019. Zatim restart: always na one-shot migracijskim kontejnerima koji se vrte u petlji, healthcheck koji prolazi dok aplikacija još nije migrirana, tajne u YAML-u i u CI logovima (docker compose config ispisuje interpolirane vrijednosti, oprez u pipelineu), i docker compose down -v bez backupa volumena.
Kada Compose nije za produkciju
Compose na jednom hostu nije dovoljan kad trebate multi-node HA i automatski reschedule preko hostova, stroge rolling update ili canary zahtjeve, compliance orkestrator s RBAC-om i policy engineom koji već imate na K8s-u, ili kad tim ne želi petlju oko jednog Docker hosta kao single point of failure, a nema vremena graditi pravi failover.
U tim slučajevima Compose i dalje može biti development/staging format; produkcija ide na Swarm/K8s ili managed container service.
Update i rollback procedura
Definirajte rutinu: pinani tag u gitu, zatim docker compose pull, pa up -d, healthcheck i smoke test. Rollback je povratak prethodnog taga u compose datoteci ili env overrideu, opet pull plus up -d. Ne radite docker compose down -v kao dio rutinog updatea.
Migracije baze držite kao eksplicitan korak (CI ili ručno), ne kao side-effect svakog restarta bez kontrole. Ako migracija nije unazad kompatibilna, rollback imagea sam nije dovoljan. Planirajte to prije deploya.
Zaključak
Bez pinanih tagova, healthchecka, limita i tajni van gita, Compose na VPS-u ostaje laptop setup. Publishajte samo ulazni proxy. Ako trebate pomoć oko stacka, pogledajte DevOps usluge.