AgentSkillsCN

flux-gitops

利用 ResourceSet,在家庭实验室 Kubernetes 平台上实践 Flux GitOps 模式。 适用场景:(1) 向平台中新增 Helm Release 或应用;(2) 将新服务部署至 Kubernetes;(3) 调试 Flux 协调问题或同步故障;(4) 理解 ResourceSet 的常见模式;(5) 配置 Kustomization 与变量替换;(6) 针对 helm-charts.yaml 或平台结构提出疑问;(7) 探讨 GitOps 工作流相关问题。 触发词:添加 Helm Release、部署至 Kubernetes、添加新服务、添加应用、Flux ResourceSet、Flux 协调、Flux 未同步、Flux 卡住、GitOps、helm-charts.yaml、平台值、Flux 调试、HelmRelease 未就绪、Kustomization、HelmRelease、添加 Chart、部署 Helm Chart。

SKILL.md
--- frontmatter
name: flux-gitops
description: |
  Flux GitOps patterns for the homelab Kubernetes platform using ResourceSets.

  Use when: (1) Adding new Helm releases or applications to the platform, (2) Deploying a new service to Kubernetes,
  (3) Debugging Flux reconciliation issues or sync problems, (4) Understanding ResourceSet patterns,
  (5) Configuring Kustomizations and variable substitution, (6) Questions about helm-charts.yaml or platform structure,
  (7) GitOps workflow questions.

  Triggers: "add helm release", "deploy to kubernetes", "add new service", "add application",
  "flux resourceset", "flux reconciliation", "flux not syncing", "flux stuck", "gitops",
  "helm-charts.yaml", "platform values", "flux debug", "HelmRelease not ready", "kustomization",
  "helmrelease", "add chart", "deploy helm chart"

Flux GitOps Platform

The homelab Kubernetes platform uses Flux ResourceSets for centralized, declarative management of Helm releases and configurations.

Platform Files Overview

FilePurpose
helm-charts.yamlResourceSet defining all Helm releases
namespaces.yamlResourceSet defining all namespaces
config.yamlResourceSet for config Kustomizations
kustomization.yamlGenerates ConfigMap from chart values
charts/Helm values files (one per release)
config/Non-Helm resources organized by subsystem

Adding a New Helm Release

Step 1: Add to helm-charts.yaml

Add an entry to the inputs array:

yaml
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:

yaml
    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
# 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:

yaml
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/:

code
config/my-new-chart/
├── kustomization.yaml
├── secret.yaml
└── config.yaml

Then reference in config.yaml ResourceSet.

ResourceSet Template Syntax

The resourcesTemplate uses Go text/template with << >> delimiters:

yaml
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 array
  • hasPrefix "oci://" inputs.chart.url - String prefix check

Variable Substitution

Flux substitutes variables from the flux-system ConfigMap:

yaml
# In values file
ingress:
  hosts:
    - host: grafana.${internal_domain}  # Substituted at reconciliation

# Available variables
${cluster_name}      # dev, integration, live
${cluster_id}        # Numeric cluster ID
${internal_domain}   # internal.dev.tomnowak.work
${external_domain}   # External domain

Dependency Management

Release Dependencies

yaml
inputs:
  - name: "grafana"
    dependsOn: [kube-prometheus-stack, promtail]  # Waits for these

ResourceSet Dependencies

yaml
spec:
  dependsOn:
    - apiVersion: fluxcd.controlplane.io/v1
      kind: ResourceSet
      name: platform-namespaces  # Waits for namespaces ResourceSet

Debugging Flux

Check ResourceSet Status

bash
kubectl get resourcesets -n flux-system
kubectl describe resourceset platform-resources -n flux-system

Check HelmRelease Status

bash
kubectl get helmreleases -A
kubectl describe helmrelease <name> -n <namespace>

Check Reconciliation Logs

bash
kubectl logs -n flux-system deploy/flux-controller -f | grep <release-name>

Force Reconciliation

bash
flux reconcile helmrelease <name> -n <namespace>
flux reconcile kustomization flux-system -n flux-system

Common Issues

SymptomCauseSolution
waiting for dependenciesDependency not readyCheck dependsOn releases
values key not foundMissing values fileAdd to kustomization.yaml configMapGenerator
chart not foundWrong chart name/URLVerify chart exists in repository
namespace not foundNamespace not createdAdd to namespaces.yaml

Best Practices

  1. Pin versions: Always specify exact chart versions
  2. Declare dependencies: Use dependsOn to ensure ordering
  3. Use substitution: Never hardcode domains or cluster names
  4. Values per release: One values file per HelmRelease
  5. Minimal values: Only override what you need to change

OCI Registry Specifics

When using OCI registries like GHCR:

yaml
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.