GitOps with Flux CD¶
This cluster is GitOps-managed by Flux CD
k3s/flux/clusters/k3s/apps.yaml is the root Kustomization - Flux's equivalent of
an "App-of-Apps". It reconciles everything under k3s/flux/apps/, which in turn renders
every per-service Kustomization and HelmRelease listed in kustomization.yaml.
Plain-manifest services point at k3s/manifests/<service>/ via spec.path. Helm-based
services reference a HelmRepository in sources.yaml.
Bootstrap Procedure¶
Run once to install the four Flux controllers and connect them to this repo. The
cluster must be reachable via kubectl.
Prerequisites¶
fluxCLI installed (brew install fluxcd/tap/fluxor the upstream install script).- A short-lived GitHub personal access token with
reposcope, exported asGITHUB_TOKEN. Flux only needs the token for the initial bootstrap; it then provisions a deploy key on the repo and stores its private half as aSecret. After bootstrap the token can be revoked.
Run bootstrap¶
export GITHUB_TOKEN=<your-token>
flux bootstrap github \
--owner=hexabyte8 \
--repository=homelab \
--branch=main \
--path=k3s/flux/clusters/k3s \
--personal
This:
- Installs the four controllers (
source,kustomize,helm,notification) in theflux-systemnamespace. - Creates a deploy key on the GitHub repo and stores its private half as the
flux-systemSecret influx-system. - Commits
gotk-components.yaml,gotk-sync.yaml, andkustomization.yamltok3s/flux/clusters/k3s/flux-system/. - Creates the root
flux-systemGitRepositoryandKustomizationthat reconciles everything ink3s/flux/clusters/k3s/.
Within ~1 minute the root apps Kustomization applies, creating every per-service
Kustomization and HelmRelease. Workloads start as soon as their secrets are patched
(see Phase 6 of the disaster-recovery runbook).
Verify¶
Adding a New Service¶
This is the canonical recipe. For a full walkthrough including ingress options and Authentik protection, see new-service.md.
Plain manifests¶
- Create your manifests under
k3s/manifests/<my-app>/. - If the namespace is not created elsewhere, add it to
k3s/flux/apps/namespaces.yaml. - Create
k3s/flux/apps/<my-app>.yaml:
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 10m
retryInterval: 2m
timeout: 5m
prune: true
wait: false
sourceRef:
kind: GitRepository
name: flux-system
path: ./k3s/manifests/my-app
targetNamespace: my-app
# dependsOn:
# - name: cert-manager
- Add
- my-app.yamlto theresources:list ink3s/flux/apps/kustomization.yaml. - Commit and push. Reconcile immediately with:
Helm chart¶
- If the chart repo is not in
k3s/flux/clusters/k3s/sources.yaml, add aHelmRepositorythere. - Create
k3s/flux/apps/<my-app>.yaml:
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: my-app
namespace: flux-system
spec:
interval: 30m
releaseName: my-app
targetNamespace: my-app
install:
createNamespace: true
chart:
spec:
chart: my-chart
version: 1.2.3
sourceRef:
kind: HelmRepository
name: my-repo
namespace: flux-system
values:
replicaCount: 1
- Add it to
kustomization.yamland commit.
Parking (disabling) a service¶
To temporarily disable a service without deleting its manifests, remove its entry from
k3s/flux/apps/kustomization.yaml and commit. Flux will prune the live resources on
the next reconciliation. There is no separate apps-disabled/ directory - the
kustomization.yaml resource list is the single source of truth for what is active.
To re-enable, add the entry back and commit.
Secrets Management¶
Secrets are managed by the Bitwarden Secrets Manager (BWS) sm-operator. The operator
watches BitwardenSecret CRDs across all namespaces and syncs secret values directly from
BWS into native k8s Secret objects. No plaintext or placeholder values are committed to git.
How it works¶
BWS (source of truth)
-> sm-operator polls every 5 minutes
-> k8s Secret created/updated
-> Reloader detects Secret change
-> Pod restarted with new value
The operator authenticates per-namespace using a bw-auth-token Secret (bootstrapped
by the k3s-patch-secrets workflow - never committed to git).
Adding a secret for a new service¶
- Create the secret in BWS under the homelab project. Copy its UUID.
- Create
k3s/manifests/<my-app>/bw-secret.yaml:
apiVersion: k8s.bitwarden.com/v1
kind: BitwardenSecret
metadata:
name: my-app-credentials
namespace: my-app
spec:
organizationId: "5f82d531-e61f-4c86-963c-b40f00c51c93"
projectId: "aece2880-f0d0-4a77-9b0c-b40f00c78f1e"
secretName: my-app-credentials
authToken:
secretName: bw-auth-token
secretKey: token
map:
- bwSecretId: "<UUID-from-BWS>"
secretKeyName: my-key
- Add the
bw-auth-tokenbootstrap for the namespace ink3s-patch-secrets.ymlif the namespace is not already covered. - Annotate your Deployment to auto-restart when the secret rotates: