YourBOX Kubernetes GitOps
Purpose
Section titled “Purpose”ADR-0010 sets the homelab Kubernetes cluster as the production target for
YourBOX, and ADR-0011 sets Argo CD as the GitOps engine for every workload in
the workspace. This page documents the Helm chart layout, the Argo CD wiring
under homelab-platform, the secret projection through External Secrets, the
platform dependencies and the security controls.
Repository Layout
Section titled “Repository Layout”The chart lives in the YourBOX repository. The Argo CD wiring lives in the homelab platform repository. The split keeps the application’s release lifecycle inside the application repository and the platform reconciliation inside the platform repository.
yourbox/└── k8s/ └── charts/yourbox/ ├── Chart.yaml ├── values.yaml └── templates/ ├── deployment.yaml ├── service.yaml ├── httproute.yaml ├── serviceaccount.yaml ├── networkpolicy.yaml ├── externalsecret.yaml ├── servicemonitor.yaml ├── poddisruptionbudget.yaml ├── horizontalpodautoscaler.yaml └── worker-deployment.yaml
homelab-platform/└── kubernetes/ └── apps/yourbox/ ├── application.yaml # Argo CD Application ├── registry-secret-sealed.yaml ├── postgres-cluster.yaml ├── meilisearch.yaml ├── minio-tenant.yaml └── kustomization.yamlArgo CD Wiring
Section titled “Argo CD Wiring”The platform repository keeps the source of truth for what is deployed. The
Argo CD Application resource references the Helm chart from the YourBOX
repository at a tagged version and pins the image digest through the values
override.
---apiVersion: argoproj.io/v1alpha1kind: Applicationmetadata: name: yourbox namespace: argocd finalizers: - resources-finalizer.argocd.argoproj.iospec: project: applications source: repoURL: https://gitlab.yourbox.site/yourbox/yourbox.git targetRevision: v0.4.2 path: k8s/charts/yourbox helm: valueFiles: - values.yaml parameters: - name: image.digest value: "sha256:<digest>" - name: image.tag value: "0.4.2" destination: server: https://kubernetes.default.svc namespace: yourbox syncPolicy: automated: prune: true selfHeal: true allowEmpty: false syncOptions: - CreateNamespace=false - ServerSideApply=true - ApplyOutOfSyncOnly=true retry: limit: 5 backoff: duration: 10s factor: 2 maxDuration: 3m revisionHistoryLimit: 10The Argo CD app of apps pattern picks up the Application resource from the
homelab-platform/kubernetes/apps/yourbox/ directory through a
Kustomization rendered by a parent Application. Adding YourBOX to the
production set is one commit on the platform repository.
The CI deploy stage opens a Merge Request against the YourBOX Application
to bump the image.digest parameter. A reviewer merges and Argo CD
reconciles within 5 minutes. A rollback is a revert of that MR.
Helm Chart Values
Section titled “Helm Chart Values”The chart values mirror the env contract from ADR-0008. The image is digest pinned at the values level per ADR-0009.
image: repository: registry.yourbox.site/yourbox tag: "0.4.2" digest: "sha256:<digest>" pullPolicy: IfNotPresent
application: replicas: 2 resources: limits: { cpu: "1", memory: "512Mi" } requests: { cpu: "200m", memory: "256Mi" } podSecurityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 seccompProfile: { type: RuntimeDefault } containerSecurityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: { drop: ["ALL"] }
worker: replicas: 1 resources: limits: { cpu: "2", memory: "1Gi" } requests: { cpu: "500m", memory: "512Mi" }
env: APP_ENV: prod APP_DEBUG: "0"
externalSecrets: enabled: true refreshInterval: 5m store: openbao-prod remoteRef: yourbox/prod
httpRoute: enabled: true parentRefs: - name: traefik namespace: networking hostnames: ["yourbox.site"] tls: enabled: true
cache: enabled: true externalDsnSecretRef: name: yourbox-env key: CACHE_DSN
postgres: externalDsnSecretRef: name: yourbox-env key: DB_DSN
meilisearch: externalUrlSecretRef: name: yourbox-env key: MEILISEARCH_URL externalKeySecretRef: name: yourbox-env key: MEILISEARCH_KEY
storage: externalDsnSecretRef: name: yourbox-env key: STORAGE_DSN
oidc: issuerSecretRef: name: yourbox-env key: OIDC_ISSUER clientIdSecretRef: name: yourbox-env key: OIDC_CLIENT_ID clientSecretSecretRef: name: yourbox-env key: OIDC_CLIENT_SECRETThe image reference rendered in the deployment template combines the tag and the digest:
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}@{{ .Values.image.digest }}"External Secrets
Section titled “External Secrets”The ExternalSecret resource (rendered by the chart) reads from OpenBao and
writes a Kubernetes Secret named yourbox-env. The Deployment projects the
secret as environment variables via envFrom.secretRef.
apiVersion: external-secrets.io/v1beta1kind: ExternalSecretmetadata: name: yourbox-env namespace: yourboxspec: refreshInterval: 5m secretStoreRef: name: openbao-prod kind: ClusterSecretStore target: name: yourbox-env template: type: Opaque dataFrom: - extract: key: yourbox/prodThe ClusterSecretStore openbao-prod is defined in the platform repository
and authenticates to OpenBao through the Kubernetes auth method scoped to the
yourbox namespace and the yourbox ServiceAccount.
The GitLab registry secret is delivered through a SealedSecret. SealedSecrets remain the bootstrap path for credentials that must exist before External Secrets can authenticate the application pod.
Platform Dependencies
Section titled “Platform Dependencies”The chart consumes platform services. Each is owned by the homelab platform repository, not by the YourBOX repository.
| Dependency | Operator or chart | Source |
|---|---|---|
| PostgreSQL 16 | CloudNativePG | kubernetes/apps/yourbox/postgres-cluster.yaml |
| Meilisearch | Meilisearch Helm chart | kubernetes/apps/yourbox/meilisearch.yaml |
| MinIO | MinIO Tenant CRD | kubernetes/apps/yourbox/minio-tenant.yaml |
| Redis cache | Bitnami Redis chart | kubernetes/apps/yourbox/redis.yaml |
| Messaging bus | (see ADR-0011) | platform decision pending |
| Authentik | Authentik Helm chart | kubernetes/platform/authentik/ |
| OpenBao + ESO | platform admin plane | kubernetes/platform/external-secrets/ |
| Sigstore policy | policy-controller | kubernetes/platform/security/ |
The platform repository owns the lifecycle of these dependencies (backups, upgrades, alerts). The YourBOX chart only declares the consumption contracts through Secret refs and Service refs. The Redis cache and the messaging bus are introduced per the platform engineering decisions in ADR-0011.
NetworkPolicies
Section titled “NetworkPolicies”The default deny applies. Egress is allowed to:
- The cluster DNS (kube-dns on port 53/UDP).
- The PostgreSQL cluster (the
yourbox-postgres-rwservice on port 5432). - The Meilisearch service (port 7700).
- The MinIO tenant service (port 9000).
- The Redis cache service (port 6379).
- The Authentik service (port 9000) for the OIDC token exchange.
- The Mailer egress to the SMTP provider declared in
SMTP_DSN. - The messaging bus service (port to be defined per ADR-0011).
Ingress is allowed from:
- The Traefik Gateway in the
networkingnamespace on port 8080. - The Prometheus operator’s ServiceMonitor scrape (port 8080 path
/metrics). - The cosign policy controller probe.
The NetworkPolicy template lives at
yourbox/k8s/charts/yourbox/templates/networkpolicy.yaml and is rendered
from the values.
Kyverno Admission
Section titled “Kyverno Admission”Kyverno enforces three policies on the YourBOX namespace, defined in
homelab-platform/kubernetes/platform/security/:
- Every container image reference must carry a digest. A pod with a non digest image is rejected.
- Every container must run as a non root UID and must drop all Linux capabilities. The Helm chart’s pod template satisfies both.
- Every container image must come from
registry.yourbox.site/*or an allowlisted public registry that matches.plumber.yaml.
The Sigstore policy controller verifies that the image is signed by the
cosign key whose public part is committed in
homelab-platform/kubernetes/platform/security/cosign-pub.yaml. An unsigned
image is rejected by admission.
Argo CD ApplicationSet For Environments
Section titled “Argo CD ApplicationSet For Environments”A single ApplicationSet generates one Argo CD Application per environment
(staging, production) by reading a generator file in the platform repository.
The generator captures per environment overrides (cluster, namespace, image
digest, replica count) and applies them through Helm value overrides.
apiVersion: argoproj.io/v1alpha1kind: ApplicationSetmetadata: name: yourbox-environments namespace: argocdspec: generators: - list: elements: - env: staging cluster: in-cluster namespace: yourbox-staging digest: sha256:<staging-digest> replicas: 1 - env: production cluster: in-cluster namespace: yourbox digest: sha256:<prod-digest> replicas: 2 template: metadata: name: yourbox-{{env}} spec: project: applications source: repoURL: https://gitlab.yourbox.site/yourbox/yourbox.git targetRevision: v0.4.2 path: k8s/charts/yourbox helm: parameters: - name: image.digest value: "{{digest}}" - name: application.replicas value: "{{replicas}}" destination: server: https://kubernetes.default.svc namespace: "{{namespace}}" syncPolicy: automated: { prune: true, selfHeal: true }Observability Wiring
Section titled “Observability Wiring”The Helm chart renders a ServiceMonitor consumed by the cluster’s Prometheus
operator. The YourBOX pod exposes a /metrics endpoint guarded by an
internal network policy.
The pods are picked up by Promtail in the logging namespace and indexed in
Loki. Grafana dashboards live at yourbox/k8s/charts/yourbox/dashboards/
and are deployed as ConfigMaps with the grafana_dashboard label.
The Observability page details the dashboard panels, alert rules and log schema.
Promotion Path
Section titled “Promotion Path”The promotion path matches the staged deployment from ADR-0010. A commit to
main produces a digest pinned image, triggers the VPS deploy, then Azure,
then opens the MR against homelab-platform/kubernetes/apps/yourbox/ to
update the digest. Argo CD reconciles within 5 minutes.
A rollback is a revert of the MR that bumped the digest. Argo CD reverts within 5 minutes and the pod template restarts onto the previous digest.