flux-gitops
Flux GitOps Platform
The homelab Kubernetes platform uses Flux ResourceSets for centralized, declarative management of Helm releases and configurations.
For ResourceSet patterns, version management, and platform architecture, see kubernetes/platform/CLAUDE.md.
How to Add a New Helm Release
Step 1: Add to helm-charts.yaml
Add an entry to the inputs array:
inputs:
- name: "my-new-chart" # Unique release name (kebab-case)
namespace: "my-namespace" # Target namespace
chart:
name: "actual-chart-name" # Chart name in repository
version: "1.0.0" # Pinned version
url: "https://example.com/charts" # Helm repository URL
dependsOn: [cilium] # Array of release names this depends on
For OCI registries:
chart:
name: "app-template"
version: "3.6.1"
url: "oci://ghcr.io/bjw-s/helm" # Prefix with oci://
Step 2: Create Values File
Create charts/<release-name>.yaml with Helm values:
# yaml-language-server: $schema=<chart-schema-url>
---
# Helm values for the chart
replicas: 1
image:
repository: myapp
tag: v1.0.0
Step 3: Add to kustomization.yaml
Add the values file to the configMapGenerator:
configMapGenerator:
- name: platform-values
files:
# ... existing entries
- charts/my-new-chart.yaml
Step 4: Add Config Resources (Optional)
If the chart needs additional resources (secrets, configs), add to config/:
config/my-new-chart/
├── kustomization.yaml
├── secret.yaml
└── config.yaml
Then reference in config.yaml ResourceSet.
Step 5: Verify PodSecurity Compliance
Before finalizing values, check the target namespace's PodSecurity level in namespaces.yaml:
- Identify the namespace security level: Look for
security: restricted,baseline, orprivilegedin the namespace inputs - If
restricted: Add full security context to chart values (see below) - Check the container image's default user: If it runs as root, set
runAsUser: 65534 - Verify all init containers and sidecars also have security context set
Required security context for restricted namespaces:
# Pod-level (chart-specific key varies: podSecurityContext, securityContext, pod.securityContext)
podSecurityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
# Container-level (every container)
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
readOnlyRootFilesystem: true
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
Restricted namespaces: cert-manager, external-secrets, system, database, kromgo. See kubernetes/platform/CLAUDE.md for the full list.
Validation gap: task k8s:validate does NOT catch PodSecurity violations. These are only caught at admission time in the cluster.
ResourceSet Template Syntax
The resourcesTemplate uses Go text/template with << >> delimiters:
resourcesTemplate: |
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: << inputs.name >>
namespace: << inputs.provider.namespace >>
spec:
<<- if inputs.dependsOn >>
dependsOn:
<<- range $dep := inputs.dependsOn >>
- name: << $dep >>
<<- end >>
<<- end >>
chart:
spec:
chart: << inputs.chart.name >>
version: << inputs.chart.version >>
Template Functions
<< inputs.field >>- Access input field<<- if condition >>- Conditional (with-to trim whitespace)<<- range $item := inputs.array >>- Loop over arrayhasPrefix "oci://" inputs.chart.url- String prefix check
Dependency Management
Release Dependencies
inputs:
- name: "grafana"
dependsOn: [kube-prometheus-stack, alloy] # Waits for these
ResourceSet Dependencies
spec:
dependsOn:
- apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
name: platform-namespaces # Waits for namespaces ResourceSet
Debugging Flux
Check ResourceSet Status
kubectl get resourcesets -n flux-system
kubectl describe resourceset platform-resources -n flux-system
Check HelmRelease Status
kubectl get helmreleases -A
kubectl describe helmrelease <name> -n <namespace>
Check Reconciliation Logs
kubectl logs -n flux-system deploy/flux-controller -f | grep <release-name>
Force Reconciliation
flux reconcile helmrelease <name> -n <namespace>
flux reconcile kustomization flux-system -n flux-system
Common Issues
| Symptom | Cause | Solution |
|---|---|---|
waiting for dependencies |
Dependency not ready | Check dependsOn releases |
values key not found |
Missing values file | Add to kustomization.yaml configMapGenerator |
chart not found |
Wrong chart name/URL | Verify chart exists in repository |
namespace not found |
Namespace not created | Add to namespaces.yaml |
Version Management
When adding a new Helm release, you must also add a version entry to kubernetes/platform/versions.env with the correct Renovate annotation. Use ${variable_name} in helm-charts.yaml to reference the version:
chart:
version: "${my_chart_version}" # Substituted from platform-versions ConfigMap
For annotation syntax, datasource selection, and debugging Renovate, see the versions-renovate skill.
OCI Registry Specifics
When using OCI registries like GHCR:
chart:
name: "app-template" # Just the chart name
version: "3.6.1"
url: "oci://ghcr.io/bjw-s/helm" # Registry URL with oci:// prefix
The ResourceSet template automatically detects OCI URLs and sets type: oci on the HelmRepository.