helm-controller/docs/spec/v2beta1/helmreleases.md

1462 lines
52 KiB
Markdown

# Helm Releases
The `HelmRelease` API defines a resource for automated controller driven Helm releases.
## Specification
A **HelmRelease** object defines a resource for controller driven reconciliation
of Helm releases via Helm actions such as install, upgrade, test, uninstall, and rollback.
This includes release placement (namespace/name), release content (chart/values overrides),
action trigger configuration, individual action configuration, and statusing.
```go
// HelmReleaseSpec defines the desired state of a Helm Release.
type HelmReleaseSpec struct {
// Chart defines the template of the v1beta1.HelmChart that should be created
// for this HelmRelease.
// +required
Chart HelmChartTemplate `json:"chart"`
// Interval at which to reconcile the Helm release.
// +required
Interval metav1.Duration `json:"interval"`
// Suspend tells the controller to suspend reconciliation for this HelmRelease,
// it does not apply to already started reconciliations. Defaults to false.
// +optional
Suspend bool `json:"suspend,omitempty"`
// ReleaseName used for the Helm release. Defaults to a composition of
// '[TargetNamespace-]Name'.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=53
// +kubebuilder:validation:Optional
// +optional
ReleaseName string `json:"releaseName,omitempty"`
// TargetNamespace to target when performing operations for the HelmRelease.
// Defaults to the namespace of the HelmRelease.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Optional
// +optional
TargetNamespace string `json:"targetNamespace,omitempty"`
// StorageNamespace used for the Helm storage.
// Defaults to the namespace of the HelmRelease.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Optional
// +optional
StorageNamespace string `json:"storageNamespace,omitempty"`
// DependsOn may contain a dependency.CrossNamespaceDependencyReference slice with
// references to HelmRelease resources that must be ready before this HelmRelease
// can be reconciled.
// +optional
DependsOn []dependency.CrossNamespaceDependencyReference `json:"dependsOn,omitempty"`
// Timeout is the time to wait for any individual Kubernetes operation (like Jobs
// for hooks) during the performance of a Helm action. Defaults to '5m0s'.
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// MaxHistory is the number of revisions saved by Helm for this HelmRelease.
// Use '0' for an unlimited number of revisions; defaults to '10'.
// +optional
MaxHistory *int `json:"maxHistory,omitempty"`
// Install holds the configuration for Helm install actions for this HelmRelease.
// +optional
Install *Install `json:"install,omitempty"`
// Upgrade holds the configuration for Helm upgrade actions for this HelmRelease.
// +optional
Upgrade *Upgrade `json:"upgrade,omitempty"`
// Test holds the configuration for Helm test actions for this HelmRelease.
// +optional
Test *Test `json:"test,omitempty"`
// Rollback holds the configuration for Helm rollback actions for this HelmRelease.
// +optional
Rollback *Rollback `json:"rollback,omitempty"`
// Uninstall holds the configuration for Helm uninstall actions for this HelmRelease.
// +optional
Uninstall *Uninstall `json:"uninstall,omitempty"`
// ValuesFrom holds references to resources containing Helm values for this HelmRelease,
// and information about how they should be merged.
ValuesFrom []ValuesReference `json:"valuesFrom,omitempty"`
// Values holds the values for this Helm release.
// +optional
Values *apiextensionsv1.JSON `json:"values,omitempty"`
// KubeConfig for reconciling the HelmRelease on a remote cluster.
// When used in combination with HelmReleaseSpec.ServiceAccountName,
// forces the controller to act on behalf of that Service Account at the
// target cluster.
// If the --default-service-account flag is set, its value will be used as
// a controller level fallback for when HelmReleaseSpec.ServiceAccountName
// is empty.
// +optional
KubeConfig *KubeConfig `json:"kubeConfig,omitempty"`
// The name of the Kubernetes service account to impersonate
// when reconciling this HelmRelease.
// +optional
ServiceAccountName string `json:"serviceAccountName,omitempty"`
// PostRenderers holds an array of Helm PostRenderers, which will be applied in order
// of their definition.
// +optional
PostRenderers []PostRenderer `json:"postRenderers,omitempty"`
}
// KubeConfig references a Kubernetes secret that contains a kubeconfig file.
type KubeConfig struct {
// SecretRef holds the name to a secret that contains a key with
// the kubeconfig file as the value. If no key is specified the key will
// default to 'value'. The secret must be in the same namespace as
// the HelmRelease.
// It is recommended that the kubeconfig is self-contained, and the secret
// is regularly updated if credentials such as a cloud-access-token expire.
// Cloud specific `cmd-path` auth helpers will not function without adding
// binaries and credentials to the Pod that is responsible for reconciling
// the HelmRelease.
// +required
SecretRef meta.SecretKeyReference `json:"secretRef,omitempty"`
}
// HelmChartTemplate defines the template from which the controller will
// generate a v1beta1.HelmChart object in the same namespace as the referenced
// v1beta1.Source.
type HelmChartTemplate struct {
// Spec holds the template for the v1beta1.HelmChartSpec for this HelmRelease.
// +required
Spec HelmChartTemplateSpec `json:"spec"`
}
// HelmChartTemplateSpec defines the template from which the controller will
// generate a v1beta1.HelmChartSpec object.
type HelmChartTemplateSpec struct {
// The name or path the Helm chart is available at in the SourceRef.
// +required
Chart string `json:"chart"`
// Version semver expression, ignored for charts from v1beta1.GitRepository and
// v1beta1.Bucket sources. Defaults to latest when omitted.
// +kubebuilder:default:=*
// +optional
Version string `json:"version,omitempty"`
// The name and namespace of the v1beta1.Source the chart is available at.
// +required
SourceRef CrossNamespaceObjectReference `json:"sourceRef"`
// Interval at which to check the v1beta1.Source for updates. Defaults to
// 'HelmReleaseSpec.Interval'.
// +optional
Interval *metav1.Duration `json:"interval,omitempty"`
// Alternative list of values files to use as the chart values (values.yaml
// is not included by default), expected to be a relative path in the SourceRef.
// Values files are merged in the order of this list with the last file overriding
// the first. Ignored when omitted.
// +optional
ValuesFiles []string `json:"valuesFiles,omitempty"`
// Alternative values file to use as the default chart values, expected to
// be a relative path in the SourceRef. Deprecated in favor of ValuesFiles,
// for backwards compatibility the file defined here is merged before the
// ValuesFiles items. Ignored when omitted.
// +optional
// +deprecated
ValuesFile string `json:"valuesFile,omitempty"`
}
// Install holds the configuration for Helm install actions performed for this
// HelmRelease.
type Install struct {
// Timeout is the time to wait for any individual Kubernetes operation (like
// Jobs for hooks) during the performance of a Helm install action. Defaults to
// 'HelmReleaseSpec.Timeout'.
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// Remediation holds the remediation configuration for when the Helm install
// action for the HelmRelease fails. The default is to not perform any action.
// +optional
Remediation *InstallRemediation `json:"remediation,omitempty"`
// DisableWait disables the waiting for resources to be ready after a Helm
// install has been performed.
// +optional
DisableWait bool `json:"disableWait,omitempty"`
// DisableWaitForJobs disables waiting for jobs to complete after a Helm
// install has been performed.
// +optional
DisableWaitForJobs bool `json:"disableWaitForJobs,omitempty"`
// DisableHooks prevents hooks from running during the Helm install action.
// +optional
DisableHooks bool `json:"disableHooks,omitempty"`
// DisableOpenAPIValidation prevents the Helm install action from validating
// rendered templates against the Kubernetes OpenAPI Schema.
// +optional
DisableOpenAPIValidation bool `json:"disableOpenAPIValidation,omitempty"`
// Replace tells the Helm install action to re-use the 'ReleaseName', but only
// if that name is a deleted release which remains in the history.
// +optional
Replace bool `json:"replace,omitempty"`
// SkipCRDs tells the Helm install action to not install any CRDs. By default,
// CRDs are installed if not already present.
//
// Deprecated use CRD policy (`crds`) attribute with value `Skip` instead.
//
// +deprecated
// +optional
SkipCRDs bool `json:"skipCRDs,omitempty"`
// CRDs upgrade CRDs from the Helm Chart's crds directory according
// to the CRD upgrade policy provided here. Valid values are `Skip`,
// `Create` or `CreateReplace`. Default is `Create` and if omitted
// CRDs are installed but not updated.
//
// Skip: do neither install nor replace (update) any CRDs.
//
// Create: new CRDs are created, existing CRDs are neither updated nor deleted.
//
// CreateReplace: new CRDs are created, existing CRDs are updated (replaced)
// but not deleted.
//
// By default, CRDs are applied (installed) during Helm install action.
// With this option users can opt-in to CRD replace existing CRDs on Helm
// install actions, which is not (yet) natively supported by Helm.
// https://helm.sh/docs/chart_best_practices/custom_resource_definitions.
//
// +kubebuilder:validation:Enum=Skip;Create;CreateReplace
// +optional
CRDs CRDsPolicy `json:"crds,omitempty"`
// CreateNamespace tells the Helm install action to create the
// HelmReleaseSpec.TargetNamespace if it does not exist yet.
// On uninstall, the namespace will not be garbage collected.
// +optional
CreateNamespace bool `json:"createNamespace,omitempty"`
}
// InstallRemediation holds the configuration for Helm install remediation.
type InstallRemediation struct {
// Retries is the number of retries that should be attempted on failures before
// bailing. Remediation, using an uninstall, is performed between each attempt.
// Defaults to '0', a negative integer equals to unlimited retries.
// +optional
Retries int `json:"retries,omitempty"`
// IgnoreTestFailures tells the controller to skip remediation when the Helm
// tests are run after an install action but fail. Defaults to
// 'Test.IgnoreFailures'.
// +optional
IgnoreTestFailures *bool `json:"ignoreTestFailures,omitempty"`
// RemediateLastFailure tells the controller to remediate the last failure, when
// no retries remain. Defaults to 'false'.
// +optional
RemediateLastFailure *bool `json:"remediateLastFailure,omitempty"`
}
// Upgrade holds the configuration for Helm upgrade actions for this
// HelmRelease.
type Upgrade struct {
// Timeout is the time to wait for any individual Kubernetes operation (like
// Jobs for hooks) during the performance of a Helm upgrade action. Defaults to
// 'HelmReleaseSpec.Timeout'.
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// Remediation holds the remediation configuration for when the Helm upgrade
// action for the HelmRelease fails. The default is to not perform any action.
// +optional
Remediation *UpgradeRemediation `json:"remediation,omitempty"`
// DisableWait disables the waiting for resources to be ready after a Helm
// upgrade has been performed.
// +optional
DisableWait bool `json:"disableWait,omitempty"`
// DisableWaitForJobs disables waiting for jobs to complete after a Helm
// upgrade has been performed.
// +optional
DisableWaitForJobs bool `json:"disableWaitForJobs,omitempty"`
// DisableHooks prevents hooks from running during the Helm upgrade action.
// +optional
DisableHooks bool `json:"disableHooks,omitempty"`
// DisableOpenAPIValidation prevents the Helm upgrade action from validating
// rendered templates against the Kubernetes OpenAPI Schema.
// +optional
DisableOpenAPIValidation bool `json:"disableOpenAPIValidation,omitempty"`
// Force forces resource updates through a replacement strategy.
// +optional
Force bool `json:"force,omitempty"`
// PreserveValues will make Helm reuse the last release's values and merge in
// overrides from 'Values'. Setting this flag makes the HelmRelease
// non-declarative.
// +optional
PreserveValues bool `json:"preserveValues,omitempty"`
// CleanupOnFail allows deletion of new resources created during the Helm
// upgrade action when it fails.
// +optional
CleanupOnFail bool `json:"cleanupOnFail,omitempty"`
// CRDs upgrade CRDs from the Helm Chart's crds directory according
// to the CRD upgrade policy provided here. Valid values are `Skip`,
// `Create` or `CreateReplace`. Default is `Skip` and if omitted
// CRDs are neither installed nor upgraded.
//
// Skip: do neither install nor replace (update) any CRDs.
//
// Create: new CRDs are created, existing CRDs are neither updated nor deleted.
//
// CreateReplace: new CRDs are created, existing CRDs are updated (replaced)
// but not deleted.
//
// By default, CRDs are not applied during Helm upgrade action. With this
// option users can opt-in to CRD upgrade, which is not (yet) natively supported by Helm.
// https://helm.sh/docs/chart_best_practices/custom_resource_definitions.
//
// +kubebuilder:validation:Enum=Skip;Create;CreateReplace
// +optional
CRDs CRDsPolicy `json:"crds,omitempty"`
}
// UpgradeRemediation holds the configuration for Helm upgrade remediation.
type UpgradeRemediation struct {
// Retries is the number of retries that should be attempted on failures before
// bailing. Remediation, using 'Strategy', is performed between each attempt.
// Defaults to '0', a negative integer equals to unlimited retries.
// +optional
Retries int `json:"retries,omitempty"`
// IgnoreTestFailures tells the controller to skip remediation when the Helm
// tests are run after an upgrade action but fail.
// Defaults to 'Test.IgnoreFailures'.
// +optional
IgnoreTestFailures *bool `json:"ignoreTestFailures,omitempty"`
// RemediateLastFailure tells the controller to remediate the last failure, when
// no retries remain. Defaults to 'false' unless 'Retries' is greater than 0.
// +optional
RemediateLastFailure *bool `json:"remediateLastFailure,omitempty"`
// Strategy to use for failure remediation. Defaults to 'rollback'.
// +kubebuilder:validation:Enum=rollback;uninstall
// +optional
Strategy *RemediationStrategy `json:"strategy,omitempty"`
}
// Test holds the configuration for Helm test actions for this HelmRelease.
type Test struct {
// Enable enables Helm test actions for this HelmRelease after an Helm install
// or upgrade action has been performed.
// +optional
Enable bool `json:"enable,omitempty"`
// Timeout is the time to wait for any individual Kubernetes operation during
// the performance of a Helm test action. Defaults to 'HelmReleaseSpec.Timeout'.
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// IgnoreFailures tells the controller to skip remediation when the Helm tests
// are run but fail. Can be overwritten for tests run after install or upgrade
// actions in 'Install.IgnoreTestFailures' and 'Upgrade.IgnoreTestFailures'.
// +optional
IgnoreFailures bool `json:"ignoreFailures,omitempty"`
}
// Rollback holds the configuration for Helm rollback actions for this
// HelmRelease.
type Rollback struct {
// Timeout is the time to wait for any individual Kubernetes operation (like
// Jobs for hooks) during the performance of a Helm rollback action. Defaults to
// 'HelmReleaseSpec.Timeout'.
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// DisableWait disables the waiting for resources to be ready after a Helm
// rollback has been performed.
// +optional
DisableWait bool `json:"disableWait,omitempty"`
// DisableWaitForJobs disables waiting for jobs to complete after a Helm
// rollback has been performed.
// +optional
DisableWaitForJobs bool `json:"disableWaitForJobs,omitempty"`
// DisableHooks prevents hooks from running during the Helm rollback action.
// +optional
DisableHooks bool `json:"disableHooks,omitempty"`
// Recreate performs pod restarts for the resource if applicable.
// +optional
Recreate bool `json:"recreate,omitempty"`
// Force forces resource updates through a replacement strategy.
// +optional
Force bool `json:"force,omitempty"`
// CleanupOnFail allows deletion of new resources created during the Helm
// rollback action when it fails.
// +optional
CleanupOnFail bool `json:"cleanupOnFail,omitempty"`
}
// Uninstall holds the configuration for Helm uninstall actions for this
// HelmRelease.
type Uninstall struct {
// Timeout is the time to wait for any individual Kubernetes operation (like
// Jobs for hooks) during the performance of a Helm uninstall action. Defaults
// to 'HelmReleaseSpec.Timeout'.
// +optional
Timeout *metav1.Duration `json:"timeout,omitempty"`
// DisableHooks prevents hooks from running during the Helm rollback action.
// +optional
DisableHooks bool `json:"disableHooks,omitempty"`
// KeepHistory tells Helm to remove all associated resources and mark the
// release as deleted, but retain the release history.
// +optional
KeepHistory bool `json:"keepHistory,omitempty"`
// DisableWait disables waiting for all the resources to be deleted after
// a Helm uninstall is performed.
// +optional
DisableWait bool `json:"disableWait,omitempty"`
}
// Kustomize Helm PostRenderer specification.
type Kustomize struct {
// Strategic merge patches, defined as inline YAML objects.
// +optional
PatchesStrategicMerge []apiextensionsv1.JSON `json:"patchesStrategicMerge,omitempty"`
// JSON 6902 patches, defined as inline YAML objects.
// +optional
PatchesJSON6902 []kustomize.JSON6902Patch `json:"patchesJson6902,omitempty"`
// Images is a list of (image name, new name, new tag or digest)
// for changing image names, tags or digests. This can also be achieved with a
// patch, but this operator is simpler to specify.
// +optional
Images []kustomize.Image `json:"images,omitempty" yaml:"images,omitempty"`
}
// PostRenderer contains a Helm PostRenderer specification.
type PostRenderer struct {
// Kustomization to apply as PostRenderer.
// +optional
Kustomize *Kustomize `json:"kustomize,omitempty"`
}
```
### Reference types
```go
// CrossNamespaceObjectReference contains enough information to let you locate the
// typed referenced object at cluster level.
type CrossNamespaceObjectReference struct {
// APIVersion of the referent.
// +optional
APIVersion string `json:"apiVersion,omitempty"`
// Kind of the referent.
// +kubebuilder:validation:Enum=HelmRepository
// +required
Kind string `json:"kind,omitempty"`
// Name of the referent.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +required
Name string `json:"name"`
// Namespace of the referent.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=63
// +kubebuilder:validation:Optional
// +optional
Namespace string `json:"namespace,omitempty"`
}
// ValuesReference contains a reference to a resource containing Helm values,
// and optionally the key they can be found at.
type ValuesReference struct {
// Kind of the values referent, valid values are ('Secret', 'ConfigMap').
// +kubebuilder:validation:Enum=Secret;ConfigMap
// +required
Kind string `json:"kind"`
// Name of the values referent. Should reside in the same namespace as the
// referring resource.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +required
Name string `json:"name"`
// ValuesKey is the data key where the values.yaml or a specific value can be
// found at. Defaults to 'values.yaml'.
// +optional
ValuesKey string `json:"valuesKey,omitempty"`
// TargetPath is the YAML dot notation path the value should be merged at. When
// set, the ValuesKey is expected to be a single flat value. Defaults to 'None',
// which results in the values getting merged at the root.
// +optional
TargetPath string `json:"targetPath,omitempty"`
// Optional marks this ValuesReference as optional. When set, a not found error
// for the values reference is ignored, but any ValuesKey, TargetPath or
// transient error will still result in a reconciliation failure.
// +optional
Optional bool `json:"optional,omitempty"`
}
```
### Status specification
```go
// HelmReleaseStatus defines the observed state of a HelmRelease.
type HelmReleaseStatus struct {
// ObservedGeneration is the last observed generation.
// +optional
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// LastHandledReconcileAt is the last manual reconciliation request (by
// annotating the HelmRelease) handled by the reconciler.
// +optional
LastHandledReconcileAt string `json:"lastHandledReconcileAt,omitempty"`
// Conditions holds the conditions for the HelmRelease.
// +optional
Conditions []meta.Condition `json:"conditions,omitempty"`
// LastAppliedRevision is the revision of the last successfully applied source.
// +optional
LastAppliedRevision string `json:"lastAppliedRevision,omitempty"`
// LastAttemptedRevision is the revision of the last reconciliation attempt.
// +optional
LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
// LastAttemptedValuesChecksum is the SHA1 checksum of the values of the last
// reconciliation attempt.
// +optional
LastAttemptedValuesChecksum string `json:"lastAttemptedValuesChecksum,omitempty"`
// LastReleaseRevision is the revision of the last successful Helm release.
// +optional
LastReleaseRevision int `json:"lastReleaseRevision,omitempty"`
// HelmChart is the namespaced name of the HelmChart resource created by
// the controller for the HelmRelease.
// +optional
HelmChart string `json:"helmChart,omitempty"`
// Failures is the reconciliation failure count against the latest observed
// state. It is reset after a successful reconciliation.
// +optional
Failures int64 `json:"failures,omitempty"`
// InstallFailures is the install failure count against the latest observed
// state. It is reset after a successful reconciliation.
// +optional
InstallFailures int64 `json:"installFailures,omitempty"`
// UpgradeFailures is the upgrade failure count against the latest observed
// state. It is reset after a successful reconciliation.
// +optional
UpgradeFailures int64 `json:"upgradeFailures,omitempty"`
}
```
#### Condition types
```go
const (
// ReleasedCondition represents the status of the last release attempt
// (install/upgrade/test) against the latest desired state.
ReleasedCondition string = "Released"
// TestSuccessCondition represents the status of the last test attempt against
// the latest desired state.
TestSuccessCondition string = "TestSuccess"
// RemediatedCondition represents the status of the last remediation attempt
// (uninstall/rollback) due to a failure of the last release attempt against the
// latest desired state.
RemediatedCondition string = "Remediated"
)
```
#### Condition reasons
```go
const (
// InstallSucceededReason represents the fact that the Helm install for the
// HelmRelease succeeded.
InstallSucceededReason string = "InstallSucceeded"
// InstallFailedReason represents the fact that the Helm install for the
// HelmRelease failed.
InstallFailedReason string = "InstallFailed"
// UpgradeSucceededReason represents the fact that the Helm upgrade for the
// HelmRelease succeeded.
UpgradeSucceededReason string = "UpgradeSucceeded"
// UpgradeFailedReason represents the fact that the Helm upgrade for the
// HelmRelease failed.
UpgradeFailedReason string = "UpgradeFailed"
// TestSucceededReason represents the fact that the Helm tests for the
// HelmRelease succeeded.
TestSucceededReason string = "TestSucceeded"
// TestFailedReason represents the fact that the Helm tests for the HelmRelease
// failed.
TestFailedReason string = "TestFailed"
// RollbackSucceededReason represents the fact that the Helm rollback for the
// HelmRelease succeeded.
RollbackSucceededReason string = "RollbackSucceeded"
// RollbackFailedReason represents the fact that the Helm test for the
// HelmRelease failed.
RollbackFailedReason string = "RollbackFailed"
// UninstallSucceededReason represents the fact that the Helm uninstall for the
// HelmRelease succeeded.
UninstallSucceededReason string = "UninstallSucceeded"
// UninstallFailedReason represents the fact that the Helm uninstall for the
// HelmRelease failed.
UninstallFailedReason string = "UninstallFailed"
// ArtifactFailedReason represents the fact that the artifact download for the
// HelmRelease failed.
ArtifactFailedReason string = "ArtifactFailed"
// InitFailedReason represents the fact that the initialization of the Helm
// configuration failed.
InitFailedReason string = "InitFailed"
// GetLastReleaseFailedReason represents the fact that observing the last
// release failed.
GetLastReleaseFailedReason string = "GetLastReleaseFailed"
)
```
## Helm release placement
The namespace/name in which to deploy and store the Helm release defaults to the namespace/name
of the `HelmRelease`. These can be overridden respectively via `spec.targetNamespace`,
`spec.storageNamespace` and `spec.releaseName`. If `spec.targetNamespace` is set,
`spec.releaseName` defaults to `<spec.targetNamespace>-<metadata.name>`.
> **Note:** that configuring the `spec.targetNamespace` only defines the namespace the release
> is made in, the metadata for the release (also known as the "Helm storage") will be stored in
> the `metadata.namespace` or `spec.storageNamespace` of the `HelmRelease`.
## Helm chart template
The `spec.chart.spec` values are used by the helm-controller as a template
to create a new `HelmChart` resource with the given spec.
The `spec.chart.spec.sourceRef` is a reference to an object managed by
[source-controller](https://github.com/fluxcd/source-controller). When the source
[revision](https://pkg.go.dev/github.com/fluxcd/source-controller/api/v1beta2#Artifact)
changes, it generates a Kubernetes event that triggers a new release.
Supported source types:
- [HelmRepository](https://github.com/fluxcd/source-controller/blob/main/docs/spec/v1beta2/helmrepositories.md)
- [GitRepository](https://github.com/fluxcd/source-controller/blob/main/docs/spec/v1beta2/gitrepositories.md)
- [Bucket](https://github.com/fluxcd/source-controller/blob/main/docs/spec/v1beta2/buckets.md)
The `HelmChart` is created in the same namespace as the `sourceRef`,
with a name matching the `HelmRelease` `<metadata.namespace>-<metadata.name>`.
> **Note** that on multi-tenant clusters, platform admins can disable cross-namespace references
> with the `--no-cross-namespace-refs=true` flag. When this flag is set, the helmrelease can only
> refer to sources in the same namespace as the helmrelease object.
The `chart.spec.chart` can either contain:
- The name of the chart as made available by the `HelmRepository`
(without any aliases), for example: `podinfo`
- The relative path the chart can be found at in the `GitRepository`,
for example: `./charts/podinfo`
The `chart.spec.version` can be a fixed semver, or any semver range
(i.e. `>=4.0.0 <5.0.0`). It is ignored for `HelmRelease` resources
that reference a `GitRepository` or `Bucket` source.
## Values overrides
The simplest way to define values overrides is inline via `spec.values`.
It is also possible to define a list of `ConfigMap` and `Secret` resources
from which to take values via `spec.valuesFrom`. The values are merged in the order given,
with the later values overwriting earlier, and then `spec.values` overwriting those:
```yaml
spec:
values:
replicaCount: 2
valuesFrom:
- kind: ConfigMap
name: prod-env-values
valuesKey: values-prod.yaml
- kind: Secret
name: prod-tls-values
valuesKey: crt
targetPath: tls.crt
optional: true
```
The definition of the listed keys for items in `spec.valuesFrom` is as follows:
- `kind`: Kind of the values referent (`ConfigMap` or `Secret`).
- `name`: Name of the values referent, in the same namespace as the
`HelmRelease`.
- `valuesKey` _(Optional)_: The data key where the values.yaml or a
specific value can be found. Defaults to `values.yaml` when omitted.
- `targetPath` _(Optional)_: The YAML dot notation path at which the
value should be merged. When set, the `valuesKey` is expected to be
a single flat value. Defaults to `None` when omitted, which results
in the values getting merged at the root.
- `optional` _(Optional)_: Whether this values reference is optional. When `true`,
a not found error for the values reference is ignored, but any valuesKey, targetPath or
transient error will still result in a reconciliation failure. Defaults to `false`
when omitted.
> **Note:** that the `targetPath` supports the same formatting as you would supply as an
> argument to the `helm` binary using `--set [path]=[value]`. In addition to this, the
> referred value can contain the same value formats (e.g. `{a,b,c}` for a list). You can
> read more about the available formats and limitations in the
> [Helm documentation](https://helm.sh/docs/intro/using_helm/#the-format-and-limitations-of---set).
## Reconciliation
If no Helm release with the matching namespace/name is found it will be installed. It will
be upgraded any time the desired state is updated, which consists of:
- `spec` (and thus `metadata.generation`)
- Latest `HelmChart` revision available
- [`ConfigMap` and `Secret` values overrides](#values-overrides). Changes to these do not trigger an
immediate reconciliation, but will be handled upon the next reconciliation. This is to avoid
a large number of upgrades occurring when multiple resources are updated.
If the latest Helm release revision was not made by the helm-controller, it may not match the
desired state, so an upgrade is made in this case as well.
The `spec.interval` tells the reconciler at which interval to reconcile the release. The
interval time units are `s`, `m` and `h` e.g. `interval: 5m`, the minimum value should be 60 seconds.
The reconciler can be told to reconcile the `HelmRelease` outside of the specified interval
by annotating the object with a `reconcile.fluxcd.io/requestedAt` annotation. For example:
```bash
kubectl annotate --overwrite helmrelease/podinfo reconcile.fluxcd.io/requestedAt="$(date +%s)"
```
Reconciliation can be suspended by setting `spec.suspend` to `true`.
The timeout for any individual Kubernetes operation (like Jobs for hooks) during the performance
of Helm actions can be configured via `spec.timeout` and can be overridden per action
via `spec.<action>.timeout`.
List all Kubernetes objects reconciled from a HelmRelease:
```sh
kubectl get all --all-namespaces \
-l=helm.toolkit.fluxcd.io/name="<HelmRelease name>" \
-l=helm.toolkit.fluxcd.io/namespace="<HelmRelease namespace>"
```
### Disabling resource waiting
For install, upgrade, rollback, and uninstall actions resource waiting is
enabled by default, but can be disabled by setting `spec.<action>.disableWait`.
Waiting for jobs to complete is enabled by default,
but can be disabled by setting `spec.<action>.disableWaitForJobs`.
### `HelmRelease` dependencies
When applying a `HelmRelease`, you may need to make sure other releases are [Ready](#status)
before the release is reconciled. For example, because your chart relies on the presence of
a Custom Resource Definition installed by another `HelmRelease`. The `spec.dependsOn` field
allows you to specify each of these dependencies.
Assuming two `HelmRelease` resources:
- `backend` - contains the backend of the application
- `frontend` - contains the frontend of the application and relies on the backend
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: backend
namespace: default
spec:
interval: 5m
chart:
spec:
chart: podinfo
version: ">=4.0.0 <5.0.0"
sourceRef:
kind: HelmRepository
name: podinfo
namespace: default
interval: 1m
upgrade:
remediation:
remediateLastFailure: true
test:
enable: true
values:
service:
grpcService: backend
resources:
requests:
cpu: 100m
memory: 64Mi
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: frontend
namespace: default
spec:
interval: 5m
chart:
spec:
chart: podinfo
version: ">=4.0.0 <5.0.0"
sourceRef:
kind: HelmRepository
name: podinfo
namespace: default
interval: 1m
dependsOn:
- name: backend
upgrade:
remediation:
remediateLastFailure: true
test:
enable: true
values:
backend: http://backend-podinfo:9898/echo
resources:
requests:
cpu: 100m
memory: 64Mi
```
> **Note** that this does not account for upgrade ordering. Kubernetes only allows
> applying one resource (`HelmRelease` in this case) at a time, so there is no way for the
> controller to know when a dependency `HelmRelease` may be updated. Also, circular
> dependencies between `HelmRelease` resources must be avoided, otherwise the
> interdependent `HelmRelease` resources will never be reconciled.
### Configuring Helm test actions
To make the controller run the Helm tests available for your chart after a successful Helm install
or upgrade, `spec.test.enable` should be set to `true`.
By default, when tests are enabled, failures in tests are considered release failures, and thus
are subject to the triggering Helm action's `remediation` configuration. However, test failures
can be ignored by setting `spec.test.ignoreFailures` to `true`. In this case, no remediation will
be taken, and the test failure will not affect the `Released` and `Ready` status conditions. This
can be overridden per Helm action by setting `spec.install.remediation.ignoreTestFailures`
or `spec.upgrade.remediation.ignoreTestFailures`.
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo
namespace: default
spec:
interval: 5m
chart:
spec:
chart: podinfo
version: ">=4.0.0 <5.0.0"
sourceRef:
kind: HelmRepository
name: podinfo
namespace: default
interval: 1m
test:
enable: true
ignoreFailures: true
values:
resources:
requests:
cpu: 100m
memory: 64Mi
```
### Configuring failure remediation
From time to time a Helm install/upgrade and accompanying [Helm test](#configuring-helm-test-actions)
may fail. When this occurs, by default no action is taken, and the release is left in a failed state.
However, several automatic failure remediation options can be set via
`spec.install.remediation` and `spec.upgrade.remediation`.
The `retries` can be set to configure the number of retries after an initial
failure. A negative integer results in infinite retries. This implicitly opts-in to a remediation
action between each attempt. The remediation action for install failures is an uninstall. The
remediation action for upgrade failures is by default a rollback, however
`spec.upgrade.remediation.strategy` can be set to `uninstall`, in which case after the uninstall,
the `spec.install` configuration takes over.
One can also opt-in to remediation of the last failure (when no retries remain) by setting
`spec.<action>.remediation.remediateLastFailure` to `true`. For upgrades, this defaults
to true if at least one retry is configured.
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo
namespace: default
spec:
interval: 5m
chart:
spec:
chart: podinfo
version: ">=4.0.0 <5.0.0"
sourceRef:
kind: HelmRepository
name: podinfo
namespace: default
interval: 1m
install:
remediation:
retries: 3
upgrade:
remediation:
remediateLastFailure: false
values:
resources:
requests:
cpu: 100m
memory: 64Mi
```
## Role-based access control
By default, a `HelmRelease` runs under the cluster admin account and can create, modify, delete cluster level objects
(cluster roles, cluster role binding, CRDs, etc) and namespeced objects (deployments, ingresses, etc).
For certain `HelmReleases` a cluster admin may wish to control what types of Kubernetes objects can
be reconciled and under which namespace.
To restrict a `HelmRelease`, one can assign a service account under which the reconciliation is performed.
Assuming you want to restrict a group of `HelmReleases` to a single namespace, you can create an account
with a role binding that grants access only to that namespace:
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: webapp
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: webapp-reconciler
namespace: webapp
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: webapp-reconciler
namespace: webapp
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: webapp-reconciler
namespace: webapp
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: webapp-reconciler
subjects:
- kind: ServiceAccount
name: webapp-reconciler
namespace: webapp
```
> **Note** that the namespace, RBAC and service account manifests should be
> placed in a Git source and applied with a Kustomization.
Create a `HelmRelease` that prevents altering the cluster state outside of the `webapp` namespace:
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: podinfo
namespace: webapp
spec:
serviceAccountName: webapp-reconciler
interval: 5m
chart:
spec:
chart: podinfo
sourceRef:
kind: HelmRepository
name: podinfo
```
When the controller reconciles the `podinfo` release, it will impersonate the `webapp-reconciler`
account. If the chart contains cluster level objects like CRDs, the reconciliation will fail since
the account it runs under has no permissions to alter objects outside of the `webapp` namespace.
### Enforce impersonation
On multi-tenant clusters, platform admins can enforce impersonation with the
`--default-service-account` flag.
When the flag is set, all HelmReleases which don't have `spec.serviceAccountName` specified
will use the service account name provided by `--default-service-account=<SA Name>`
in the namespace of the object.
## Remote Clusters / Cluster-API
If the `spec.kubeConfig` field is set, Helm actions will run against the default cluster specified
in that KubeConfig instead of the local cluster that is responsible for the reconciliation of the
HelmRelease.
The secret defined in the `spec.kubeConfig.secretRef` must exist in the same namespace as the
HelmRelease. On every reconciliation, the KubeConfig bytes will be loaded from the `.secretRef.key`
key (default: `value` or `value.yaml`) of the Secret's data , and the Secret can thus be regularly
updated if cluster-access-tokens have to rotate due to expiration.
The Helm storage is stored on the remote cluster in a namespace that equals to the namespace of
the HelmRelease, or the configured `spec.storageNamespace`. The release itself is made in a
namespace that equals to the namespace of the HelmRelease, or the configured `spec.targetNamespace`.
The namespaces are expected to exist, with the exception that `spec.targetNamespace` can be
created on demand by Helm when `spec.install.createNamespace` is set to `true`.
Other references to Kubernetes resources in the HelmRelease, like ValuesReference resources,
are expected to exist on the reconciling cluster.
This composes well with Cluster API bootstrap providers such as CAPBK (kubeadm), as well as the
CAPA (AWS) EKS integration.
To reconcile a HelmRelease to a CAPI controlled cluster, put the HelmRelease in the same
namespace as your Cluster object, and set the `spec.kubeConfig.secretRef.name` to
`<cluster-name>-kubeconfig`:
```yaml
apiVersion: cluster.x-k8s.io/v1alpha3
kind: Cluster
metadata:
name: stage # the kubeconfig Secret will contain the Cluster name
namespace: capi-stage
spec:
clusterNetwork:
pods:
cidrBlocks:
- 10.100.0.0/16
serviceDomain: stage-cluster.local
services:
cidrBlocks:
- 10.200.0.0/12
controlPlaneRef:
apiVersion: controlplane.cluster.x-k8s.io/v1alpha3
kind: KubeadmControlPlane
name: stage-control-plane
namespace: capi-stage
infrastructureRef:
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3
kind: DockerCluster
name: stage
namespace: capi-stage
---
# ... unrelated Cluster API objects omitted for brevity ...
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: kube-prometheus-stack
namespace: capi-stage
spec:
kubeConfig:
secretRef:
name: stage-kubeconfig # Cluster API creates this for the matching Cluster
chart:
spec:
chart: prometheus
version: ">=4.0.0 <5.0.0"
sourceRef:
kind: HelmRepository
name: prometheus-community
install:
remediation:
retries: -1
```
The Cluster and HelmRelease can be created at the same time if the install remediation
configuration is set to a forgiving amount of retries. The HelmRelease will then eventually
reconcile once the cluster is available.
If you wish to target clusters created by other means than CAPI, you can create a ServiceAccount
on the remote cluster, generate a KubeConfig for that account, and then create a secret on the
cluster where helm-controller is running e.g.:
```sh
kubectl -n default create secret generic prod-kubeconfig \
--from-file=value.yaml=./kubeconfig
```
> **Note** that the KubeConfig should be self-contained and not rely on binaries, environment,
> or credential files from the helm-controller Pod. This matches the constraints of KubeConfigs
> from current Cluster API providers. KubeConfigs with cmd-path in them likely won't work without
> a custom, per-provider installation of helm-controller.
When both `spec.kubeConfig` and `spec.ServiceAccountName` are specified,
the controller will impersonate the service account on the target cluster.
## Post Renderers
HelmRelease resources has a built-in [Kustomize](https://kubectl.docs.kubernetes.io/references/kustomize/builtins/)
compatible [Post Renderer](https://helm.sh/docs/topics/advanced/#post-rendering), which provides
the following Kustomize directives:
- [patches](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patches/)
- [patchesStrategicMerge](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesstrategicmerge/)
- [patchesJson6902](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/patchesjson6902/)
- [images](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/images/)
The following example uses the built-in `kustomize` _Post Renderer_ to apply a strategic merge patch,
which adds a [toleration](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/)
to the Helm rendered output:
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: metrics-server
namespace: kube-system
spec:
interval: 1m
chart:
spec:
chart: metrics-server
version: "5.3.4"
sourceRef:
kind: HelmRepository
name: bitnami
namespace: kube-system
interval: 1m
postRenderers:
# Instruct helm-controller to use built-in "kustomize" post renderer.
- kustomize:
# Array of inline strategic merge patch definitions as YAML object.
# Note, this is a YAML object and not a string, to avoid syntax
# indention errors.
patchesStrategicMerge:
- kind: Deployment
apiVersion: apps/v1
metadata:
name: metrics-server
spec:
template:
spec:
tolerations:
- key: "workload-type"
operator: "Equal"
value: "cluster-services"
effect: "NoSchedule"
# Array of inline JSON6902 patch definitions as YAML object.
# Note, this is a YAML object and not a string, to avoid syntax
# indention errors.
patchesJson6902:
- target:
version: v1
kind: Deployment
name: metrics-server
patch:
- op: add
path: /spec/template/priorityClassName
value: system-cluster-critical
images:
- name: docker.io/bitnami/metrics-server
newName: docker.io/bitnami/metrics-server
newTag: 0.4.1-debian-10-r54
```
## CRDs
Helm does support [installing CRDs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#method-1-let-helm-do-it-for-you),
but it has no native support for [upgrading CRDs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations):
> There is no support at this time for upgrading or deleting CRDs using Helm.
> This was an explicit decision after much community discussion due to the danger for unintentional
> data loss. Furthermore, there is currently no community consensus around how to handle CRDs and
> their lifecycle. As this evolves, Helm will add support for those use cases.
If your write your own Helm Charts you can work-around this limitation by putting your CRDs into
the `templates` instead of the `crds` directory or by out-factoring them into a separate Helm
Chart as suggested by the
[offical Helm documentation](https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#method-2-separate-charts).
However, if you have to integrate and use many existing (upstream) Helm Charts, not being able to
upgrade the CRDs via Flux's `HelmRelease` objects might become a cumbersome limitation within your GitOps
workflow. Therefore, Flux allows you to opt-in to upgrading CRDs by setting the `crds` policy on
the `HelmRelease.spec.install` and `HelmRelease.spec.upgrade` objects.
The following CRD upgrade policies are supported:
- `Skip` Skip CRDs do neither install nor replace (update) any CRDs.
- `Create` Only create new CRDs which do not yet exist, neither update nor delete any existing CRDs.
- `CreateReplace` Create new CRDs, update (replace) existing ones, but do **not** delete CRDs which
no longer exist in the current helm release.
**Example**:
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: my-operator
namespace: default
spec:
interval: 1m
chart:
spec:
chart: my-operator
version: "1.0.1"
sourceRef:
kind: HelmRepository
name: my-operator-repo
namespace: default
interval: 1m
install:
crds: CreateReplace
upgrade:
crds: CreateReplace
```
### Drift detection
**Note:** This feature is experimental and can be enabled by setting `--feature-gates=DetectDrift=true`.
When a HelmRelease is in-sync with the Helm release object in the storage, the controller will
compare the manifests from the Helm storage with the current state of the cluster using a
[server-side dry-run apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/).
If this comparison detects a drift (either due resource being created or modified during the
dry-run), the controller will perform an upgrade for the release, restoring the desired state.
### Excluding resources from drift detection
The drift detection feature can be configured to exclude certain resources from the comparison
by labeling or annotating them with `helm.toolkit.fluxcd.io/driftDetection: disabled`. Using
[post-renderers](#post-renderers), this can be applied to any resource rendered by Helm.
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: app
namespace: webapp
spec:
postRenderers:
- kustomize:
patches:
- target:
version: v1
kind: Deployment
name: my-app
patch: |
- op: add
path: /metadata/annotations/helm.toolkit.fluxcd.io~1driftDetection
value: disabled
```
**Note:** For some charts, we have observed the drift detection feature can detect spurious
changes due to Helm not properly patching an object, which seems to be related to
[Helm#5915](https://github.com/helm/helm/issues/5915) and issues alike. In this case (and
when possible for your workload), configuring `.spec.upgrade.force` to `true` might be a
more fitting solution than ignoring the object in full.
#### Drift exclusion example Prometheus Stack
```yaml
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: kube-prometheus-stack
spec:
interval: 5m
chart:
spec:
version: "45.x"
chart: kube-prometheus-stack
sourceRef:
kind: HelmRepository
name: prometheus-community
interval: 60m
upgrade:
crds: CreateReplace
# Force recreation due to Helm not properly patching Deployment with e.g. added port,
# causing spurious drift detection
force: true
postRenderers:
- kustomize:
patches:
- target:
# Ignore these objects from Flux diff as they are mutated from chart hooks
kind: (ValidatingWebhookConfiguration|MutatingWebhookConfiguration)
name: kube-prometheus-stack-admission
patch: |
- op: add
path: /metadata/annotations/helm.toolkit.fluxcd.io~1driftDetection
value: disabled
- target:
# Ignore these objects from Flux diff as they are mutated at apply time but not
# at dry-run time
kind: PrometheusRule
patch: |
- op: add
path: /metadata/annotations/helm.toolkit.fluxcd.io~1driftDetection
value: disabled
```
## Status
When the controller completes a reconciliation, it reports the result in the status sub-resource.
The following `status.conditions` types are advertised. Here, "desired state" is as detailed in
[reconciliation](#reconciliation):
- `Ready` - status of the last reconciliation attempt
- `Released` - status of the last release attempt (install/upgrade/test) against the latest desired state
- `TestSuccess` - status of the last test attempt against the latest desired state
- `Remediated` - status of the last remediation attempt (uninstall/rollback) due to a failure of the
last release attempt against the latest desired state
For example, you can wait for a successful helm-controller reconciliation with:
```sh
kubectl wait helmrelease/podinfo --for=condition=ready
```
Each of these conditions also include descriptive `reason` / `message` fields
as to why the status is as such.
### Examples
#### Install success
```yaml
status:
conditions:
- lastTransitionTime: "2020-07-13T13:13:40Z"
message: Helm install succeeded
reason: InstallSucceeded
status: "True"
type: Released
- lastTransitionTime: "2020-07-13T13:13:40Z"
message: Helm test succeeded
reason: TestSucceeded
status: "True"
type: TestSuccess
- lastTransitionTime: "2020-07-13T13:13:42Z"
message: release reconciliation succeeded
reason: ReconciliationSucceeded
status: "True"
type: Ready
lastAppliedRevision: 4.0.6
lastAttemptedRevision: 4.0.6
lastReleaseRevision: 1
observedGeneration: 2
```
#### Upgrade failure
```yaml
status:
conditions:
- lastTransitionTime: "2020-07-13T13:17:28Z"
message:
'error validating "": error validating data: ValidationError(Deployment.spec.replicas):
invalid type for io.k8s.api.apps.v1.DeploymentSpec.replicas: got "string",
expected "integer"'
reason: UpgradeFailed
status: "False"
type: Released
- lastTransitionTime: "2020-07-13T13:17:28Z"
message:
'error validating "": error validating data: ValidationError(Deployment.spec.replicas):
invalid type for io.k8s.api.apps.v1.DeploymentSpec.replicas: got "string",
expected "integer"'
reason: UpgradeFailed
status: "False"
type: Ready
failures: 1
lastAppliedRevision: 4.0.6
lastAttemptedRevision: 4.0.6
lastReleaseRevision: 1
observedGeneration: 3
```
#### Ignored test failure
```yaml
status:
conditions:
- lastTransitionTime: "2020-07-13T13:13:40Z"
message: Helm install succeeded
reason: InstallSucceeded
status: "True"
type: Released
- lastTransitionTime: "2020-07-13T13:13:40Z"
message: Helm test failed
reason: TestFailed
status: "False"
type: TestSuccess
- lastTransitionTime: "2020-07-13T13:13:42Z"
message: release reconciliation succeeded
reason: ReconciliationSucceeded
status: "True"
type: Ready
lastAppliedRevision: 4.0.6
lastAttemptedRevision: 4.0.6
lastReleaseRevision: 1
observedGeneration: 2
```