{"id":13646732,"url":"https://github.com/fluxcd/helm-operator-get-started","last_synced_at":"2025-04-21T21:31:11.895Z","repository":{"id":52410617,"uuid":"122050470","full_name":"fluxcd/helm-operator-get-started","owner":"fluxcd","description":"Managing Helm releases with Flux Helm Operator","archived":true,"fork":false,"pushed_at":"2021-02-09T12:13:11.000Z","size":549,"stargazers_count":454,"open_issues_count":5,"forks_count":673,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-11-09T20:37:45.518Z","etag":null,"topics":["ci-cd","gitops","helm","kubernetes","secrets-management"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluxcd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-19T11:00:39.000Z","updated_at":"2024-09-13T16:44:08.000Z","dependencies_parsed_at":"2022-08-25T05:41:27.894Z","dependency_job_id":null,"html_url":"https://github.com/fluxcd/helm-operator-get-started","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fhelm-operator-get-started","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fhelm-operator-get-started/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fhelm-operator-get-started/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluxcd%2Fhelm-operator-get-started/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluxcd","download_url":"https://codeload.github.com/fluxcd/helm-operator-get-started/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250136676,"owners_count":21380876,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ci-cd","gitops","helm","kubernetes","secrets-management"],"created_at":"2024-08-02T01:03:04.429Z","updated_at":"2025-04-21T21:31:11.488Z","avatar_url":"https://github.com/fluxcd.png","language":"HTML","readme":"# Managing Helm releases the GitOps way\n\n## We are moving to Flux v2\n\n\u003e ⚠️ Please note: In preparation of [Flux v2](https://toolkit.fluxcd.io/) GA this repository with Flux v1 examples has been archived. The Flux v2 equivalent of what is shown here can be found at [flux2-kustomize-helm-example](https://github.com/fluxcd/flux2-kustomize-helm-example).\n\u003e\n\u003e Thanks a lot for your interest.\n\n## What is GitOps?\n\nGitOps is a way to do Continuous Delivery, it works by using Git as a source of truth for declarative infrastructure and workloads.\nFor Kubernetes this means using `git push` instead of `kubectl create/apply` or `helm install/upgrade`.\n\nIn a traditional CICD pipeline, CD is an implementation extension powered by the\ncontinuous integration tooling to promote build artifacts to production.\nIn the GitOps pipeline model, any change to production must be committed in source control\n(preferable via a pull request) prior to being applied on the cluster.\nThis way rollback and audit logs are provided by Git.\nIf the entire production state is under version control and described in a single Git repository, when disaster strikes,\nthe whole infrastructure can be quickly restored from that repository.\n\nTo better understand the benefits of this approach to CD and what the differences between GitOps and\nInfrastructure-as-Code tools are, head to the Weaveworks website and read [GitOps - What you need to know](https://www.weave.works/technologies/gitops/) article.\n\nIn order to apply the GitOps pipeline model to Kubernetes you need three things:\n\n* a Git repository with your workloads definitions in YAML format, Helm charts and any other Kubernetes custom resource that defines your cluster desired state (I will refer to this as the *config* repository)\n* a container registry where your CI system pushes immutable images (no *latest* tags, use *semantic versioning* or git *commit sha*)\n* an operator that runs in your cluster and does a two-way synchronization:\n    * watches the registry for new image releases and based on deployment policies updates the workload definitions with the new image tag and commits the changes to the config repository\n    * watches for changes in the config repository and applies them to your cluster\n\nI will be using GitHub to host the config repo, Docker Hub as the container registry and Flux as the GitOps Kubernetes Operator.\n\n![gitops](https://github.com/fluxcd/helm-operator-get-started/blob/master/diagrams/flux-helm-operator-registry.png)\n\n### Prerequisites\n\nYou'll need a Kubernetes cluster v1.11 or newer, a GitHub account, git and kubectl installed locally.\n\nInstall Helm v3 and fluxctl for macOS with Homebrew:\n\n```sh\nbrew install helm fluxctl\n```\n\nOn Windows you can use Chocolatey:\n\n```sh\nchoco install kubernetes-helm fluxctl\n```\n\nOn Linux you can download the [helm](https://github.com/helm/helm/releases)\nand [fluxctl](https://github.com/fluxcd/flux/releases) binaries from GitHub.\n\n### Install Flux\n\nThe first step in automating Helm releases with [Flux](https://github.com/fluxcd/flux) is to create a Git repository with your charts source code.\n\nOn GitHub, fork this repository and clone it locally\n(replace `fluxcd` with your GitHub username): \n\n```sh\ngit clone https://github.com/fluxcd/helm-operator-get-started\ncd helm-operator-get-started\n```\n\n*If you fork, update the release definitions with your Docker Hub repository and GitHub username located in\n\\releases\\(dev/stg/prod)\\podinfo.yaml in your master branch before proceeding.\n\nAdd FluxCD repository to Helm repos:\n\n```bash\nhelm repo add fluxcd https://charts.fluxcd.io\n```\n\nCreate the `fluxcd` namespace:\n\n```sh\nkubectl create ns fluxcd\n```\n\nInstall Flux by specifying your fork URL (replace `fluxcd` with your GitHub username): \n\n```bash\nhelm upgrade -i flux fluxcd/flux --wait \\\n--namespace fluxcd \\\n--set git.url=git@github.com:fluxcd/helm-operator-get-started\n```\n\nInstall the `HelmRelease` Kubernetes custom resource definition:\n\n```sh\nkubectl apply -f https://raw.githubusercontent.com/fluxcd/helm-operator/master/deploy/crds.yaml\n```\n\nInstall Flux Helm Operator with ***Helm v3*** support:\n\n```bash\nhelm upgrade -i helm-operator fluxcd/helm-operator --wait \\\n--namespace fluxcd \\\n--set git.ssh.secretName=flux-git-deploy \\\n--set helm.versions=v3\n```\n\nThe Flux Helm operator provides an extension to Flux that automates Helm Chart releases for it.\nA Chart release is described through a Kubernetes custom resource named HelmRelease.\nThe Flux daemon synchronizes these resources from git to the cluster,\nand the Flux Helm operator makes sure Helm charts are released as specified in the resources.\n\nNote that Flux Helm Operator works with Kubernetes 1.11 or newer.\n\nAt startup, Flux generates a SSH key and logs the public key. Find the public key with:\n\n```bash\nfluxctl identity --k8s-fwd-ns fluxcd\n```\n\nIn order to sync your cluster state with Git you need to copy the public key and\ncreate a **deploy key** with **write access** on your GitHub repository.\n\nOpen GitHub, navigate to your fork, go to _Setting \u003e Deploy keys_ click on _Add deploy key_, check\n_Allow write access_, paste the Flux public key and click _Add key_.\n\n### GitOps pipeline example\n\nThe config repo has the following structure:\n\n```\n├── charts\n│   └── podinfo\n│       ├── Chart.yaml\n│       ├── README.md\n│       ├── templates\n│       └── values.yaml\n├── hack\n│   ├── Dockerfile.ci\n│   └── ci-mock.sh\n├── namespaces\n│   ├── dev.yaml\n│   └── stg.yaml\n└── releases\n    ├── dev\n    │   └── podinfo.yaml\n    └── stg\n        └── podinfo.yaml\n```\n\nI will be using [podinfo](https://github.com/stefanprodan/podinfo) to demonstrate a full CI/CD pipeline including promoting releases between environments.\n\nI'm assuming the following Git branching model:\n* dev branch (feature-ready state)\n* stg branch (release-candidate state)\n* master branch (production-ready state)\n\nWhen a PR is merged in the dev or stg branch will produce a immutable container image as in `repo/app:branch-commitsha`.\n\nInside the *hack* dir you can find a script that simulates the CI process for dev and stg.\nThe *ci-mock.sh* script does the following:\n* pulls the podinfo source code from GitHub\n* generates a random string and modifies the code\n* generates a random Git commit short SHA\n* builds a Docker image with the format: `yourname/podinfo:branch-sha`\n* pushes the image to Docker Hub\n\nLet's create an image corresponding to the `dev` branch (replace `stefanprodan` with your Docker Hub username):\n\n```\n$ cd hack \u0026\u0026 ./ci-mock.sh -r stefanprodan/podinfo -b dev\n\nSending build context to Docker daemon  4.096kB\nStep 1/15 : FROM golang:1.13 as builder\n....\nStep 9/15 : FROM alpine:3.10\n....\nStep 12/15 : COPY --from=builder /go/src/github.com/stefanprodan/k8s-podinfo/podinfo .\n....\nStep 15/15 : CMD [\"./podinfo\"]\n....\nSuccessfully built 71bee4549fb2\nSuccessfully tagged stefanprodan/podinfo:dev-kb9lm91e\nThe push refers to repository [docker.io/stefanprodan/podinfo]\n36ced78d2ca2: Pushed\n```\n\nInside the *charts* directory there is a podinfo Helm chart.\nUsing this chart I want to create a release in the `dev` namespace with the image I've just published to Docker Hub.\nInstead of editing the `values.yaml` from the chart source, I create a `HelmRelease` definition (located in /releases/dev/podinfo.yaml):\n\n```yaml\napiVersion: helm.fluxcd.io/v1\nkind: HelmRelease\nmetadata:\n  name: podinfo-dev\n  namespace: dev\n  annotations:\n    fluxcd.io/automated: \"true\"\n    filter.fluxcd.io/chart-image: glob:dev-*\nspec:\n  releaseName: podinfo-dev\n  chart:\n    git: git@github.com:fluxcd/helm-operator-get-started\n    path: charts/podinfo\n    ref: master\n  values:\n    image:\n      repository: stefanprodan/podinfo\n      tag: dev-kb9lm91e\n    replicaCount: 1\n```\n\nFlux Helm release fields:\n\n* `metadata.name` is mandatory and needs to follow Kubernetes naming conventions\n* `metadata.namespace` is optional and determines where the release is created\n* `spec.releaseName` is optional and if not provided the release name will be $namespace-$name\n* `spec.chart.path` is the directory containing the chart, given relative to the repository root\n* `spec.values` are user customizations of default parameter values from the chart itself\n\nThe options specified in the HelmRelease `spec.values` will override the ones in `values.yaml` from the chart source.\n\nWith the `fluxcd.io/automated` annotations I instruct Flux to automate this release.\nWhen a new tag with the prefix `dev` is pushed to Docker Hub, Flux will update the image field in the yaml file,\nwill commit and push the change to Git and finally will apply the change on the cluster.\n\n![gitops-automation](https://github.com/stefanprodan/openfaas-flux/blob/master/docs/screens/flux-helm-image-update.png)\n\nWhen the `podinfo-dev` HelmRelease object changes inside the cluster,\nKubernetes API will notify the Flux Helm Operator and the operator will perform a Helm release upgrade.\n\n```\n$ helm -n dev history podinfo-dev\n\nREVISION\tSTATUS    \tCHART        \tDESCRIPTION\n1       \tsuperseded\tpodinfo-0.2.0\tInstall complete\n2       \tdeployed  \tpodinfo-0.2.0\tUpgrade complete\n```\n\nThe Flux Helm Operator reacts to changes in the HelmRelease collection but will also detect changes in the charts source files.\nIf I make a change to the podinfo chart, the operator will pick that up and run an upgrade.\n\n![gitops-chart-change](https://github.com/stefanprodan/openfaas-flux/blob/master/docs/screens/flux-helm-chart-update.png)\n\n```\n$ helm -n dev history podinfo-dev\n\nREVISION\tSTATUS    \tCHART        \tDESCRIPTION\n1       \tsuperseded\tpodinfo-0.2.0\tInstall complete\n2       \tsuperseded\tpodinfo-0.2.0\tUpgrade complete\n3       \tdeployed  \tpodinfo-0.2.1\tUpgrade complete\n```\n\nNow let's assume that I want to promote the code from the `dev` branch into a more stable environment for others to test it.\nI would create a release candidate by merging the podinfo code from `dev` into the `stg` branch.\nThe CI would kick in and publish a new image:\n\n```bash\n$ cd hack \u0026\u0026 ./ci-mock.sh -r stefanprodan/podinfo -b stg\n\nSuccessfully tagged stefanprodan/podinfo:stg-9ij63o4c\nThe push refers to repository [docker.io/stefanprodan/podinfo]\n8f21c3669055: Pushed\n```\n\nAssuming the staging environment has some sort of automated load testing in place,\nI want to have a different configuration than dev:\n\n```yaml\napiVersion: helm.fluxcd.io/v1\nkind: HelmRelease\nmetadata:\n  name: podinfo-rc\n  namespace: stg\n  annotations:\n    fluxcd.io/automated: \"true\"\n    filter.fluxcd.io/chart-image: glob:stg-*\nspec:\n  releaseName: podinfo-rc\n  chart:\n    git: git@github.com:fluxcd/helm-operator-get-started\n    path: charts/podinfo\n    ref: master\n  values:\n    image:\n      repository: stefanprodan/podinfo\n      tag: stg-9ij63o4c\n    replicaCount: 2\n    hpa:\n      enabled: true\n      maxReplicas: 10\n      cpu: 50\n      memory: 128Mi\n```\n\nWith Flux Helm releases it's easy to manage different configurations per environment.\nWhen adding a new option in the chart source make sure it's turned off by default so it will not affect all environments.\n\nIf I want to create a new environment, let's say for hotfixes testing, I would do the following:\n* create a new namespace definition in `namespaces/hotfix.yaml`\n* create a dir `releases/hotfix`\n* create a HelmRelease named `podinfo-hotfix`\n* set the automation filter to `glob:hotfix-*`\n* make the CI tooling publish images from my hotfix branch to `stefanprodan/podinfo:hotfix-sha`\n\n### Production promotions with sem ver\n\nFor production, instead of tagging the images with the Git commit, I will use [Semantic Versioning](https://semver.org).\n\nLet's assume that I want to promote the code from the `stg` branch into `master` and do a production release.\nAfter merging `stg` into `master` via a pull request, I would cut a release by tagging `master` with version `0.4.10`.\n\nWhen I push the git tag, the CI will publish a new image in the `repo/app:git_tag` format:\n\n```bash\n$ cd hack \u0026\u0026 ./ci-mock.sh -r stefanprodan/podinfo -v 0.4.10\n\nSuccessfully built f176482168f8\nSuccessfully tagged stefanprodan/podinfo:0.4.10\n```\n\nIf I want to automate the production deployment based on version tags, I would use `semver` filters instead of `glob`:\n\n```yaml\napiVersion: helm.fluxcd.io/v1\nkind: HelmRelease\nmetadata:\n  name: podinfo-prod\n  namespace: prod\n  annotations:\n    fluxcd.io/automated: \"true\"\n    filter.fluxcd.io/chart-image: semver:~0.4\nspec:\n  releaseName: podinfo-prod\n  chart:\n    git: git@github.com:fluxcd/helm-operator-get-started\n    path: charts/podinfo\n    ref: master\n  values:\n    image:\n      repository: stefanprodan/podinfo\n      tag: 0.4.10\n    replicaCount: 3\n```\n\nNow if I release a new patch, let's say `0.4.11`, Flux will automatically deploy it.\n\n```bash\n$ cd hack \u0026\u0026 ./ci-mock.sh -r stefanprodan/podinfo -v 0.4.11\n\nSuccessfully tagged stefanprodan/podinfo:0.4.11\n```\n\n![gitops-semver](https://github.com/stefanprodan/openfaas-flux/blob/master/docs/screens/flux-helm-semver.png)\n\n### Managing Kubernetes secrets\n\nIn order to store secrets safely in a public Git repo you can use the Bitnami [Sealed Secrets controller](https://github.com/bitnami-labs/sealed-secrets)\nand encrypt your Kubernetes Secrets into SealedSecrets.\nThe SealedSecret can be decrypted only by the controller running in your cluster.\n\nThe Sealed Secrets Helm chart is available on [Helm Hub](https://hub.helm.sh/charts/stable/sealed-secrets),\nso I can use the Helm repository instead of a git repo. This is the sealed-secrets controller release:\n\n```yaml\napiVersion: helm.fluxcd.io/v1\nkind: HelmRelease\nmetadata:\n  name: sealed-secrets\n  namespace: adm\nspec:\n  releaseName: sealed-secrets\n  chart:\n    repository: https://kubernetes-charts.storage.googleapis.com/\n    name: sealed-secrets\n    version: 1.6.1\n```\n\nNote that this release is not automated, since this is a critical component I prefer to update it manually.\n\nInstall the kubeseal CLI:\n\n```bash\nbrew install kubeseal\n```\n\nAt startup, the sealed-secrets controller generates a RSA key and logs the public key.\nUsing kubeseal you can save your public key as `pub-cert.pem`,\nthe public key can be safely stored in Git, and can be used to encrypt secrets without direct access to the Kubernetes cluster:\n\n```bash\nkubeseal --fetch-cert \\\n--controller-namespace=adm \\\n--controller-name=sealed-secrets \\\n\u003e pub-cert.pem\n```\n\nYou can generate a Kubernetes secret locally with kubectl and encrypt it with kubeseal:\n\n```bash\nkubectl -n dev create secret generic basic-auth \\\n--from-literal=user=admin \\\n--from-literal=password=admin \\\n--dry-run \\\n-o json \u003e basic-auth.json\n\nkubeseal --format=yaml --cert=pub-cert.pem \u003c basic-auth.json \u003e basic-auth.yaml\n```\n\nThis generates a custom resource of type `SealedSecret` that contains the encrypted credentials:\n\n```yaml\napiVersion: bitnami.com/v1alpha1\nkind: SealedSecret\nmetadata:\n  name: basic-auth\n  namespace: adm\nspec:\n  encryptedData:\n    password: AgAR5nzhX2TkJ.......\n    user: AgAQDO58WniIV3gTk.......\n```\n\nDelete the `basic-auth.json` file and push the `pub-cert.pem` and `basic-auth.yaml` to Git:\n\n```bash\nrm basic-auth.json\nmv basic-auth.yaml /releases/dev/\n\ngit commit -a -m \"Add basic auth credentials to dev namespace\" \u0026\u0026 git push\n```\n\nFlux will apply the sealed secret on your cluster and sealed-secrets controller will then decrypt it into a\nKubernetes secret.\n\n![SealedSecrets](https://github.com/fluxcd/helm-operator-get-started/blob/master/diagrams/flux-helm-operator-sealed-secrets.png)\n\nTo prepare for disaster recovery you should backup the sealed-secrets controller private key with:\n\n```bash\nkubectl get secret -n adm sealed-secrets-key -o yaml --export \u003e sealed-secrets-key.yaml\n```\n\nTo restore from backup after a disaster, replace the newly-created secret and restart the controller:\n\n```bash\nkubectl replace secret -n adm sealed-secrets-key -f sealed-secrets-key.yaml\nkubectl delete pod -n adm -l app=sealed-secrets\n```\n\n### \u003ca name=\"help\"\u003e\u003c/a\u003eGetting Help\n\nIf you have any questions about Helm Operator and continuous delivery:\n\n- Read [the Helm Operator docs](https://docs.fluxcd.io/projects/helm-operator/en/latest/).\n- Read [the Flux integration with the Helm operator docs](https://docs.fluxcd.io/en/latest/references/helm-operator-integration.html).\n- Invite yourself to the \u003ca href=\"https://slack.cncf.io\" target=\"_blank\"\u003eCNCF community\u003c/a\u003e\n  slack and ask a question on the [#flux](https://cloud-native.slack.com/messages/flux/)\n  channel.\n- To be part of the conversation about Helm Operator's development, join the\n  [flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).\n- [File an issue.](https://github.com/fluxcd/flux/issues/new)\n\nYour feedback is always welcome!\n","funding_links":[],"categories":["HTML"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluxcd%2Fhelm-operator-get-started","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluxcd%2Fhelm-operator-get-started","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluxcd%2Fhelm-operator-get-started/lists"}