24 kontejnery na jednom VPS: technická architektura vysoké hustoty pro middle/senior DevOps
Klíčový přístup — striktní síťová izolace. Každý projekt je umístěn ve vlastní Docker síti (bridge), což vylučuje vzájemné závislosti a minimalizuje plochu útoku. Společná síť shared se používá pouze pro systémové služby (například monitoring nebo společný Redis). Interní porty (9200, 8088, 9222) jsou dostupné výhradně přes 127.0.0.1, externí přístup je zakázán na úrovni iptables a konfigurace nginx.
Odolnost je zajištěna prostřednictvím healthcheck závislostí v docker-compose.yml. Například PHP služby v projektu EdTech nezačínají, dokud SSH tunel k vzdálené databázi neprojde kontrolou nc -z 127.0.0.1 3306. To zaručuje, že aplikace se nebude snažit připojit k nedostupné databázi a nezablokuje frontu chybami.
Sledovatelnost je postavena bez Prometheus/Grafana — kvůli omezení RAM. Místo toho se používá bash skript, který se spouští každých 15 minut:
- Kontrola HTTP stavů veřejných endpointů (
/health,/webhook/advert) - Hledání nemocných kontejnerů prostřednictvím
docker ps --filter "health=unhealthy" - Monitoring disku a využití swapu
- Upozornění jsou odesílána do Telegram chatu pomocí curl k Bot API
To poskytuje minimální, ale dostatečnou viditelnost pro jednoho administrátora.
Kritické komponenty: Elasticsearch, Chrome Headless a SSH tunely
Tři komponenty určují hranice výkonu VPS:
- Elasticsearch 8.12.2 spotřebovává 1,47 GB RAM. Bez explicitního
memory: 2gvdeploy.resources.limitszačne JVM vytláčet sousední procesy do swapu, což způsobuje nestabilitu. Pro index o cca 50 tisících dokumentech a protokolování je to optimální rovnováha mezi funkcionalitou a zatížením. Alternativa — Meilisearch — vyžaduje migraci stávajících indexů a změnu klientského kódu, což je v současné fázi hodnoceno jako náročná a málo rentabilní úloha.
- Chrome Headless (zenika/alpine-chrome) zabírá 636 MB RAM, i když se používá jen jednou za hodinu pro scrapování JS renderingu. Spuštění
on-demandprostřednictvímdocker run --rmby ušetřilo paměť, ale přidalo by 5–10 sekund zpoždění na každý volání. Pro služby s přísnými SLA je to nepřijatelné; zde je to však přijatelný kompromis.
- SSH tunely jsou implementovány v samostatných alpine kontejnerech s
autossh. Zajišťují bezpečný přístup k MySQL na shared hostingu bez otevírání portů ven. Konfigurace zahrnujeServerAliveInterval=30,AUTOSSH_GATETIME=0a healthcheck prostřednictvímnc. Toto řešení funguje se všemi hostingy podporujícími SSH a plně nahrazuje placené managed databáze.
Optimalizace Nginx a PHP: snížení latence na milisekundy
Nginx je nastaven pouze pro webhooks a API — žádné statické soubory kromě /health. Klíčová optimalizace — vyjmutí zpracování Telegram webhooků do samostatného PHP souboru (webhook-advert.php), který nenabíhá Laravel bootstrap. To zkracuje čas odezvy z 80–120 ms na 15–25 ms, což je kritické při masivních webhook voláních od Telegram API (maximální timeout — 60 sekund).
Konfigurace také zahrnuje:
- Povinný přesměrování HTTP → HTTPS
- Odmítnutí zpracování jakýchkoli cest kromě
/health,/webhook/a/api/telegram/ - Zvýšený
fastcgi_read_timeoutna 120 sekund pro dlouhotrvající úkoly - Použití
realpath_rootpro správné zpracováníindex.php
SSL a bezpečnost: tři strategie na jednom hostu
SSL terminace je organizována hybridně:
- getssl + Let's Encrypt — pro domény, kde je potřeba end-to-end šifrování a není Cloudflare
- Cloudflare Proxy — pro většinu domén: SSL terminuje na edge, provoz do VPS probíhá přes HTTP, ale je chráněn IP filtrací (jen Cloudflare ASN)
- Ruční aktualizace — dočasná opatření pro AI backend, který je v procesu automatizace prostřednictvím Caddy
Nastavení Cloudflare zahrnuje povinné zapnutí Always Use HTTPS, WAF a Rate Limiting (100 požadavků/min na IP), což kompenzuje absence WAF na straně VPS.
Co je důležité
- Striktní síťová izolace prostřednictvím samostatných Docker sítí zabraňuje kaskádovým selháním a zjednodušuje bezpečnostní audit.
- Healthcheck závislosti v docker-compose zaručují, že služby startují pouze po připravenosti svých závislostí (například SSH tunelu k databázi).
- Elasticsearch vyžaduje striktní memory limit (2 GB), jinak JVM vytláčí sousední kontejnery do swapu, což způsobuje OOM-killer.
- Chrome Headless je vhodné držet v režimu always-on při nízké frekvenci použití, pokud je zpoždění spuštění kritické pro business logiku.
- Bash monitoring s Telegram alerty — funkční náhrada Prometheus/Grafana při nedostatku RAM, za předpokladu jasně definovaných SLO.
— Editorial Team
Zatím žádné komentáře.