This repository was archived by the owner on Feb 4, 2026. It is now read-only.

Repository files navigation

EKS GitOps Workshop

For this example we assume a scenario with two clusters: dev and production. The end goal is to leverage Flux and Kustomize to manage both clusters while minimizing duplicated declarations.

We will configure Flux to install, test and upgrade a demo app using HelmRepository and HelmRelease custom resources. Flux will monitor the Helm repository, and it will automatically upgrade the Helm releases to their latest chart version based on semver ranges.

Prerequisites

You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18. For a quick local test, you can use Kubernetes kind. Any other Kubernetes setup will work as well though.

In order to follow the guide you'll need a GitHub account and a personal access token that can create repositories (check all permissions under repo).

Install the Flux CLI on MacOS and Linux using Homebrew:

brew install fluxcd/tap/flux

Or install the CLI by downloading precompiled binaries using a Bash script:

curl -s https://fluxcd.io/install.sh | sudo bash

Repository structure

The Git repository contains the following top directories:

  • apps dir contains Helm releases with a custom configuration per cluster
  • infrastructure dir contains infra tools such as NGINX ingress controller and Helm repository definitions
  • clusters dir contains the Flux configuration per cluster
├── apps
│ ├── base
│ ├── production │ └── dev
├── infrastructure
│ ├── nginx
│ ├── redis
│ └── sources
└── clusters
├── production
└── dev

The apps configuration is structured into:

  • apps/base/ dir contains namespaces and Helm release definitions
  • apps/production/ dir contains the production Helm release values
  • apps/dev/ dir contains the dev values
./apps/
├── base
│ └── podinfo
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── production
│ ├── kustomization.yaml
│ └── podinfo-patch.yaml
└── dev
├── kustomization.yaml
└── podinfo-patch.yaml

In apps/base/podinfo/ dir we have a HelmRelease with common values for both clusters:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
releaseName: podinfochart:
spec:
chart: podinfosourceRef:
kind: HelmRepositoryname: podinfonamespace: flux-systeminterval: 5mvalues:
cache: redis-master.redis:6379ingress:
enabled: trueannotations:
kubernetes.io/ingress.class: nginx

In apps/dev/ dir we have a Kustomize patch with the dev specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfospec:
chart:
spec:
version: ">=1.0.0-alpha"test:
enable: truevalues:
ingress:
hosts:
- host: podinfo.dev

Note that with version: ">=1.0.0-alpha" we configure Flux to automatically upgrade the HelmRelease to the latest chart version including alpha, beta and pre-releases.

In apps/production/ dir we have a Kustomize patch with the production specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
chart:
spec:
version: ">=1.0.0"values:
ingress:
hosts:
- host: podinfo.production

Note that with version: ">=1.0.0" we configure Flux to automatically upgrade the HelmRelease to the latest stable chart version (alpha, beta and pre-releases will be ignored).

In infrastructure/dev/ dir we have infrastructure toold with dev specific values:

./infrastructure/dev
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/production/ dir we have infrastructure toold with dev specific values:

./infrastructure/production
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/*/sources/ dir we have the Helm repositories definitions:

apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: podinfospec:
interval: 5murl: https://stefanprodan.github.io/podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: bitnamispec:
interval: 30murl: https://charts.bitnami.com/bitnami

Note that with interval: 5m we configure Flux to pull the Helm repository index every five minutes. If the index contains a new chart version that matches a HelmRelease semver range, Flux will upgrade the release.

Bootstrap dev and production

The clusters dir contains the Flux configuration:

./clusters/
├── production
│ ├── apps.yaml
│ └── infrastructure.yaml
└── dev
├── apps.yaml
└── infrastructure.yaml

In clusters/dev/ dir we have the Kustomization definitions:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: appsnamespace: flux-systemspec:
interval: 10m0sdependsOn:
- name: infrastructuresourceRef:
kind: GitRepositoryname: flux-systempath: ./apps/devprune: truevalidation: client
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: infrastructurenamespace: flux-systemspec:
interval: 10m0ssourceRef:
kind: GitRepositoryname: flux-systempath: ./infrastructure/dev

Note that with path: ./apps/dev we configure Flux to sync the dev Kustomize overlay and with dependsOn we tell Flux to create the infrastructure items before deploying the apps.

Fork this repository on your personal GitHub account and export your GitHub access token, username and repo name:

export GITHUB_TOKEN=<your-token>export GITHUB_USER=<your-username>export GITHUB_REPO=<repository-name>

Verify that your dev cluster satisfies the prerequisites with:

flux check --pre

Set the kubectl context to your dev cluster and bootstrap Flux:

flux bootstrap github \
--context=dev \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--branch=main \
--private=false \
--personal \
--path=clusters/dev

The bootstrap command commits the manifests for the Flux components in clusters/dev/flux-system dir and creates a deploy key with read-only access on GitHub, so it can pull changes inside the cluster.

Watch for the Helm releases being install on dev:

$ watch flux get helmreleases --all-namespaces NAMESPACE	NAME REVISION	SUSPENDED	READY	MESSAGE nginx nginx 5.6.14 False True release reconciliation succeeded	podinfo podinfo	5.0.3 False True release reconciliation succeeded	redis redis 11.3.4 False True release reconciliation succeeded

Verify that the demo app can be accessed via ingress:

$ kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &
$ curl -H "Host: podinfo.dev" http://localhost:8080{ "hostname": "podinfo-59489db7b5-lmwpn", "version": "5.0.3"}

Bootstrap Flux on production by setting the context and path to your production cluster:

flux bootstrap github \
--context=production \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--private=false \
--branch=main \
--personal \
--path=clusters/production

Watch the production reconciliation:

$ watch flux get kustomizationsNAME REVISION READYapps main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueflux-system main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueinfrastructure	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True

About

Demo application using GitOps best practices with Flux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

14 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
This repository was archived by the owner on Feb 4, 2026. It is now read-only.

Repository files navigation

EKS GitOps Workshop

For this example we assume a scenario with two clusters: dev and production. The end goal is to leverage Flux and Kustomize to manage both clusters while minimizing duplicated declarations.

We will configure Flux to install, test and upgrade a demo app using HelmRepository and HelmRelease custom resources. Flux will monitor the Helm repository, and it will automatically upgrade the Helm releases to their latest chart version based on semver ranges.

Prerequisites

You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18. For a quick local test, you can use Kubernetes kind. Any other Kubernetes setup will work as well though.

In order to follow the guide you'll need a GitHub account and a personal access token that can create repositories (check all permissions under repo).

Install the Flux CLI on MacOS and Linux using Homebrew:

brew install fluxcd/tap/flux

Or install the CLI by downloading precompiled binaries using a Bash script:

curl -s https://fluxcd.io/install.sh | sudo bash

Repository structure

The Git repository contains the following top directories:

  • apps dir contains Helm releases with a custom configuration per cluster
  • infrastructure dir contains infra tools such as NGINX ingress controller and Helm repository definitions
  • clusters dir contains the Flux configuration per cluster
├── apps
│ ├── base
│ ├── production │ └── dev
├── infrastructure
│ ├── nginx
│ ├── redis
│ └── sources
└── clusters
├── production
└── dev

The apps configuration is structured into:

  • apps/base/ dir contains namespaces and Helm release definitions
  • apps/production/ dir contains the production Helm release values
  • apps/dev/ dir contains the dev values
./apps/
├── base
│ └── podinfo
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── production
│ ├── kustomization.yaml
│ └── podinfo-patch.yaml
└── dev
├── kustomization.yaml
└── podinfo-patch.yaml

In apps/base/podinfo/ dir we have a HelmRelease with common values for both clusters:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
releaseName: podinfochart:
spec:
chart: podinfosourceRef:
kind: HelmRepositoryname: podinfonamespace: flux-systeminterval: 5mvalues:
cache: redis-master.redis:6379ingress:
enabled: trueannotations:
kubernetes.io/ingress.class: nginx

In apps/dev/ dir we have a Kustomize patch with the dev specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfospec:
chart:
spec:
version: ">=1.0.0-alpha"test:
enable: truevalues:
ingress:
hosts:
- host: podinfo.dev

Note that with version: ">=1.0.0-alpha" we configure Flux to automatically upgrade the HelmRelease to the latest chart version including alpha, beta and pre-releases.

In apps/production/ dir we have a Kustomize patch with the production specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
chart:
spec:
version: ">=1.0.0"values:
ingress:
hosts:
- host: podinfo.production

Note that with version: ">=1.0.0" we configure Flux to automatically upgrade the HelmRelease to the latest stable chart version (alpha, beta and pre-releases will be ignored).

In infrastructure/dev/ dir we have infrastructure toold with dev specific values:

./infrastructure/dev
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/production/ dir we have infrastructure toold with dev specific values:

./infrastructure/production
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/*/sources/ dir we have the Helm repositories definitions:

apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: podinfospec:
interval: 5murl: https://stefanprodan.github.io/podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: bitnamispec:
interval: 30murl: https://charts.bitnami.com/bitnami

Note that with interval: 5m we configure Flux to pull the Helm repository index every five minutes. If the index contains a new chart version that matches a HelmRelease semver range, Flux will upgrade the release.

Bootstrap dev and production

The clusters dir contains the Flux configuration:

./clusters/
├── production
│ ├── apps.yaml
│ └── infrastructure.yaml
└── dev
├── apps.yaml
└── infrastructure.yaml

In clusters/dev/ dir we have the Kustomization definitions:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: appsnamespace: flux-systemspec:
interval: 10m0sdependsOn:
- name: infrastructuresourceRef:
kind: GitRepositoryname: flux-systempath: ./apps/devprune: truevalidation: client
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: infrastructurenamespace: flux-systemspec:
interval: 10m0ssourceRef:
kind: GitRepositoryname: flux-systempath: ./infrastructure/dev

Note that with path: ./apps/dev we configure Flux to sync the dev Kustomize overlay and with dependsOn we tell Flux to create the infrastructure items before deploying the apps.

Fork this repository on your personal GitHub account and export your GitHub access token, username and repo name:

export GITHUB_TOKEN=<your-token>export GITHUB_USER=<your-username>export GITHUB_REPO=<repository-name>

Verify that your dev cluster satisfies the prerequisites with:

flux check --pre

Set the kubectl context to your dev cluster and bootstrap Flux:

flux bootstrap github \
--context=dev \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--branch=main \
--private=false \
--personal \
--path=clusters/dev

The bootstrap command commits the manifests for the Flux components in clusters/dev/flux-system dir and creates a deploy key with read-only access on GitHub, so it can pull changes inside the cluster.

Watch for the Helm releases being install on dev:

$ watch flux get helmreleases --all-namespaces NAMESPACE	NAME REVISION	SUSPENDED	READY	MESSAGE nginx nginx 5.6.14 False True release reconciliation succeeded	podinfo podinfo	5.0.3 False True release reconciliation succeeded	redis redis 11.3.4 False True release reconciliation succeeded

Verify that the demo app can be accessed via ingress:

$ kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &
$ curl -H "Host: podinfo.dev" http://localhost:8080{ "hostname": "podinfo-59489db7b5-lmwpn", "version": "5.0.3"}

Bootstrap Flux on production by setting the context and path to your production cluster:

flux bootstrap github \
--context=production \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--private=false \
--branch=main \
--personal \
--path=clusters/production

Watch the production reconciliation:

$ watch flux get kustomizationsNAME REVISION READYapps main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueflux-system main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueinfrastructure	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True

About

Demo application using GitOps best practices with Flux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

14 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Feb 4, 2026. It is now read-only.

Repository files navigation

EKS GitOps Workshop

For this example we assume a scenario with two clusters: dev and production. The end goal is to leverage Flux and Kustomize to manage both clusters while minimizing duplicated declarations.

We will configure Flux to install, test and upgrade a demo app using HelmRepository and HelmRelease custom resources. Flux will monitor the Helm repository, and it will automatically upgrade the Helm releases to their latest chart version based on semver ranges.

Prerequisites

You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18. For a quick local test, you can use Kubernetes kind. Any other Kubernetes setup will work as well though.

In order to follow the guide you'll need a GitHub account and a personal access token that can create repositories (check all permissions under repo).

Install the Flux CLI on MacOS and Linux using Homebrew:

brew install fluxcd/tap/flux

Or install the CLI by downloading precompiled binaries using a Bash script:

curl -s https://fluxcd.io/install.sh | sudo bash

Repository structure

The Git repository contains the following top directories:

  • apps dir contains Helm releases with a custom configuration per cluster
  • infrastructure dir contains infra tools such as NGINX ingress controller and Helm repository definitions
  • clusters dir contains the Flux configuration per cluster
├── apps
│ ├── base
│ ├── production │ └── dev
├── infrastructure
│ ├── nginx
│ ├── redis
│ └── sources
└── clusters
├── production
└── dev

The apps configuration is structured into:

  • apps/base/ dir contains namespaces and Helm release definitions
  • apps/production/ dir contains the production Helm release values
  • apps/dev/ dir contains the dev values
./apps/
├── base
│ └── podinfo
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── production
│ ├── kustomization.yaml
│ └── podinfo-patch.yaml
└── dev
├── kustomization.yaml
└── podinfo-patch.yaml

In apps/base/podinfo/ dir we have a HelmRelease with common values for both clusters:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
releaseName: podinfochart:
spec:
chart: podinfosourceRef:
kind: HelmRepositoryname: podinfonamespace: flux-systeminterval: 5mvalues:
cache: redis-master.redis:6379ingress:
enabled: trueannotations:
kubernetes.io/ingress.class: nginx

In apps/dev/ dir we have a Kustomize patch with the dev specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfospec:
chart:
spec:
version: ">=1.0.0-alpha"test:
enable: truevalues:
ingress:
hosts:
- host: podinfo.dev

Note that with version: ">=1.0.0-alpha" we configure Flux to automatically upgrade the HelmRelease to the latest chart version including alpha, beta and pre-releases.

In apps/production/ dir we have a Kustomize patch with the production specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
chart:
spec:
version: ">=1.0.0"values:
ingress:
hosts:
- host: podinfo.production

Note that with version: ">=1.0.0" we configure Flux to automatically upgrade the HelmRelease to the latest stable chart version (alpha, beta and pre-releases will be ignored).

In infrastructure/dev/ dir we have infrastructure toold with dev specific values:

./infrastructure/dev
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/production/ dir we have infrastructure toold with dev specific values:

./infrastructure/production
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/*/sources/ dir we have the Helm repositories definitions:

apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: podinfospec:
interval: 5murl: https://stefanprodan.github.io/podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: bitnamispec:
interval: 30murl: https://charts.bitnami.com/bitnami

Note that with interval: 5m we configure Flux to pull the Helm repository index every five minutes. If the index contains a new chart version that matches a HelmRelease semver range, Flux will upgrade the release.

Bootstrap dev and production

The clusters dir contains the Flux configuration:

./clusters/
├── production
│ ├── apps.yaml
│ └── infrastructure.yaml
└── dev
├── apps.yaml
└── infrastructure.yaml

In clusters/dev/ dir we have the Kustomization definitions:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: appsnamespace: flux-systemspec:
interval: 10m0sdependsOn:
- name: infrastructuresourceRef:
kind: GitRepositoryname: flux-systempath: ./apps/devprune: truevalidation: client
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: infrastructurenamespace: flux-systemspec:
interval: 10m0ssourceRef:
kind: GitRepositoryname: flux-systempath: ./infrastructure/dev

Note that with path: ./apps/dev we configure Flux to sync the dev Kustomize overlay and with dependsOn we tell Flux to create the infrastructure items before deploying the apps.

Fork this repository on your personal GitHub account and export your GitHub access token, username and repo name:

export GITHUB_TOKEN=<your-token>export GITHUB_USER=<your-username>export GITHUB_REPO=<repository-name>

Verify that your dev cluster satisfies the prerequisites with:

flux check --pre

Set the kubectl context to your dev cluster and bootstrap Flux:

flux bootstrap github \
--context=dev \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--branch=main \
--private=false \
--personal \
--path=clusters/dev

The bootstrap command commits the manifests for the Flux components in clusters/dev/flux-system dir and creates a deploy key with read-only access on GitHub, so it can pull changes inside the cluster.

Watch for the Helm releases being install on dev:

$ watch flux get helmreleases --all-namespaces NAMESPACE	NAME REVISION	SUSPENDED	READY	MESSAGE nginx nginx 5.6.14 False True release reconciliation succeeded	podinfo podinfo	5.0.3 False True release reconciliation succeeded	redis redis 11.3.4 False True release reconciliation succeeded

Verify that the demo app can be accessed via ingress:

$ kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &
$ curl -H "Host: podinfo.dev" http://localhost:8080{ "hostname": "podinfo-59489db7b5-lmwpn", "version": "5.0.3"}

Bootstrap Flux on production by setting the context and path to your production cluster:

flux bootstrap github \
--context=production \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--private=false \
--branch=main \
--personal \
--path=clusters/production

Watch the production reconciliation:

$ watch flux get kustomizationsNAME REVISION READYapps main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueflux-system main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueinfrastructure	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True

About

Demo application using GitOps best practices with Flux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

14 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Feb 4, 2026. It is now read-only.

Repository files navigation

EKS GitOps Workshop

For this example we assume a scenario with two clusters: dev and production. The end goal is to leverage Flux and Kustomize to manage both clusters while minimizing duplicated declarations.

We will configure Flux to install, test and upgrade a demo app using HelmRepository and HelmRelease custom resources. Flux will monitor the Helm repository, and it will automatically upgrade the Helm releases to their latest chart version based on semver ranges.

Prerequisites

You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18. For a quick local test, you can use Kubernetes kind. Any other Kubernetes setup will work as well though.

In order to follow the guide you'll need a GitHub account and a personal access token that can create repositories (check all permissions under repo).

Install the Flux CLI on MacOS and Linux using Homebrew:

brew install fluxcd/tap/flux

Or install the CLI by downloading precompiled binaries using a Bash script:

curl -s https://fluxcd.io/install.sh | sudo bash

Repository structure

The Git repository contains the following top directories:

  • apps dir contains Helm releases with a custom configuration per cluster
  • infrastructure dir contains infra tools such as NGINX ingress controller and Helm repository definitions
  • clusters dir contains the Flux configuration per cluster
├── apps
│ ├── base
│ ├── production │ └── dev
├── infrastructure
│ ├── nginx
│ ├── redis
│ └── sources
└── clusters
├── production
└── dev

The apps configuration is structured into:

  • apps/base/ dir contains namespaces and Helm release definitions
  • apps/production/ dir contains the production Helm release values
  • apps/dev/ dir contains the dev values
./apps/
├── base
│ └── podinfo
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── production
│ ├── kustomization.yaml
│ └── podinfo-patch.yaml
└── dev
├── kustomization.yaml
└── podinfo-patch.yaml

In apps/base/podinfo/ dir we have a HelmRelease with common values for both clusters:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
releaseName: podinfochart:
spec:
chart: podinfosourceRef:
kind: HelmRepositoryname: podinfonamespace: flux-systeminterval: 5mvalues:
cache: redis-master.redis:6379ingress:
enabled: trueannotations:
kubernetes.io/ingress.class: nginx

In apps/dev/ dir we have a Kustomize patch with the dev specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfospec:
chart:
spec:
version: ">=1.0.0-alpha"test:
enable: truevalues:
ingress:
hosts:
- host: podinfo.dev

Note that with version: ">=1.0.0-alpha" we configure Flux to automatically upgrade the HelmRelease to the latest chart version including alpha, beta and pre-releases.

In apps/production/ dir we have a Kustomize patch with the production specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
chart:
spec:
version: ">=1.0.0"values:
ingress:
hosts:
- host: podinfo.production

Note that with version: ">=1.0.0" we configure Flux to automatically upgrade the HelmRelease to the latest stable chart version (alpha, beta and pre-releases will be ignored).

In infrastructure/dev/ dir we have infrastructure toold with dev specific values:

./infrastructure/dev
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/production/ dir we have infrastructure toold with dev specific values:

./infrastructure/production
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/*/sources/ dir we have the Helm repositories definitions:

apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: podinfospec:
interval: 5murl: https://stefanprodan.github.io/podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: bitnamispec:
interval: 30murl: https://charts.bitnami.com/bitnami

Note that with interval: 5m we configure Flux to pull the Helm repository index every five minutes. If the index contains a new chart version that matches a HelmRelease semver range, Flux will upgrade the release.

Bootstrap dev and production

The clusters dir contains the Flux configuration:

./clusters/
├── production
│ ├── apps.yaml
│ └── infrastructure.yaml
└── dev
├── apps.yaml
└── infrastructure.yaml

In clusters/dev/ dir we have the Kustomization definitions:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: appsnamespace: flux-systemspec:
interval: 10m0sdependsOn:
- name: infrastructuresourceRef:
kind: GitRepositoryname: flux-systempath: ./apps/devprune: truevalidation: client
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: infrastructurenamespace: flux-systemspec:
interval: 10m0ssourceRef:
kind: GitRepositoryname: flux-systempath: ./infrastructure/dev

Note that with path: ./apps/dev we configure Flux to sync the dev Kustomize overlay and with dependsOn we tell Flux to create the infrastructure items before deploying the apps.

Fork this repository on your personal GitHub account and export your GitHub access token, username and repo name:

export GITHUB_TOKEN=<your-token>export GITHUB_USER=<your-username>export GITHUB_REPO=<repository-name>

Verify that your dev cluster satisfies the prerequisites with:

flux check --pre

Set the kubectl context to your dev cluster and bootstrap Flux:

flux bootstrap github \
--context=dev \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--branch=main \
--private=false \
--personal \
--path=clusters/dev

The bootstrap command commits the manifests for the Flux components in clusters/dev/flux-system dir and creates a deploy key with read-only access on GitHub, so it can pull changes inside the cluster.

Watch for the Helm releases being install on dev:

$ watch flux get helmreleases --all-namespaces NAMESPACE	NAME REVISION	SUSPENDED	READY	MESSAGE nginx nginx 5.6.14 False True release reconciliation succeeded	podinfo podinfo	5.0.3 False True release reconciliation succeeded	redis redis 11.3.4 False True release reconciliation succeeded

Verify that the demo app can be accessed via ingress:

$ kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &
$ curl -H "Host: podinfo.dev" http://localhost:8080{ "hostname": "podinfo-59489db7b5-lmwpn", "version": "5.0.3"}

Bootstrap Flux on production by setting the context and path to your production cluster:

flux bootstrap github \
--context=production \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--private=false \
--branch=main \
--personal \
--path=clusters/production

Watch the production reconciliation:

$ watch flux get kustomizationsNAME REVISION READYapps main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueflux-system main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueinfrastructure	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True

About

Demo application using GitOps best practices with Flux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

14 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
This repository was archived by the owner on Feb 4, 2026. It is now read-only.

Repository files navigation

EKS GitOps Workshop

For this example we assume a scenario with two clusters: dev and production. The end goal is to leverage Flux and Kustomize to manage both clusters while minimizing duplicated declarations.

We will configure Flux to install, test and upgrade a demo app using HelmRepository and HelmRelease custom resources. Flux will monitor the Helm repository, and it will automatically upgrade the Helm releases to their latest chart version based on semver ranges.

Prerequisites

You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18. For a quick local test, you can use Kubernetes kind. Any other Kubernetes setup will work as well though.

In order to follow the guide you'll need a GitHub account and a personal access token that can create repositories (check all permissions under repo).

Install the Flux CLI on MacOS and Linux using Homebrew:

brew install fluxcd/tap/flux

Or install the CLI by downloading precompiled binaries using a Bash script:

curl -s https://fluxcd.io/install.sh | sudo bash

Repository structure

The Git repository contains the following top directories:

  • apps dir contains Helm releases with a custom configuration per cluster
  • infrastructure dir contains infra tools such as NGINX ingress controller and Helm repository definitions
  • clusters dir contains the Flux configuration per cluster
├── apps
│ ├── base
│ ├── production │ └── dev
├── infrastructure
│ ├── nginx
│ ├── redis
│ └── sources
└── clusters
├── production
└── dev

The apps configuration is structured into:

  • apps/base/ dir contains namespaces and Helm release definitions
  • apps/production/ dir contains the production Helm release values
  • apps/dev/ dir contains the dev values
./apps/
├── base
│ └── podinfo
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── production
│ ├── kustomization.yaml
│ └── podinfo-patch.yaml
└── dev
├── kustomization.yaml
└── podinfo-patch.yaml

In apps/base/podinfo/ dir we have a HelmRelease with common values for both clusters:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
releaseName: podinfochart:
spec:
chart: podinfosourceRef:
kind: HelmRepositoryname: podinfonamespace: flux-systeminterval: 5mvalues:
cache: redis-master.redis:6379ingress:
enabled: trueannotations:
kubernetes.io/ingress.class: nginx

In apps/dev/ dir we have a Kustomize patch with the dev specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfospec:
chart:
spec:
version: ">=1.0.0-alpha"test:
enable: truevalues:
ingress:
hosts:
- host: podinfo.dev

Note that with version: ">=1.0.0-alpha" we configure Flux to automatically upgrade the HelmRelease to the latest chart version including alpha, beta and pre-releases.

In apps/production/ dir we have a Kustomize patch with the production specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
chart:
spec:
version: ">=1.0.0"values:
ingress:
hosts:
- host: podinfo.production

Note that with version: ">=1.0.0" we configure Flux to automatically upgrade the HelmRelease to the latest stable chart version (alpha, beta and pre-releases will be ignored).

In infrastructure/dev/ dir we have infrastructure toold with dev specific values:

./infrastructure/dev
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/production/ dir we have infrastructure toold with dev specific values:

./infrastructure/production
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/*/sources/ dir we have the Helm repositories definitions:

apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: podinfospec:
interval: 5murl: https://stefanprodan.github.io/podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: bitnamispec:
interval: 30murl: https://charts.bitnami.com/bitnami

Note that with interval: 5m we configure Flux to pull the Helm repository index every five minutes. If the index contains a new chart version that matches a HelmRelease semver range, Flux will upgrade the release.

Bootstrap dev and production

The clusters dir contains the Flux configuration:

./clusters/
├── production
│ ├── apps.yaml
│ └── infrastructure.yaml
└── dev
├── apps.yaml
└── infrastructure.yaml

In clusters/dev/ dir we have the Kustomization definitions:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: appsnamespace: flux-systemspec:
interval: 10m0sdependsOn:
- name: infrastructuresourceRef:
kind: GitRepositoryname: flux-systempath: ./apps/devprune: truevalidation: client
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: infrastructurenamespace: flux-systemspec:
interval: 10m0ssourceRef:
kind: GitRepositoryname: flux-systempath: ./infrastructure/dev

Note that with path: ./apps/dev we configure Flux to sync the dev Kustomize overlay and with dependsOn we tell Flux to create the infrastructure items before deploying the apps.

Fork this repository on your personal GitHub account and export your GitHub access token, username and repo name:

export GITHUB_TOKEN=<your-token>export GITHUB_USER=<your-username>export GITHUB_REPO=<repository-name>

Verify that your dev cluster satisfies the prerequisites with:

flux check --pre

Set the kubectl context to your dev cluster and bootstrap Flux:

flux bootstrap github \
--context=dev \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--branch=main \
--private=false \
--personal \
--path=clusters/dev

The bootstrap command commits the manifests for the Flux components in clusters/dev/flux-system dir and creates a deploy key with read-only access on GitHub, so it can pull changes inside the cluster.

Watch for the Helm releases being install on dev:

$ watch flux get helmreleases --all-namespaces NAMESPACE	NAME REVISION	SUSPENDED	READY	MESSAGE nginx nginx 5.6.14 False True release reconciliation succeeded	podinfo podinfo	5.0.3 False True release reconciliation succeeded	redis redis 11.3.4 False True release reconciliation succeeded

Verify that the demo app can be accessed via ingress:

$ kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &
$ curl -H "Host: podinfo.dev" http://localhost:8080{ "hostname": "podinfo-59489db7b5-lmwpn", "version": "5.0.3"}

Bootstrap Flux on production by setting the context and path to your production cluster:

flux bootstrap github \
--context=production \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--private=false \
--branch=main \
--personal \
--path=clusters/production

Watch the production reconciliation:

$ watch flux get kustomizationsNAME REVISION READYapps main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueflux-system main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueinfrastructure	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True

About

Demo application using GitOps best practices with Flux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

14 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Feb 4, 2026. It is now read-only.

Repository files navigation

EKS GitOps Workshop

For this example we assume a scenario with two clusters: dev and production. The end goal is to leverage Flux and Kustomize to manage both clusters while minimizing duplicated declarations.

We will configure Flux to install, test and upgrade a demo app using HelmRepository and HelmRelease custom resources. Flux will monitor the Helm repository, and it will automatically upgrade the Helm releases to their latest chart version based on semver ranges.

Prerequisites

You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18. For a quick local test, you can use Kubernetes kind. Any other Kubernetes setup will work as well though.

In order to follow the guide you'll need a GitHub account and a personal access token that can create repositories (check all permissions under repo).

Install the Flux CLI on MacOS and Linux using Homebrew:

brew install fluxcd/tap/flux

Or install the CLI by downloading precompiled binaries using a Bash script:

curl -s https://fluxcd.io/install.sh | sudo bash

Repository structure

The Git repository contains the following top directories:

  • apps dir contains Helm releases with a custom configuration per cluster
  • infrastructure dir contains infra tools such as NGINX ingress controller and Helm repository definitions
  • clusters dir contains the Flux configuration per cluster
├── apps
│ ├── base
│ ├── production │ └── dev
├── infrastructure
│ ├── nginx
│ ├── redis
│ └── sources
└── clusters
├── production
└── dev

The apps configuration is structured into:

  • apps/base/ dir contains namespaces and Helm release definitions
  • apps/production/ dir contains the production Helm release values
  • apps/dev/ dir contains the dev values
./apps/
├── base
│ └── podinfo
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── production
│ ├── kustomization.yaml
│ └── podinfo-patch.yaml
└── dev
├── kustomization.yaml
└── podinfo-patch.yaml

In apps/base/podinfo/ dir we have a HelmRelease with common values for both clusters:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
releaseName: podinfochart:
spec:
chart: podinfosourceRef:
kind: HelmRepositoryname: podinfonamespace: flux-systeminterval: 5mvalues:
cache: redis-master.redis:6379ingress:
enabled: trueannotations:
kubernetes.io/ingress.class: nginx

In apps/dev/ dir we have a Kustomize patch with the dev specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfospec:
chart:
spec:
version: ">=1.0.0-alpha"test:
enable: truevalues:
ingress:
hosts:
- host: podinfo.dev

Note that with version: ">=1.0.0-alpha" we configure Flux to automatically upgrade the HelmRelease to the latest chart version including alpha, beta and pre-releases.

In apps/production/ dir we have a Kustomize patch with the production specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
chart:
spec:
version: ">=1.0.0"values:
ingress:
hosts:
- host: podinfo.production

Note that with version: ">=1.0.0" we configure Flux to automatically upgrade the HelmRelease to the latest stable chart version (alpha, beta and pre-releases will be ignored).

In infrastructure/dev/ dir we have infrastructure toold with dev specific values:

./infrastructure/dev
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/production/ dir we have infrastructure toold with dev specific values:

./infrastructure/production
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/*/sources/ dir we have the Helm repositories definitions:

apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: podinfospec:
interval: 5murl: https://stefanprodan.github.io/podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: bitnamispec:
interval: 30murl: https://charts.bitnami.com/bitnami

Note that with interval: 5m we configure Flux to pull the Helm repository index every five minutes. If the index contains a new chart version that matches a HelmRelease semver range, Flux will upgrade the release.

Bootstrap dev and production

The clusters dir contains the Flux configuration:

./clusters/
├── production
│ ├── apps.yaml
│ └── infrastructure.yaml
└── dev
├── apps.yaml
└── infrastructure.yaml

In clusters/dev/ dir we have the Kustomization definitions:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: appsnamespace: flux-systemspec:
interval: 10m0sdependsOn:
- name: infrastructuresourceRef:
kind: GitRepositoryname: flux-systempath: ./apps/devprune: truevalidation: client
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: infrastructurenamespace: flux-systemspec:
interval: 10m0ssourceRef:
kind: GitRepositoryname: flux-systempath: ./infrastructure/dev

Note that with path: ./apps/dev we configure Flux to sync the dev Kustomize overlay and with dependsOn we tell Flux to create the infrastructure items before deploying the apps.

Fork this repository on your personal GitHub account and export your GitHub access token, username and repo name:

export GITHUB_TOKEN=<your-token>export GITHUB_USER=<your-username>export GITHUB_REPO=<repository-name>

Verify that your dev cluster satisfies the prerequisites with:

flux check --pre

Set the kubectl context to your dev cluster and bootstrap Flux:

flux bootstrap github \
--context=dev \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--branch=main \
--private=false \
--personal \
--path=clusters/dev

The bootstrap command commits the manifests for the Flux components in clusters/dev/flux-system dir and creates a deploy key with read-only access on GitHub, so it can pull changes inside the cluster.

Watch for the Helm releases being install on dev:

$ watch flux get helmreleases --all-namespaces NAMESPACE	NAME REVISION	SUSPENDED	READY	MESSAGE nginx nginx 5.6.14 False True release reconciliation succeeded	podinfo podinfo	5.0.3 False True release reconciliation succeeded	redis redis 11.3.4 False True release reconciliation succeeded

Verify that the demo app can be accessed via ingress:

$ kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &
$ curl -H "Host: podinfo.dev" http://localhost:8080{ "hostname": "podinfo-59489db7b5-lmwpn", "version": "5.0.3"}

Bootstrap Flux on production by setting the context and path to your production cluster:

flux bootstrap github \
--context=production \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--private=false \
--branch=main \
--personal \
--path=clusters/production

Watch the production reconciliation:

$ watch flux get kustomizationsNAME REVISION READYapps main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueflux-system main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueinfrastructure	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True

About

Demo application using GitOps best practices with Flux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

14 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Feb 4, 2026. It is now read-only.

Repository files navigation

EKS GitOps Workshop

For this example we assume a scenario with two clusters: dev and production. The end goal is to leverage Flux and Kustomize to manage both clusters while minimizing duplicated declarations.

We will configure Flux to install, test and upgrade a demo app using HelmRepository and HelmRelease custom resources. Flux will monitor the Helm repository, and it will automatically upgrade the Helm releases to their latest chart version based on semver ranges.

Prerequisites

You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18. For a quick local test, you can use Kubernetes kind. Any other Kubernetes setup will work as well though.

In order to follow the guide you'll need a GitHub account and a personal access token that can create repositories (check all permissions under repo).

Install the Flux CLI on MacOS and Linux using Homebrew:

brew install fluxcd/tap/flux

Or install the CLI by downloading precompiled binaries using a Bash script:

curl -s https://fluxcd.io/install.sh | sudo bash

Repository structure

The Git repository contains the following top directories:

  • apps dir contains Helm releases with a custom configuration per cluster
  • infrastructure dir contains infra tools such as NGINX ingress controller and Helm repository definitions
  • clusters dir contains the Flux configuration per cluster
├── apps
│ ├── base
│ ├── production │ └── dev
├── infrastructure
│ ├── nginx
│ ├── redis
│ └── sources
└── clusters
├── production
└── dev

The apps configuration is structured into:

  • apps/base/ dir contains namespaces and Helm release definitions
  • apps/production/ dir contains the production Helm release values
  • apps/dev/ dir contains the dev values
./apps/
├── base
│ └── podinfo
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── production
│ ├── kustomization.yaml
│ └── podinfo-patch.yaml
└── dev
├── kustomization.yaml
└── podinfo-patch.yaml

In apps/base/podinfo/ dir we have a HelmRelease with common values for both clusters:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
releaseName: podinfochart:
spec:
chart: podinfosourceRef:
kind: HelmRepositoryname: podinfonamespace: flux-systeminterval: 5mvalues:
cache: redis-master.redis:6379ingress:
enabled: trueannotations:
kubernetes.io/ingress.class: nginx

In apps/dev/ dir we have a Kustomize patch with the dev specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfospec:
chart:
spec:
version: ">=1.0.0-alpha"test:
enable: truevalues:
ingress:
hosts:
- host: podinfo.dev

Note that with version: ">=1.0.0-alpha" we configure Flux to automatically upgrade the HelmRelease to the latest chart version including alpha, beta and pre-releases.

In apps/production/ dir we have a Kustomize patch with the production specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
chart:
spec:
version: ">=1.0.0"values:
ingress:
hosts:
- host: podinfo.production

Note that with version: ">=1.0.0" we configure Flux to automatically upgrade the HelmRelease to the latest stable chart version (alpha, beta and pre-releases will be ignored).

In infrastructure/dev/ dir we have infrastructure toold with dev specific values:

./infrastructure/dev
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/production/ dir we have infrastructure toold with dev specific values:

./infrastructure/production
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/*/sources/ dir we have the Helm repositories definitions:

apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: podinfospec:
interval: 5murl: https://stefanprodan.github.io/podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: bitnamispec:
interval: 30murl: https://charts.bitnami.com/bitnami

Note that with interval: 5m we configure Flux to pull the Helm repository index every five minutes. If the index contains a new chart version that matches a HelmRelease semver range, Flux will upgrade the release.

Bootstrap dev and production

The clusters dir contains the Flux configuration:

./clusters/
├── production
│ ├── apps.yaml
│ └── infrastructure.yaml
└── dev
├── apps.yaml
└── infrastructure.yaml

In clusters/dev/ dir we have the Kustomization definitions:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: appsnamespace: flux-systemspec:
interval: 10m0sdependsOn:
- name: infrastructuresourceRef:
kind: GitRepositoryname: flux-systempath: ./apps/devprune: truevalidation: client
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: infrastructurenamespace: flux-systemspec:
interval: 10m0ssourceRef:
kind: GitRepositoryname: flux-systempath: ./infrastructure/dev

Note that with path: ./apps/dev we configure Flux to sync the dev Kustomize overlay and with dependsOn we tell Flux to create the infrastructure items before deploying the apps.

Fork this repository on your personal GitHub account and export your GitHub access token, username and repo name:

export GITHUB_TOKEN=<your-token>export GITHUB_USER=<your-username>export GITHUB_REPO=<repository-name>

Verify that your dev cluster satisfies the prerequisites with:

flux check --pre

Set the kubectl context to your dev cluster and bootstrap Flux:

flux bootstrap github \
--context=dev \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--branch=main \
--private=false \
--personal \
--path=clusters/dev

The bootstrap command commits the manifests for the Flux components in clusters/dev/flux-system dir and creates a deploy key with read-only access on GitHub, so it can pull changes inside the cluster.

Watch for the Helm releases being install on dev:

$ watch flux get helmreleases --all-namespaces NAMESPACE	NAME REVISION	SUSPENDED	READY	MESSAGE nginx nginx 5.6.14 False True release reconciliation succeeded	podinfo podinfo	5.0.3 False True release reconciliation succeeded	redis redis 11.3.4 False True release reconciliation succeeded

Verify that the demo app can be accessed via ingress:

$ kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &
$ curl -H "Host: podinfo.dev" http://localhost:8080{ "hostname": "podinfo-59489db7b5-lmwpn", "version": "5.0.3"}

Bootstrap Flux on production by setting the context and path to your production cluster:

flux bootstrap github \
--context=production \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--private=false \
--branch=main \
--personal \
--path=clusters/production

Watch the production reconciliation:

$ watch flux get kustomizationsNAME REVISION READYapps main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueflux-system main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueinfrastructure	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True

About

Demo application using GitOps best practices with Flux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

14 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
This repository was archived by the owner on Feb 4, 2026. It is now read-only.

Repository files navigation

EKS GitOps Workshop

For this example we assume a scenario with two clusters: dev and production. The end goal is to leverage Flux and Kustomize to manage both clusters while minimizing duplicated declarations.

We will configure Flux to install, test and upgrade a demo app using HelmRepository and HelmRelease custom resources. Flux will monitor the Helm repository, and it will automatically upgrade the Helm releases to their latest chart version based on semver ranges.

Prerequisites

You will need a Kubernetes cluster version 1.16 or newer and kubectl version 1.18. For a quick local test, you can use Kubernetes kind. Any other Kubernetes setup will work as well though.

In order to follow the guide you'll need a GitHub account and a personal access token that can create repositories (check all permissions under repo).

Install the Flux CLI on MacOS and Linux using Homebrew:

brew install fluxcd/tap/flux

Or install the CLI by downloading precompiled binaries using a Bash script:

curl -s https://fluxcd.io/install.sh | sudo bash

Repository structure

The Git repository contains the following top directories:

  • apps dir contains Helm releases with a custom configuration per cluster
  • infrastructure dir contains infra tools such as NGINX ingress controller and Helm repository definitions
  • clusters dir contains the Flux configuration per cluster
├── apps
│ ├── base
│ ├── production │ └── dev
├── infrastructure
│ ├── nginx
│ ├── redis
│ └── sources
└── clusters
├── production
└── dev

The apps configuration is structured into:

  • apps/base/ dir contains namespaces and Helm release definitions
  • apps/production/ dir contains the production Helm release values
  • apps/dev/ dir contains the dev values
./apps/
├── base
│ └── podinfo
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── production
│ ├── kustomization.yaml
│ └── podinfo-patch.yaml
└── dev
├── kustomization.yaml
└── podinfo-patch.yaml

In apps/base/podinfo/ dir we have a HelmRelease with common values for both clusters:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
releaseName: podinfochart:
spec:
chart: podinfosourceRef:
kind: HelmRepositoryname: podinfonamespace: flux-systeminterval: 5mvalues:
cache: redis-master.redis:6379ingress:
enabled: trueannotations:
kubernetes.io/ingress.class: nginx

In apps/dev/ dir we have a Kustomize patch with the dev specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfospec:
chart:
spec:
version: ">=1.0.0-alpha"test:
enable: truevalues:
ingress:
hosts:
- host: podinfo.dev

Note that with version: ">=1.0.0-alpha" we configure Flux to automatically upgrade the HelmRelease to the latest chart version including alpha, beta and pre-releases.

In apps/production/ dir we have a Kustomize patch with the production specific values:

apiVersion: helm.toolkit.fluxcd.io/v2beta1kind: HelmReleasemetadata:
name: podinfonamespace: podinfospec:
chart:
spec:
version: ">=1.0.0"values:
ingress:
hosts:
- host: podinfo.production

Note that with version: ">=1.0.0" we configure Flux to automatically upgrade the HelmRelease to the latest stable chart version (alpha, beta and pre-releases will be ignored).

In infrastructure/dev/ dir we have infrastructure toold with dev specific values:

./infrastructure/dev
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/production/ dir we have infrastructure toold with dev specific values:

./infrastructure/production
├── nginx
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
├── redis
│ ├── kustomization.yaml
│ ├── namespace.yaml
│ └── release.yaml
└── sources
├── bitnami.yaml
├── kustomization.yaml
└── podinfo.yaml

In infrastructure/*/sources/ dir we have the Helm repositories definitions:

apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: podinfospec:
interval: 5murl: https://stefanprodan.github.io/podinfo
---
apiVersion: source.toolkit.fluxcd.io/v1beta1kind: HelmRepositorymetadata:
name: bitnamispec:
interval: 30murl: https://charts.bitnami.com/bitnami

Note that with interval: 5m we configure Flux to pull the Helm repository index every five minutes. If the index contains a new chart version that matches a HelmRelease semver range, Flux will upgrade the release.

Bootstrap dev and production

The clusters dir contains the Flux configuration:

./clusters/
├── production
│ ├── apps.yaml
│ └── infrastructure.yaml
└── dev
├── apps.yaml
└── infrastructure.yaml

In clusters/dev/ dir we have the Kustomization definitions:

apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: appsnamespace: flux-systemspec:
interval: 10m0sdependsOn:
- name: infrastructuresourceRef:
kind: GitRepositoryname: flux-systempath: ./apps/devprune: truevalidation: client
---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1kind: Kustomizationmetadata:
name: infrastructurenamespace: flux-systemspec:
interval: 10m0ssourceRef:
kind: GitRepositoryname: flux-systempath: ./infrastructure/dev

Note that with path: ./apps/dev we configure Flux to sync the dev Kustomize overlay and with dependsOn we tell Flux to create the infrastructure items before deploying the apps.

Fork this repository on your personal GitHub account and export your GitHub access token, username and repo name:

export GITHUB_TOKEN=<your-token>export GITHUB_USER=<your-username>export GITHUB_REPO=<repository-name>

Verify that your dev cluster satisfies the prerequisites with:

flux check --pre

Set the kubectl context to your dev cluster and bootstrap Flux:

flux bootstrap github \
--context=dev \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--branch=main \
--private=false \
--personal \
--path=clusters/dev

The bootstrap command commits the manifests for the Flux components in clusters/dev/flux-system dir and creates a deploy key with read-only access on GitHub, so it can pull changes inside the cluster.

Watch for the Helm releases being install on dev:

$ watch flux get helmreleases --all-namespaces NAMESPACE	NAME REVISION	SUSPENDED	READY	MESSAGE nginx nginx 5.6.14 False True release reconciliation succeeded	podinfo podinfo	5.0.3 False True release reconciliation succeeded	redis redis 11.3.4 False True release reconciliation succeeded

Verify that the demo app can be accessed via ingress:

$ kubectl -n nginx port-forward svc/nginx-ingress-controller 8080:80 &
$ curl -H "Host: podinfo.dev" http://localhost:8080{ "hostname": "podinfo-59489db7b5-lmwpn", "version": "5.0.3"}

Bootstrap Flux on production by setting the context and path to your production cluster:

flux bootstrap github \
--context=production \
--owner=${GITHUB_USER} \
--repository=${GITHUB_REPO} \
--private=false \
--branch=main \
--personal \
--path=clusters/production

Watch the production reconciliation:

$ watch flux get kustomizationsNAME REVISION READYapps main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueflux-system main/797cd90cc8e81feb30cfe471a5186b86daf2758d	Trueinfrastructure	main/797cd90cc8e81feb30cfe471a5186b86daf2758d	True

About

Demo application using GitOps best practices with Flux

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

14 stars

Watchers

2 watching

Forks

Used by

Contributors

Languages