Using ResourceSets for Image Update Automation
This guide demonstrates how to use the Flux Operator APIs as an alternative to the Flux Image Automation controllers.
The Flux Operator approach to image update automation is suitable for Gitless GitOps workflows where instead of pushing changes to a Git repository, the updates are applied directly to the cluster based on policies defined in the desired state.
How ResourceSets and Input Providers Work
Before diving into the configuration, it's important to understand how The Flux Operator APIs work together to enable deployment rollouts based on container image updates.
The ResourceSet API allows you to define a set of Flux resources
for deploying an application, while the ResourceSetInputProvider API
is used to provide inputs to the ResourceSet
, such as Helm chart versions and container image tags
that determine which configuration of the application should be deployed.
GitOps Workflow
To demonstrate the image update automation workflow, we'll define a series of Flux Operator custom resources in a cluster. Note that the cluster must be provisioned with a Flux Instance.
For this example, we'll use the podinfo
demo application, that consists of a Helm chart
stored as an OCI artifact in GitHub Container Registry that deploys two container images:
podinfo
and redis
.
Configure Registry Scanning
First, we'll create a ResourceSetInputProvider
that scan the registry for new versions
of the podinfo
Helm chart and pick the latest stable version according to semver:
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: podinfo-chart
namespace: apps
annotations:
fluxcd.controlplane.io/reconcileEvery: "15m"
spec:
type: OCIArtifactTag
url: oci://ghcr.io/stefanprodan/charts/podinfo
filter:
semver: ">=6.0.0"
limit: 1
Next, we'll create a ResourceSetInputProvider
the podinfo container image that scans
the registry for new digests of ghcr.io/stefanprodan/podinfo:latest
image:
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: podinfo-image
namespace: apps
annotations:
fluxcd.controlplane.io/reconcileEvery: "5m"
spec:
type: OCIArtifactTag
url: oci://ghcr.io/stefanprodan/podinfo
filter:
includeTag: "latest"
limit: 1
Finally, we'll create a ResourceSetInputProvider
for the docker.io/redis
image
that picks the latest semver version of the alpine variant:
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
name: redis-image
namespace: apps
annotations:
fluxcd.controlplane.io/reconcileEvery: "15m"
spec:
type: OCIArtifactTag
url: oci://docker.io/redis
filter:
semver: ">0.0.0-0"
includeTag: ".*-alpine$"
limit: 1
Note that you can provide credentials for private registries by referencing
a Secret of type kubernetes.io/dockerconfigjson
in the spec.secretRef
field.
Configure the App Deployment
With the providers in place, we can now create a ResourceSet
that generates
the Flux resources required to deploy the podinfo
application using the latest chart
and container images exported by the input providers:
apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
name: podinfo
namespace: apps
annotations:
fluxcd.controlplane.io/reconcileTimeout: "5m"
spec:
inputStrategy:
name: Permute
inputsFrom:
- kind: ResourceSetInputProvider
name: podinfo-chart
- kind: ResourceSetInputProvider
name: podinfo-image
- kind: ResourceSetInputProvider
name: redis-image
resources:
- apiVersion: source.toolkit.fluxcd.io/v1
kind: OCIRepository
metadata:
name: podinfo
namespace: << inputs.podinfo_chart.provider.namespace >>
spec:
interval: 12h
url: oci://ghcr.io/stefanprodan/charts/podinfo
ref:
tag: << inputs.podinfo_chart.tag >>
- apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: podinfo
namespace: << inputs.podinfo_chart.provider.namespace >>
spec:
interval: 30m
releaseName: podinfo
chartRef:
kind: OCIRepository
name: podinfo
values:
image:
tag: "<< inputs.podinfo_image.tag >>@<< inputs.podinfo_image.digest >>"
redis:
enabled: true
tag: "<< inputs.redis_image.tag >>@<< inputs.redis_image.digest >>"
In the resources section of the ResourceSet
, we define an OCIRepository
that points
to the Helm chart and a HelmRelease
that deploys the application using the chart.
The chart version is set using the << inputs.podinfo_chart.tag >>
template variable,
which is populated by the podinfo-chart
input provider. Every time the input provider
detects a new chart version, the ResourceSet
will trigger a Helm release upgrade to
deploy the new version.
The container image tags for podinfo
and redis
are set along with their digests
using the following template variables:
<< inputs.podinfo_image.tag >>@<< inputs.podinfo_image.digest >>
<< inputs.redis_image.tag >>@<< inputs.redis_image.digest >>
These template variables are populated by the respective input providers and will
trigger a Helm release upgrade whenever a new image version is detected, either
based on a new digest for the latest
tag of podinfo
or a new semver version
of the redis
image.
Patching Container Images
There are cases when a Helm chart does not expose all its images in values. In such cases, you can use Kustomize patches to modify the manifests before helm-controller applies them:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
spec:
postRenderers:
- kustomize:
images:
- name: ghcr.io/stefanprodan/podinfo
newTag: << inputs.podinfo_image.tag | quote >>
digest: << inputs.podinfo_image.digest | quote >>
Similarly, when an application is deployed using a Flux Kustomization
,
you can use the .spec.images
field to define the container images to be updated:
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
spec:
images:
- name: ghcr.io/stefanprodan/podinfo
newTag: << inputs.podinfo_image.tag | quote >>
digest: << inputs.podinfo_image.digest | quote >>
Configure Notifications
To get notified when the image update triggers a deployment, we can create a Flux Alert that sends notifications to e.g. a Slack channel:
---
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
name: slack-bot
namespace: apps
spec:
type: slack
channel: general
address: https://slack.com/api/chat.postMessage
secretRef:
name: slack-bot-token
---
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
name: slack
namespace: apps
spec:
providerRef:
name: slack-bot
eventSources:
- kind: OCIRepository
name: '*'
- kind: HelmRelease
name: '*'
- kind: Kustomization
name: '*'
- kind: ResourceSet
name: '*'
eventMetadata:
cluster: "dev-cluster-1"
region: "us-east-1"
Working with ResourceSets
Using the Flux Operator CLI, you can interact with ResourceSets and their input providers.
To view the status of the ResourceSet
, its input providers and the deployed HelmRelease
:
flux-operator -n apps get all
To pause the update automation for a particular image, you can suspend the corresponding
ResourceSetInputProvider
with:
flux-operator -n apps suspend rsip redis-image
To pause the entire image update automation workflow, you can suspend the ResourceSet
with:
flux-operator -n apps suspend rset podinfo
To resume the automation:
flux-operator -n apps resume rsip redis-image
flux-operator -n apps resume rset podinfo
To trigger an immediate image scan:
flux-operator -n apps reconcile rsip redis-image
In addition, you can use the CLI to build the ResourceSet
locally and verify
that the templates are valid with mock input data:
flux-operator build rset -f podinfo-resourceset.yaml \
--inputs-from-provider static-inputs.yaml
Further reading
To learn more about ResourceSets and the various configuration options, see the following docs: