Production-grade platform engineering handbook — Kubernetes, Terraform, Flux CD, GitHub Actions, AWS, and more.
67
84%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Passed
No known issues
ResourceSet (fluxcd.controlplane.io/v1) generates Kubernetes resources from input value matrices using templates. It powers multi-tenant orchestration, fleet management, and self-service platform patterns that would otherwise require N copies of the same manifest.
A ResourceSet takes one or more sets of inputs and renders a template block once per input entry. The result is a set of Kubernetes resources owned and reconciled by the Flux Operator.
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: tenant-apps
namespace: flux-system
spec:
inputsFrom:
- kind: ResourceSetInputProvider
name: tenant-list
resources:
- apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: << inputs.tenant >>-apps
namespace: flux-system
spec:
interval: 10m
prune: true
sourceRef:
kind: OCIRepository
name: << inputs.tenant >>-manifests
path: ./apps
serviceAccountName: << inputs.tenant >>Template delimiters are << >> — not {{ }}.
Templates use slim-sprig (Go sprig subset):
<< inputs.tenant >> # simple substitution
<< inputs.tag | default "latest" >> # default value
<< inputs.config | toYaml | nindent 4 >> # serialize nested object
<< if eq inputs.env "prod" >>3<< else >>1<< end >> # conditional| Strategy | Behaviour |
|---|---|
Flatten (default) | Concatenates all inputs into a flat list |
Permute | Cartesian product of all provider outputs |
Under Permute, field names are namespaced under the normalized provider name. A provider named image-tag is accessed as inputs.image_tag.tag. Inline inputs on a ResourceSet named my-apps require inputs.my_apps.region, not inputs.region.
Always set
filter.limit: 1on OCIArtifactTag providers used withPermute— multiple exports per provider create a cross-product explosion (operator stalls at 10,000 permutations).
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: tenant-list
namespace: flux-system
spec:
type: Static # Static | OCIArtifactTag | ECRArtifactTag | GitHubTag | GitHubPullRequest | GitLabTag | AzureContainerTag | ExternalService
defaultValues:
region: eu-west-1| Type | Exported fields | Use case |
|---|---|---|
Static | From defaultValues | Fixed config, shared cluster variables |
OCIArtifactTag | id, tag, digest | Gitless image automation |
ECRArtifactTag | id, tag, digest | ECR-native gitless automation |
GitHubTag | id, tag, sha | Fleet release tracking |
GitHubPullRequest | id, sha, branch, author, title | Preview environments per PR |
GitLabTag | id, tag, sha | GitLab fleet release tracking |
AzureContainerTag | id, tag, digest | ACR gitless automation |
ExternalService | From HTTP JSON response | Custom registry / inventory API |
Key spec fields:
| Field | Purpose |
|---|---|
type | Provider type (required) |
url | Registry or repo URL |
secretRef.name | Credentials secret |
filter.limit | Max inputs returned (default: 100) |
filter.semver | Semver range to filter/sort tags |
defaultValues | Merged defaults added to every exported entry |
schedule | Cron expression for reconciliation windows |
Reconciliation interval is set via spec.interval on the ResourceSetInputProvider. The annotation form is also supported as an override:
spec:
interval: 5m # polling interval on the provider
# Optional override via annotation (takes precedence over spec.interval):
# annotations:
# fluxcd.controlplane.io/reconcileEvery: "5m"ResourceSets support CEL-based readiness expressions:
spec:
dependsOn:
- kind: Kustomization
name: platform-rbac
namespace: flux-system
readyExpr: >
status.conditions.filter(e, e.type == 'Ready').all(e, e.status == 'True')
- kind: Kustomization
name: cert-manager
namespace: flux-system
readyExpr: "status.observedGeneration >= 0" # reconciled-once checkresources:
- apiVersion: v1
kind: Namespace
metadata:
name: << inputs.tenant >>
annotations:
fluxcd.controlplane.io/reconcile: << if eq inputs.active "true" >>enabled<< else >>disabled<< end >>When the annotation value is disabled, that resource is excluded for that input entry.
Copies ConfigMaps or Secrets from another namespace and keeps them in sync. Required for distributing shared config across tenant namespaces:
spec:
resources:
- apiVersion: v1
kind: ConfigMap
metadata:
name: cluster-config
namespace: << inputs.tenant >>
annotations:
fluxcd.controlplane.io/copyFrom: flux-system/cluster-configFor Secrets, the type field must also be set in the template.
| Field | Description |
|---|---|
inputs._index | Zero-based index of current input |
inputs._id | Adler-32 checksum of input values — stable unique ID |
inputs.provider.kind | ResourceSet or ResourceSetInputProvider |
inputs.provider.name | Name of the providing object |
When multiple inputs produce resources with identical GVK + namespace + name, the last input wins.
Chain of ResourceSets with dependsOn: policies → infra → apps. Each tenant gets a Namespace, OCIRepository, Kustomization, RBAC, and registry credentials — all from a single ResourceSet template.
A GitHubPullRequest provider with label filter feeds a ResourceSet that spins up per-PR namespaces and deployments. Cleaned up automatically when the PR closes.
OCIArtifactTag provider + Permute strategy pins HelmRelease resources to tag@digest without Git commits. Set limit: 1 per provider.
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: app-image
namespace: flux-system
annotations:
fluxcd.controlplane.io/reconcileEvery: "2m"
spec:
type: OCIArtifactTag
url: oci://ghcr.io/my-org/my-app
secretRef:
name: registry-auth
filter:
limit: 1
semver: ">=1.0.0"
---
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: app-release
namespace: flux-system
spec:
inputsFrom:
- kind: ResourceSetInputProvider
name: app-image
resources:
- apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: my-app
namespace: apps
spec:
interval: 10m
chartRef:
kind: OCIRepository
name: my-app-chart
values:
image:
tag: "<< inputs.tag >>@<< inputs.digest >>"# List all ResourceSets
kubectl get resourceset -A
# Inspect inputs and generated resources
kubectl describe resourceset <name> -n flux-system
# List resources generated by a specific ResourceSet
kubectl get kustomization,helmrelease -l resourceset.fluxcd.io/name=<name> -A
# Force immediate reconciliation
kubectl annotate resourceset <name> -n flux-system \
fluxcd.controlplane.io/requestedAt="$(date -u +%Y-%m-%dT%H:%M:%SZ)" --overwrite.claude-plugin
.github
commands
docs
examples
agent-self-improve
argocd
awesome-docs
aws
cloudfront
functions
lambda-edge
functions
azure
compliance
conventional-commits
datadog
llm-observability
demo
documentation
dora
dynatrace
fluxcd
github-actions
composite-actions
configure-cloud
db-migrate
docker-build-push
k8s-deploy
notify-slack
pr-comment
release-tag
security-scan
setup-env
setup-terraform
terraform-plan
helm
web-service
templates
kubernetes
kyverno
mcp
observability
openshift
pr-review
ownership
runtime-security
supply-chain
terraform
references
scripts
skills
platform-skills
tests