Architecture
Ultron Infra is an app-agnostic GitOps platform: a
single k3s node named ultron (Oracle Cloud 24GB Ampere A1, arm64) that
provides edge, TLS, metrics, delivery, and databases, then lets apps plug in.
Traefik is the sole edge; the Kubernetes API is
Tailscale-only. A handful of platform operators run as
namespaces, all reconciled from the <owner>/gitops repo by
Argo CD. Each workload lives under workloads/<app> and
onboards the same way (Penvoice is just one such app).
Topology
Section titled “Topology”The diagram below shows the platform layer plus a single generic <app>
workload. Add more apps by dropping another workloads/<app> alongside it.
flowchart TB
subgraph ext[Externals]
SPA[App frontend<br/>e.g. Vercel SPA]
Oracle[Oracle Object Storage<br/>Postgres backups]
GHCR[GHCR<br/>container images]
TS[Tailscale<br/>k8s API access]
end
Internet((Internet)) -->|"80 / 443"| Traefik
subgraph ultron[node: ultron · k3s arm64]
Traefik[Traefik edge<br/>+ cert-manager TLS]
subgraph platform[platform layer]
subgraph argocd[ns: argocd]
Argo[Argo CD<br/>+ Rollouts / Workflows / Events]
end
subgraph cm[ns: cert-manager]
CM[cert-manager]
end
subgraph mon[ns: monitoring]
Prom[Prometheus / Grafana / Alertmanager]
end
subgraph cnpg[ns: cnpg-system]
CNPG[CloudNativePG operator]
end
subgraph kc[ns: keycloak]
KCop[Keycloak operator]
KCi[Keycloak instance]
KCpg[(keycloak-pg)]
end
end
subgraph app[ns: <app> · e.g. Penvoice]
API[<app> Rollout]
APIpg[(<app>-pg)]
end
Traefik --> Argo
Traefik --> KCi
Traefik --> API
API --> APIpg
KCi --> KCpg
end
SPA -->|JWT to| API
SPA -->|PKCE login| KCi
GHCR -->|pulls image| API
APIpg -->|WAL + base backup| Oracle
KCpg -->|WAL + base backup| Oracle
TS -.->|6443| ultron
The k8s API never listens on a public 6443 — ultron resolves to the node’s
Tailscale IP on dev machines. Only 80/443 are open to the internet, both
handled by Traefik.
What runs where, and how
Section titled “What runs where, and how”Two delivery mechanisms: a one-time Helm bootstrap for the platform plumbing, then GitOps for everything else (the remaining operators + your apps). See GitOps & the app-of-apps for the reconcile model.
The platform layer is fixed; the app rows are templated — each app you onboard
adds one GitOps row under workloads/<app>.
| Component | How | Namespace |
|---|---|---|
| cert-manager | Helm (bootstrap) | cert-manager |
| kube-prometheus-stack (Prometheus / Grafana / Alertmanager) | Helm (bootstrap) | monitoring |
| Argo CD / Rollouts / Workflows / Events | Helm (bootstrap) | argocd |
| CNPG operator | GitOps — apps/cnpg-operator | cnpg-system |
| Keycloak operator | GitOps — apps/keycloak-operator | keycloak |
| Keycloak instance + Postgres | GitOps — apps/keycloak | keycloak |
<app> + Postgres (e.g. Penvoice) | GitOps — workloads/<app> | <app> |
The Helm layer is what you can’t bootstrap with Argo CD because it is Argo CD
(plus the issuers and metrics stack it leans on). Once it’s up,
bootstrap/root-app.yaml takes over and reconciles the rest — every operator
and every workloads/<app>.
Pinned versions
Section titled “Pinned versions”Exact chart/operator versions installed during the Helm bootstrap of the platform:
| Chart / operator | Version |
|---|---|
| cert-manager | v1.20.2 |
| kube-prometheus-stack | 86.2.3 |
| argo-cd | 9.5.21 |
| argo-rollouts | 2.41.0 |
| argo-workflows | 1.0.15 |
| argo-events | 2.4.21 |
| CloudNativePG | 0.28.3 (operator v1.29.1) |
| Keycloak operator | 26.6.3 |
Live endpoints
Section titled “Live endpoints”Platform consoles are fixed; app endpoints follow each app’s own domain.
| URL | What | Served by |
|---|---|---|
argocd.<auth-domain> | Argo CD UI | Traefik → argocd |
auth.<auth-domain> | Keycloak instance | Traefik → keycloak |
api.<domain> | <app> API (e.g. Penvoice) | Traefik → <app> |
<domain> | <app> frontend | external (e.g. Vercel) |
Ready to add an app?
Section titled “Ready to add an app?”The recipe — Dockerfile, CI to GHCR, Argo Application, Rollout, CNPG database,
metric-gated canary — is the
Onboard an app playbook. Drop it under workloads/<app>
and the platform delivers it like any other.