V březnu 2016 jsme nasadili první Docker kontejner do produkce. O rok později máme v kontejnerech přes 40 služeb. Tady je to, co jsme se naučili — včetně chyb, které bychom rádi neudělali.
Proč jsme začali s Dockerem¶
Klasický příběh: „na mém stroji to funguje.” Vývojáři měli na laptopech Ubuntu 16.04, staging běžel na CentOS 7, produkce na Red Hatu. Každý deploy byl dobrodružství. Knihovny v jiných verzích, jiné systémové závislosti, jiné konfigurace. Docker měl být řešením — a skutečně je. Ale cesta k němu nebyla přímočará.
První impulz přišel od vývojového týmu, který chtěl rychlejší onboarding nových členů. Místo dvoudenního setupu lokálního prostředí stačilo docker-compose up a za pět minut běžel celý stack. To samotné prodalo Docker managementu.
Image management — kde to začíná i končí¶
Pravidlo číslo jedna: nikdy nepoužívejte tag latest v produkci. Zní to jako banalita, ale v prvních měsících jsme to porušovali. Výsledek? Nereplikovatelné buildy a „ale včera to fungovalo.” Dnes má každý image tag odvozený z git commitu — krátký SHA hash plus číslo buildu.
# Špatně
FROM node:latest
# Správně
FROM node:8.9.4-alpine
Multi-stage buildy změnily hru. Dříve jsme měli build image 1.2 GB (Node.js aplikace s devDependencies, build toolchain, zdrojáky). Po přechodu na multi-stage build se produkční image zmenšil na 89 MB. Menší image = rychlejší pull = rychlejší deploy = menší attack surface.
Provozujeme vlastní Docker registry na bázi Harbor. Důvody: kontrola nad daty (některé projekty spadají pod NDA), vulnerability scanning integrovaný přímo do push pipeline, a garbage collection starých image. Docker Hub je fajn pro open source, ne pro enterprise.
Logování — nedělejte naši chybu¶
První měsíce jsme logovali do souborů uvnitř kontejnerů. Ano, přesně tak špatně, jak to zní. Kontejner spadl, logy zmizely. Debugging produkčních problémů se stal noční můrou.
Řešení bylo přejít na centralizované logování. Aplikace píšou na stdout/stderr (12-factor app princip), Docker log driver je přeposílá do Fluentd, a odtamtud do Elasticsearch. Grafana a Kibana pro vizualizaci. Celý EFK stack běží — samozřejmě — v kontejnerech.
# docker-compose.yml - logging konfigurace
services:
api:
image: registry.core.cz/api:${BUILD_SHA}
logging:
driver: fluentd
options:
fluentd-address: "localhost:24224"
tag: "api.{{.Name}}"
Důležitý detail: strukturované logování. Ne console.log("Error: " + err), ale JSON s kontextem — request ID, user ID, timestamp, severity. Bez toho je hledání v milionech logů jako hledání jehly v kupce sena.
Síťování — overlay networks a service discovery¶
Docker networking je oblast, kde se člověk naučí víc o TCP/IP, než by chtěl. Overlay networks fungují, ale mají overhead. Pro většinu workloadů to nevadí, ale u latency-sensitive služeb (real-time API, WebSocket) jsme přešli na host networking.
Service discovery řešíme přes Consul. Každý kontejner se při startu zaregistruje, health check ověřuje dostupnost, a ostatní služby ho najdou přes DNS. Zkoušeli jsme i Docker built-in DNS, ale Consul nabízí víc — KV store, prepared queries, multi-datacenter support.
Bezpečnost — kontejner není VM¶
Tohle je kritické a často podceňované. Kontejner sdílí kernel s hostem. Pokud útočník unikne z kontejneru, má přístup k celému hostu. Proto:
- Neběžte jako root uvnitř kontejneru. Přidejte
USER nonrootdo Dockerfile. - Read-only filesystem kde to jde:
--read-onlyflag. - Omezte capabilities:
--cap-drop=ALL --cap-add=NET_BIND_SERVICE— kontejner potřebuje jen to, co skutečně používá. - Skenujte image na zranitelnosti. Harbor to dělá automaticky přes Clair. Každý push projde skenem a image s critical CVE se nedostane do produkce.
- Aktualizujte base image. Alpine linux vydává security patche pravidelně — ale vy musíte rebuildit a redeployit.
Monitoring a health checks¶
Docker HEALTHCHECK je nutnost, ne luxus. Bez něj Docker neví, jestli vaše aplikace skutečně funguje — ví jen, že proces běží. Rozdíl je obrovský. Aplikace může viset v deadlocku, mít plný connection pool, nebo čekat na nedostupnou databázi.
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
Na úrovni orchestrace (Docker Swarm, Kubernetes) health checks řídí rolling updates a automatický restart nezdravých kontejnerů. Investice do dobrého health endpointu se vrátí stonásobně.
Čeho bychom se vyvarovali příště¶
Příliš velké kontejnery. Na začátku jsme měli monolitické aplikace v jednom kontejneru. Dnes rozumíme, že kontejner by měl dělat jednu věc dobře. Microservices architektura a kontejnery jdou ruku v ruce.
Ignorování resource limitů. Kontejner bez memory limitu může sežrat veškerou RAM na hostu a způsobit OOM kill jiných služeb. Vždy nastavujte --memory a --cpus.
Podceňování persistent storage. Docker volumes nejsou zálohované automaticky. Databáze v kontejneru? Ano, ale s promyšlenou storage strategií — named volumes, pravidelné backupy, testované restore procedury.
Docker v produkci stojí za investici¶
Po roce máme rychlejší deploys (z hodin na minuty), konzistentní prostředí od dev po produkci, a lepší využití hardwaru. Ale není to zadarmo — vyžaduje to změnu myšlení, nové nástroje a nové znalosti v týmu. Pokud zvažujete Docker pro produkci, začněte s jednou stateless službou, naučte se základy, a postupně rozšiřujte.