{"id":26127446,"url":"https://github.com/banzaicloud/crd-updater","last_synced_at":"2025-07-13T13:34:24.210Z","repository":{"id":48093270,"uuid":"394630649","full_name":"banzaicloud/crd-updater","owner":"banzaicloud","description":"Helm 3 library chart that emulates Helm 2 CRD update behavior.","archived":false,"fork":false,"pushed_at":"2021-08-18T08:52:41.000Z","size":78,"stargazers_count":10,"open_issues_count":2,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-27T07:04:21.542Z","etag":null,"topics":["crd","customresourcedefinition","helm-chart","helm3","kubernetes"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/banzaicloud.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":"CODEOWNERS","security":null,"support":null}},"created_at":"2021-08-10T11:40:54.000Z","updated_at":"2024-01-22T08:50:20.000Z","dependencies_parsed_at":"2022-08-12T18:31:00.289Z","dependency_job_id":null,"html_url":"https://github.com/banzaicloud/crd-updater","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/banzaicloud/crd-updater","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/banzaicloud%2Fcrd-updater","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/banzaicloud%2Fcrd-updater/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/banzaicloud%2Fcrd-updater/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/banzaicloud%2Fcrd-updater/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/banzaicloud","download_url":"https://codeload.github.com/banzaicloud/crd-updater/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/banzaicloud%2Fcrd-updater/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265151408,"owners_count":23719120,"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":["crd","customresourcedefinition","helm-chart","helm3","kubernetes"],"created_at":"2025-03-10T18:08:19.584Z","updated_at":"2025-07-13T13:34:24.168Z","avatar_url":"https://github.com/banzaicloud.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Helm 3: CRD update support library\n\nThis repository contains a helm library chart that can be used to emulate the old Helm 2 behavior of updating CustomResourceDefinitions on the target cluster during `helm upgrade` commands.\n\n# Background: Helm 3 vs. CRDs\n\n[`CustomResourceDefinitions`](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) (`CRDs` for short) can be used to define your Kubernetes objects and is widely used by Kubernetes based projects relying on the [Operator Pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/).\n\nWith the release of Helm 3 the Helm maintainers choose to exclude [CRD update support from Helm](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/).\n\nThere are quite many reasons for the Helm maintainers to reach this conclusion, however, I need to mention one corner case that can be extremely painful when using CRDs.\n\nThe main issue is where a `CustomResourceDefinition` changes. It's quite common to include non-breaking (new fields etc.) into a CRD without creating a new version of the CRD. The issue is when the update contains such changes that cannot be patched into the existing CRD or if an immutable field changes.\n\nFor any Resource (not just CRDS) usually, these conflicts are handled by deleting and creating a new Resource. The drawback of this approach is that in the case of a `Pod` or `Deployment` this might cause a micro-outage during deployment, but depending on the criticality and redundancy (multi-cluster) properties of the service this might be acceptable.\n\nIn case of deletion of a CRD, however, there's a side-effect: all of the `CustomResources` defined by the given `CustomResourceDefinition` will be removed from Kubernetes. This - for example - means that if you are upgrading your Istio deployment, and the DestinationRules CRD gets deleted, all of your DestinationRules settings will be lost on the cluster.\n\nPlease bear in mind this corner case when managing CRDs. The `crd-updater` takes a different approach to this issue: it will not delete any CRDs, but instead, it will fail the upgrade if the patch cannot be applied.\n\nThis saves the system from the previous issue but will fail any helm deployments when this issue is present.\n\n# Why not use this library?\n\nThe removal of the CRD update from Helm 3 is not as big of an issue as it seems, as most deployments rely on some kind of (CI)/CD solution such as ArgoCD for managing clusters. These tools are mostly using Helm for what it's great for: as a templating language, then they rely on their implementation (instead of Helm's) to reconcile the cluster into the expected state.\n\nFor developers experimenting with new tools, the current approach is also fine: they install the given helm chart experiment with it, and get rid of Helm release or the whole cluster at some point in time. They are usually not concerned about upgradeability due to these reasons.\n\nSo when to use this library? Only if you are forced (due to technical requirements, etc.) to rely on Helm's capabilities to upgrade a given `Release` over an extended period. But please consider using a proper CI/CD tool such as ArgoCD.\n\n# Usage\n\nTo use this library chart, you need to have a Helm 3 chart (`version: v2` in `Chart.yaml`). First of all, you will need to add a dependency into your existing Helm chart to `crd-updater`:\n\n```yaml\ndependencies:\n  - name: \"crd-updater\"\n    version: \"0.0.3\"\n    repository: \"https://kubernetes-charts.banzaicloud.com\"\n```\n\nThen please update the charts folder by executing the following command in your chart directory:\n\n```sh\nhelm dependency update\n```\n\nThis exposes a new Helm template called `crd-update.tpl` to your existing chart. To start utilizing this new template first please add the following to you values.yaml:\n\n```yaml\ncrd:\n  manage: false\n```\n\nAs you see we recommend setting the `.crd.manage` to false. The reason behind this is that if a proper CI/CD system is used to manage the Helm chart the `crd-updater` is not needed and it's better if the CI/CD system reconciles the CRDs too.\n\nThen create a new file called `crd-updater.yaml` in the template folder:\n\n```yaml\n{{- if .Values.crd.manage -}}\n\n{{{ $currentScope := . }}\n{{ $crdManifests := list }}\n{{ range $path, $_ := .Files.Glob \"crds/*.yaml\" }}\n  {{ with $currentScope}}\n    {{ $crdManifests = append $crdManifests (.Files.Get $path) }}\n  {{ end }}\n{{ end }}\n\ninclude \"crd-update.tpl\" (list . .Values.crd (dict\n      \"pre-install,pre-upgrade,pre-rollback\" $crdManifests\n))\n{{- end -}}\n```\n\nAssuming that CRDs are stored in the `crds` folder at the root of your chart, your CRDs will be automatically updated on every Helm upgrade.\n\n# Usage: adding custom resources\n\nFor certain operators, it makes sense to not just install/update the CRDs, but also create a custom resource as part of the installation. For example, if you are installing the `prometheus-operator` chart, it will install the `Prometheus` CRD and it will automatically create a new `Prometheus` custom resource so that a Prometheus instance gets preconfigured on the cluster.\n\nWhen thinking about the Helm upgrade flow, this causes an issue a new field/property is added to the CRD and the CustomResource provisioned automatically by the Helm chart would include that field too. What will happen, if an end-user tries to upgrade to this new release of the helm chart is:\n- Helm does not update the CRDs from the chart\n- Helm loads the CRDs from the Kubernetes API server (but those will be the old version of the CRD without the field, due to the previous item)\n- Helm tries to validate the CustomResource against the old version of the CRD and reports an error\n\nIn case you would like to support such upgrades, `crd-updater` got you covered. Let me use the [CronTab](https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/) from the Kubernetes handbook as an example. If a chart would like to provision this custom resource it will most like contain such a YAML template in the `templates` folder:\n\n```yaml\napiVersion: \"stable.example.com/v1\"\nkind: CronTab\nmetadata:\n  name: {{ .Release.Name }}\nspec:\n  cronSpec: \"* * * * */5\"\n  image: my-awesome-cron-image\n```\n\nFor `crd-updater` to be able to update this resource, the chart maintainer needs to modify this file to prevent it from Helm to reconcile this Resource and make `crd-updater` do the reconciliation. The first step is to rename the file from `crontab.yaml` to `crontab.tpl`. Then the contents needs to be changed like this:\n\n```yaml\n{{ define \"crontab.tpl\" }}\napiVersion: \"stable.example.com/v1\"\nkind: CronTab\nmetadata:\n  name: {{ .Release.Name }}\nspec:\n  cronSpec: \"* * * * */5\"\n  image: my-awesome-cron-image\n{{ end }}\n```\n\nWhat happened is that now a `crontab.tpl` template is defined, for which we can use the [`include` command](https://helm.sh/docs/chart_template_guide/named_templates/) to render the YAML manifest.\n\nNext we need to change the `crd-updater.yaml` to this:\n```yaml\n{{- if .Values.crd.manage -}}\n\n{{ $currentScope := . }}\n{{ $crdManifests := list }}\n{{ range $path, $_ := .Files.Glob \"crds/*.yaml\" }}\n  {{ with $currentScope}}\n    {{ $crdManifests = append $crdManifests (.Files.Get $path) }}\n  {{ end }}\n{{ end }}\n\n{{- include \"crd-update.tpl\" (list . .Values.crd (dict\n      \"pre-install,pre-upgrade,pre-rollback\" $crdManifests\n      \"post-install,post-upgrade,post-rollback,pre-delete\" (list (include \"crontab.tpl\" .))\n    )) -}}\n{{- else -}}\n{{ include \"crontab.tpl\" . }}\n{{- end -}}\n```\n\nThere are two changes compared to the previous one: when invoking the `crd-update.tpl` we add a new line stating that when Helm is executing `post-install,post-upgrade,post-rollback,pre-delete` [hooks](https://helm.sh/docs/topics/charts_hooks/) it should also reconcile the `crontab.tpl`.\n\nAs it is visible, the CR is added after the installation/upgrade (`post-install` hook). The reason behind is that if a helm user changes the `.crd.mange` value from false to true, then helm will remove the CronTab custom resource and then after intallation `crd-updater` will create the new one. Please note that this might mean traffic disruption, so it's not recommended to do so.\n\nThe inclusion of `pre-delete` hook ensures that the CR will be removed when uninstalling the release. In the case of `pre-delete` and `post-delete` hooks, crd-updater automatically changes into delete mode. Finalizers are honored during this deletion: crd-updater will wait for the resource to completely get removed from the target cluster, before continuing the execution.\n\nThe second change is the inclusion of the `{{- else -}}` branch in the condition: if the current release is not managing CRDs, then we should output our CustomResources for Helm (or any other CICD system) to handle.\n\nPlease note: when including multiple manifests (such as CRDs) in a list the order of resource creation is not based on the argument position: CRD Updater will determine the [optimal installation order](https://github.com/banzaicloud/operator-tools/blob/v0.24.0/pkg/utils/sort.go#L29).\n\nLast but not least we need to grant access for `crd-updater` to manage these resources. For namespaced resources add the following to your values.yaml (under the existing `crd` key):\n\n```yaml\ncrd:\n  roleRules:\n  - apiGroups: [\"stable.example.com\"]\n    resources: [\"crontabs\"]\n    verbs: [ \"create\", \"get\", \"watch\", \"list\", \"delete\", \"update\" ]\n```\n\nFor non-namespaced resources please use the following keys:\n\n```yaml\ncrd:\n  clusterRoleRules:\n  - apiGroups: [\"stable.example.com\"]\n    resources: [\"crontabs\"]\n    verbs: [ \"create\", \"get\", \"watch\", \"list\", \"delete\", \"update\" ]\n```\n\n\n# Values.yaml settings\n\nCRD updater supports the following settings from values.yaml:\n\n| Key | Type | Usage |\n|---|---|---|\n| `.crd.image.repository` | string | repository to fetch crd-updater docker image from |\n| `.crd.image.tag` | string | tag to use when fetching crd-updater |\n| `.crd.image.pullPolicy` | string | `ImagePullPolicy` to use when creating the updater job |\n| `.crd.clusterRoleRules` | list | additional cluster-wide permissions to grant to crd updater |\n| `.crd.roleRules` | list | additional namespace-wide permissions to grant to crd updater |\n| `.crd.pod.annotations`| map | additional annotations to use on the `Pod` provisioned by the `Job` that crd-updater creates |\n| `.crd.hookDeletePolicy` | string | see [`hook-delete-policy` in Helm documentation](https://helm.sh/docs/topics/charts_hooks/) |\n| `.crd.imagePullSecrets` | list | List of image pull secrets to be used by the `Pod` provisioned by the `Job` that crd-updater creates |\n\n# Troubleshooting\n\nIn case a reconciliation error occurs, a helm timeout will happen (as the reconciliation Job will retry until Helm times out).\n\nThe easiest way to troubleshoot any issues is to make sure that the `.crd.hookDeletePolicy` is unset (that means the default of `before-hook-creation`), then take a look on the logs of the failing `Job`'s `Pods'` logs using the `kubectl logs` command.\n\n# Subcharts\n\nPlease note that a template function is only able to access files in its own chart. It might be compelling to create a chart and add a subchart to it, then rely on `crd-updater` from the main chart to reconcile the subchart's CRDs. This will not work due to the previous limitation.\n\n# Istio (or other Service Meshes)\n\nWhen using `crd-updater` with Istio you will need to ensure that no sidecar gets injected, or that the sidecar stops as soon as the updater completes. In the case of Istio by specifying these values, the injection of `istio-proxy` can be disabled:\n\n```yaml\ncrd:\n  pod:\n    annotations:\n      sidecar.istio.io/inject: \"false\"\n```\n\n# Performance\n\nPlease note that using this library might increase the time it takes for Helm to upgrade/install the Helm chart as it creates objects one-by-one.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbanzaicloud%2Fcrd-updater","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbanzaicloud%2Fcrd-updater","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbanzaicloud%2Fcrd-updater/lists"}