diff --git a/rfcs/0002-helm-oci/README.md b/rfcs/0002-helm-oci/README.md new file mode 100644 index 0000000000..878055fc68 --- /dev/null +++ b/rfcs/0002-helm-oci/README.md @@ -0,0 +1,174 @@ +# RFC-0002 Flux OCI support for Helm + +**Status:** implementable + +**Creation date:** 2022-03-30 + +**Last update:** 2022-04-13 + +## Summary + +Given that Helm v3.8 supports [OCI](https://helm.sh/docs/topics/registries/) for package distribution, +we should extend the Flux Source API to allow fetching Helm charts from container registries. + +## Motivation + +Helm OCI support is one of the most requested feature in Flux +as seen on this [issue](https://github.com/fluxcd/source-controller/issues/124). + +With OCI support, Flux users can automate chart updates to Git in the same way +they do today for container images. + +### Goals + +- Add support for fetching Helm charts stored as OCI artifacts with minimal API changes to Flux. +- Make it easy for users to switch from [HTTP/S Helm repositories](https://github.com/helm/helm-www/blob/416fabea6ffab8dc156b6a0c5eb5e8df5f5ef7dc/content/en/docs/topics/chart_repository.md) + to OCI repositories. + +### Non-Goals + +- Introduce a new API kind for referencing charts stored as OCI artifacts. + +## Proposal + +Introduce an optional field called `type` to the `HelmRepository` spec. + +When not specified, the `spec.type` field defaults to `Default` which preserve the current `HelmRepository` API behaviour. + +When the `spec.type` field is set to `OCI`, the `spec.url` field must be prefixed with `oci://` (to follow the Helm conventions). +For `oci://` URLs, source-controller will use the Helm SDK and the `oras` library to connect to the OCI remote storage. +For authentication, the controller will use Kubernetes secrets of `kubernetes.io/dockerconfigjson` type. + +### User Stories + +#### Story 1 + +> As a developer I want to use Flux `HelmReleases` that refer to Helm charts stored +> as OCI artifacts in GitHub Container Registry. + +First create a secret using a GitHub token that allows access to GHCR: + +```sh +kubectl create secret docker-registry ghcr-charts \ + --docker-server=ghcr.io \ + --docker-username=$GITHUB_USER \ + --docker-password=$GITHUB_TOKEN +``` + +Then define a `HelmRepository` of type `OCI` and reference the `dockerconfig` secret: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1beta2 +kind: HelmRepository +metadata: + name: ghcr-charts + namespace: default +spec: + type: OCI + url: oci://ghcr.io/my-org/charts/ + secretRef: + name: ghcr-charts +``` + +And finally in Flux `HelmReleases`, refer to the ghcr-charts `HelmRepository`: + +```yaml +apiVersion: helm.toolkit.fluxcd.io/v2beta1 +kind: HelmRelease +metadata: + name: my-app + namespace: default +spec: + interval: 60m + chart: + spec: + chart: my-app + version: '1.0.x' + sourceRef: + kind: HelmRepository + name: ghcr-charts + interval: 1m # check for new OCI artifacts every minute +``` + +#### Story 2 + +> As a platform admin I want to automate Helm chart updates based on a semver ranges. +> When a new patch version is available in the container registry, I want Flux to open a PR +> with the version set in the `HelmRelease` manifests. + +Given that charts are stored in container registries, you can use Flux image automation +and patch the chart version in Git, in the same way Flux works for updating container image tags. + +Define an image registry and a policy for the chart artifact: + +```yaml +apiVersion: image.toolkit.fluxcd.io/v1beta1 +kind: ImageRepository +metadata: + name: my-app + namespace: default +spec: + image: ghcr.io/my-org/charts/my-app + interval: 1m0s +--- +apiVersion: image.toolkit.fluxcd.io/v1beta1 +kind: ImagePolicy +metadata: + name: my-app + namespace: default +spec: + imageRepositoryRef: + name: my-app + policy: + semver: + range: 1.0.x +``` + +Then add the policy marker to the `HelmRelease` manifests in Git: + +```yaml +apiVersion: helm.toolkit.fluxcd.io/v2beta1 +kind: HelmRelease +metadata: + name: my-app + namespace: default +spec: + interval: 60m + chart: + spec: + chart: my-app + version: 1.0.0 # {"$imagepolicy": "default:my-app:tag"} + sourceRef: + kind: HelmRepository + name: ghcr-charts + interval: 1m +``` + +### Alternatives + +We could introduce a new API type e.g. `HelmRegistry` to hold the reference to auth secret, +as proposed in [#2573](https://github.com/fluxcd/flux2/pull/2573). +That is considered unpractical, as there is no benefit for users in having a dedicated kind instead of +a `type` field in the current `HelmRepository` API. Adding a `type` field to the spec follows the Flux +Bucket API design, where the same Kind servers different implementations: AWS S3 vs Azure Blob vs Google Storage. + +## Design Details + +In source-controller we'll add a new predicate for filtering `HelmRepositories` based on the `spec.type` field. + +The current `HelmRepositoryReconciler` will be renamed to `HelmRepositoryDefaultReconciler`, +it's scope remains unchanged, and it will handle only objects with `type: Default`. + +We'll introduce a new reconciler named `HelmRepositoryOCIReconciler`, that will handle +objects with `type: OCI`. This reconciler will set the `HelmRepository` Ready status to +`False` if the URL is not prefixed with `oci://`, otherwise the Ready status will be set to `True`. + +The current `HelmChartReconciler` will be renamed to `HelmChartDefaultReconciler`, +it's scope remains unchanged, and it will handle only objects that refer to `HelmRepositories` with `type: Default`. + +For `type: OCI` we'll introduce a new reconciler `HelmChartOCIReconciler` that uses `oras` to download charts +and their dependencies. + +### Enabling the feature + +The feature is enabled by default.