Ur repot
Hur deploys når prod (GitOps)
För: stacken-utvecklare. Gäller: customer-prod (Hetzner), plattformen-ägt.
Ursprung: skriven av plattformen-sidan 2026-07-26 efter att marknadssajten gått i drift som första app i customer-prod, och överlämnad hit eftersom modellen saknades i stacken-repot. Verifierad mot koden innan den lades in: charterna har mycket riktigt
externalSecrets.enabledsom grindarexternalsecret.yaml, såfalseavaktiverar ESO-vägen utan att röra något annat.
TL;DR: Du deployar inte. Du uttrycker önskat läge i git — plattformens ArgoCD gör resten. Ändra tjänsten → bumpa
appVersioni chartensChart.yaml→ mergamain→ CI bygger imagen → ArgoCD auto-syncar den till klustret. Ingenhelm, ingenkubectl, ingen ESO.
Ägar-uppdelning (kickoff-sömmen)
- stacken bygger images (GHCR) och definierar Helm-charts (
charts/<svc>). - plattformen äger klustret och deklarerar vad som körs via ArgoCD.
- Du har ingen kubeconfig och rör aldrig klustret direkt. Allt går via git.
Så här får du en ändring i drift
- Ändra tjänstens kod (
services/<svc>/frontends/<svc>) eller charten (charts/<svc>). - Bumpa
appVersionicharts/<svc>/Chart.yaml. En innehållsändring = en appVersion-bump, så att det som körs syns i git. (Deploya påappVersion, aldriglatest.) - Öppna PR → merga till
main. - CI (
frontends.ymlför frontends,_template.yml-mönstret för backend-tjänster) bygger + pushar imagen tillghcr.io/digitalist-se/<svc>med taggarnasha/appVersion/latest, med SBOM + provenance, trivy-scannad blockerande på HIGH/CRITICAL. - ArgoCD på customer-prod följer
mainoch auto-syncar (selfHeal+prune). Rullande uppdatering (PDB) → noll nedtid. Alembic-migrationer körs automatiskt som PreSync-hook före ny version rullas ut.
Din ändring är i drift inom någon minut efter merge. Ingen manuell åtgärd.
appVersion-bumpen är inte administration — den ÄR utrullningen
Steg 2 ovan är det enda steget som brukar glömmas, och konsekvensen är obehaglig
eftersom ingenting går sönder. Utan bump renderar charten samma manifest som
före mergen, ArgoCD ser ingen diff, och ingen utrullning sker. Din fix är byggd,
publicerad — och körs inte. imagePullPolicy: IfNotPresent gör dessutom att en
nod som redan har taggen cachad aldrig hämtar den nya.
Därtill blir appVersion en rörlig tagg om den aldrig ändras: två olika
commits ger olika kod under samma namn, vilket är precis det latest kritiseras
för. Det hände under migrations-uppstarten — fixar byggdes, klustret fortsatte
köra gammal kod tills plattformen pinnade om för hand.
Grinden: chart-version.yml failar en PR som rör services/<svc>/ eller
frontends/<namn>/ utan att motsvarande charts/<svc>/Chart.yaml:s appVersion
ändrats i samma PR. Teständringar, docs/ och .md-filer träffar den inte — de
hamnar inte i imagen (runtime-steget kopierar det installerade paketet och
alembic/, inget annat). Ändringar i libs/** varnar men fäller inte: ett
delat libb ligger i alla tjänsteimages, och att kräva elva bumpar per libbändring
vore oproportionerligt — men att låta dem passera tyst vore att återskapa buggen.
Två versioner, två betydelser. version är chartens paketversion (bumpa när
charten ändras), appVersion är applikationens (bumpa när koden ändras). De följs
inte åt.
Secrets: SOPS, INTE external-secrets-operator
Plattformen kör SOPS+age, inte ESO (ADR-0014). Konkret:
- Charten renderas med
externalSecrets.enabled: false(plattformen sätter det). Du behöver ingenClusterSecretStore/platform-secret-store— den modellen används inte. - Varje tjänst läser sin Secret som redan heter
<svc>i namespacet. - Behöver din tjänst en NY secret-nyckel? Definiera den i charten (env från Secret
<svc>) och säg till plattformen — de lägger nyckeln i den SOPS-krypterade secreten. Det är en koordineringspunkt, inte något du provisionerar själv. - DB-URL-nyans (per tjänst): SQLAlchemy-async-tjänster vill ha
postgresql+asyncpg://, tjänster på råasyncpg(t.ex. llm-gateway) vill ha plainpostgresql://. CNPG genererar plain — plattformen sätter rätt schema per tjänst. Idealt normaliserar appen schemat själv.
Vad du ALDRIG gör
- Kör inte
helm install/upgradeellerkubectl applymot prod. ArgoCD äger klustret; manuella ändringar självläks bort. - Provisionera inte ESO / ClusterSecretStore.
- Deploya inte på
:latesteller mutabla taggar.
Koordineringspunkter med plattformen (säg till, gör inte själv)
-
Ny secret-nyckel → plattformen lägger den i SOPS.
-
Ny publik host → plattformen lägger DNS-post + ingress + cert (Let’s Encrypt).
-
Privat GHCR-paket → plattformen kopplar pull-secret i namespacet.
Avgjort 2026-07-26 (Fabian): paketen förblir privata. Samtliga paket i organisationen är privata, och att göra ett enda publikt hade gjort det till undantaget — avvikelser i leveranskedjan är där misstag bor. Dessutom hade en publik image skyltat med basimagens version, vilket vi medvetet döljer i HTTP-svaren (
server_tokens off).Den verkliga luckan är en annan, och den gäller alla tolv charts: ingen av dem stöder
imagePullSecretseller sätterserviceAccountName. Alla förlitar sig på att någon manuellt kopplat secreten till namespacets standardkonto — ett odokumenterat handgrepp som måste upprepas per namespace, och vars fel (ImagePullBackOffmed 401) syns i podden och inte i ArgoCD:s app-status.charts/marketing-sitehar nu ett valfrittimagePullSecrets-värde (tomt = renderar ingenting, alltså oförändrat beteende). De elva backend-charterna saknar det fortfarande — en uppföljning att ta gemensamt med plattformen, inte ensidigt i tolv charts.
Vad som är superseded i wave1-bring-up-runbooken
Den interna bring-up-planen för wave 1 skrevs före plattformens beslut och är inaktuell på tre punkter:
- Phase 1 (ESO/ClusterSecretStore) → superseded av SOPS+age.
- Phase 3 (
helm --set image.tag=<sha>+ manuellkubectl rolloutper tjänst) → superseded av ArgoCD GitOps (ApplicationSet för de 11 + enskild Application för marketing-site). - Phase 4 (frontends på Cloudflare Pages) → superseded av D-66 (frontends flyttas in i k8s).
Runbooken är fortfarande giltig som förstagångs-uppstart-checklista på infra-nivå ([ditt bord]-stegen), men den löpande deploy-modellen är den här filen.
Nuläge (2026-07-26)
- marketing-site följer
appVersion→ merge + appVersion-bump auto-deployar (fullt enligt ovan). - De 11 backend-tjänsterna är just nu
image.tag-pinnade till specifika merge-shas i ArgoCD-ApplicationSet:en (en kontrollåtgärd från migrations-uppstarten). Tills de konvergerar motappVersion-spårning kräver en backend-release att plattformen pinnar om taggen. Målet är att avpinna dem så att samma auto-flöde gäller alla.