You are viewing documentation for Flux version: 2.0

Version 2.0 of the documentation is no longer actively maintained. The site that you are currently viewing is an archived snapshot. For up-to-date documentation, see the latest version.

Promote Flux Helm Releases with GitHub Actions

How to configure a promotion workflow for Flux HelmReleases with GitHub Actions.

This guide shows how to configure Flux and GitHub Actions to promote Helm Releases across environments when a new Helm chart version is available.

Flux Helm promotion GitHub workflow

For this guide we assume a scenario with two clusters: staging and production; with the following promotion pipeline:

  • On the staging cluster, Flux will monitor the Helm repository for new chart versions, and it will automatically upgrade and test the Helm release.
  • After the Helm release is successfully upgraded, Flux will send an event to GitHub that will trigger a GitHub Actions workflow.
  • The GitHub workflow receives the new chart version, updates the Flux HelmRelease manifest YAML for the production cluster and opens a Pull Request.
  • When the Pull Request is merged, Flux upgrades the Helm release on the production cluster to the chart version that was tested in staging.


For this guide we assume you have two clusters bootstrapped with Flux and a good understanding of how Flux manages Helm releases. Please see the helm example repository to familiarise yourself with Flux and Helm.

Define staging and production releases

For the staging cluster, we’ll define a HelmRelease for which Flux will monitor the Helm repository, and it will automatically upgrade the Helm release to the latest chart version based on a semver range.

Example of clusters/staging/apps/demo.yaml:

kind: HelmRelease
  name: demo
  namespace: apps
  interval: 60m
      chart: demo
      version: "1.x" # automatically upgrade to the latest version
      interval: 5m # scan the Helm repository every five minutes
        kind: HelmRepository
        name: demo-charts
    enable: true # run tests on upgrades
    - kind: Secret
      name: demo-staging-values

For the production cluster, we’ll define a HelmRelease with a fixed version, the chart version will be update in Git by GitHub Actions based on the Flux events.

Example of clusters/production/apps/demo.yaml:

kind: HelmRelease
  name: demo
  namespace: apps
  interval: 60m
      chart: demo
      # This field will be updated by GitHub Actions.
      version: "1.0.0"
        kind: HelmRepository
        name: demo-charts
    - kind: Secret
      name: demo-production-values

Define the promotion GitHub workflow

To promote a chart version that was successfully deployed and tested on staging, we’ll create a GitHub workflow that reacts to Flux repository dispatch events.

Example of .github/workflows/demo-promotion.yaml:

name: demo-promotion
      - HelmRelease/demo.apps

  contents: write
  pull-requests: write

    runs-on: ubuntu-latest
    # Start promotion when the staging cluster has successfully
    # upgraded the Helm release to a new chart version.
    if: |
      github.event.client_payload.metadata.env == 'staging' &&
      github.event.client_payload.severity == 'info'      
      # Checkout main branch.
      - uses: actions/checkout@v3
          ref: main
      # Parse the event metadata to determine the chart version deployed on staging.
      - name: Get chart version from staging
        id: staging
        run: |
          VERSION=$(echo ${{ github.event.client_payload.metadata.revision }} | cut -d '@' -f1)
          echo VERSION=${VERSION} >> $GITHUB_OUTPUT          
      # Patch the chart version in the production Helm release manifest.
      - name: Set chart version in production
        id: production
          CHART_VERSION: ${{ steps.staging.outputs.version }}
        run: |
          echo "set chart version to ${CHART_VERSION}"
          yq eval '.spec.chart.spec.version=env(CHART_VERSION)' -i ./clusters/production/apps/demo.yaml          
      # Open a Pull Request if an upgraded is needed in production.
      - name: Open promotion PR
        uses: peter-evans/create-pull-request@v4
          branch: demo-promotion
          delete-branch: true
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: Update demo to v${{ steps.staging.outputs.version }}
          title: Promote demo release to v${{ steps.staging.outputs.version }}
          body: |
            Promote demo release on production to v${{ steps.staging.outputs.version }}

The above workflow does the following:

  • Runs on repository dispatch events issued by Flux with the HelmRelease/demo.apps type.
  • Filters the events to take into consideration only success Helm release upgrades.
  • Clones the main branch where the Flux HelmRelease YAML manifests are defined.
  • Parses the event metadata to determine the chart version deployed on staging.
  • Patches the chart version in the HelmRelease manifest at clusters/production/apps/demo.yaml.
  • Creates a new branch called demo-promotion, commits the version change and opens a Pull Request against main.

Note that you should adapt the workflow to match your release name, namespace and YAML path.

Configure Flux for repository dispatching

On the staging cluster, we’ll configure Flux to send events to GitHub every time it performs a Helm release upgrade.

Example of clusters/staging/apps/demo-github.yaml:

kind: Provider
  name: github
  namespace: apps
  type: githubdispatch
    name: github-token
kind: Alert
  name: demo-dispatch
  namespace: apps
    name: github
  summary: "Trigger promotion"
    env: staging
    cluster: staging-1
    region: eu-central-1
  eventSeverity: info
    - kind: HelmRelease
      name: demo
    - ".*.upgrade.*succeeded.*"

Note that you should adapt the above definitions to match your GitHub repository address. If testing is enabled in your HelmRelease, you can use the ".*.test.*succeeded.*" expression in the inclusion list instead of ".*.upgrade.*succeeded.*". This will ensure the promotion happens only after tests have been successfully run.

You also need to create a Kubernetes secret with a GitHub Personal Access Token that has access to the repository:

kubectl -n apps create secret generic github-token \

Relevant documentation