Kubernetes¶
The cluster runs Talos Linux on three control plane nodes. Workloads
are scheduled on all three. Flux reconciles everything under
kubernetes/apps/.
See GitOps for how that works.
Directory layout¶
kubernetes/apps/<namespace>/
├── kustomization.yaml # Namespace + list of app ks.yaml files + shared components
├── namespace.yaml
└── <app>/
├── ks.yaml # Flux Kustomization
└── app/
├── kustomization.yaml
├── ocirepository.yaml # Chart source (usually app-template)
├── helmrelease.yaml
├── externalsecret.yaml # Optional: secrets from 1Password
└── resources/ # Optional: files for configMapGenerator
An app is enabled by listing its ks.yaml in the namespace kustomization.yaml.
Commenting it out disables the app, and Flux prunes it.
Namespace kustomizations usually pull in two components for
every app in the namespace: alerts (Flux alerts to Alertmanager and GitHub
commit statuses) and kopiur/secret (the repository credentials Kopiur needs).
The Flux Kustomization¶
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: &app memini
spec:
components:
- ../../../../components/kopiur/backup
interval: 1h
path: ./kubernetes/apps/ai/memini/app
postBuild:
substitute:
APP: *app
KOPIUR_MOVER_UID: "1000"
KOPIUR_MOVER_GID: "1000"
prune: true
sourceRef:
kind: GitRepository
name: flux-system
namespace: flux-system
targetNamespace: ai
What not to add
timeout, retryInterval, deletionPolicy and the HelmRelease
install/upgrade strategies are injected by cluster-apps (see
cluster-wide defaults).
commonMetadata isn't used: the chart already sets the
app.kubernetes.io/* labels.
wait is not injected. Leave it unset for a normal app. Set
wait: true only when another Kustomization dependsOn this one and it
has no healthChecks/healthCheckExprs, as the operator Kustomizations
(CloudNative-PG, Dragonfly, Rook-Ceph and others) do. With health checks
defined, leave wait unset, because wait: true makes Flux ignore them.
The HelmRelease¶
Almost every app uses the
bjw-s app-template
chart, pinned through an OCIRepository at
oci://ghcr.io/bjw-s-labs/helm/app-template. A HelmRelease describes
controllers, service, route (an HTTPRoute attached to envoy-internal
or envoy-external) and persistence.
Conventions:
- Containers run as non-root with a read-only root filesystem and all capabilities dropped, unless the image can't.
- Liveness and readiness probes are set, and resource requests are always present.
- Hostnames are
${APP_DOMAIN:=${APP_SUBDOMAIN:=${APP}}.bykaj.app}, so they default to<app>.bykaj.appand can be overridden fromks.yaml. - Gatus monitors every route automatically. Opt out with
gatus.home-operations.com/enabled: "false", or customize the check with agatus.home-operations.com/endpointannotation. - YAML keys follow the repository sorting rules.
The Adding an App runbook walks through scaffolding one.
Validating changes locally¶
kustomize build kubernetes/apps/<namespace>/<app>/app
yamllint --config-file .yamllint.yaml kubernetes/apps/<namespace>/<app>
${APP}-style variables staying literal in the output is expected. Flux
substitutes them at apply time. To render exactly what Flux would apply,
including components and substitutions:
Opening a pull request also triggers konflate, which posts the rendered Flux diff as a PR comment and status check.
Pages in this section¶
- Talos: machine config templates, schematics, rendering
- Components: reusable kustomize components
- Applications: every app running in the cluster