Reply Pilot Container Runtime Contract

Tento dokument je source of truth pro zmeny v Docker image, Docker Compose a deploy skriptech v repozitari Reply Pilot.

Doplňuje:

  • docs/remote-server.md pro server a remote deploy pravidla
  • AGENTS.md pro projektove provozni konvence

Vztah k ostatnim artefaktum:

  • docs/remote-server.md se porad pouziva pro server a remote deploy pravidla.
  • Tento dokument drzi projektovy runtime kontrakt pro image, Compose a deploy skripty.
  • Codex skill shift-planner-deploy-runtime neni source of truth; jen odkazuje na dokumentaci a hlida konzistenci zmen.
  • Skill se do tohoto repozitare nekopiruje. Codex ho ma nacitat z lokalniho skill adresare ${CODEX_HOME:-$HOME/.codex}/skills/.

Scope

Plati pro vsechny kontejnery provozovane z tohoto repozitare v produkci na mathbox.90.cz, zejmena pro projekt reply-pilot a dalsi dlouhodobe bezici sluzby pridane do tohoto repozitare.

Neresi:

  • aplikacni feature behavior
  • HAProxy konfiguraci do detailu
  • obsah business logiky aplikace

Repository Layout

Reply Pilot je multi-service repozitar. Kazda dlouhodobe bezici sluzba ma byt samostatny top-level modul, napriklad reply-pilot-app/, reply-pilot-be/, reply-pilot-gmail/, reply-pilot-search/, reply-pilot-docs/ nebo reply-pilot-worker/.

Kazdy modul ma obsahovat:

  • vlastni Dockerfile
  • vlastni docker-compose.yml
  • vlastni .env.example
  • vlastni README.md
  • vlastni data/, logs/ a conf/
  • operacni skripty pojmenovane podle modulu:
  • scripts/<module_name>-start.sh
  • scripts/<module_name>-stop.sh
  • scripts/<module_name>-deploy.sh

Docker image ma pouzivat stejne jmeno jako modul.

Deployment Dependencies

Nasledujici diagram zachycuje deployment topologii Reply Pilotu. Plne sipky znaci aktualni runtime zavislosti. Prerusovane sipky znaci cilove prime PostgreSQL napojeni, ktere bude doplneno pri dalsim kroku integrace DB do aplikacnich modulu.

Reply Pilot deployment dependencies

Env File Convention

  • .env.example je verzovana sablona vsech podporovanych promennych s vysvetlenim jednotlivych hodnot.
  • .env.local je necommitovany lokalni runtime config pro modulovy start skript.
  • .env.server je necommitovany serverovy runtime config pro modulovy deploy skript.
  • Pokud se lokalni nebo serverovy config verzue, ma byt source of truth sifrovany soubor secrets/<environment>/<module>.env spravovany pres sops; .env.local a .env.server pak vznikaji jen jako lokalni nebo docasne materializovane runtime soubory.
  • start a deploy skripty musi nacitat sve env soubory explicitne, ne spolehat na implicitni .env.
  • Relativni host path v .env se vyhodnocuji vuci koreni konkretniho modulu, ne vuci aktualnimu shell cwd.
  • Pokud HOST_UID a HOST_GID nejsou v env souboru nastavene, skript je ma odvodit z id -u a id -g.
  • Vyjimka je prijatelna jen u vendor-backed image, ktere bez vlastniho entrypoint/runtime modelu nespusti podporovany init flow. Typicky priklad je oficialni PostgreSQL image.

SOPS Access For Another Person

Kdyz ma mit dalsi clovek pristup ke stavajicim sifrovanym secretum:

  1. Novy clovek si u sebe vygeneruje vlastni age keypair:
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
  1. Posle jen svuj public key:
age-keygen -y ~/.config/sops/age/keys.txt
  1. Maintainer prida tenhle public key do .sops.yaml mezi recipients.
  2. Maintainer rekeyne existujici secrets, aby sly otevrit i novym keypair:
export SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt"
sops updatekeys -y secrets/local/*.env secrets/prod/*.env
  1. Maintainer commitne zmenenou .sops.yaml a rekeynute secrets.

Pravidla:

  • public key se sdili bezpecne; private key se nikdy nesdili
  • samotny public key neumoznuje decryption
  • ~/.config/sops/age/keys.txt je private keyring, ne public key
  • kdyz nekdo ztrati pristup, nestaci ho odebrat z .sops.yaml; je potreba znovu rekeynout files a u citlivych systemu otocit samotne secrets

Rozdeleni odpovednosti

Docker runtime kontrakt neni jen o image. Je rozdelen mezi tri vrstvy:

  1. Image
  2. Compose
  3. Deploy skript

Kazda z nich musi dodrzet svou cast. Zmena jen v jedne vrstve je podezrela a musi byt vedoma.

Image Rules

  • Aplikacni proces v kontejneru musi umet bezet jako non-root uzivatel.
  • Image nesmi vyzadovat root-only operace pri beznem startu aplikace.
  • Image musi pouzivat stabilni aplikacni cesty pod /app.
  • Aplikace musi zapisovat jen do adresaru, ktere jsou pro to urcene mounty nebo internim tmp adresarem.
  • Pokud image potrebuje inicializaci souboru nebo adresaru, musi byt kompatibilni s cizim numerickym UID:GID predanym z runtime.
  • Vendor-backed image mohou mit zdokumentovanou vyjimku z ciziho UID:GID, pokud to vyzaduje jejich oficialni startup sekvence. V takovem pripade je povinna samostatna modulova dokumentace a jasne oddelene host path pro data/logy/conf.

Compose Rules

  • Kazda produkcni sluzba = jeden dlouhodobe bezici kontejner.
  • Runtime uzivatel se predava pres HOST_UID a HOST_GID.
  • Compose ma explicitne nastavit runtime uzivatele tak, aby proces nebezel jako root.
  • Compose patri do konkretniho moduloveho adresare.
  • Mounty musi zustat konzistentni s modulovou strukturou:
  • data: /home/agent/docker_deployments/reply-pilot/<module_name>/data -> /app/data
  • logs: /home/agent/docker_deployments/reply-pilot/<module_name>/logs -> /app/logs
  • conf: /home/agent/docker_deployments/reply-pilot/<module_name>/conf -> /app/conf
  • Konfiguracni mount /app/conf ma byt read-only.
  • Data mount muze byt read-only, pokud sluzba data jen cte.
  • Logs mount musi zustat zapisovatelny runtime uzivatelem.
  • Porty na hostu maji byt explicitni a v souladu s deploy dokumentaci.
  • Pokud modul publikuje operatorni nebo admin rozhrani na host, defaultni bind ma byt 127.0.0.1, dokud neni zdokumentovany vedomy duvod pro sirejsi vystaveni.
  • Image name a operacni skripty maji byt pojmenovane stejne jako modul.
  • Vyjimka z HOST_UID/HOST_GID je dovolena jen pro vendor-backed image, kde by prepsani runtime uzivatele rozbilo podporovany init flow. Takova sluzba musi zustat zdokumentovana jako vyjimka a stale musi drzet bind mounty per modul.

Deploy Script Rules

  • Pri remote deployi se HOST_UID a HOST_GID musi odvodit z uzivatele, pod kterym bezi deploy na serveru:
  • id -u
  • id -g
  • Modul ma mit vlastni start, stop a deploy skript.
  • start skript ma pouzivat .env.local; deploy skript ma pouzivat .env.server.
  • Pokud se pouziva sops, start workflow ma pred startem modulu vyrenderovat aktualni .env.local z secrets/local/<module>.env; kdyz encrypted source of truth chybi, start ma skoncit chybou.
  • Pokud se pouziva sops, wrapper nebo operator musi .env.server vyrenderovat pred deployem a po deployi ho zase odstranit.
  • Deploy skript musi tyto hodnoty predat do docker compose.
  • Pred startem musi zajistit existenci potrebnych host adresaru.
  • Pokud se objevi root-owned soubory v data/ nebo logs/, musi byt ownership srovnan pred dalsim startem.
  • Pri zmene runtime kontraktu musi deploy skript, compose a dokumentace zustat ve shode.

Standardni Host Paths

  • Obecny pattern:
  • data: /home/agent/docker_deployments/reply-pilot/<module_name>/data
  • logs: /home/agent/docker_deployments/reply-pilot/<module_name>/logs
  • conf: /home/agent/docker_deployments/reply-pilot/<module_name>/conf
  • Aktualni moduly:
  • data: /home/agent/docker_deployments/reply-pilot/reply-pilot-app/data
  • logs: /home/agent/docker_deployments/reply-pilot/reply-pilot-app/logs
  • conf: /home/agent/docker_deployments/reply-pilot/reply-pilot-app/conf
  • data: /home/agent/docker_deployments/reply-pilot/reply-pilot-be/data
  • logs: /home/agent/docker_deployments/reply-pilot/reply-pilot-be/logs
  • conf: /home/agent/docker_deployments/reply-pilot/reply-pilot-be/conf
  • data: /home/agent/docker_deployments/reply-pilot/reply-pilot-gmail/data
  • logs: /home/agent/docker_deployments/reply-pilot/reply-pilot-gmail/logs
  • conf: /home/agent/docker_deployments/reply-pilot/reply-pilot-gmail/conf
  • data: /home/agent/docker_deployments/reply-pilot/reply-pilot-worker/data
  • logs: /home/agent/docker_deployments/reply-pilot/reply-pilot-worker/logs
  • conf: /home/agent/docker_deployments/reply-pilot/reply-pilot-worker/conf
  • data: /home/agent/docker_deployments/reply-pilot/reply-pilot-search/data
  • logs: /home/agent/docker_deployments/reply-pilot/reply-pilot-search/logs
  • conf: /home/agent/docker_deployments/reply-pilot/reply-pilot-search/conf
  • data: /home/agent/docker_deployments/reply-pilot/reply-pilot-docs/data
  • logs: /home/agent/docker_deployments/reply-pilot/reply-pilot-docs/logs
  • conf: /home/agent/docker_deployments/reply-pilot/reply-pilot-docs/conf
  • data: /home/agent/docker_deployments/reply-pilot/reply-pilot-db/data
  • logs: /home/agent/docker_deployments/reply-pilot/reply-pilot-db/logs
  • conf: /home/agent/docker_deployments/reply-pilot/reply-pilot-db/conf

Inter-Service Network Contract

  • Dlouhodobe bezici Reply Pilot kontejnery se propojuji pres externi Docker sit reply-pilot-internal.
  • Sit se vytvari mimo jednotlive compose projekty a jednotlive modulove skripty maji zajistit jeji existenci pred docker compose up.
  • Inter-service DNS alias ma odpovidat nazvu modulu, napr. reply-pilot-be.

Standardni Container Paths

  • data: /app/data
  • logs: /app/logs
  • conf: /app/conf

Logging Contract

  • Kazda dlouhodobe bezici sluzba zapisuje aktivni log do logs/<module_name>.log.
  • Rotace probiha po 100 MB.
  • Rotovane soubory maji format <module_name>.0001.log, <module_name>.0002.log, ...
  • Aktivni log po rotaci zustava <module_name>.log.

Monitoring Contract

  • Kazda dlouhodobe bezici produkcni sluzba musi mit restart: unless-stopped.
  • HTTP sluzby, ktere spravujeme v tomto repozitari, musi vystavovat GET /healthz.
  • GET /healthz vraci JSON:
  • healthy: 200 {"status":"ok"}
  • unhealthy: 503 {"status":"unhealthy","reason":"..."}
  • Compose ma mit healthcheck vsude, kde je to technicky rozumne.
  • Probe v healthchecku je service-specific:
  • nepouzivej slepe curl, pokud image nema curl
  • pro Python image je v poradku probe pres python
  • pro ne-HTTP sluzby je v poradku heartbeat nebo process-based probe
  • Pokud jde o third-party image, je prijatelny vendor-specific endpoint nebo zdokumentovana vyjimka.

Ownership Contract

  • Host adresare data/ a logs/ musi byt zapisovatelne runtime UID:GID.
  • Kontejner nesmi pri beznem startu vytvaret root-owned soubory v bind mountech.
  • Pokud sluzba zapisuje jen do logs, musi stale umet bezet pod non-root uzivatelem.
  • Vendor-backed vyjimka je dovolena jen tam, kde image sama spravuje startup ownership a provoz pod vlastnim ne-root uzivatelem. reply-pilot-db je tento pripad; data zustavaji v bind mountu, ale ownership uvnitr lifecycle ridi oficialni PostgreSQL image.

Change Checklist

Pri zmene Dockerfile, docker-compose*.yml nebo deploy skriptu zkontroluj vzdy vsechny body:

  1. Proces v kontejneru opravdu bezi jako non-root.
  2. HOST_UID/HOST_GID jsou dohledatelne a propisane az do runtime.
  3. Pracujes ve spravnem modulovem adresari a image i skripty jsou pojmenovane podle modulu.
  4. Mounty odpovidaji data/, logs/, conf.
  5. Host path odpovida patternu /home/agent/docker_deployments/reply-pilot/<module_name>/....
  6. conf mount zustava read-only.
  7. Sluzba nevytvari root-owned soubory v data/ nebo logs/.
  8. Log soubor zustava v logs/<module_name>.log.
  9. Long-running sluzba ma restart: unless-stopped.
  10. Health endpoint nebo alternativni health probe odpovida typu sluzby.
  11. Dokumentace zustava ve shode s implementaci.

Kdy otevrit tento dokument

Otevri tento dokument vzdy, kdyz:

  • menis Dockerfile
  • menis docker-compose.yml nebo docker-compose.dev.yml
  • menis deploy skript v scripts/
  • resis non-root runtime, ownership nebo mounty
  • resis HOST_UID/HOST_GID