diff --git a/hips/README.md b/hips/README.md index 96abdd42..697db237 100644 --- a/hips/README.md +++ b/hips/README.md @@ -32,4 +32,5 @@ restricted markdown format and can be found in the - [hip-0021: Enhanced logging library for Helm](hip-0021.md) - [hip-0022: Wait With kstatus](hip-0022.md) - [hip-0023: Utilize Server Side Apply for installs/upgrades](hip-0023.md) -- [hip:0024: Improve the Helm Documentation](hip-0024.md) +- [hip-0024: Improve the Helm Documentation](hip-0024.md) +- [hip-0025: Better Support for Resource Creation Sequencing](hip-0025.md) diff --git a/hips/hip-0025.md b/hips/hip-0025.md new file mode 100644 index 00000000..3c8d908f --- /dev/null +++ b/hips/hip-0025.md @@ -0,0 +1,275 @@ +--- +hip: "0025" +title: "Better Support for Resource Creation Sequencing" +authors: [ "Joe Beck ", "Evans Mungai " ] +created: "2025-05-21" +type: "feature" +status: "draft" +--- + +## Abstract + +This HIP proposes a new feature set in Chart v3 to provide [Application Distributors](https://github.com/helm/community/blob/main/user-profiles.md#2-application-distributor)—a key Helm user profile—with a first-class mechanism for defining the deployment order of chart resources and subcharts. By default, Helm applies all rendered manifests simultaneously. This HIP introduces the ability for Helm to deploy resources in ordered batches and evaluate their readiness before proceeding. + +At a high level, this HIP proposes the following +- Ability for chart authors to specify how to sequence deployment of **resources within a single chart** +- Ability for chart authors to specify how to sequence **subcharts within a parent chart** +- Ability for Helm operators and tool developers to enable sequencing behaviour using `--wait=ordered` CLI flag and `WaitStrategy=ordered` SDK parameter respectively + +The HIP only targets resources deployed in the Helm install phase. Resources deployed as hooks are not sequenced using changes proposed here. Any sequencing of hooks will still rely on using `"helm.sh/hook-weight"` annotations. Annotations added to resources in hooks will be ignored. + +## Motivation + +The driving motivator here is to allow application distributors to control what order resources are bundled and sent to the K8s API server, referred to as resource sequencing for the rest of this HIP. + +Today, to accomplish resource sequencing, there are currently two main options: using Helm hooks, or building the sequencing logic into the application itself (e.g., using startup code or init containers). The existing hooks and weights can be tedious to build and maintain for application distributors, and built-in app sequencing can unnecessarily increase complexity of a Helm application that needs to be maintained by application distributors. Helm, as a package manager, should provide built-in mechanisms for sequencing resource deployment, reducing reliance on complex hooks or in-application logic. This will significantly improve the application distributor's experience. + +Additionally, Helm currently doesn't provide a way to sequence when chart dependencies are deployed and this featureset would ideally address this. + +## Rationale + +The proposed design prioritizes simplicity and ease of use for both Helm developers and chart authors. It leverages familiar YAML patterns and Helm conventions, avoiding heavyweight solutions while offering powerful orchestration capabilities. + +## Specification + +At a high level, allow Chart Developers to assign named dependencies to both their Helm templated resources and Helm chart dependencies that Helm then uses to generate a deployment sequence at installation time. + +For Helm CLI, the `--wait=ordered` flag will enable sequencing where resources are applied in groups. SDK users will also be able to enable sequencing by setting a `WaitStrategy` field. By default, resources are all applied at once which is the same behaviour in Chart v2. + +Each release will store information of whether sequencing was used or not. This information is used when performing uninstalls and rollbacks. + +### Sequencing Execution Flow + +When sequencing is enabled, Helm installs resources in a structured order across both subcharts and resource-groups: + +**1. Subchart Ordering** + +Helm builds a dependency graph from definitions in `Chart.yaml`: + +* `helm.sh/depends-on/subcharts` key in `annotations` field +* `depends-on` key on `dependencies` list entries + +Subcharts are installed in dependency order. Each subchart must be fully deployed and ready before its dependents begin. + +**2. Resource-Group Sequencing (Per Chart)** + +Within each chart (parent and subcharts), Helm builds a resource-group graph using: + +* `helm.sh/resource-group` +* `helm.sh/depends-on/resource-groups` + +Resources in each group are deployed together, and Helm waits for all to be ready before continuing to the next group. + +**3. Unsequenced Resources** + +Resources that: + +* lack annotations, +* depend on non-existent groups, or +* belong to isolated groups + +will be deployed after all properly sequenced groups have been processed. + +If a resource includes sequencing annotations but falls into this unsequenced category due to misconfiguration (e.g., referencing missing groups), Helm will emit a warning to alert the user of the potential issue. + +*Additions to templates* + +The following annotations would be added to enable this. +- `helm.sh/resource-group`: Annotation to declare a resource-group that a given resource belongs to. Any number of resources can belong to a group. A resource can only belong to one group. +- `helm.sh/depends-on/resource-groups`: Annotation to declare resource-groups that must exist and in a ready state before this resource can be deployed. The order in which they are listed does not affect deployment sequencing. + +These annotations are only used for sequencing resources within the same chart. They do not influence or interact with resources across charts or subcharts. + +*Additions to Chart.yaml* +* `helm.sh/depends-on/subcharts`: An annotation added to `Chart.yaml` to specify chart dependencies—identified by their `name` or `alias`—that must be fully deployed and in a ready state before the current chart resources can be installed. A dependent chart is considered ready only when all of its resources, including any defined sequencing, have been successfully deployed and marked ready. The order in which dependencies are listed has no effect on execution. +- `depends-on`: A new field added to `Chart.yaml` `dependencies` fields that is meant to declare a list of subcharts, by `name` or `alias`, that need to be ready before the subchart in question get installed. This will be used to create a dependency graph for subcharts. + +The installation process would group resources in the same group and send them to the K8s API Server in one bundle, and once all resources are "ready", the next group would be installed. A resource-group would not be considered "ready" and the next group installed until all resources in that group are considered "ready". Readiness is described in a later section. A similar process would apply for upgrades. Uninstalls would function on the same resource-group order, but in reverse, where a resource-group is not uninstalled until all resource-groups that depend on it are first uninstalled. Upgrades would follow the same order as installation. + +#### Template examples: +```yaml +# resource 1 +metadata: + name: db-service + annotations: + helm.sh/resource-group: database +--- +# resource 2 +metadata: + name: my-app + annotations: + helm.sh/resource-group: app + helm.sh/depends-on/resource-groups: ["database", "queue"] +--- +# resource 3 +metadata: + name: queue-processor + annotations: + helm.sh/resource-group: queue + helm.sh/depends-on/resource-groups: ["another-group"] + +``` +In this example, Helm would be responsible for resolving the annotations on these three resources and deploy all resources in the following order. Resources in `database` and `queue` resource-groups would be deployed at the same time. They would need to be ready before attempting to deploy `app` resource-group: + +``` +"database" group: [db-service] + || +"queue" group: || [queue-processor] + || || + || || + \/ \/ + \\ // + \\ // + \/ \/ +"app" group: [my-app] +``` + +#### Chart dependencies example + +To control the order in which subcharts are installed, upgraded, or uninstalled, chart authors must use the `helm.sh/depends-on/subcharts` annotation or the `depends-on` field in the `Chart.yaml`. These declarations enable Helm to determine the correct sequencing of subchart operations, as illustrated below. + +```yaml +name: foo +annotations: + helm.sh/depends-on/subcharts: ["bar", "rabbitmq"] +dependencies: + - name: nginx + version: "18.3.1" + repository: "oci://registry-1.docker.io/bitnamicharts" + - name: rabbitmq + version: "9.3.1" + repository: "oci://registry-1.docker.io/bitnamicharts" + - name: bar # This is a subchart packaged with "foo" in charts dir. It's not pulled from a remote location + version: "0.1.0" + depends-on: ["nginx", "rabbitmq"] + condition: bar.enabled +``` + +``` + [nginx] [rabbitmq] + || || + || || + \/ \/ + \\ // + \/ \/ + [bar] + || + || + \/ + [foo] +``` + +In this example, Helm will first install and wait for all resources of `nginx` and `rabbitmq` dependencies to be "ready" before attempting to install `bar` resources. Once all resources of `bar` are "ready" then and only then will `foo` chart resources be installed. `foo` would require `rabbitmq` to be ready but since the subchart resources would have been installed before `bar`, this requirement would have been fulfilled. + +This approach of building a directed acyclic graph (DAG) is prone to circular dependencies. During the templating phase, Helm will have logic to detect, and report any circular dependencies found in the chart templates. Helm will also provide a command to print the DAG for development and troubleshooting purposes. + +### Readiness + +To enforce sequencing, Helm determines whether resources are “ready” before deploying dependent resources. By default, Helm uses [`kstatus`](https://github.com/kubernetes-sigs/cli-utils/blob/master/pkg/kstatus/README.md#the-ready-condition) library to assess readiness based on the resource’s type and `.status` field. + +Chart authors can optionally override this behavior using the following annotations: + +* `helm.sh/readiness-success`: A list of custom success conditions. If any are true, the resource is marked **ready**. +* `helm.sh/readiness-failure`: A list of custom failure conditions. If any are true, the resource is marked **failed**, which takes precedence over any success check. + +Both `helm.sh/readiness-success` and `helm.sh/readiness-failure` must both be provided to override the default readiness logic. If only one is present, Helm will fall back to `kstatus` and emit a warning. Helm will also fail linting when only one of the two is defined, to prevent ambiguous readiness evaluation. + +#### JsonPath syntax + +The `readiness-success` and `readiness-failure` annotations accept lists of expressions with the format: + +``` +{} +``` + +Where: + +* `` is a [Kubernetes JSONPath](https://kubernetes.io/docs/reference/kubectl/jsonpath/) query scoped to `.status`. +* `` supports: `==`, `!=`, `<`, `<=`, `>`, `>=`. +* `` is the expected literal for comparison. The value should be a scalor (string, number, boolean). Object comparisons will not be supported. + +##### Example + +```yaml +kind: Job +metadata: + name: db-init + annotations: + helm.sh/readiness-success: ["{.succeeded} == 1", "{.succeeded} == 2"] + helm.sh/readiness-failure: ["{.failed} >= 1"] +status: + succeeded: 1 +``` + +In this case, Helm will consider the resource ready because `.status.succeeded == 1`. If `.status.failed >= 1` had been true, the Job would instead be marked as failed. + +A resources readiness is checked if there is a resource that depends on it as per the sequencing DAG, otherwise the checks are ignored. + +Helm will wait up to a default of **1 minute** for a resource to either succeed or fail. If the resource does not reach a success or failure state within this period, the operation will time out, causing the chart install or upgrade to fail. This timeout can be customized using the `--readiness-timeout` CLI flag or the `ReadinessTimeout` field in the SDK. However, the specified readiness timeout must not exceed the overall `--timeout` value, which defines the maximum duration allowed for the entire chart installation or upgrade process. + +### Sequencing order + +Resources with sequencing annotations in a chart would be deployed first followed by resources without. If the chart has a `helm.sh/depends-on/subcharts` annotation in the `Chart.yaml`, all resources of the defined subcharts would be deployed before deploying the main chart. If any sequencing annotations are defined in the subchart resources, Helm will enforce ordering of resources within. Sequencing of resources in a chart are sandboxed within the chart. Sequencing annotations will not affect resources in other charts. + +- Installs: Helm will install resources in the order defined by the DAG. If any of the readiness checks fail or timeout, the entire install would fail and the release marked as failed. If `--atomic`, or its SDK equivalent is used, a rollback to the last successful install would take place. +- Uninstalls: Helm would uninstall resources in the reverse order they were installed, as per the sequencing order. The logic to delete each resource will not change. +- Rollbacks: Helm will check from the release object whether the revision being rolled back to, was installed in a sequenced manner. If it was, Helm will respect and enforce this order when installing resources from that revision. When deleting unneeded resources of the revision being rolled back from, the reverse order is followed just like uninstalls. +- `helm template` would print all resources in the order they would be deployed. Groups of resources in a resource-group would be delimited using a `## START resource-group: / ` comment indicating the beginning of each resource-group and `END resource-group: / `. + +```yaml +## START resource-group: foo group1 +# resource 1 +metadata: + name: foo + annotations: + helm.sh/resource-group: group1 +--- +# resource 2 +metadata: + name: bar + annotations: + helm.sh/resource-group: group1 +## END resource-group: foo group1 +--- +## START resource-group: foo/bar group2 +# resource 3 +metadata: + name: fizz + annotations: + helm.sh/resource-group: group2 + helm.sh/depends-on/resource-groups: ["group1"] +## END resource-group: foo/bar group2 +``` + +## Backwards compatibility + +Helm will continue to install/upgrade/uninstall/rollback all resources and dependencies at one go for all charts using `Charts v2` and below. + +## Security implications + +None. + +## How to teach this + +- Document how sequencing works in the official helm documentation website. Include ordering of Kubernetes resources that Helm enforces when applying resources to the cluster. Examples will be added to best demonstrate how this feature works. +- Document how this feature works for SDK users. + +## Reference implementation + +N/A + +## Rejected ideas + +1. A weight based system, similar to Helm hooks + - Static numbering of the order is more challenging to develop and maintain + - Modifying the order can lead to cascading changes. + - Dynamically named system solves these problems for the application distributors. + +## Open issues + +## Prior raised issues + +- https://github.com/helm/helm/pull/12541 +- https://github.com/helm/helm/pull/9534 +- https://github.com/helm/helm/issues/8439 +- https://github.com/helm/community/pull/230