Skip to content

Using ResourceSets for Time-Based Delivery

In highly regulated industries, deploying software changes requires strict adherence to compliance frameworks and operational policies. These organizations must demonstrate control over when changes are deployed to production systems, often requiring:

  • Change Advisory Board (CAB) approval windows - Deployments only during pre-approved time slots
  • Business continuity requirements - No deployments during peak business hours or critical operations
  • Compliance auditing - Detailed records of when and why deployments occurred
  • Risk management - Controlled rollout windows to minimize business impact
  • Operational readiness - Ensuring sufficient staff coverage during deployment windows

The Flux Operator addresses these requirements through time-based reconciliation schedules, providing organizations with the governance controls they need while maintaining the benefits of GitOps automation.

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 controlled deployments.

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 Git commit SHA and branch name or tag name, that determine what version of the application should be deployed.

Instead of using a Flux GitRepository and Kustomization directly, we'll generate these resources dynamically with a ResourceSet. To control when Flux pulls changes from Git we'll pin the GitRepository to a specific commit SHA, the ResourceSetInputProvider will be responsible for fetching the latest commit SHA from a Git branch or tag, at the defined reconciliation schedule.

GitOps Workflow

  • Define a ResourceSetInputProvider: This provider will scan a Git branch or tag for changes and export the commit SHA as an input.
  • Configure schedule: The provider will have a reconciliation schedule that defines when it should check for changes in the Git repository.
  • Define a ResourceSet: The ResourceSet will use the inputs from the provider to create a GitRepository and Kustomization that deploys the application at the specified commit SHA.

ResourceSetInputProvider Definition

Assuming the Kubernetes deployment manifests for an application are stored in a Git repository, you can define a input provider that scans a branch for changes and exports the commit SHA:

apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
  name: my-app-main
  namespace: apps
  labels:
    app.kubernetes.io/name: my-app
  annotations:
    fluxcd.controlplane.io/reconcileEvery: "10m"
    fluxcd.controlplane.io/reconcileTimeout: "1m"
spec:
  schedule:
    - cron: "0 8 * * 1-5"
      timeZone: "Europe/London"
      window: 8h
  type: GitHubBranch # or GitLabBranch
  url: https://github.com/my-org/my-app
  secretRef:
    name: gh-app-auth
  filter:
    includeBranch: "^main$"
  defaultValues:
    env: "production"

For when Git tags are used to version the application, you can define an input provider that scans the Git tags and exports the latest tag according to a semantic versioning:

apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
  name: my-app-release
  namespace: apps
  labels:
    app.kubernetes.io/name: my-app
  annotations:
    fluxcd.controlplane.io/reconcileEvery: "10m"
    fluxcd.controlplane.io/reconcileTimeout: "1m"
spec:
  schedule:
    - cron: "0 8 * * 1-5"
      timeZone: "Europe/London"
      window: 8h
  type: GitHubTag # or GitLabTag
  url: https://github.com/my-org/my-app
  secretRef:
    name: gh-auth
  filter:
    semver: ">=1.0.0"
    limit: 1

ResourceSet Definition

The exported inputs can then be used in a ResourceSet to deploy the application using the commit SHA from the input provider:

apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
  name: my-app
  namespace: apps
spec:
  inputsFrom:
    - kind: ResourceSetInputProvider
      selector:
        matchLabels:
          app.kubernetes.io/name: my-app
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: GitRepository
      metadata:
        name: my-app
        namespace: << inputs.provider.namespace >>
      spec:
        interval: 12h
        url: https://github.com/my-org/my-app
        ref:
          commit: << inputs.sha >>
        secretRef:
          name: gh-auth
        sparseCheckout:
          - deploy
    - apiVersion: kustomize.toolkit.fluxcd.io/v1
      kind: Kustomization
      metadata:
        name: my-app
        namespace: << inputs.provider.namespace >>
      spec:
        interval: 30m
        retryInterval: 5m
        prune: true
        wait: true
        timeout: 5m
        sourceRef:
          kind: GitRepository
          name: my-app
        path: deploy/<< inputs.env >>

When the ResourceSetInputProvider runs according to its schedule, if it finds a new commit, the ResourceSet will be automatically updated with the new commit SHA which will trigger an application deployment for the new version.

Helm Release Workflow

For applications packaged with Helm, you can use a similar approach to trigger a Helm release upgrade in a controlled manner when a new chart version is available. For this to work, the Helm chart version must match the Git tag versioning scheme.

Example ResourceSetInputProvider that scans a repository for Git tags in semver format and exports the latest stable version as an input:

apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
   name: podinfo-release
   namespace: apps
   labels:
      app.kubernetes.io/name: podinfo
   annotations:
      fluxcd.controlplane.io/reconcileEvery: "10m"
      fluxcd.controlplane.io/reconcileTimeout: "1m"
spec:
   schedule:
      - cron: "0 12 * * 1-5"
        timeZone: "UTC"
   type: GitHubTag
   url: https://github.com/stefanprodan/podinfo
   filter:
      semver: ">=1.0.0"
      limit: 1

Example ResourceSet that deploys a Flux HelmRelease using the Git tag exported by the input provider as the latest chart version:

apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSet
metadata:
  name: podinfo
  namespace: apps
spec:
  inputsFrom:
    - kind: ResourceSetInputProvider
      selector:
        matchLabels:
          app.kubernetes.io/name: podinfo
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: OCIRepository
      metadata:
        name: podinfo
        namespace: << inputs.provider.namespace >>
      spec:
        interval: 10m
        url: oci://ghcr.io/stefanprodan/charts/podinfo
        ref:
          tag: << inputs.tag >>
    - apiVersion: helm.toolkit.fluxcd.io/v2
      kind: HelmRelease
      metadata:
        name: podinfo
        namespace: << inputs.provider.namespace >>
      spec:
        interval: 30m
        releaseName: podinfo
        chartRef:
          kind: OCIRepository
          name: podinfo
        values:
          replicaCount: 2

OCI Artifacts Support

Note that in a future release, Flux Operator will support scanning container registries for OCI artifacts, allowing you to decouple the Helm chart versioning from the Git repository.

Scheduling Configuration

The .spec.schedule field in the ResourceSetInputProvider allows you to define when the input provider should run to check for changes in source repositories.

Schedule Definition

The schedule is defined as a list of cron expressions, each with an optional time zone and window.

Example:

apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
spec:
  schedule:
    # Every day-of-week from Monday through Thursday
    # between 10:00 to 16:00
    - cron: "0 10 * * 1-4"
      timeZone: "America/New_York"
      window: "6h"

The cron field accepts standard cron expressions with five fields:

┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)
│ │ │ │ │
* * * * *

Use crontab.guru to help generate and validate cron expressions.

The timeZone field specifies the time zone for interpreting the cron schedule using IANA time zone names. If not specified, the time zone defaults to UTC.

The window field defines the duration during which reconciliations are allowed to run after the scheduled time. The format is a Go duration string, e.g. 30m, 1h, 2h30m. Must be either 0s (no window) or at least twice the reconciliation timeout 4m.

Schedule Window

When a non-zero window is specified, reconciliation is allowed throughout the entire window duration:

apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
   annotations:
    fluxcd.controlplane.io/reconcileEvery: "10m"
spec:
  schedule:
    - cron: "0 8 * * 1-5"
      timeZone: "UTC"
      window: "8h"

In this case:

  • At creation time, the input provider will not execute immediately, but will wait for the next scheduled time.
  • The input provider will start reconciling at 08:00 UTC every weekday (Monday to Friday).
  • The reconciliation will continue until 16:00 UTC, every 10 minutes, as specified by the reconcileEvery annotation.
  • Any changes to the input provider object during this window will be reconciled immediately.

Zero-Duration Window

When the window is omitted or set to 0s, flux-operator makes the best effort to reconcile at the exact scheduled time:

apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
metadata:
   annotations:
    fluxcd.controlplane.io/reconcileEvery: "10m"
spec:
  schedule:
    - cron: "0 8 * * 1-5"
      timeZone: "UTC"
      window: "0s"

In this case:

  • At creation time, the input provider will execute immediately ignoring the schedule.
  • The input provider will reconcile at 08:00 UTC every weekday (Monday to Friday).
  • Any changes to the input provider object will be reconciled immediately, even outside the scheduled time.

Multiple Schedules

The schedule can contain multiple cron expressions, allowing for complex scheduling scenarios:

apiVersion: fluxcd.controlplane.io/v1
kind: ResourceSetInputProvider
spec:
  schedule:
    # Every day-of-week from Monday through Thursday
    # between 10:00 to 16:00 NY time
    - cron: "0 10 * * 1-4"
      timeZone: "America/New_York"
      window: "6h"
    # Every Friday from 10:00 to 13:00 UK time
    - cron: "0 10 * * 5"
      timeZone: "Europe/London"
      window: "3h"

In this case:

  • The input provider reconciles if any schedule matches the current time.
  • The next scheduled time is determined by the earliest upcoming schedule.
  • Each schedule operates independently with its own time zone and window.

Command-Line Operations

The flux-operator CLI can be used to perform manual operations such as forcing a reconciliation, checking the status of the input provider or disabling it.

To force a reconciliation outside the defined schedule:

flux-operator reconcile rsip my-app-main --namespace apps --force

To check the status of input providers including their next schedule time:

flux-operator get rsip --all-namespaces

To suspend an input provider and prevent it from reconciling:

flux-operator suspend rsip my-app-main --namespace apps

To resume a suspended input provider:

flux-operator resume rsip my-app-main --namespace apps

See the Flux Operator CLI documentation for more details on how to use the CLI.

Further reading

To learn more about ResourceSets and the various configuration options, see the following docs: