diff --git a/README-zh_CN.md b/README-zh_CN.md index 33cf1b80..dafa3ab9 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -72,7 +72,13 @@ Helmfile 是一个声明式Helm Chart管理工具 让我们从最简单的 helmfile 开始,逐渐改进它以适应您的用例! -假设表示您 helm releases 的期望状态的 helmfile.yaml 看起来像这样: +使用脚手架命令生成具有最佳实践目录结构的项目: + +```console +helmfile create my-project && cd my-project +``` + +或者手动创建 `helmfile.yaml`。假设表示您 helm releases 的期望状态的 helmfile.yaml 看起来像这样: ```yaml repositories: diff --git a/README.md b/README.md index 9f6b2d0e..e170cd0f 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,13 @@ requirements: [Go](https://golang.org/dl/) Let's start with a simple `helmfile` and gradually improve it to fit your use-case! -Suppose the `helmfile.yaml` representing the desired state of your helm releases looks like: +Generate a project scaffold with best-practice directory structure: + +```console +helmfile create my-project && cd my-project +``` + +Or create a `helmfile.yaml` manually. Suppose the `helmfile.yaml` representing the desired state of your helm releases looks like: ```yaml repositories: diff --git a/docs/advanced-features.md b/docs/advanced-features.md index 555c6bfc..63238b51 100644 --- a/docs/advanced-features.md +++ b/docs/advanced-features.md @@ -1,4 +1,4 @@ -## Advanced Features +# Advanced Features - [Resource Tracking with Kubedog](#resource-tracking-with-kubedog) - [Import Configuration Parameters into Helmfile](#import-configuration-parameters-into-helmfile) @@ -6,11 +6,11 @@ - [Adhoc Kustomization of Helm Charts](#adhoc-kustomization-of-helm-charts) - [Adding dependencies without forking the chart](#adding-dependencies-without-forking-the-chart) -### Resource Tracking with Kubedog +## Resource Tracking with Kubedog Helmfile can use [kubedog](https://github.com/werf/kubedog) for advanced resource tracking instead of Helm's built-in `--wait` flag. This provides more detailed feedback and control over deployment progress. -#### Basic Usage +### Basic Usage Enable kubedog tracking in your `helmfile.yaml`: @@ -29,13 +29,13 @@ Or use command-line flags: helmfile apply --track-mode kubedog --track-timeout 300 --track-logs ``` -#### Configuration Options +### Configuration Options - **`trackMode`**: Set to `kubedog` to enable kubedog tracking, or `helm-legacy` to use Helm v4's legacy wait mode (default: `helm`) - **`trackTimeout`**: Timeout in seconds for tracking resources (default: 300) - **`trackLogs`**: Enable real-time log streaming from tracked resources -#### Track Modes +### Track Modes Helmfile supports three track modes: @@ -43,7 +43,7 @@ Helmfile supports three track modes: - **`helm-legacy`**: Uses Helm v4's `--wait=legacy` flag. This is useful when migrating from Helm v3 to Helm v4 and you have charts that may have compatibility issues with the new watcher-based wait mechanism (e.g., charts with `livenessProbe` but no `startupProbe`). Note: This mode only works with Helm v4; with Helm v3 it falls back to regular `--wait`. - **`kubedog`**: Uses kubedog for advanced resource tracking with detailed feedback -#### Resource Filtering +### Resource Filtering Control which resources to track using whitelist/blacklist: @@ -62,7 +62,7 @@ releases: - Secret ``` -#### Specific Resource Tracking +### Specific Resource Tracking Track only specific resources by name and namespace: @@ -79,7 +79,7 @@ releases: name: myapp-job ``` -#### Priority Rules +### Priority Rules Resource filtering follows this priority (highest to lowest): @@ -87,14 +87,14 @@ Resource filtering follows this priority (highest to lowest): 2. **`skipKinds`**: Blacklist resource kinds 3. **`trackKinds`**: Whitelist resource kinds -#### Benefits +### Benefits - **Real-time feedback**: See deployment progress with detailed status updates - **Log streaming**: View container logs during deployment - **Fine-grained control**: Track only the resources you care about - **Better debugging**: Immediate visibility into deployment issues -#### Helm v4 Legacy Wait Mode +### Helm v4 Legacy Wait Mode When using Helm v4 with charts that have broken `livenessProbe` configurations without `startupProbe`, the default `--wait=watcher` mode may fail. Helm v4 introduces `--wait=legacy` which uses the simpler polling mechanism compatible with Helm v3's behavior. @@ -113,16 +113,32 @@ Or via command-line: helmfile apply --track-mode helm-legacy ``` -#### Compatibility +### Compatibility - **`helm`**: Default mode, uses Helm's built-in `--wait` flag - **`helm-legacy`**: Uses Helm v4's `--wait=legacy` flag (only available in Helm v4) - **`kubedog`**: Uses kubedog library for advanced resource tracking - Kubedog tracking is compatible with Helm 3.x and 4.x - Kubedog is a compiled dependency and is only used when `trackMode: kubedog` is set -- Works with charts that deploy supported workload kinds (currently `Deployment`, `StatefulSet`, `DaemonSet`, and `Job`); other resource kinds are created by Helm/Helmfile as usual but are ignored by the kubedog tracker +- Works with charts that deploy supported workload kinds (currently `Deployment`, `StatefulSet`, `DaemonSet`, `Job`, and `Canary`); other resource kinds are created by Helm/Helmfile as usual but are ignored by the kubedog tracker -### Import Configuration Parameters into Helmfile +### Advanced Kubedog Settings + +```yaml +releases: + - name: myapp + chart: ./charts/myapp + trackMode: kubedog + trackTimeout: 600 + trackLogs: true + kubedogQPS: 5.0 + kubedogBurst: 10 +``` + +- **`kubedogQPS`**: QPS (queries per second) for the kubedog kubernetes client (default: uses cluster defaults) +- **`kubedogBurst`**: Burst for the kubedog kubernetes client (default: uses cluster defaults) + +## Import Configuration Parameters into Helmfile Helmfile integrates [vals]() to import configuration parameters from following backends: @@ -136,7 +152,7 @@ See [Vals "Supported Backends"](https://github.com/helmfile/vals#supported-backe This feature was implemented in https://github.com/roboll/helmfile/pull/906. If you're curious about how it's designed and how it works, please review the pull request. -### Deploy Kustomizations with Helmfile +## Deploy Kustomizations with Helmfile You can deploy [kustomize](https://github.com/kubernetes-sigs/kustomize) "kustomization"s with Helmfile. @@ -212,7 +228,7 @@ After all, Helmfile just installs the temporary chart like standard charts, whic Please also see [test/advanced/helmfile.yaml](https://github.com/helmfile/helmfile/tree/master/test/advanced/helmfile.yaml) for an example of kustomization support and more. -### Adhoc Kustomization of Helm charts +## Adhoc Kustomization of Helm charts With Helmfile's integration with Kustomize, not only deploying Kustomization as a Helm chart, you can kustomize charts before installation. @@ -225,7 +241,7 @@ Currently, Helmfile allows you to set the following fields for kustomizing the c - `releases[].jsonPatches` - [`releases[].transformers`](#transformers) -#### `strategicMergePatches` +### `strategicMergePatches` You can add/update any Kubernetes resource field rendered from a Helm chart by specifying `releases[].strategicMergePatches`: @@ -269,7 +285,7 @@ There's also `releases[].jsonPatches` that works similarly to `strategicMergePat Please also see [test/advanced/helmfile.yaml](https://github.com/helmfile/helmfile/tree/master/test/advanced/helmfile.yaml) for an example of patching support and more. -#### `transformers` +### `transformers` You can set `transformers` to apply [Kustomize's transformers](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/configureBuiltinPlugin.md#configuring-the-builtin-plugins-instead). @@ -331,7 +347,7 @@ transformers: Please see https://github.com/kubernetes-sigs/kustomize/blob/master/examples/configureBuiltinPlugin.md#configuring-the-builtin-plugins-instead for more information on how to declare transformers. -### Adding dependencies without forking the chart +## Adding dependencies without forking the chart With Helmfile, you can add chart dependencies to a Helm chart without forking it. @@ -418,7 +434,7 @@ dependencies: Please read https://github.com/roboll/helmfile/issues/1762#issuecomment-816341251 for more details. -#### OCI chart dependencies +### OCI chart dependencies With Helmfile version v0.146.0 or later, you can add OCI chart to chart dependencies. @@ -433,7 +449,7 @@ releases: version: 1.5 ``` -### Lockfile per environment +## Lockfile per environment In some cases it can be handy for CI/CD pipelines to be able to roll out updates gradually for environments, such as staging and production while using the same set of charts. This can be achieved by using `lockFilePath` in combination with environments, such as: diff --git a/docs/builtin-objects.md b/docs/builtin-objects.md index a3039854..2daca963 100644 --- a/docs/builtin-objects.md +++ b/docs/builtin-objects.md @@ -1,4 +1,6 @@ -# helmfile template built-in objects +# Built-in Objects + +## helmfile template built-in objects - `Environment`: The information about the environment. This is set by the `--environment` flag. It has several objects inside of it: diff --git a/docs/cli.md b/docs/cli.md new file mode 100644 index 00000000..cc264720 --- /dev/null +++ b/docs/cli.md @@ -0,0 +1,380 @@ +# CLI Reference + +## CLI Reference + +``` +Declaratively deploy your Kubernetes manifests, Kustomize configs, and Charts as Helm releases in one shot +V1 mode = false +YAML library = go.yaml.in/yaml/v3 + +Usage: + helmfile [command] + +Available Commands: + apply Apply all resources from state file only when there are changes + build Build all resources from state file + create Create a helmfile deployment project scaffold + cache Cache management + charts DEPRECATED: sync releases from state file (helm upgrade --install) + completion Generate the autocompletion script for the specified shell + delete DEPRECATED: delete releases from state file (helm delete) + deps Update charts based on their requirements + destroy Destroys and then purges releases + diff Diff releases defined in state file + fetch Fetch charts from state file + help Help about any command + init Initialize the helmfile, includes version checking and installation of helm and plug-ins + lint Lint charts from state file (helm lint) + list List releases defined in state file + repos Add chart repositories defined in state file + show-dag It prints a table with 3 columns, GROUP, RELEASE, and DEPENDENCIES. GROUP is the unsigned, monotonically increasing integer starting from 1. All the releases with the same GROUP are deployed concurrently. Everything in GROUP 2 starts being deployed only after everything in GROUP 1 got successfully deployed. RELEASE is the release that belongs to the GROUP. DEPENDENCIES is the list of releases that the RELEASE depends on. It should always be empty for releases in GROUP 1. DEPENDENCIES for a release in GROUP 2 should have some or all dependencies appeared in GROUP 1. It can be "some" because Helmfile simplifies the DAGs of releases into a DAG of groups, so that Helmfile always produce a single DAG for everything written in helmfile.yaml, even when there are technically two or more independent DAGs of releases in it. + status Retrieve status of releases in state file + sync Sync releases defined in state file + template Template releases defined in state file + test Test charts from state file (helm test) + unittest Unit test charts from state file using helm-unittest plugin + version Print the CLI version + write-values Write values files for releases. Similar to `helmfile template`, write values files instead of manifests. + +Flags: + --allow-no-matching-release Do not exit with an error code if the provided selector has no matching releases. + -c, --chart string Set chart. Uses the chart set in release by default, and is available in template as {{ .Chart }} + --color Output with color + --debug Enable verbose output for Helm and set log-level to debug, this disables --quiet/-q effect + --disable-force-update do not force helm repos to update when executing "helm repo add" + --enable-live-output Show live output from the Helm binary Stdout/Stderr into Helmfile own Stdout/Stderr. + It only applies for the Helm CLI commands, Stdout/Stderr for Hooks are still displayed only when it's execution finishes. + -e, --environment string specify the environment name. Overrides "HELMFILE_ENVIRONMENT" OS environment variable when specified. defaults to "default" + -f, --file helmfile.yaml load config from file or directory. defaults to "helmfile.yaml" or "helmfile.yaml.gotmpl" or "helmfile.d" (means "helmfile.d/*.yaml" or "helmfile.d/*.yaml.gotmpl") in this preference. Specify - to load the config from the standard input. + -b, --helm-binary string Path to the helm binary (default "helm") + -h, --help help for helmfile + -i, --interactive Request confirmation before attempting to modify clusters + --kube-context string Set kubectl context. Uses current context by default + -k, --kustomize-binary string Path to the kustomize binary (default "kustomize") + --log-level string Set log level, default info (default "info") + -n, --namespace string Set namespace. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }} + --no-color Output without color + -q, --quiet Silence output. Equivalent to log-level warn + -l, --selector stringArray Only run using the releases that match labels. Labels can take the form of foo=bar or foo!=bar. + A release must match all labels in a group in order to be used. Multiple groups can be specified at once. + "--selector tier=frontend,tier!=proxy --selector tier=backend" will match all frontend, non-proxy releases AND all backend releases. + The name of a release can be used as a label: "--selector name=myrelease" + --skip-deps skip running "helm repo update" and "helm dependency build" + --state-values-file stringArray specify state values in a YAML file. Used to override .Values within the helmfile template (not values template). + --state-values-set stringArray set state values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2). Used to override .Values within the helmfile template (not values template). + --state-values-set-string stringArray set state STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2). Used to override .Values within the helmfile template (not values template). + --sequential-helmfiles Process helmfile.d files sequentially in alphabetical order instead of in parallel + --strip-args-values-on-exit-error Strip the potential secret values of the helm command args contained in a helmfile error message (default true) + -v, --version version for helmfile + +Use "helmfile [command] --help" for more information about a command. +``` + +**Note:** Each command has its own specific flags. Use `helmfile [command] --help` to see command-specific options. For example, `helmfile sync --help` shows operational flags like `--timeout`, `--wait`, and `--wait-for-jobs`. + +### init + +The `helmfile init` sub-command checks the dependencies required for helmfile operation, such as `helm`, `helm diff plugin`, `helm secrets plugin`, `helm helm-git plugin`, `helm s3 plugin`. When it does not exist or the version is too low, it can be installed automatically. + +### cache + +The `helmfile cache` sub-command is designed for cache management. Go-getter-backed remote file system are cached by `helmfile`. There is no TTL implemented, if you need to update the cached files or directories, you need to clean individually or run a full cleanup with `helmfile cache cleanup` + +#### OCI Chart Cache + +OCI charts are cached in the shared cache directory (`~/.cache/helmfile` by default, or `$HELMFILE_CACHE_HOME`). This cache is shared across all helmfile processes. + +**Cache Behavior:** + +- When a chart exists in the shared cache and is valid, it is reused without re-downloading +- The `--skip-refresh` flag can be used to skip checking for updates to cached charts stored in process-specific temporary directories (it does not affect charts already present in the shared cache) +- When running multiple helmfile processes in parallel (e.g., as an ArgoCD plugin), charts in the shared cache are not refreshed/deleted to prevent race conditions + +**Forcing a Cache Refresh:** + +To force a refresh of cached OCI charts, run: +```bash +helmfile cache cleanup +``` + +This will clear the shared cache, allowing the next helmfile command to re-download charts. + +#### cache info + +Display information about the cache directory. + +#### cache cleanup + +Remove all cached files from the cache directory. + +### sync + +The `helmfile sync` sub-command sync your cluster state as described in your `helmfile`. The default helmfile is `helmfile.yaml`, but any YAML file can be passed by specifying a `--file path/to/your/yaml/file` flag. + +Under the covers, Helmfile executes `helm upgrade --install` for each `release` declared in the manifest, by optionally decrypting [secrets](#secrets) to be consumed as helm chart values. It also updates specified chart repositories and updates the +dependencies of any referenced local charts. + +#### Common sync flags + +* `--timeout SECONDS` - Override the default timeout for all releases in this sync operation. This takes precedence over `helmDefaults.timeout` and per-release `timeout` settings. +* `--wait` - Override the default wait behavior for all releases +* `--wait-for-jobs` - Override the default wait-for-jobs behavior for all releases + +Examples: + +```bash +# Override timeout for all releases to 10 minutes +helmfile sync --timeout 600 + +# Combine timeout with wait flags +helmfile sync --timeout 900 --wait --wait-for-jobs + +# Target specific releases with custom timeout +helmfile sync --selector tier=backend --timeout 1200 +``` + +For Helm 2.9+ you can use a username and password to authenticate to a remote repository. + +### deps + +The `helmfile deps` sub-command locks your helmfile state and local charts dependencies. + +It basically runs `helm dependency update` on your helmfile state file and all the referenced local charts, so that you get a "lock" file per each helmfile state or local chart. + +All the other `helmfile` sub-commands like `sync` use chart versions recorded in the lock files, so that e.g. untested chart versions won't suddenly get deployed to the production environment. + +For example, the lock file for a helmfile state file named `helmfile.1.yaml` will be `helmfile.1.lock`. The lock file for a local chart would be `requirements.lock`, which is the same as `helm`. + +The lock file can be changed using `lockFilePath` in helm state, which makes it possible to for example have a different lock file per environment via templating. + +It is recommended to version-control all the lock files, so that they can be used in the production deployment pipeline for extra reproducibility. + +To bring in chart updates systematically, it would also be a good idea to run `helmfile deps` regularly, test it, and then update the lock files in the version-control system. + +### diff + +The `helmfile diff` sub-command executes the [helm-diff](https://github.com/databus23/helm-diff) plugin across all of +the charts/releases defined in the manifest. + +To supply the diff functionality Helmfile needs the [helm-diff](https://github.com/databus23/helm-diff) plugin v2.9.0+1 or greater installed. For Helm 2.3+ +you should be able to simply execute `helm plugin install https://github.com/databus23/helm-diff`. For more details +please look at their [documentation](https://github.com/databus23/helm-diff#helm-diff-plugin). + +### apply + +The `helmfile apply` sub-command begins by executing `diff`. If `diff` finds that there is any changes, `sync` is executed. Adding `--interactive` instructs Helmfile to request your confirmation before `sync`. + +An expected use-case of `apply` is to schedule it to run periodically, so that you can auto-fix skews between the desired and the current state of your apps running on Kubernetes clusters. + +### destroy + +The `helmfile destroy` sub-command uninstalls and purges all the releases defined in the manifests. + +`helmfile --interactive destroy` instructs Helmfile to request your confirmation before actually deleting releases. + +`destroy` basically runs `helm uninstall --purge` on all the targeted releases. If you don't want purging, use `helmfile delete` instead. +If `--skip-charts` flag is not set, destroy would prepare all releases, by fetching charts and templating them. + +### delete (DEPRECATED) + +The `helmfile delete` sub-command deletes all the releases defined in the manifests. + +`helmfile --interactive delete` instructs Helmfile to request your confirmation before actually deleting releases. + +Note that `delete` doesn't purge releases. So `helmfile delete && helmfile sync` results in sync failed due to that releases names are not deleted but preserved for future references. If you really want to remove releases for reuse, add `--purge` flag to run it like `helmfile delete --purge`. +If `--skip-charts` flag is not set, destroy would prepare all releases, by fetching charts and templating them. + +### secrets + +The `secrets` parameter in a `helmfile.yaml` causes the [helm-secrets](https://github.com/jkroepke/helm-secrets) plugin to be executed to decrypt the file. + +To supply the secret functionality Helmfile needs the `helm secrets` plugin installed. For Helm 2.3+ +you should be able to simply execute `helm plugin install https://github.com/jkroepke/helm-secrets +`. + +### test + +The `helmfile test` sub-command runs a `helm test` against specified releases in the manifest, default to all + +Use `--cleanup` to delete pods upon completion. + +### lint + +The `helmfile lint` sub-command runs a `helm lint` across all of the charts/releases defined in the manifest. Non local charts will be fetched into a temporary folder which will be deleted once the task is completed. + +### unittest + +The `helmfile unittest` sub-command runs `helm unittest` (from the [helm-unittest plugin](https://github.com/helm-unittest/helm-unittest)) on releases that have `unitTests` defined. It automatically generates the final merged values files for each release and passes them to `helm unittest`. + +This requires the `helm-unittest` plugin to be installed. You can install it with: + +```bash +helm plugin install https://github.com/helm-unittest/helm-unittest +``` + +Releases without `unitTests` defined are skipped. Non-local charts will be fetched into a temporary folder which will be deleted once the task is completed. + +Example helmfile configuration: + +```yaml +releases: + - name: my-app + chart: ./charts/my-app + values: + - values.yaml + unitTests: + - tests +``` + +The `unitTests` paths are relative to the chart directory and follow helm-unittest conventions. +If a path does not contain glob characters, it is treated as a directory and `/*_test.yaml` is appended automatically. +You can also specify explicit glob patterns (e.g., `tests/**/*_test.yaml`). + +Running `helmfile unittest` will: + +1. Merge all values files defined for the release +2. Run `helm unittest ./charts/my-app --values --file tests/*_test.yaml` + +You can pass additional flags: + +```bash +# Run with additional values +helmfile unittest --values extra-values.yaml + +# Run with --set overrides +helmfile unittest --set key=value + +# Target specific releases +helmfile unittest --selector name=my-app + +# Fail fast on first test failure +helmfile unittest --fail-fast + +# Enable colored output (Helm 3 only; ignored on Helm 4 due to flag parsing issues) +helmfile unittest --color + +# Enable verbose plugin output +helmfile unittest --debug-plugin + +# Pass extra arguments to helm unittest +helmfile unittest --args "--strict" +``` + +### create + +The `helmfile create` sub-command generates a helmfile deployment project scaffold with best-practice directory structure. + +```bash +# Create a project in a new directory +helmfile create my-project + +# Create a project in the current directory +helmfile create + +# Specify a custom output directory +helmfile create my-project --output-dir /path/to/project + +# Overwrite existing scaffold files +helmfile create my-project --force +``` + +This generates: + +* `helmfile.yaml` — Main configuration with commented examples for repositories, environments, and releases +* `environments/default.yaml` — Default environment values file +* `values/.gitkeep` — Placeholder for release-specific value files + +**Flags:** + +| Flag | Default | Description | +|------|---------|-------------| +| `-o`, `--output-dir` | `""` | Output directory (defaults to NAME or current directory) | +| `--force` | false | Overwrite existing scaffold files | + +The command validates the project name (no path separators, `.`, `..`, or whitespace-only names). Without `--force`, it atomically checks all target paths before writing to avoid partial scaffolds. + +### fetch + +The `helmfile fetch` sub-command downloads or copies local charts to a local directory for debug purpose. The local directory +must be specified with `--output-dir`. + +### list + +The `helmfile list` sub-command lists releases defined in the manifest. Optional `--output` flag accepts `json` to output releases in JSON format. + +If `--skip-charts` flag is not set, list would prepare all releases, by fetching charts and templating them. + +### version + +The `helmfile version` sub-command prints the version of Helmfile.Optional `-o` flag accepts `json` `yaml` `short` to output version in JSON, YAML or short format. + +default it will check for the latest version of Helmfile and print a tip if the current version is not the latest. To disable this behavior, set environment variable `HELMFILE_UPGRADE_NOTICE_DISABLED` to any non-empty value. + +### show-dag + +It prints a table with 3 columns, GROUP, RELEASE, and DEPENDENCIES. + +GROUP is the unsigned, monotonically increasing integer starting from 1. All the releases with the same GROUP are deployed concurrently. Everything in GROUP 2 starts being deployed only after everything in GROUP 1 got successfully deployed. + +RELEASE is the release that belongs to the GROUP. + +DEPENDENCIES is the list of releases that the RELEASE depends on. It should always be empty for releases in GROUP 1. DEPENDENCIES for a release in GROUP 2 should have some or all dependencies appeared in GROUP 1. It can be "some" because Helmfile simplifies the DAGs of releases into a DAG of groups, so that Helmfile always produce a single DAG for everything written in helmfile.yaml, even when there are technically two or more independent DAGs of releases in it. + +### print-env + +The `helmfile print-env` sub-command prints the parsed environment configuration including merged values (with decrypted secrets). This is useful for debugging environment configuration. + +```bash +# Print environment in YAML format (default) +helmfile print-env + +# Print environment in JSON format +helmfile print-env --output json + +# Print a specific environment +helmfile print-env -e production +``` + +### status + +The `helmfile status` sub-command retrieves the status of releases in the state file by running `helm status` for each release. + +### Additional CLI Flags + +The following global flags are also available but not shown in the main help output: + +| Flag | Default | Description | +|------|---------|-------------| +| `--kubeconfig` | `""` | Use a particular kubeconfig file | +| `--skip-refresh` | false | Skip running `helm repo update` (lighter than `--skip-deps` which also skips dependency build) | +| `--enforce-plugin-verification` | false | Fail plugin installation if verification is not supported | +| `--oci-plain-http` | false | Use plain HTTP for OCI registries (required for local/insecure registries in Helm 4) | + +#### fetch flags + +| Flag | Default | Description | +|------|---------|-------------| +| `--output-dir` | temp dir | Directory to store charts. If not set, a temporary directory is used and deleted when the command terminates | +| `--output-dir-template` | (default template) | Go text template for generating the output directory. Available fields: `{{ .OutputDir }}`, `{{ .ChartName }}`, `{{ .Release.* }}`, `{{ .Environment.Name }}`, `{{ .Environment.KubeContext }}`, `{{ .Environment.Values.* }}` | +| `--write-output` | false | Write a helmfile.yaml to stdout with chart references updated to point to the downloaded local chart paths. Requires `--output-dir` | +| `--concurrency` | 0 | Maximum number of concurrent helm processes to run, 0 is unlimited | + +This is useful for air-gapped environments: download charts with `--output-dir` and `--write-output`, then transfer the output directory and the generated helmfile.yaml to the air-gapped environment. + +#### destroy flags + +| Flag | Default | Description | +|------|---------|-------------| +| `--skip-charts` | false | Don't prepare charts when destroying releases | +| `--deleteWait` | false | Override helmDefaults.wait, sets `helm uninstall --wait` | +| `--deleteTimeout` | 300 | Time in seconds to wait for helm uninstall | +| `--cascade` | background | Pass cascade to helm exec | +| `--concurrency` | 0 | Maximum number of concurrent helm processes to run, 0 is unlimited | + +#### list flags + +| Flag | Default | Description | +|------|---------|-------------| +| `--skip-charts` | false | Don't prepare charts when listing releases | +| `--keep-temp-dir` | false | Keep temporary directory after listing | +| `--output` | `""` | Output format: `json` for JSON output | diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..7fd94b0a --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,528 @@ +# Configuration Reference + +This page is a comprehensive reference for all options available in `helmfile.yaml`. + +**If you're new to Helmfile**, start with the [Getting Started](index.md#getting-started) tutorial on the home page, then read [Writing Helmfile](writing-helmfile.md) for patterns. Come back here when you need to look up a specific field. + +**CAUTION**: This documentation is for the development version of Helmfile. If you are looking for the documentation for any of releases, please switch to the corresponding release tag like [v0.143.4](https://github.com/helmfile/helmfile/tree/v0.143.4). + +## Quick Reference + +A `helmfile.yaml` has these top-level sections: + +| Section | Purpose | +|---------|---------| +| `repositories` | Helm chart repositories to use | +| `releases` | The Helm releases to deploy (the core of helmfile) | +| `helmDefaults` | Default Helm options for all releases | +| `environments` | Environment-specific values (dev, staging, prod) | +| `helmfiles` | Include other helmfile.yaml files (nesting) | +| `bases` | Shared base files merged before this helmfile | +| `values` | Default values available in templates | +| `commonLabels` | Labels applied to all releases | +| `templates` | Reusable release templates | +| `hooks` | Global lifecycle hooks | +| `apiVersions` / `kubeVersion` | Kubernetes version capabilities | + +## Full Reference + +The default name for a helmfile is `helmfile.yaml`: + +```yaml +# Chart repositories used from within this state file +# +# Use `helm-s3` and `helm-git` and whatever Helm Downloader plugins +# to use repositories other than the official repository or one backend by chartmuseum. +repositories: +# To use official "stable" charts a.k.a https://github.com/helm/charts/tree/master/stable +- name: stable + url: https://charts.helm.sh/stable +# To use official "incubator" charts a.k.a https://github.com/helm/charts/tree/master/incubator +- name: incubator + url: https://charts.helm.sh/incubator +# helm-git powered repository: You can treat any Git repository as a charts repository +- name: polaris + url: git+https://github.com/reactiveops/polaris@deploy/helm?ref=master +# Advanced configuration: You can setup basic or tls auth and optionally enable helm OCI integration +- name: roboll + url: roboll.io/charts + certFile: optional_client_cert + keyFile: optional_client_key + # username is retrieved from the environment with the format _USERNAME for CI usage, here ROBOLL_USERNAME + username: optional_username + # password is retrieved from the environment with the format _PASSWORD for CI usage, here ROBOLL_PASSWORD + password: optional_password + oci: true + passCredentials: true + verify: true + keyring: path/to/keyring.gpg +# Advanced configuration: You can use a ca bundle to use an https repo +# with a self-signed certificate +- name: insecure + url: https://charts.my-insecure-domain.com + caFile: optional_ca_crt +# Advanced configuration: You can skip the verification of TLS for an https repo +- name: skipTLS + url: https://ss.my-insecure-domain.com + skipTLSVerify: true +# Advanced configuration: Connect to a repo served over plain http +- name: plainHTTP + url: http://just.http.domain.com + plainHttp: true + +# context: kube-context # this directive is deprecated, please consider using helmDefaults.kubeContext + +# Path to alternative helm binary (--helm-binary) +# Supports both Helm 3.x and Helm 4.x +helmBinary: path/to/helm + +# Path to alternative kustomize binary (--kustomize-binary) +kustomizeBinary: path/to/kustomize + +# Path to alternative lock file. The default is .lock, i.e for helmfile.yaml it's helmfile.lock. +lockFilePath: path/to/lock.file + +# Default values to set for args along with dedicated keys that can be set by contributors, cli args take precedence over these. +# In other words, unset values results in no flags passed to helm. +# See the helm usage (helm SUBCOMMAND -h) for more info on default values when those flags aren't provided. +helmDefaults: + kubeContext: kube-context #dedicated default key for kube-context (--kube-context) + cleanupOnFail: false #dedicated default key for helm flag --cleanup-on-fail + # additional and global args passed to helm (default "") + args: + - "--set k=v" + diffArgs: + - "--suppress-secrets" + syncArgs: + - "--labels=app.kubernetes.io/managed-by=helmfile" + # verify the chart before upgrading (only works with packaged charts not directories) (default false) + verify: true + keyring: path/to/keyring.gpg + # --skip-schema-validation flag to helm 'install', 'upgrade' and 'lint' (default false) + skipSchemaValidation: false + # wait for k8s resources via --wait. (default false) + wait: true + # DEPRECATED: waitRetries is no longer supported as the --wait-retries flag was removed from Helm. + # This configuration is ignored and preserved only for backward compatibility. + # waitRetries: 3 + # if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout (default false) + waitForJobs: true + # time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks, and waits on pod/pvc/svc/deployment readiness) (default 300) + timeout: 600 + # performs pods restart for the resource if applicable (default false) + recreatePods: true + # forces resource update through delete/recreate if needed (default false) + force: false + # limit the maximum number of revisions saved per release. Use 0 for no limit. (default 10) + historyMax: 10 + # automatically create release namespaces if they do not exist (default true) + createNamespace: true + # if used with charts museum allows to pull unstable charts for deployment, for example: if 1.2.3 and 1.2.4-dev versions exist and set to true, 1.2.4-dev will be pulled (default false) + devel: true + # When set to `true`, skips running `helm dep up` and `helm dep build` on this release's chart. + # Useful when the chart is broken, like seen in https://github.com/roboll/helmfile/issues/1547 + skipDeps: false + # If set to true, reuses the last release's values and merges them with ones provided in helmfile. + # This attribute, can be overriden in CLI with --reset/reuse-values flag of apply/sync/diff subcommands + reuseValues: false + # propagate `--post-renderer` to helmv3 template and helm install + postRenderer: "path/to/postRenderer" + # propagate `--post-renderer-args` to helmv3 template and helm install. This allows using Powershell + # scripts on Windows as a post renderer + postRendererArgs: + - PowerShell + - "-Command" + - "theScript.ps1" + # cascade `--cascade` to helmv3 delete, available values: background, foreground, or orphan, default: background + cascade: "background" + # insecureSkipTLSVerify is true if the TLS verification should be skipped when fetching remote chart + insecureSkipTLSVerify: false + # plainHttp is true if fetching the remote chart should be done using HTTP + plainHttp: false + # --wait flag for destroy/delete, if set to true, will wait until all resources are deleted before mark delete command as successful + deleteWait: false + # Timeout is the time in seconds to wait for helmfile destroy/delete (default 300) + deleteTimeout: 300 + # suppressOutputLineRegex is a list of regex patterns to suppress output lines from helm diff (default []), available in helmfile v0.162.0 + suppressOutputLineRegex: + - "version" + # syncReleaseLabels is a list of labels to be added to the release when syncing. + syncReleaseLabels: false + + +# these labels will be applied to all releases in a Helmfile. Useful in templating if you have a helmfile per environment or customer and don't want to copy the same label to each release +commonLabels: + hello: world + +# The desired states of Helm releases. +# +# Helmfile runs various helm commands to converge the current state in the live cluster to the desired state defined here. +releases: + # Published chart example + - name: vault # name of this release + namespace: vault # target namespace + createNamespace: true # automatically create release namespace (default true) + labels: # Arbitrary key value pairs for filtering releases + foo: bar + chart: roboll/vault-secret-manager # the chart being installed to create this release, referenced by `repository/chart` syntax + version: ~1.24.1 # the semver of the chart. range constraint is supported + condition: vault.enabled # The values lookup key for filtering releases. Corresponds to the boolean value of `vault.enabled`, where `vault` is an arbitrary value + missingFileHandler: Warn # set to either "Error" or "Warn". "Error" instructs helmfile to fail when unable to find a values or secrets file. When "Warn", it prints the file and continues. + missingFileHandlerConfig: + # Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error. + # See https://github.com/helmfile/helmfile/issues/392 + ignoreMissingGitBranch: true + # Values files used for rendering the chart + values: + # Value files passed via --values + - vault.yaml + # Inline values, passed via a temporary values file and --values, so that it doesn't suffer from type issues like --set + - address: https://vault.example.com + # Go template available in inline values and values files. + - image: + # The end result is more or less YAML. So do `quote` to prevent number-like strings from accidentally parsed into numbers! + # See https://github.com/roboll/helmfile/issues/608 + tag: {{ requiredEnv "IMAGE_TAG" | quote }} + # Otherwise: + # tag: "{{ requiredEnv "IMAGE_TAG" }}" + # tag: !!string {{ requiredEnv "IMAGE_TAG" }} + db: + username: {{ requiredEnv "DB_USERNAME" }} + # value taken from environment variable. Quotes are necessary. Will throw an error if the environment variable is not set. $DB_PASSWORD needs to be set in the calling environment ex: export DB_PASSWORD='password1' + password: {{ requiredEnv "DB_PASSWORD" }} + proxy: + # Interpolate environment variable with a fixed string + domain: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com + scheme: {{ env "SCHEME" | default "https" }} + # Use `values` whenever possible! + # `setString` translates to helm's `--set-string key=val` + setString: + # set a single array value in an array, translates to --set-string bar[0]={1,2} + - name: bar[0] + values: + - 1 + - 2 + # set a templated value + - name: namespace + value: {{ .Namespace }} + # `set` translates to helm's `--set key=val`, that is known to suffer from type issues like https://github.com/roboll/helmfile/issues/608 + set: + # single value loaded from a local file, translates to --set-file foo.config=path/to/file + - name: foo.config + file: path/to/file + # set a single array value in an array, translates to --set bar[0]={1,2} + - name: bar[0] + values: + - 1 + - 2 + # set a templated value + - name: namespace + value: {{ .Namespace }} + # will attempt to decrypt it using helm-secrets plugin + secrets: + - vault_secret.yaml + # Override helmDefaults options for verify, wait, waitForJobs, timeout, recreatePods, force and reuseValues. + verify: true + keyring: path/to/keyring.gpg + # --skip-schema-validation flag to helm 'install', 'upgrade' and 'lint' (default false) + skipSchemaValidation: false + wait: true + # DEPRECATED: waitRetries is no longer supported - see documentation above + # waitRetries: 3 + waitForJobs: true + timeout: 60 + recreatePods: true + force: false + reuseValues: false + # set `false` to uninstall this release on sync. (default true) + installed: true + # Defines the strategy to use when updating. Possible value is: + # - "reinstallIfForbidden": Performs an uninstall before the update only if the update is forbidden (e.g., due to permission issues or conflicts). + updateStrategy: "" + # restores previous state in case of failed release (default false) + atomic: true + # when true, cleans up any new resources created during a failed release (default false) + cleanupOnFail: false + # --kube-context to be passed to helm commands + # See https://github.com/roboll/helmfile/issues/642 + # (default "", which means the standard kubeconfig, either ~/kubeconfig or the file pointed by $KUBECONFIG environment variable) + kubeContext: kube-context + # passes --disable-validation to helm diff plugin, this requires diff plugin >= 3.1.2 + # It may be helpful to deploy charts with helm api v1 CRDS + # https://github.com/roboll/helmfile/pull/1373 + disableValidation: false + # passes --disable-validation to helm diff plugin, this requires diff plugin >= 3.1.2 + # It is useful when any release contains custom resources for CRDs that is not yet installed onto the cluster. + # https://github.com/roboll/helmfile/pull/1618 + disableValidationOnInstall: false + # passes --disable-openapi-validation to helm diff plugin, this requires diff plugin >= 3.1.2 + # It may be helpful to deploy charts with helm api v1 CRDS + # https://github.com/roboll/helmfile/pull/1373 + disableOpenAPIValidation: false + # limit the maximum number of revisions saved per release. Use 0 for no limit (default 10) + historyMax: 10 + # When set to `true`, skips running `helm dep up` and `helm dep build` on this release's chart. + # Useful when the chart is broken, like seen in https://github.com/roboll/helmfile/issues/1547 + skipDeps: false + # propagate `--post-renderer` to helmv3 template and helm install + postRenderer: "path/to/postRenderer" + # propagate `--post-renderer-args` to helmv3 template and helm install. This allows using Powershell + # scripts on Windows as a post renderer + postRendererArgs: + - PowerShell + - "-Command" + - "theScript.ps1" + # cascade `--cascade` to helmv3 delete, available values: background, foreground, or orphan, default: background + cascade: "background" + # insecureSkipTLSVerify is true if the TLS verification should be skipped when fetching remote chart + insecureSkipTLSVerify: false + # plainHttp is true if fetching the remote chart should be done using HTTP + plainHttp: false + # suppressDiff skip the helm diff output. Useful for charts which produces large not helpful diff, default: false + suppressDiff: false + # suppressOutputLineRegex is a list of regex patterns to suppress output lines from helm diff (default []), available in helmfile v0.162.0 + suppressOutputLineRegex: + - "version" + # syncReleaseLabels is a list of labels to be added to the release when syncing. + syncReleaseLabels: false + # unitTests is a list of test file or directory paths for helm-unittest integration. + # When specified, `helmfile unittest` will run `helm unittest` with the merged values and these test paths. + # Requires the helm-unittest plugin: https://github.com/helm-unittest/helm-unittest + unitTests: + - tests/vault + + + # Local chart example + - name: grafana # name of this release + namespace: another # target namespace + chart: ../my-charts/grafana # the chart being installed to create this release, referenced by relative path to local helmfile + values: + - "../../my-values/grafana/values.yaml" # Values file (relative path to manifest) + - ./values/{{ requiredEnv "PLATFORM_ENV" }}/config.yaml # Values file taken from path with environment variable. $PLATFORM_ENV must be set in the calling environment. + wait: true + +# +# Advanced Configuration: Nested States +# +helmfiles: +- # Path to the helmfile state file being processed BEFORE releases in this state file + path: path/to/subhelmfile.yaml + # Label selector used for filtering releases in the nested state. + # For example, `name=prometheus` in this context is equivalent to processing the nested state like + # helmfile -f path/to/subhelmfile.yaml -l name=prometheus sync + selectors: + - name=prometheus + # Override state values + values: + # Values files merged into the nested state's values + - additional.values.yaml + # One important aspect of using values here is that they first need to be defined in the values section + # of the origin helmfile, so in this example key1 needs to be in the values or environments.NAME.values of path/to/subhelmfile.yaml + # Inline state values merged into the nested state's values + - key1: val1 +- # All the nested state files under `helmfiles:` is processed in the order of definition. + # So it can be used for preparation for your main `releases`. An example would be creating CRDs required by `releases` in the parent state file. + path: path/to/mycrd.helmfile.yaml +- # Terraform-module-like URL for importing a remote directory and use a file in it as a nested-state file + # The nested-state file is locally checked-out along with the remote directory containing it. + # Therefore all the local paths in the file are resolved relative to the file + path: git::https://github.com/cloudposse/helmfiles.git@releases/kiam.yaml?ref=0.40.0 +- # By default git repositories aren't updated unless the ref is updated. + # Alternatively, refer to a named ref and disable the caching. + path: git::ssh://git@github.com/cloudposse/helmfiles.git@releases/kiam.yaml?ref=main&cache=false +# If set to "Error", return an error when a subhelmfile points to a +# non-existent path. The default behavior is to print a warning and continue. +missingFileHandler: Error +missingFileHandlerConfig: + # Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error. + # See https://github.com/helmfile/helmfile/issues/392 + ignoreMissingGitBranch: true + +# +# Advanced Configuration: Environments +# + +# The list of environments managed by helmfile. +# +# The default is `environments: {"default": {}}` which implies: +# +# - `{{ .Environment.Name }}` evaluates to "default" +# - `{{ .Values }}` being empty +environments: + # The "default" environment is available and used when `helmfile` is run without `--environment NAME`. + default: + # Everything from the values.yaml is available via `{{ .Values.KEY }}`. + # Suppose `{"foo": {"bar": 1}}` contained in the values.yaml below, + # `{{ .Values.foo.bar }}` is evaluated to `1`. + values: + - environments/default/values.yaml + # Everything from the values.hcl in the `values` block is available via `{{ .Values.KEY }}`. + # More details in its dedicated section + - environments/default/values.hcl + # Each entry in values can be either a file path or inline values. + # The below is an example of inline values, which is merged to the `.Values` + - myChartVer: 1.0.0-dev + # Any environment other than `default` is used only when `helmfile` is run with `--environment NAME`. + # That is, the "production" env below is used when and only when it is run like `helmfile --environment production sync`. + production: + values: + - environments/production/values.yaml + - myChartVer: 1.0.0 + # disable vault release processing + - vault: + enabled: false + ## `secrets.yaml` is decrypted by `helm-secrets` and available via `{{ .Environment.Values.KEY }}` + secrets: + - environments/production/secrets.yaml + # Instructs helmfile to fail when unable to find a environment values file listed under `environments.NAME.values`. + # + # Possible values are "Error", "Warn", "Info", "Debug". The default is "Error". + # + # Use "Warn", "Info", or "Debug" if you want helmfile to not fail when a values file is missing, while just leaving + # a message about the missing file at the log-level. + missingFileHandler: Error + missingFileHandlerConfig: + # Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error. + # See https://github.com/helmfile/helmfile/issues/392 + ignoreMissingGitBranch: true + # kubeContext to use for this environment + kubeContext: kube-context + +# +# Advanced Configuration: Layering +# +# Helmfile merges all the "base" state files and this state file before processing. +# +# Assuming this state file is named `helmfile.yaml`, all the files are merged in the order of: +# environments.yaml <- defaults.yaml <- templates.yaml <- helmfile.yaml +bases: +- environments.yaml +- defaults.yaml +- templates.yaml + +# +# Advanced Configuration: API Capabilities +# +# 'helmfile template' renders releases locally without querying an actual cluster, +# and in this case `.Capabilities.APIVersions` cannot be populated. +# When a chart queries for a specific CRD or the Kubernetes version, this can lead to unexpected results. +# +# Note that `Capabilities.KubeVersion` is deprecated in Helm 3 and `helm template` won't populate it. +# All you can do is fix your chart to respect `.Capabilities.APIVersions` instead, rather than trying to figure out +# how to set `Capabilities.KubeVersion` in Helmfile. +# +# Configure a fixed list of API versions to pass to 'helm template' via the --api-versions flag with the below: +apiVersions: +- example/v1 + +# Set the kubeVersion to render the chart with your desired Kubernetes version. +# The flag --kube-version was deprecated in helm v3 but it was added again. +# For further information https://github.com/helm/helm/issues/7326 +kubeVersion: v1.21 +``` + +### Additional helmDefaults fields + +The following `helmDefaults` fields are also available but not shown in the example above: + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `enableDNS` | bool | false | Enable DNS lookups when rendering templates | +| `skipCRDs` | bool | false | Skip CRDs during installation | +| `skipRefresh` | bool | false | Skip running `helm dependency up` | +| `forceConflicts` | bool | false | Force server-side apply changes against conflicts (Helm 4 only) | +| `takeOwnership` | bool | false | Take ownership of existing resources | +| `trackMode` | string | `""` | Default tracking mode for resources. See [Advanced Features](advanced-features.md#resource-tracking-with-kubedog) | +| `disableAutoDetectedKubeVersionForDiff` | bool | false | Disable auto-detected kubeVersion being passed to helm diff | + +### Additional release fields + +The following per-release fields are also available: + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `valuesTemplate` | list | | Like `values` but template expressions are rendered before being passed to Helm | +| `setTemplate` | list | | Like `set` but template expressions are rendered before being passed to Helm | +| `apiVersions` | list | | Per-release API versions (overrides top-level `apiVersions`) | +| `kubeVersion` | string | | Per-release kube version (overrides top-level `kubeVersion`) | +| `valuesPathPrefix` | string | | Prefix for values file paths | +| `verifyTemplate` | string | | Templated verify flag (e.g., `{{ .Values.verify \| default "false" }}`) | +| `waitTemplate` | string | | Templated wait flag | +| `installedTemplate` | string | | Templated installed flag | +| `adopt` | list | | List of resources to adopt (passes `--adopt` to Helm) | +| `forceGoGetter` | bool | false | Force go-getter URL parsing for the chart field. Useful when go-getter URL parsing fails unexpectedly | +| `forceNamespace` | string | | Force namespace on all K8s resources rendered by the chart, even when the template doesn't use `{{ .Namespace }}`. Use with caution | +| `skipRefresh` | bool | false | Per-release skip for `helm dependency up` | +| `disableAutoDetectedKubeVersionForDiff` | bool | false | Disable auto-detected kubeVersion for helm diff on this release | +| `takeOwnership` | bool | false | Take ownership of existing resources for this release | +| `forceConflicts` | bool | false | Force server-side apply against conflicts (Helm 4 only) | +| `description` | string | | Description of the release | +| `enableDNS` | bool | false | Enable DNS lookups when rendering templates | + +### Release tracking fields (kubedog) + +See [Advanced Features](advanced-features.md#resource-tracking-with-kubedog) for more details: + +| Field | Type | Default | Description | +|-------|------|---------|-------------| +| `trackMode` | string | `""` | Track mode: `helm`, `helm-legacy`, or `kubedog` | +| `trackTimeout` | int | 300 | Tracking timeout in seconds | +| `trackLogs` | bool | false | Enable real-time log streaming | +| `trackKinds` | list | | Whitelist of resource kinds to track | +| `skipKinds` | list | | Blacklist of resource kinds to skip | +| `trackResources` | list | | Specific resources to track (objects with `kind`, `name`, `namespace`) | +| `kubedogQPS` | float | | QPS for kubedog kubernetes client | +| `kubedogBurst` | int | | Burst for kubedog kubernetes client | + +### Hook kubectlApply + +Hooks also support a `kubectlApply` field for running `kubectl apply` directly: + +```yaml +releases: +- name: myapp + chart: mychart + hooks: + - events: ["presync"] + showlogs: true + kubectlApply: + filename: manifests/my-resource.yaml +``` + +Or with kustomize: + +```yaml + hooks: + - events: ["presync"] + showlogs: true + kubectlApply: + kustomize: overlays/default/ +``` + +### Repository additional fields + +| Field | Type | Description | +|-------|------|-------------| +| `registryConfig` | string | Path to registry configuration file | +| `managed` | string | Managed repository mode | + +### Template Partials + +Files matching `_*.tpl` in the same directory as the helmfile are automatically loaded as helper templates. For example, a file named `_helpers.tpl` can define named templates that are reusable across your helmfile: + +`_helpers.tpl`: +``` +{{- define "myapp.labels" -}} +app: myapp +env: {{ .Environment.Name }} +{{- end -}} +``` + +`helmfile.yaml`: +```yaml +releases: +- name: myapp + chart: mychart + values: + - labels: {{ include "myapp.labels" . | toYaml | nindent 4 }} +``` diff --git a/docs/environments.md b/docs/environments.md new file mode 100644 index 00000000..41eb7476 --- /dev/null +++ b/docs/environments.md @@ -0,0 +1,332 @@ +# Environments + +## Environment + +When you want to customize the contents of `helmfile.yaml` or `values.yaml` files per environment, use this feature. + +You can define as many environments as you want under `environments` in `helmfile.yaml`. +`environments` section should be separated from `releases` with `---`. + +The environment name defaults to `default`, that is, `helmfile sync` implies the `default` environment. +The selected environment name can be referenced from `helmfile.yaml` and `values.yaml.gotmpl` by `{{ .Environment.Name }}`. + +If you want to specify a non-default environment, provide a `--environment NAME` flag to `helmfile` like `helmfile --environment production sync`. + +The below example shows how to define a production-only release: + +```yaml +environments: + default: + production: + +--- + +releases: +- name: newrelic-agent + installed: {{ eq .Environment.Name "production" | toYaml }} + # snip +- name: myapp + # snip +``` + +### Environment Values +Helmfile supports 3 values languages : +- Straight yaml +- Go templates to generate straight yaml +- HCL + +Environment Values allows you to inject a set of values specific to the selected environment, into `values.yaml` templates. +Use it to inject common values from the environment to multiple values files, to make your configuration DRY. + +Suppose you have three files `helmfile.yaml`, `production.yaml` and `values.yaml.gotmpl`: + +`helmfile.yaml` + +```yaml +environments: + production: + values: + - production.yaml + +--- + +releases: +- name: myapp + values: + - values.yaml.gotmpl +``` + +`production.yaml` + +```yaml +domain: prod.example.com +releaseName: prod +``` + +`values.yaml.gotmpl` + +```yaml +domain: {{ .Values | get "domain" "dev.example.com" }} +``` + +`helmfile sync` installs `myapp` with the value `domain=dev.example.com`, +whereas `helmfile --environment production sync` installs the app with the value `domain=prod.example.com`. + +For even more flexibility, you can now use values declared in the `environments:` section in other parts of your helmfiles: + +consider: +`default.yaml` + +```yaml +domain: dev.example.com +releaseName: dev +``` + +```yaml +environments: + default: + values: + - default.yaml + production: + values: + - production.yaml # bare .yaml file, content will be used verbatim + - other.yaml.gotmpl # template directives with potential side-effects like `exec` and `readFile` will be honoured + +--- + +releases: +- name: myapp-{{ .Values.releaseName }} # release name will be one of `dev` or `prod` depending on selected environment + values: + - values.yaml.gotmpl +- name: production-specific-release + # this release would be installed only if selected environment is `production` + installed: {{ eq .Values.releaseName "prod" | toYaml }} + ... +``` + +#### HCL specifications + +Since Helmfile v0.164.0, HCL language is supported for environment values only. +HCL values supports interpolations and sharing values across files + +* Only `.hcl` suffixed files will be interpreted as is +* Helmfile supports 2 different blocks: `values` and `locals` +* `values` block is a shared block where all values are accessible everywhere in all loaded files +* `locals` block can't reference external values apart from the ones in the block itself, and where its defined values are only accessible in its local file +* Only values in `values` blocks are made available to the final root `.Values` (e.g : ` values { myvar = "var" }` is accessed through `{{ .Values.myvar }}`) +* There can only be 1 `locals` block per file +* Helmfile hcl `values` are referenced using the `hv` accessor. +* Helmfile hcl `locals` are referenced using the `local` accessor. +* When the same key is defined multiple times across imported `.hcl` files in `values` blocks, values from later files override those from earlier files (last file loaded wins). Map values are merged per key, while list values are replaced as a whole (i.e. not deep-merged). Mixed-types overrides (e.g. bool -> string) are supported (latest value/type wins). +* All cty [standard library functions](`https://pkg.go.dev/github.com/zclconf/go-cty@v1.14.3/cty/function/stdlib`) are available and custom functions could be created in the future + +Consider the following example : + +```terraform +# values1.hcl +locals { + hostname = "host1" +} +values { + domain = "DEV.EXAMPLE.COM" + hostnameV1 = "${local.hostname}.${lower(hv.domain)}" # "host1.dev.example.com" +} +``` +```terraform +# values2.hcl +locals { + hostname = "host2" +} + +values { + hostnameV2 = "${local.hostname}.${hv.domain}" # "host2.DEV.EXAMPLE.COM" +} +``` +#### Note on Environment.Values vs Values + +The `{{ .Values.foo }}` syntax is the recommended way of using environment values. + +Prior to this [pull request](https://github.com/roboll/helmfile/pull/647), environment values were made available through the `{{ .Environment.Values.foo }}` syntax. +This is still working but is **deprecated** and the new `{{ .Values.foo }}` syntax should be used instead. + +You can read more infos about the feature proposal [here](https://github.com/roboll/helmfile/issues/640). + +### Environment Secrets + +Environment Secrets *(not to be confused with Kubernetes Secrets)* are encrypted versions of `Environment Values`. +You can list any number of `secrets.yaml` files created using `helm secrets` or `sops`, so that +Helmfile could automatically decrypt and merge the secrets into the environment values. + +First you must have the [helm-secrets](https://github.com/jkroepke/helm-secrets) plugin installed along with a +`.sops.yaml` file to configure the method of encryption (this can be in the same directory as your helmfile or +in the subdirectory containing your secrets files). + +Then suppose you have a secret `foo.bar` defined in `environments/production/secrets.yaml`: + +```yaml +foo.bar: "mysupersecretstring" +``` + +You can then encrypt it with `helm secrets enc environments/production/secrets.yaml` + +Then reference that encrypted file in `helmfile.yaml`: + +```yaml +environments: + production: + secrets: + - environments/production/secrets.yaml + +--- + +releases: +- name: myapp + chart: mychart + values: + - values.yaml.gotmpl +``` + +Then the environment secret `foo.bar` can be referenced by the below template expression in your `values.yaml.gotmpl`: + +```yaml +{{ .Values.foo.bar }} +``` + +#### Loading remote Environment secrets files + +Since Helmfile v0.149.0, you can use `go-getter`-style URLs to refer to remote secrets files, the same way as in values files: +```yaml +environments: + staging: + secrets: + - git::https://{{ env "GITHUB_PAT" }}@github.com/org/repo.git@/environments/staging.secret.yaml?ref=main + - http://$HOSTNAME/artifactory/example-repo-local/test.tgz@environments/staging.secret.yaml + production: + secrets: + - git::https://{{ env "GITHUB_PAT" }}@github.com/org/repo.git@/environments/production.secret.yaml?ref=main + - http://$HOSTNAME/artifactory/example-repo-local/test.tgz@environments/production.secret.yaml +``` + +### Loading remote Environment values files + +Since Helmfile v0.118.8, you can use `go-getter`-style URLs to refer to remote values files: + +```yaml +environments: + cluster-azure-us-west: + values: + - git::https://git.company.org/helmfiles/global/azure.yaml?ref=master + - git::https://git.company.org/helmfiles/global/us-west.yaml?ref=master + - git::https://gitlab.com/org/repository-name.git@/config/config.test.yaml?ref=main # Public Gilab Repo + cluster-gcp-europe-west: + values: + - git::https://git.company.org/helmfiles/global/gcp.yaml?ref=master + - git::https://git.company.org/helmfiles/global/europe-west.yaml?ref=master + - git::https://ci:{{ env "CI_JOB_TOKEN" }}@gitlab.com/org/repository-name.git@/config.dev.yaml?ref={{ env "APP_COMMIT_SHA" }} # Private Gitlab Repo + staging: + values: + - git::https://{{ env "GITHUB_PAT" }}@github.com/[$GITHUB_ORGorGITHUB_USER]/repository-name.git@/values.dev.yaml?ref=main #Github Private repo + - http://$HOSTNAME/artifactory/example-repo-local/test.tgz@values.yaml #Artifactory url +--- + +releases: + - ... +``` + +Since Helmfile v0.158.0, support more protocols, such as: s3, https, http +``` +values: + - s3::https://helm-s3-values-example.s3.us-east-2.amazonaws.com/values.yaml + - s3://helm-s3-values-example/subdir/values.yaml + - https://john:doe@helm-s3-values-example.s3.us-east-2.amazonaws.com/values.yaml + - http://helm-s3-values-example.s3.us-east-2.amazonaws.com/values.yaml +``` + +For more information about the supported protocols see: [go-getter Protocol-Specific Options](https://github.com/hashicorp/go-getter#protocol-specific-options-1). + +This is particularly useful when you co-locate helmfiles within your project repo but want to reuse the definitions in a global repo. + +### Environment values precedence +With the introduction of HCL, a new value precedence was introduced over environment values. +Here is the order of precedence from least to greatest (the last one overrides all others) +1. `yaml` / `yaml.gotmpl` +2. `hcl` +3. `yaml` secrets + +Example: + +--- + +```yaml +# values1.yaml +domain: "dev.example.com" +``` + +```terraform +# values2.hcl +values { + domain = "overdev.example.com" + env = "dev" + willBeOverridden = "override_me" +} +``` + +```terraform +# values3.hcl +values { + env = "local" +} +``` + +```yaml +# secrets.yml (assuming this one has been encrypted) +willBeOverridden: overridden +``` + +``` +# helmfile.yaml.gotmpl +environments: + default: + values: + - values1.yaml + - values2.hcl + - values3.hcl + secrets: + - secrets.yml +--- +releases: +- name: random-release + [...] + values: + domain: "{{ .Values.domain }}" # == "overdev.example.com" + env: "{{ .Values.env }}" # == "local" + willBeOverridden: "{{ .Values.willBeOverridden }}" # == "overridden" +``` + +### Environment defaults + +In addition to `values`, environments support a `defaults` block that provides a separate layer of default values. These are merged **before** `values`, giving `values` higher priority: + +```yaml +environments: + default: + defaults: + - cluster: dev + replicas: 1 + values: + - replicas: 3 +``` + +The merge order for environment values is: + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 1. Environment defaults (merged first, lowest priority) │ +│ 2. Environment values (yaml/yaml.gotmpl) │ +│ 3. Environment values (HCL) │ +│ 4. Environment secrets (non-HCL, decrypted) │ +│ 5. CLI overrides (--state-values-set, --state-values-file) │ +└─────────────────────────────────────────────────────────────────┘ +``` + +In the example above, `{{ .Values.replicas }}` would be `3` (values overrides defaults) and `{{ .Values.cluster }}` would be `dev` (only defined in defaults). diff --git a/docs/experimental-features.md b/docs/experimental-features.md index f081173b..6cbb3e1b 100644 --- a/docs/experimental-features.md +++ b/docs/experimental-features.md @@ -1,7 +1,30 @@ # Experimental Features -This document describes the experimental features that are available in Helmfile v1. +This document describes the experimental features that are available in Helmfile. Any experimental feature may be removed or changed in a future release without notice. -- HCL helmfile-values-file support (PR #1423) +Enable experimental features with the environment variable: + +```bash +# Enable all experimental features +export HELMFILE_EXPERIMENTAL=true + +# Enable a specific feature +export HELMFILE_EXPERIMENTAL=explicit-selector-inheritance +``` + +## explicit-selector-inheritance + +By default, CLI selectors (e.g., `helmfile -l name=myapp sync`) are inherited by sub-helmfiles. This experimental feature changes the behavior so that sub-helmfiles without explicit `selectors` do **not** inherit selectors from their parent or the CLI. + +When enabled: +* Sub-helmfiles without `selectors` do not inherit parent/CLI selectors +* Use `selectorsInherited: true` on a sub-helmfile to explicitly opt into inheriting selectors +* `selectors: []` selects all releases (same as current behavior) + +See [Selectors and needs](releases.md#selectors) for detailed examples. + +## HCL helmfile-values-file support + +HCL language is supported for environment values files (`.hcl` suffix). This was introduced as experimental in PR #1423 and is now a stable feature. See [Environments](environments.md#hcl-specifications) for details. diff --git a/docs/hooks.md b/docs/hooks.md new file mode 100644 index 00000000..9c538271 --- /dev/null +++ b/docs/hooks.md @@ -0,0 +1,294 @@ +# Hooks + +## Hooks + +A Helmfile hook is a per-release extension point that is composed of: + +* `events` +* `command` +* `args` +* `showlogs` +* `kubectlApply` (alternative to `command`/`args`) + +Helmfile triggers various `events` while it is running. +Once `events` are triggered, associated `hooks` are executed, by running the `command` with `args`. The standard output of the `command` will be displayed if `showlogs` is set and it's value is `true`. + +Hooks exec order follows the order of definition in the helmfile state. + +Currently supported `events` are: + +* `prepare` +* `preapply` +* `presync` +* `preuninstall` +* `postuninstall` +* `postsync` +* `cleanup` + +Hooks associated to `prepare` events are triggered after each release in your helmfile is loaded from YAML, before execution. +`prepare` hooks are triggered on the release as long as it is not excluded by the helmfile selector(e.g. `helmfile -l key=value`). + +Hooks associated to `presync` events are triggered before each release is synced (installed or upgraded) on the cluster. +This is the ideal event to execute any commands that may mutate the cluster state as it will not be run for read-only operations like `lint`, `diff` or `template`. + +`preapply` hooks are triggered before a release is uninstalled, installed, or upgraded as part of `helmfile apply`. +This is the ideal event to hook into when you are going to use `helmfile apply` for every kind of change. Note that preapply hooks will only run if at least one release has changes to apply. Be sure to make each `preapply` hook command idempotent. Otherwise, rerunning `helmfile apply` on a transient failure may end up either breaking your cluster, or the hook that runs for the second time will never succeed. + +`preuninstall` hooks are triggered immediately before a release is uninstalled as part of `helmfile apply`, `helmfile sync`, `helmfile delete`, and `helmfile destroy`. + +`postuninstall` hooks are triggered immediately after successful uninstall of a release while running `helmfile apply`, `helmfile sync`, `helmfile delete`, `helmfile destroy`. + +`postsync` hooks are triggered after each release is synced (installed or upgraded) on the cluster, regardless if the sync was successful or not. +This is the ideal place to execute any commands that may mutate the cluster state as it will not be run for read-only operations like `lint`, `diff` or `template`. + +`cleanup` hooks are triggered after each release is processed. +This is the counterpart to `prepare`, as any release on which `prepare` has been triggered gets `cleanup` triggered as well. + +The following is an example hook that just prints the contextual information provided to hook: + +```yaml +releases: +- name: myapp + chart: mychart + # *snip* + hooks: + - events: ["prepare", "cleanup"] + showlogs: true + command: "echo" + args: ["{{`{{.Environment.Name}}`}}", "{{`{{.Release.Name}}`}}", "{{`{{.HelmfileCommand}}`}}\ +"] +``` + +Let's say you ran `helmfile --environment prod sync`, the above hook results in executing: + +``` +echo {{Environment.Name}} {{.Release.Name}} {{.HelmfileCommand}} +``` + +Whereas the template expressions are executed thus the command becomes: + +``` +echo prod myapp sync +``` + +Now, replace `echo` with any command you like, and rewrite `args` that actually conforms to the command, so that you can integrate any command that does: + +* templating +* linting +* testing + +Hooks expose additional template expressions: + +`.Event.Name` is the name of the hook event. + +`.Event.Error` is the error generated by a failed release, exposed for `postsync` hooks only when a release fails, otherwise its value is `nil`. + +You can use the hooks event expressions to send notifications to platforms such as `Slack`, `MS Teams`, etc. + +The following example passes arguments to a script which sends a notification: + +```yaml +releases: +- name: myapp + chart: mychart + # *snip* + hooks: + - events: + - presync + - postsync + showlogs: true + command: notify.sh + args: + - --event + - '{{`{{ .Event.Name }}`}}' + - --status + - '{{`{{ if .Event.Error }}failure{{ else }}success{{ end }}`}}' + - --environment + - '{{`{{ .Environment.Name }}`}}' + - --namespace + - '{{`{{ .Release.Namespace }}`}}' + - --release + - '{{`{{ .Release.Name }}`}}' +``` + +For templating, imagine that you created a hook that generates a helm chart on-the-fly by running an external tool like ksonnet, kustomize, or your own template engine. +It will allow you to write your helm releases with any language you like, while still leveraging goodies provided by helm. + +### Hooks, Kubectl and Environments + +Hooks can also be used in combination with small tasks using `kubectl` directly, +e.g.: in order to install a custom storage class. + +In the following example, a specific release depends on a custom storage class. +Further, all enviroments have a default kube context configured where releases are deployed into. +The `.Environment.KubeContext` is used in order to apply / remove the YAML to the correct context depending on the environment. + +`environments.yaml`: + +```yaml +environments: + dev: + values: + - ../values/default.yaml + - ../values/dev.yaml + kubeContext: dev-cluster + prod: + values: + - ../values/default.yaml + - ../values/prod.yaml + kubeContext: prod-cluster +``` + +`helmfile.yaml`: + +```yaml +bases: + - ./environments.yaml + +--- +releases: + - name: myService + namespace: my-ns + installed: true + chart: mychart + version: "1.2.3" + values: + - ../services/my-service/values.yaml.gotmpl + hooks: + - events: ["presync"] + showlogs: true + command: "kubectl" + args: + - "apply" + - "-f" + - "./custom-storage-class.yaml" + - "--context" + - "{{`{{.Environment.KubeContext}}`}}" + - events: ["postuninstall"] + showlogs: true + command: "kubectl" + args: + - "delete" + - "-f" + - "./custom-storage-class.yaml" + - "--context" + - "{{`{{.Environment.KubeContext}}`}}" +``` + +### Global Hooks + +In contrast to the per release hooks mentioned above these are run only once at the very beginning and end of the execution of a helmfile command and only the `prepare` and `cleanup` hooks are available respectively. + +They use the same syntax as per release hooks, but at the top level of your helmfile: + +```yaml +hooks: +- events: ["prepare", "cleanup"] + showlogs: true + command: "echo" + args: ["{{`{{.Environment.Name}}`}}", "{{`{{.HelmfileCommand}}`}}\ +"] +``` + +### Helmfile + Kustomize + +Do you prefer `kustomize` to write and organize your Kubernetes apps, but still want to leverage helm's useful features +like rollback, history, and so on? This section is for you! + +The combination of `hooks` and [helmify-kustomize](https://gist.github.com/mumoshu/f9d0bd98e0eb77f636f79fc2fb130690) +enables you to integrate [kustomize](https://github.com/kubernetes-sigs/kustomize) into Helmfile. + +That is, you can use `kustomize` to build a local helm chart from a kustomize overlay. + +Let's assume you have a kustomize project named `foo-kustomize` like this: + +``` +foo-kustomize/ +├── base +│   ├── configMap.yaml +│   ├── deployment.yaml +│   ├── kustomization.yaml +│   └── service.yaml +└── overlays + ├── default + │   ├── kustomization.yaml + │   └── map.yaml + ├── production + │   ├── deployment.yaml + │   └── kustomization.yaml + └── staging + ├── kustomization.yaml + └── map.yaml + +5 directories, 10 files +``` + +Write `helmfile.yaml`: + +```yaml +- name: kustomize + chart: ./foo + hooks: + - events: ["prepare", "cleanup"] + command: "../helmify" + args: ["{{`{{if eq .Event.Name \"prepare\"}}build{{else}}clean{{end}}`}}", "{{`{{.Release.Ch\ +art}}`}}", "{{`{{.Environment.Name}}`}}"] +``` + +Run `helmfile --environment staging sync` and see it results in helmfile running `kustomize build foo-kustomize/overlays/staging > foo/templates/all.yaml`. + +Voilà! You can mix helm releases that are backed by remote charts, local charts, and even kustomize overlays. + +### kubectlApply Hook + +Instead of specifying `command` and `args`, you can use the `kubectlApply` field to run `kubectl apply` directly: + +```yaml +releases: +- name: myapp + chart: mychart + hooks: + - events: ["presync"] + showlogs: true + kubectlApply: + filename: manifests/custom-resource.yaml +``` + +Or apply a kustomize overlay: + +```yaml + hooks: + - events: ["presync"] + showlogs: true + kubectlApply: + kustomize: overlays/default/ +``` + +The `kubectlApply` field accepts either: +* `filename:` - runs `kubectl apply -f ` +* `kustomize:` - runs `kubectl apply -k ` + +**Note:** `filename` and `kustomize` cannot be used together. When `kubectlApply` is set, the `command` field is ignored with a warning. + +### Hook Template Data + +Hooks have access to the following template data: + +Per-release hooks: +* `{{ .Environment.Name }}` - the environment name +* `{{ .Environment.KubeContext }}` - the environment kube context +* `{{ .Release.Name }}` - the release name +* `{{ .Release.Namespace }}` - the release namespace +* `{{ .Release.Labels }}` - the release labels +* `{{ .Release.Chart }}` - the release chart +* `{{ .Values }}` - state values +* `{{ .HelmfileCommand }}` - the helmfile command name (e.g., `sync`, `apply`) +* `{{ .Event.Name }}` - the hook event name +* `{{ .Event.Error }}` - the error (available in `postsync` hooks when a release fails) + +Global hooks: +* `{{ .Environment.Name }}` - the environment name +* `{{ .HelmfileCommand }}` - the helmfile command name +* `{{ .Event.Name }}` - the hook event name +* `{{ .Event.Error }}` - the error + diff --git a/docs/index.md b/docs/index.md index 3783a2bb..dc47d7d4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -54,7 +54,7 @@ To avoid upgrades for each iteration of `helm`, the `helmfile` executable delega ## Installation * download one of [releases](https://github.com/helmfile/helmfile/releases) -* [run as a container](https://helmfile.readthedocs.io/en/latest/#running-as-a-container) +* [run as a container](#running-as-a-container) * Archlinux: install via `pacman -S helmfile` * openSUSE: install via `zypper in helmfile` assuming you are on Tumbleweed; if you are on Leap you must add the [kubic](https://download.opensuse.org/repositories/devel:/kubic/) repo for your distribution version once before that command, e.g. `zypper ar https://download.opensuse.org/repositories/devel:/kubic/openSUSE_Leap_\$releasever kubic` * Windows (using [scoop](https://scoop.sh/)): `scoop install helmfile` @@ -62,16 +62,16 @@ To avoid upgrades for each iteration of `helm`, the `helmfile` executable delega ### Running as a container -The [Helmfile Docker images are available in GHCR](https://github.com/helmfile/helmfile/pkgs/container/helmfile). There is no `latest` tag, since the `0.x` versions can contain breaking changes, so make sure you pick the right tag. Example using `helmfile 0.156.0`: +The [Helmfile Docker images are available in GHCR](https://github.com/helmfile/helmfile/pkgs/container/helmfile). Make sure you pick the right tag for your version. Example: ```sh-session -$ docker run --rm --net=host -v "${HOME}/.kube:/helm/.kube" -v "${HOME}/.config/helm:/helm/.config/helm" -v "${PWD}:/wd" --workdir /wd ghcr.io/helmfile/helmfile:v0.156.0 helmfile sync +$ docker run --rm --net=host -v "${HOME}/.kube:/helm/.kube" -v "${HOME}/.config/helm:/helm/.config/helm" -v "${PWD}:/wd" --workdir /wd ghcr.io/helmfile/helmfile:v1.1.0 helmfile sync ``` You can also use a shim to make calling the binary easier: ```sh-session -$ printf '%s\n' '#!/bin/sh' 'docker run --rm --net=host -v "${HOME}/.kube:/helm/.kube" -v "${HOME}/.config/helm:/helm/.config/helm" -v "${PWD}:/wd" --workdir /wd ghcr.io/helmfile/helmfile:v0.156.0 helmfile "$@"' | +$ printf '%s\n' '#!/bin/sh' 'docker run --rm --net=host -v "${HOME}/.kube:/helm/.kube" -v "${HOME}/.config/helm:/helm/.config/helm" -v "${PWD}:/wd" --workdir /wd ghcr.io/helmfile/helmfile:v1.1.0 helmfile "$@"' | tee helmfile $ chmod +x helmfile $ ./helmfile sync @@ -79,821 +79,125 @@ $ ./helmfile sync ## Getting Started -Let's start with a simple `helmfile` and gradually improve it to fit your use-case! +### Prerequisites -Suppose the `helmfile.yaml` representing the desired state of your helm releases looks like: +* A Kubernetes cluster (e.g., [minikube](https://minikube.sigs.k8s.io/), [kind](https://kind.sigs.k8s.io/), or a cloud provider) +* [Helm 3+](https://helm.sh/docs/intro/install/) installed (`helm version` to verify) + +### Step 1: Install Helmfile + +Choose one of the following: + +```bash +# macOS +brew install helmfile + +# Linux - download from GitHub releases +curl -L https://github.com/helmfile/helmfile/releases/latest/download/helmfile_$(uname -s)_$(uname -m) -o /usr/local/bin/helmfile && chmod +x /usr/local/bin/helmfile + +# Windows +scoop install helmfile +``` + +Verify: `helmfile version` + +### Step 2: Create your first helmfile.yaml + +Use `helmfile create` to generate a project scaffold with best-practice directory structure: + +```bash +# Scaffold a new project +helmfile create my-project +cd my-project +``` + +Or create a `helmfile.yaml` manually: ```yaml repositories: - - name: prometheus-community - url: https://prometheus-community.github.io/helm-charts + - name: prometheus-community + url: https://prometheus-community.github.io/helm-charts releases: -- name: prom-norbac-ubuntu - namespace: prometheus - chart: prometheus-community/prometheus - set: - - name: rbac.create - value: false + - name: my-prometheus + namespace: monitoring + createNamespace: true + chart: prometheus-community/prometheus + values: + - server: + persistentVolume: + enabled: false ``` -Install required dependencies using [init](https://helmfile.readthedocs.io/en/latest/#init): +**What does this do?** +* `repositories` — tells Helm where to find charts (like a package registry) +* `releases` — each entry is a Helm release to deploy + * `name` — a unique name for this deployment + * `namespace` — which Kubernetes namespace to deploy into + * `chart` — which Helm chart to use (`repository-name/chart-name`) + * `values` — customize the chart's default settings -```console +### Step 3: Initialize and deploy + +```bash +# Initialize - checks helm and installs required plugins helmfile init -``` -Sync your Kubernetes cluster state to the desired one by running: +# See what would be deployed (dry-run) +helmfile diff -```console +# Deploy to your cluster helmfile apply ``` -Congratulations! You now have your first Prometheus deployment running inside your cluster. +Congratulations! You now have Prometheus running in your cluster. -Iterate on the `helmfile.yaml` by referencing: +### Step 4: Make changes and re-apply -* [Configuration](#configuration) -* [CLI reference](#cli-reference). -* [Helmfile Best Practices Guide](writing-helmfile.md) -* [Values Merging and Data Flow](values-and-merging.md) - Understanding how Helmfile merges values - -## Configuration - -**CAUTION**: This documentation is for the development version of Helmfile. If you are looking for the documentation for any of releases, please switch to the corresponding release tag like [v0.143.4](https://github.com/helmfile/helmfile/tree/v0.143.4). - -The default name for a helmfile is `helmfile.yaml`: - -```yaml -# Chart repositories used from within this state file -# -# Use `helm-s3` and `helm-git` and whatever Helm Downloader plugins -# to use repositories other than the official repository or one backend by chartmuseum. -repositories: -# To use official "stable" charts a.k.a https://github.com/helm/charts/tree/master/stable -- name: stable - url: https://charts.helm.sh/stable -# To use official "incubator" charts a.k.a https://github.com/helm/charts/tree/master/incubator -- name: incubator - url: https://charts.helm.sh/incubator -# helm-git powered repository: You can treat any Git repository as a charts repository -- name: polaris - url: git+https://github.com/reactiveops/polaris@deploy/helm?ref=master -# Advanced configuration: You can setup basic or tls auth and optionally enable helm OCI integration -- name: roboll - url: roboll.io/charts - certFile: optional_client_cert - keyFile: optional_client_key - # username is retrieved from the environment with the format _USERNAME for CI usage, here ROBOLL_USERNAME - username: optional_username - # password is retrieved from the environment with the format _PASSWORD for CI usage, here ROBOLL_PASSWORD - password: optional_password - oci: true - passCredentials: true - verify: true - keyring: path/to/keyring.gpg -# Advanced configuration: You can use a ca bundle to use an https repo -# with a self-signed certificate -- name: insecure - url: https://charts.my-insecure-domain.com - caFile: optional_ca_crt -# Advanced configuration: You can skip the verification of TLS for an https repo -- name: skipTLS - url: https://ss.my-insecure-domain.com - skipTLSVerify: true -# Advanced configuration: Connect to a repo served over plain http -- name: plainHTTP - url: http://just.http.domain.com - plainHttp: true - -# context: kube-context # this directive is deprecated, please consider using helmDefaults.kubeContext - -# Path to alternative helm binary (--helm-binary) -# Supports both Helm 3.x and Helm 4.x -helmBinary: path/to/helm - -# Path to alternative kustomize binary (--kustomize-binary) -kustomizeBinary: path/to/kustomize - -# Path to alternative lock file. The default is .lock, i.e for helmfile.yaml it's helmfile.lock. -lockFilePath: path/to/lock.file - -# Default values to set for args along with dedicated keys that can be set by contributors, cli args take precedence over these. -# In other words, unset values results in no flags passed to helm. -# See the helm usage (helm SUBCOMMAND -h) for more info on default values when those flags aren't provided. -helmDefaults: - kubeContext: kube-context #dedicated default key for kube-context (--kube-context) - cleanupOnFail: false #dedicated default key for helm flag --cleanup-on-fail - # additional and global args passed to helm (default "") - args: - - "--set k=v" - diffArgs: - - "--suppress-secrets" - syncArgs: - - "--labels=app.kubernetes.io/managed-by=helmfile" - # verify the chart before upgrading (only works with packaged charts not directories) (default false) - verify: true - keyring: path/to/keyring.gpg - # --skip-schema-validation flag to helm 'install', 'upgrade' and 'lint' (default false) - skipSchemaValidation: false - # wait for k8s resources via --wait. (default false) - wait: true - # DEPRECATED: waitRetries is no longer supported as the --wait-retries flag was removed from Helm. - # This configuration is ignored and preserved only for backward compatibility. - # waitRetries: 3 - # if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout (default false) - waitForJobs: true - # time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks, and waits on pod/pvc/svc/deployment readiness) (default 300) - timeout: 600 - # performs pods restart for the resource if applicable (default false) - recreatePods: true - # forces resource update through delete/recreate if needed (default false) - force: false - # limit the maximum number of revisions saved per release. Use 0 for no limit. (default 10) - historyMax: 10 - # automatically create release namespaces if they do not exist (default true) - createNamespace: true - # if used with charts museum allows to pull unstable charts for deployment, for example: if 1.2.3 and 1.2.4-dev versions exist and set to true, 1.2.4-dev will be pulled (default false) - devel: true - # When set to `true`, skips running `helm dep up` and `helm dep build` on this release's chart. - # Useful when the chart is broken, like seen in https://github.com/roboll/helmfile/issues/1547 - skipDeps: false - # If set to true, reuses the last release's values and merges them with ones provided in helmfile. - # This attribute, can be overriden in CLI with --reset/reuse-values flag of apply/sync/diff subcommands - reuseValues: false - # propagate `--post-renderer` to helmv3 template and helm install - postRenderer: "path/to/postRenderer" - # propagate `--post-renderer-args` to helmv3 template and helm install. This allows using Powershell - # scripts on Windows as a post renderer - postRendererArgs: - - PowerShell - - "-Command" - - "theScript.ps1" - # cascade `--cascade` to helmv3 delete, available values: background, foreground, or orphan, default: background - cascade: "background" - # insecureSkipTLSVerify is true if the TLS verification should be skipped when fetching remote chart - insecureSkipTLSVerify: false - # plainHttp is true if fetching the remote chart should be done using HTTP - plainHttp: false - # --wait flag for destroy/delete, if set to true, will wait until all resources are deleted before mark delete command as successful - deleteWait: false - # Timeout is the time in seconds to wait for helmfile destroy/delete (default 300) - deleteTimeout: 300 - # suppressOutputLineRegex is a list of regex patterns to suppress output lines from helm diff (default []), available in helmfile v0.162.0 - suppressOutputLineRegex: - - "version" - # syncReleaseLabels is a list of labels to be added to the release when syncing. - syncReleaseLabels: false - - -# these labels will be applied to all releases in a Helmfile. Useful in templating if you have a helmfile per environment or customer and don't want to copy the same label to each release -commonLabels: - hello: world - -# The desired states of Helm releases. -# -# Helmfile runs various helm commands to converge the current state in the live cluster to the desired state defined here. -releases: - # Published chart example - - name: vault # name of this release - namespace: vault # target namespace - createNamespace: true # automatically create release namespace (default true) - labels: # Arbitrary key value pairs for filtering releases - foo: bar - chart: roboll/vault-secret-manager # the chart being installed to create this release, referenced by `repository/chart` syntax - version: ~1.24.1 # the semver of the chart. range constraint is supported - condition: vault.enabled # The values lookup key for filtering releases. Corresponds to the boolean value of `vault.enabled`, where `vault` is an arbitrary value - missingFileHandler: Warn # set to either "Error" or "Warn". "Error" instructs helmfile to fail when unable to find a values or secrets file. When "Warn", it prints the file and continues. - missingFileHandlerConfig: - # Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error. - # See https://github.com/helmfile/helmfile/issues/392 - ignoreMissingGitBranch: true - # Values files used for rendering the chart - values: - # Value files passed via --values - - vault.yaml - # Inline values, passed via a temporary values file and --values, so that it doesn't suffer from type issues like --set - - address: https://vault.example.com - # Go template available in inline values and values files. - - image: - # The end result is more or less YAML. So do `quote` to prevent number-like strings from accidentally parsed into numbers! - # See https://github.com/roboll/helmfile/issues/608 - tag: {{ requiredEnv "IMAGE_TAG" | quote }} - # Otherwise: - # tag: "{{ requiredEnv "IMAGE_TAG" }}" - # tag: !!string {{ requiredEnv "IMAGE_TAG" }} - db: - username: {{ requiredEnv "DB_USERNAME" }} - # value taken from environment variable. Quotes are necessary. Will throw an error if the environment variable is not set. $DB_PASSWORD needs to be set in the calling environment ex: export DB_PASSWORD='password1' - password: {{ requiredEnv "DB_PASSWORD" }} - proxy: - # Interpolate environment variable with a fixed string - domain: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com - scheme: {{ env "SCHEME" | default "https" }} - # Use `values` whenever possible! - # `setString` translates to helm's `--set-string key=val` - setString: - # set a single array value in an array, translates to --set-string bar[0]={1,2} - - name: bar[0] - values: - - 1 - - 2 - # set a templated value - - name: namespace - value: {{ .Namespace }} - # `set` translates to helm's `--set key=val`, that is known to suffer from type issues like https://github.com/roboll/helmfile/issues/608 - set: - # single value loaded from a local file, translates to --set-file foo.config=path/to/file - - name: foo.config - file: path/to/file - # set a single array value in an array, translates to --set bar[0]={1,2} - - name: bar[0] - values: - - 1 - - 2 - # set a templated value - - name: namespace - value: {{ .Namespace }} - # will attempt to decrypt it using helm-secrets plugin - secrets: - - vault_secret.yaml - # Override helmDefaults options for verify, wait, waitForJobs, timeout, recreatePods, force and reuseValues. - verify: true - keyring: path/to/keyring.gpg - # --skip-schema-validation flag to helm 'install', 'upgrade' and 'lint' (default false) - skipSchemaValidation: false - wait: true - # DEPRECATED: waitRetries is no longer supported - see documentation above - # waitRetries: 3 - waitForJobs: true - timeout: 60 - recreatePods: true - force: false - reuseValues: false - # set `false` to uninstall this release on sync. (default true) - installed: true - # Defines the strategy to use when updating. Possible value is: - # - "reinstallIfForbidden": Performs an uninstall before the update only if the update is forbidden (e.g., due to permission issues or conflicts). - updateStrategy: "" - # restores previous state in case of failed release (default false) - atomic: true - # when true, cleans up any new resources created during a failed release (default false) - cleanupOnFail: false - # --kube-context to be passed to helm commands - # See https://github.com/roboll/helmfile/issues/642 - # (default "", which means the standard kubeconfig, either ~/kubeconfig or the file pointed by $KUBECONFIG environment variable) - kubeContext: kube-context - # passes --disable-validation to helm diff plugin, this requires diff plugin >= 3.1.2 - # It may be helpful to deploy charts with helm api v1 CRDS - # https://github.com/roboll/helmfile/pull/1373 - disableValidation: false - # passes --disable-validation to helm diff plugin, this requires diff plugin >= 3.1.2 - # It is useful when any release contains custom resources for CRDs that is not yet installed onto the cluster. - # https://github.com/roboll/helmfile/pull/1618 - disableValidationOnInstall: false - # passes --disable-openapi-validation to helm diff plugin, this requires diff plugin >= 3.1.2 - # It may be helpful to deploy charts with helm api v1 CRDS - # https://github.com/roboll/helmfile/pull/1373 - disableOpenAPIValidation: false - # limit the maximum number of revisions saved per release. Use 0 for no limit (default 10) - historyMax: 10 - # When set to `true`, skips running `helm dep up` and `helm dep build` on this release's chart. - # Useful when the chart is broken, like seen in https://github.com/roboll/helmfile/issues/1547 - skipDeps: false - # propagate `--post-renderer` to helmv3 template and helm install - postRenderer: "path/to/postRenderer" - # propagate `--post-renderer-args` to helmv3 template and helm install. This allows using Powershell - # scripts on Windows as a post renderer - postRendererArgs: - - PowerShell - - "-Command" - - "theScript.ps1" - # cascade `--cascade` to helmv3 delete, available values: background, foreground, or orphan, default: background - cascade: "background" - # insecureSkipTLSVerify is true if the TLS verification should be skipped when fetching remote chart - insecureSkipTLSVerify: false - # plainHttp is true if fetching the remote chart should be done using HTTP - plainHttp: false - # suppressDiff skip the helm diff output. Useful for charts which produces large not helpful diff, default: false - suppressDiff: false - # suppressOutputLineRegex is a list of regex patterns to suppress output lines from helm diff (default []), available in helmfile v0.162.0 - suppressOutputLineRegex: - - "version" - # syncReleaseLabels is a list of labels to be added to the release when syncing. - syncReleaseLabels: false - # unitTests is a list of test file or directory paths for helm-unittest integration. - # When specified, `helmfile unittest` will run `helm unittest` with the merged values and these test paths. - # Requires the helm-unittest plugin: https://github.com/helm-unittest/helm-unittest - unitTests: - - tests/vault - - - # Local chart example - - name: grafana # name of this release - namespace: another # target namespace - chart: ../my-charts/grafana # the chart being installed to create this release, referenced by relative path to local helmfile - values: - - "../../my-values/grafana/values.yaml" # Values file (relative path to manifest) - - ./values/{{ requiredEnv "PLATFORM_ENV" }}/config.yaml # Values file taken from path with environment variable. $PLATFORM_ENV must be set in the calling environment. - wait: true - -# -# Advanced Configuration: Nested States -# -helmfiles: -- # Path to the helmfile state file being processed BEFORE releases in this state file - path: path/to/subhelmfile.yaml - # Label selector used for filtering releases in the nested state. - # For example, `name=prometheus` in this context is equivalent to processing the nested state like - # helmfile -f path/to/subhelmfile.yaml -l name=prometheus sync - selectors: - - name=prometheus - # Override state values - values: - # Values files merged into the nested state's values - - additional.values.yaml - # One important aspect of using values here is that they first need to be defined in the values section - # of the origin helmfile, so in this example key1 needs to be in the values or environments.NAME.values of path/to/subhelmfile.yaml - # Inline state values merged into the nested state's values - - key1: val1 -- # All the nested state files under `helmfiles:` is processed in the order of definition. - # So it can be used for preparation for your main `releases`. An example would be creating CRDs required by `releases` in the parent state file. - path: path/to/mycrd.helmfile.yaml -- # Terraform-module-like URL for importing a remote directory and use a file in it as a nested-state file - # The nested-state file is locally checked-out along with the remote directory containing it. - # Therefore all the local paths in the file are resolved relative to the file - path: git::https://github.com/cloudposse/helmfiles.git@releases/kiam.yaml?ref=0.40.0 -- # By default git repositories aren't updated unless the ref is updated. - # Alternatively, refer to a named ref and disable the caching. - path: git::ssh://git@github.com/cloudposse/helmfiles.git@releases/kiam.yaml?ref=main&cache=false -# If set to "Error", return an error when a subhelmfile points to a -# non-existent path. The default behavior is to print a warning and continue. -missingFileHandler: Error -missingFileHandlerConfig: - # Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error. - # See https://github.com/helmfile/helmfile/issues/392 - ignoreMissingGitBranch: true - -# -# Advanced Configuration: Environments -# - -# The list of environments managed by helmfile. -# -# The default is `environments: {"default": {}}` which implies: -# -# - `{{ .Environment.Name }}` evaluates to "default" -# - `{{ .Values }}` being empty -environments: - # The "default" environment is available and used when `helmfile` is run without `--environment NAME`. - default: - # Everything from the values.yaml is available via `{{ .Values.KEY }}`. - # Suppose `{"foo": {"bar": 1}}` contained in the values.yaml below, - # `{{ .Values.foo.bar }}` is evaluated to `1`. - values: - - environments/default/values.yaml - # Everything from the values.hcl in the `values` block is available via `{{ .Values.KEY }}`. - # More details in its dedicated section - - environments/default/values.hcl - # Each entry in values can be either a file path or inline values. - # The below is an example of inline values, which is merged to the `.Values` - - myChartVer: 1.0.0-dev - # Any environment other than `default` is used only when `helmfile` is run with `--environment NAME`. - # That is, the "production" env below is used when and only when it is run like `helmfile --environment production sync`. - production: - values: - - environments/production/values.yaml - - myChartVer: 1.0.0 - # disable vault release processing - - vault: - enabled: false - ## `secrets.yaml` is decrypted by `helm-secrets` and available via `{{ .Environment.Values.KEY }}` - secrets: - - environments/production/secrets.yaml - # Instructs helmfile to fail when unable to find a environment values file listed under `environments.NAME.values`. - # - # Possible values are "Error", "Warn", "Info", "Debug". The default is "Error". - # - # Use "Warn", "Info", or "Debug" if you want helmfile to not fail when a values file is missing, while just leaving - # a message about the missing file at the log-level. - missingFileHandler: Error - missingFileHandlerConfig: - # Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error. - # See https://github.com/helmfile/helmfile/issues/392 - ignoreMissingGitBranch: true - # kubeContext to use for this environment - kubeContext: kube-context - -# -# Advanced Configuration: Layering -# -# Helmfile merges all the "base" state files and this state file before processing. -# -# Assuming this state file is named `helmfile.yaml`, all the files are merged in the order of: -# environments.yaml <- defaults.yaml <- templates.yaml <- helmfile.yaml -bases: -- environments.yaml -- defaults.yaml -- templates.yaml - -# -# Advanced Configuration: API Capabilities -# -# 'helmfile template' renders releases locally without querying an actual cluster, -# and in this case `.Capabilities.APIVersions` cannot be populated. -# When a chart queries for a specific CRD or the Kubernetes version, this can lead to unexpected results. -# -# Note that `Capabilities.KubeVersion` is deprecated in Helm 3 and `helm template` won't populate it. -# All you can do is fix your chart to respect `.Capabilities.APIVersions` instead, rather than trying to figure out -# how to set `Capabilities.KubeVersion` in Helmfile. -# -# Configure a fixed list of API versions to pass to 'helm template' via the --api-versions flag with the below: -apiVersions: -- example/v1 - -# Set the kubeVersion to render the chart with your desired Kubernetes version. -# The flag --kube-version was deprecated in helm v3 but it was added again. -# For further information https://github.com/helm/helm/issues/7326 -kubeVersion: v1.21 -``` - -## Templating - -Helmfile uses [Go templates](https://godoc.org/text/template) for templating your helmfile.yaml. While go ships several built-in functions, we have added all of the functions in the [Sprig library](https://godoc.org/github.com/Masterminds/sprig). - -We also added the following functions: - -* [`env`](templating_funcs.md#env) -* [`requiredEnv`](templating_funcs.md#requiredenv) -* [`exec`](templating_funcs.md#exec) -* [`envExec`](templating_funcs.md#envexec) -* [`readFile`](templating_funcs.md#readfile) -* [`readDir`](templating_funcs.md#readdir) -* [`readDirEntries`](templating_funcs.md#readdirentries) -* [`toYaml`](templating_funcs.md#toyaml) -* [`fromYaml`](templating_funcs.md#fromyaml) -* [`setValueAtPath`](templating_funcs.md#setvalueatpath) -* [`get`](templating_funcs.md#get) (Sprig's original `get` is available as `sprigGet`) -* [`getOrNil`](templating_funcs.md#getornil) -* [`tpl`](templating_funcs.md#tpl) -* [`required`](templating_funcs.md#required) -* [`fetchSecretValue`](templating_funcs.md#fetchsecretvalue) -* [`expandSecretRefs`](templating_funcs.md#expandsecretrefs) -* [`include`](templating_funcs.md#include) - -More details on each function can be found at the ["Template Functions" page in our documentation](templating_funcs.md). - - -## Using environment variables - -Environment variables can be used in most places for templating the helmfile. Currently this is supported for `name`, `namespace`, `value` (in set), `values` and `url` (in repositories). - -Examples: +Edit `helmfile.yaml` to add another release: ```yaml repositories: -- name: your-private-git-repo-hosted-charts - url: https://{{ requiredEnv "GITHUB_TOKEN"}}@raw.githubusercontent.com/kmzfs/helm-repo-in-github/master/ -``` + - name: prometheus-community + url: https://prometheus-community.github.io/helm-charts -```yaml releases: - - name: {{ requiredEnv "NAME" }}-vault - namespace: {{ requiredEnv "NAME" }} - chart: roboll/vault-secret-manager + - name: my-prometheus + namespace: monitoring + createNamespace: true + chart: prometheus-community/prometheus values: - - db: - username: {{ requiredEnv "DB_USERNAME" }} - password: {{ requiredEnv "DB_PASSWORD" }} - set: - - name: proxy.domain - value: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com - - name: proxy.scheme - value: {{ env "SCHEME" | default "https" }} + - server: + persistentVolume: + enabled: false + + - name: my-grafana + namespace: monitoring + chart: grafana/grafana ``` -### Note +Run `helmfile apply` again — Helmfile will detect the new release and only deploy what changed. -If you wish to treat your enviroment variables as strings always, even if they are boolean or numeric values you can use `{{ env "ENV_NAME" | quote }}` or `"{{ env "ENV_NAME" }}"`. These approaches also work with `requiredEnv`. - -### Useful internal Helmfile environment variables - -Helmfile uses some OS environment variables to override default behaviour: - -* `HELMFILE_DISABLE_INSECURE_FEATURES` - disable insecure features, expecting `true` lower case -* `HELMFILE_DISABLE_RUNNER_UNIQUE_ID` - disable unique logging ID, expecting any non-empty value -* `HELMFILE_SKIP_INSECURE_TEMPLATE_FUNCTIONS` - disable insecure template functions, expecting `true` lower case -* `HELMFILE_USE_HELM_STATUS_TO_CHECK_RELEASE_EXISTENCE` - expecting non-empty value to use `helm status` to check release existence, instead of `helm list` which is the default behaviour -* `HELMFILE_EXPERIMENTAL` - enable experimental features, expecting `true` lower case -* `HELMFILE_ENVIRONMENT` - specify [Helmfile environment](https://helmfile.readthedocs.io/en/latest/#environment), it has lower priority than CLI argument `--environment` -* `HELMFILE_TEMPDIR` - specify directory to store temporary files -* `HELMFILE_UPGRADE_NOTICE_DISABLED` - expecting any non-empty value to skip the check for the latest version of Helmfile in [helmfile version](https://helmfile.readthedocs.io/en/latest/#version) -* `HELMFILE_GO_YAML_V3` - use *go.yaml.in/yaml/v3* instead of *go.yaml.in/yaml/v2*. It's `false` by default in Helmfile v0.x, and `true` in Helmfile v1.x. -* `HELMFILE_CACHE_HOME` - specify directory to store cached files for remote operations -* `HELMFILE_FILE_PATH` - specify the path to the helmfile.yaml file -* `HELMFILE_INTERACTIVE` - enable interactive mode, expecting `true` lower case. The same as `--interactive` CLI flag -* `HELMFILE_RENDER_YAML` - force helmfile.yaml to be rendered as a Go template regardless of file extension, expecting `true` lower case. Useful for migrating from v0 to v1 without renaming files to `.gotmpl` -* `HELMFILE_AWS_SDK_LOG_LEVEL` - configure AWS SDK logging level for vals library. Valid values: `off` (default, secure, case-insensitive), `minimal`, `standard`, `verbose`, or custom comma-separated values like `request,response`. See issue #2270 for details -* `HELMFILE_VALS_FAIL_ON_MISSING_KEY_IN_MAP` - enable strict mode for vals secret references. When set to `true` (or any value accepted by Go's `strconv.ParseBool` like `TRUE`, `1`), vals will fail when a referenced key does not exist in the secret map. Invalid values will cause an error when vals is initialized (when secret refs are first evaluated). Default is `false` (when unset or empty) for backward compatibility. See issue #1563 for details - -## CLI Reference - -``` -Declaratively deploy your Kubernetes manifests, Kustomize configs, and Charts as Helm releases in one shot -V1 mode = false -YAML library = go.yaml.in/yaml/v3 - -Usage: - helmfile [command] - -Available Commands: - apply Apply all resources from state file only when there are changes - build Build all resources from state file - cache Cache management - charts DEPRECATED: sync releases from state file (helm upgrade --install) - completion Generate the autocompletion script for the specified shell - delete DEPRECATED: delete releases from state file (helm delete) - deps Update charts based on their requirements - destroy Destroys and then purges releases - diff Diff releases defined in state file - fetch Fetch charts from state file - help Help about any command - init Initialize the helmfile, includes version checking and installation of helm and plug-ins - lint Lint charts from state file (helm lint) - list List releases defined in state file - repos Add chart repositories defined in state file - show-dag It prints a table with 3 columns, GROUP, RELEASE, and DEPENDENCIES. GROUP is the unsigned, monotonically increasing integer starting from 1. All the releases with the same GROUP are deployed concurrently. Everything in GROUP 2 starts being deployed only after everything in GROUP 1 got successfully deployed. RELEASE is the release that belongs to the GROUP. DEPENDENCIES is the list of releases that the RELEASE depends on. It should always be empty for releases in GROUP 1. DEPENDENCIES for a release in GROUP 2 should have some or all dependencies appeared in GROUP 1. It can be "some" because Helmfile simplifies the DAGs of releases into a DAG of groups, so that Helmfile always produce a single DAG for everything written in helmfile.yaml, even when there are technically two or more independent DAGs of releases in it. - status Retrieve status of releases in state file - sync Sync releases defined in state file - template Template releases defined in state file - test Test charts from state file (helm test) - unittest Unit test charts from state file using helm-unittest plugin - version Print the CLI version - write-values Write values files for releases. Similar to `helmfile template`, write values files instead of manifests. - -Flags: - --allow-no-matching-release Do not exit with an error code if the provided selector has no matching releases. - -c, --chart string Set chart. Uses the chart set in release by default, and is available in template as {{ .Chart }} - --color Output with color - --debug Enable verbose output for Helm and set log-level to debug, this disables --quiet/-q effect - --disable-force-update do not force helm repos to update when executing "helm repo add" - --enable-live-output Show live output from the Helm binary Stdout/Stderr into Helmfile own Stdout/Stderr. - It only applies for the Helm CLI commands, Stdout/Stderr for Hooks are still displayed only when it's execution finishes. - -e, --environment string specify the environment name. Overrides "HELMFILE_ENVIRONMENT" OS environment variable when specified. defaults to "default" - -f, --file helmfile.yaml load config from file or directory. defaults to "helmfile.yaml" or "helmfile.yaml.gotmpl" or "helmfile.d" (means "helmfile.d/*.yaml" or "helmfile.d/*.yaml.gotmpl") in this preference. Specify - to load the config from the standard input. - -b, --helm-binary string Path to the helm binary (default "helm") - -h, --help help for helmfile - -i, --interactive Request confirmation before attempting to modify clusters - --kube-context string Set kubectl context. Uses current context by default - -k, --kustomize-binary string Path to the kustomize binary (default "kustomize") - --log-level string Set log level, default info (default "info") - -n, --namespace string Set namespace. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }} - --no-color Output without color - -q, --quiet Silence output. Equivalent to log-level warn - -l, --selector stringArray Only run using the releases that match labels. Labels can take the form of foo=bar or foo!=bar. - A release must match all labels in a group in order to be used. Multiple groups can be specified at once. - "--selector tier=frontend,tier!=proxy --selector tier=backend" will match all frontend, non-proxy releases AND all backend releases. - The name of a release can be used as a label: "--selector name=myrelease" - --skip-deps skip running "helm repo update" and "helm dependency build" - --state-values-file stringArray specify state values in a YAML file. Used to override .Values within the helmfile template (not values template). - --state-values-set stringArray set state values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2). Used to override .Values within the helmfile template (not values template). - --state-values-set-string stringArray set state STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2). Used to override .Values within the helmfile template (not values template). - --sequential-helmfiles Process helmfile.d files sequentially in alphabetical order instead of in parallel - --strip-args-values-on-exit-error Strip the potential secret values of the helm command args contained in a helmfile error message (default true) - -v, --version version for helmfile - -Use "helmfile [command] --help" for more information about a command. -``` - -**Note:** Each command has its own specific flags. Use `helmfile [command] --help` to see command-specific options. For example, `helmfile sync --help` shows operational flags like `--timeout`, `--wait`, and `--wait-for-jobs`. - -### init - -The `helmfile init` sub-command checks the dependencies required for helmfile operation, such as `helm`, `helm diff plugin`, `helm secrets plugin`, `helm helm-git plugin`, `helm s3 plugin`. When it does not exist or the version is too low, it can be installed automatically. - -### cache - -The `helmfile cache` sub-command is designed for cache management. Go-getter-backed remote file system are cached by `helmfile`. There is no TTL implemented, if you need to update the cached files or directories, you need to clean individually or run a full cleanup with `helmfile cache cleanup` - -#### OCI Chart Cache - -OCI charts are cached in the shared cache directory (`~/.cache/helmfile` by default, or `$HELMFILE_CACHE_HOME`). This cache is shared across all helmfile processes. - -**Cache Behavior:** - -- When a chart exists in the shared cache and is valid, it is reused without re-downloading -- The `--skip-refresh` flag can be used to skip checking for updates to cached charts stored in process-specific temporary directories (it does not affect charts already present in the shared cache) -- When running multiple helmfile processes in parallel (e.g., as an ArgoCD plugin), charts in the shared cache are not refreshed/deleted to prevent race conditions - -**Forcing a Cache Refresh:** - -To force a refresh of cached OCI charts, run: -```bash -helmfile cache cleanup -``` - -This will clear the shared cache, allowing the next helmfile command to re-download charts. - -#### cache info - -Display information about the cache directory. - -#### cache cleanup - -Remove all cached files from the cache directory. - -### sync - -The `helmfile sync` sub-command sync your cluster state as described in your `helmfile`. The default helmfile is `helmfile.yaml`, but any YAML file can be passed by specifying a `--file path/to/your/yaml/file` flag. - -Under the covers, Helmfile executes `helm upgrade --install` for each `release` declared in the manifest, by optionally decrypting [secrets](#secrets) to be consumed as helm chart values. It also updates specified chart repositories and updates the -dependencies of any referenced local charts. - -#### Common sync flags - -* `--timeout SECONDS` - Override the default timeout for all releases in this sync operation. This takes precedence over `helmDefaults.timeout` and per-release `timeout` settings. -* `--wait` - Override the default wait behavior for all releases -* `--wait-for-jobs` - Override the default wait-for-jobs behavior for all releases - -Examples: +### Step 5: Clean up ```bash -# Override timeout for all releases to 10 minutes -helmfile sync --timeout 600 - -# Combine timeout with wait flags -helmfile sync --timeout 900 --wait --wait-for-jobs - -# Target specific releases with custom timeout -helmfile sync --selector tier=backend --timeout 1200 +# Remove everything +helmfile destroy ``` -For Helm 2.9+ you can use a username and password to authenticate to a remote repository. +### Next Steps -### deps +Now that you have the basics, explore these topics: -The `helmfile deps` sub-command locks your helmfile state and local charts dependencies. +**Core concepts** (read in order): +1. [Writing Helmfile](writing-helmfile.md) — patterns and best practices for structuring helmfiles +2. [Values and Merging](values-and-merging.md) — how Helmfile merges values from multiple sources +3. [Environments](environments.md) — manage dev/staging/production with a single helmfile -It basically runs `helm dependency update` on your helmfile state file and all the referenced local charts, so that you get a "lock" file per each helmfile state or local chart. - -All the other `helmfile` sub-commands like `sync` use chart versions recorded in the lock files, so that e.g. untested chart versions won't suddenly get deployed to the production environment. - -For example, the lock file for a helmfile state file named `helmfile.1.yaml` will be `helmfile.1.lock`. The lock file for a local chart would be `requirements.lock`, which is the same as `helm`. - -The lock file can be changed using `lockFilePath` in helm state, which makes it possible to for example have a different lock file per environment via templating. - -It is recommended to version-control all the lock files, so that they can be used in the production deployment pipeline for extra reproducibility. - -To bring in chart updates systematically, it would also be a good idea to run `helmfile deps` regularly, test it, and then update the lock files in the version-control system. - -### diff - -The `helmfile diff` sub-command executes the [helm-diff](https://github.com/databus23/helm-diff) plugin across all of -the charts/releases defined in the manifest. - -To supply the diff functionality Helmfile needs the [helm-diff](https://github.com/databus23/helm-diff) plugin v2.9.0+1 or greater installed. For Helm 2.3+ -you should be able to simply execute `helm plugin install https://github.com/databus23/helm-diff`. For more details -please look at their [documentation](https://github.com/databus23/helm-diff#helm-diff-plugin). - -### apply - -The `helmfile apply` sub-command begins by executing `diff`. If `diff` finds that there is any changes, `sync` is executed. Adding `--interactive` instructs Helmfile to request your confirmation before `sync`. - -An expected use-case of `apply` is to schedule it to run periodically, so that you can auto-fix skews between the desired and the current state of your apps running on Kubernetes clusters. - -### destroy - -The `helmfile destroy` sub-command uninstalls and purges all the releases defined in the manifests. - -`helmfile --interactive destroy` instructs Helmfile to request your confirmation before actually deleting releases. - -`destroy` basically runs `helm uninstall --purge` on all the targeted releases. If you don't want purging, use `helmfile delete` instead. -If `--skip-charts` flag is not set, destroy would prepare all releases, by fetching charts and templating them. - -### delete (DEPRECATED) - -The `helmfile delete` sub-command deletes all the releases defined in the manifests. - -`helmfile --interactive delete` instructs Helmfile to request your confirmation before actually deleting releases. - -Note that `delete` doesn't purge releases. So `helmfile delete && helmfile sync` results in sync failed due to that releases names are not deleted but preserved for future references. If you really want to remove releases for reuse, add `--purge` flag to run it like `helmfile delete --purge`. -If `--skip-charts` flag is not set, destroy would prepare all releases, by fetching charts and templating them. - -### secrets - -The `secrets` parameter in a `helmfile.yaml` causes the [helm-secrets](https://github.com/jkroepke/helm-secrets) plugin to be executed to decrypt the file. - -To supply the secret functionality Helmfile needs the `helm secrets` plugin installed. For Helm 2.3+ -you should be able to simply execute `helm plugin install https://github.com/jkroepke/helm-secrets -`. - -### test - -The `helmfile test` sub-command runs a `helm test` against specified releases in the manifest, default to all - -Use `--cleanup` to delete pods upon completion. - -### lint - -The `helmfile lint` sub-command runs a `helm lint` across all of the charts/releases defined in the manifest. Non local charts will be fetched into a temporary folder which will be deleted once the task is completed. - -### unittest - -The `helmfile unittest` sub-command runs `helm unittest` (from the [helm-unittest plugin](https://github.com/helm-unittest/helm-unittest)) on releases that have `unitTests` defined. It automatically generates the final merged values files for each release and passes them to `helm unittest`. - -This requires the `helm-unittest` plugin to be installed. You can install it with: - -```bash -helm plugin install https://github.com/helm-unittest/helm-unittest -``` - -Releases without `unitTests` defined are skipped. Non-local charts will be fetched into a temporary folder which will be deleted once the task is completed. - -Example helmfile configuration: - -```yaml -releases: - - name: my-app - chart: ./charts/my-app - values: - - values.yaml - unitTests: - - tests -``` - -The `unitTests` paths are relative to the chart directory and follow helm-unittest conventions. -If a path does not contain glob characters, it is treated as a directory and `/*_test.yaml` is appended automatically. -You can also specify explicit glob patterns (e.g., `tests/**/*_test.yaml`). - -Running `helmfile unittest` will: - -1. Merge all values files defined for the release -2. Run `helm unittest ./charts/my-app --values --file tests/*_test.yaml` - -You can pass additional flags: - -```bash -# Run with additional values -helmfile unittest --values extra-values.yaml - -# Run with --set overrides -helmfile unittest --set key=value - -# Target specific releases -helmfile unittest --selector name=my-app - -# Fail fast on first test failure -helmfile unittest --fail-fast - -# Enable colored output (Helm 3 only; ignored on Helm 4 due to flag parsing issues) -helmfile unittest --color - -# Enable verbose plugin output -helmfile unittest --debug-plugin - -# Pass extra arguments to helm unittest -helmfile unittest --args "--strict" -``` - -### fetch - -The `helmfile fetch` sub-command downloads or copies local charts to a local directory for debug purpose. The local directory -must be specified with `--output-dir`. - -### list - -The `helmfile list` sub-command lists releases defined in the manifest. Optional `--output` flag accepts `json` to output releases in JSON format. - -If `--skip-charts` flag is not set, list would prepare all releases, by fetching charts and templating them. - -### version - -The `helmfile version` sub-command prints the version of Helmfile.Optional `-o` flag accepts `json` `yaml` `short` to output version in JSON, YAML or short format. - -default it will check for the latest version of Helmfile and print a tip if the current version is not the latest. To disable this behavior, set environment variable `HELMFILE_UPGRADE_NOTICE_DISABLED` to any non-empty value. - -### show-dag - -It prints a table with 3 columns, GROUP, RELEASE, and DEPENDENCIES. - -GROUP is the unsigned, monotonically increasing integer starting from 1. All the releases with the same GROUP are deployed concurrently. Everything in GROUP 2 starts being deployed only after everything in GROUP 1 got successfully deployed. - -RELEASE is the release that belongs to the GROUP. - -DEPENDENCIES is the list of releases that the RELEASE depends on. It should always be empty for releases in GROUP 1. DEPENDENCIES for a release in GROUP 2 should have some or all dependencies appeared in GROUP 1. It can be "some" because Helmfile simplifies the DAGs of releases into a DAG of groups, so that Helmfile always produce a single DAG for everything written in helmfile.yaml, even when there are technically two or more independent DAGs of releases in it. - -## Paths Overview - -Using manifest files in conjunction with command line argument can be a bit confusing. - -A few rules to clear up this ambiguity: - -* Absolute paths are always resolved as absolute paths -* Relative paths referenced *in* the Helmfile manifest itself are relative to that manifest -* Relative paths referenced on the command line are relative to the current working directory the user is in -- Relative paths referenced from within the helmfile loaded from the standard input using `helmfile -f -` are relative to the current working directory - -For additional context, take a look at [paths examples](paths.md). +**Reference material** (look up as needed): +* [Configuration Reference](configuration.md) — complete `helmfile.yaml` schema +* [CLI Reference](cli.md) — all commands and flags +* [Template Functions](templating_funcs.md) — functions available in Go templates ## Labels Overview @@ -909,7 +213,7 @@ The `selector` parameter can be specified multiple times. Each parameter is reso In addition to user supplied labels, the name, the namespace, and the chart are available to be used as selectors. The chart will just be the chart name excluding the repository (Example `stable/filebeat` would be selected using `--selector chart=filebeat`). -`commonLabels` can be used when you want to apply the same label to all releases and use [templating](##Templates) based on that. +`commonLabels` can be used when you want to apply the same label to all releases and use [templating](templating.md) based on that. For instance, you install a number of charts on every customer but need to provide different values file per customer. templates/common.yaml: @@ -944,1047 +248,27 @@ releases: - <<: *cert-manager ``` -## Templates +## Advanced -You can use go's text/template expressions in `helmfile.yaml` and `values.yaml.gotmpl` (templated helm values files). `values.yaml` references will be used verbatim. In other words: +* [Advanced Features](advanced-features.md) - Kubedog, Kustomize, chartify, vals integration +* [Hooks](hooks.md) - Lifecycle hooks (prepare, presync, postsync, cleanup) +* [Secrets](remote-secrets.md) - Remote secrets (vault, SSM, etc.) +* [Shared Configuration Across Teams](shared-configuration-across-teams.md) - Multi-team Helmfile patterns -* for value files ending with `.gotmpl`, template expressions will be rendered -* for plain value files (ending in `.yaml`), content will be used as-is +## Community -In addition to built-in ones, the following custom template functions are available: - -* `readFile` reads the specified local file and generate a golang string -* `readDir` reads the files within provided directory path. (folders are excluded) -* `readDirEntries` Returns a list of [https://pkg.go.dev/os#DirEntry](DirEntry) within provided directory path -* `fromYaml` reads a golang string and generates a map -* `setValueAtPath PATH NEW_VALUE` traverses a golang map, replaces the value at the PATH with NEW_VALUE -* `toYaml` marshals a map into a string -* `get` returns the value of the specified key if present in the `.Values` object, otherwise will return the default value defined in the function - -### Values Files Templates - -You can reference a template of values file in your `helmfile.yaml` like below: - -```yaml -releases: -- name: myapp - chart: mychart - values: - - values.yaml.gotmpl -``` - -Every values file whose file extension is `.gotmpl` is considered as a template file. - -Suppose `values.yaml.gotmpl` was something like: - -```yaml -{{ readFile "values.yaml" | fromYaml | setValueAtPath "foo.bar" "FOO_BAR" | toYaml }} -``` - -And `values.yaml` was: - -```yaml -foo: - bar: "" -``` - -The resulting, temporary values.yaml that is generated from `values.yaml.gotmpl` would become: - -```yaml -foo: - # Notice `setValueAtPath "foo.bar" "FOO_BAR"` in the template above - bar: FOO_BAR -``` - -## Refactoring `helmfile.yaml` with values files templates - -One of expected use-cases of values files templates is to keep `helmfile.yaml` small and concise. - -See the example `helmfile.yaml` below: - -```yaml -releases: - - name: {{ requiredEnv "NAME" }}-vault - namespace: {{ requiredEnv "NAME" }} - chart: roboll/vault-secret-manager - values: - - db: - username: {{ requiredEnv "DB_USERNAME" }} - password: {{ requiredEnv "DB_PASSWORD" }} - set: - - name: proxy.domain - value: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com - - name: proxy.scheme - value: {{ env "SCHEME" | default "https" }} -``` - -The `values` and `set` sections of the config file can be separated out into a template: - -`helmfile.yaml`: - -```yaml -releases: - - name: {{ requiredEnv "NAME" }}-vault - namespace: {{ requiredEnv "NAME" }} - chart: roboll/vault-secret-manager - values: - - values.yaml.gotmpl -``` - -`values.yaml.gotmpl`: - -```yaml -db: - username: {{ requiredEnv "DB_USERNAME" }} - password: {{ requiredEnv "DB_PASSWORD" }} -proxy: - domain: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com - scheme: {{ env "SCHEME" | default "https" }} -``` - -## Environment - -When you want to customize the contents of `helmfile.yaml` or `values.yaml` files per environment, use this feature. - -You can define as many environments as you want under `environments` in `helmfile.yaml`. -`environments` section should be separated from `releases` with `---`. - -The environment name defaults to `default`, that is, `helmfile sync` implies the `default` environment. -The selected environment name can be referenced from `helmfile.yaml` and `values.yaml.gotmpl` by `{{ .Environment.Name }}`. - -If you want to specify a non-default environment, provide a `--environment NAME` flag to `helmfile` like `helmfile --environment production sync`. - -The below example shows how to define a production-only release: - -```yaml -environments: - default: - production: - ---- - -releases: -- name: newrelic-agent - installed: {{ eq .Environment.Name "production" | toYaml }} - # snip -- name: myapp - # snip -``` - -### Environment Values -Helmfile supports 3 values languages : -- Straight yaml -- Go templates to generate straight yaml -- HCL - -Environment Values allows you to inject a set of values specific to the selected environment, into `values.yaml` templates. -Use it to inject common values from the environment to multiple values files, to make your configuration DRY. - -Suppose you have three files `helmfile.yaml`, `production.yaml` and `values.yaml.gotmpl`: - -`helmfile.yaml` - -```yaml -environments: - production: - values: - - production.yaml - ---- - -releases: -- name: myapp - values: - - values.yaml.gotmpl -``` - -`production.yaml` - -```yaml -domain: prod.example.com -releaseName: prod -``` - -`values.yaml.gotmpl` - -```yaml -domain: {{ .Values | get "domain" "dev.example.com" }} -``` - -`helmfile sync` installs `myapp` with the value `domain=dev.example.com`, -whereas `helmfile --environment production sync` installs the app with the value `domain=prod.example.com`. - -For even more flexibility, you can now use values declared in the `environments:` section in other parts of your helmfiles: - -consider: -`default.yaml` - -```yaml -domain: dev.example.com -releaseName: dev -``` - -```yaml -environments: - default: - values: - - default.yaml - production: - values: - - production.yaml # bare .yaml file, content will be used verbatim - - other.yaml.gotmpl # template directives with potential side-effects like `exec` and `readFile` will be honoured - ---- - -releases: -- name: myapp-{{ .Values.releaseName }} # release name will be one of `dev` or `prod` depending on selected environment - values: - - values.yaml.gotmpl -- name: production-specific-release - # this release would be installed only if selected environment is `production` - installed: {{ eq .Values.releaseName "prod" | toYaml }} - ... -``` - -#### HCL specifications - -Since Helmfile v0.164.0, HCL language is supported for environment values only. -HCL values supports interpolations and sharing values across files - -* Only `.hcl` suffixed files will be interpreted as is -* Helmfile supports 2 different blocks: `values` and `locals` -* `values` block is a shared block where all values are accessible everywhere in all loaded files -* `locals` block can't reference external values apart from the ones in the block itself, and where its defined values are only accessible in its local file -* Only values in `values` blocks are made available to the final root `.Values` (e.g : ` values { myvar = "var" }` is accessed through `{{ .Values.myvar }}`) -* There can only be 1 `locals` block per file -* Helmfile hcl `values` are referenced using the `hv` accessor. -* Helmfile hcl `locals` are referenced using the `local` accessor. -* When the same key is defined multiple times across imported `.hcl` files in `values` blocks, values from later files override those from earlier files (last file loaded wins). Map values are merged per key, while list values are replaced as a whole (i.e. not deep-merged). Mixed-types overrides (e.g. bool -> string) are supported (latest value/type wins). -* All cty [standard library functions](`https://pkg.go.dev/github.com/zclconf/go-cty@v1.14.3/cty/function/stdlib`) are available and custom functions could be created in the future - -Consider the following example : - -```terraform -# values1.hcl -locals { - hostname = "host1" -} -values { - domain = "DEV.EXAMPLE.COM" - hostnameV1 = "${local.hostname}.${lower(hv.domain)}" # "host1.dev.example.com" -} -``` -```terraform -# values2.hcl -locals { - hostname = "host2" -} - -values { - hostnameV2 = "${local.hostname}.${hv.domain}" # "host2.DEV.EXAMPLE.COM" -} -``` -#### Note on Environment.Values vs Values - -The `{{ .Values.foo }}` syntax is the recommended way of using environment values. - -Prior to this [pull request](https://github.com/roboll/helmfile/pull/647), environment values were made available through the `{{ .Environment.Values.foo }}` syntax. -This is still working but is **deprecated** and the new `{{ .Values.foo }}` syntax should be used instead. - -You can read more infos about the feature proposal [here](https://github.com/roboll/helmfile/issues/640). - -### Environment Secrets - -Environment Secrets *(not to be confused with Kubernetes Secrets)* are encrypted versions of `Environment Values`. -You can list any number of `secrets.yaml` files created using `helm secrets` or `sops`, so that -Helmfile could automatically decrypt and merge the secrets into the environment values. - -First you must have the [helm-secrets](https://github.com/jkroepke/helm-secrets) plugin installed along with a -`.sops.yaml` file to configure the method of encryption (this can be in the same directory as your helmfile or -in the subdirectory containing your secrets files). - -Then suppose you have a secret `foo.bar` defined in `environments/production/secrets.yaml`: - -```yaml -foo.bar: "mysupersecretstring" -``` - -You can then encrypt it with `helm secrets enc environments/production/secrets.yaml` - -Then reference that encrypted file in `helmfile.yaml`: - -```yaml -environments: - production: - secrets: - - environments/production/secrets.yaml - ---- - -releases: -- name: myapp - chart: mychart - values: - - values.yaml.gotmpl -``` - -Then the environment secret `foo.bar` can be referenced by the below template expression in your `values.yaml.gotmpl`: - -```yaml -{{ .Values.foo.bar }} -``` - -#### Loading remote Environment secrets files - -Since Helmfile v0.149.0, you can use `go-getter`-style URLs to refer to remote secrets files, the same way as in values files: -```yaml -environments: - staging: - secrets: - - git::https://{{ env "GITHUB_PAT" }}@github.com/org/repo.git@/environments/staging.secret.yaml?ref=main - - http://$HOSTNAME/artifactory/example-repo-local/test.tgz@environments/staging.secret.yaml - production: - secrets: - - git::https://{{ env "GITHUB_PAT" }}@github.com/org/repo.git@/environments/production.secret.yaml?ref=main - - http://$HOSTNAME/artifactory/example-repo-local/test.tgz@environments/production.secret.yaml -``` - -### Loading remote Environment values files - -Since Helmfile v0.118.8, you can use `go-getter`-style URLs to refer to remote values files: - -```yaml -environments: - cluster-azure-us-west: - values: - - git::https://git.company.org/helmfiles/global/azure.yaml?ref=master - - git::https://git.company.org/helmfiles/global/us-west.yaml?ref=master - - git::https://gitlab.com/org/repository-name.git@/config/config.test.yaml?ref=main # Public Gilab Repo - cluster-gcp-europe-west: - values: - - git::https://git.company.org/helmfiles/global/gcp.yaml?ref=master - - git::https://git.company.org/helmfiles/global/europe-west.yaml?ref=master - - git::https://ci:{{ env "CI_JOB_TOKEN" }}@gitlab.com/org/repository-name.git@/config.dev.yaml?ref={{ env "APP_COMMIT_SHA" }} # Private Gitlab Repo - staging: - values: - - git::https://{{ env "GITHUB_PAT" }}@github.com/[$GITHUB_ORGorGITHUB_USER]/repository-name.git@/values.dev.yaml?ref=main #Github Private repo - - http://$HOSTNAME/artifactory/example-repo-local/test.tgz@values.yaml #Artifactory url ---- - -releases: - - ... -``` - -Since Helmfile v0.158.0, support more protocols, such as: s3, https, http -``` -values: - - s3::https://helm-s3-values-example.s3.us-east-2.amazonaws.com/values.yaml - - s3://helm-s3-values-example/subdir/values.yaml - - https://john:doe@helm-s3-values-example.s3.us-east-2.amazonaws.com/values.yaml - - http://helm-s3-values-example.s3.us-east-2.amazonaws.com/values.yaml -``` - -For more information about the supported protocols see: [go-getter Protocol-Specific Options](https://github.com/hashicorp/go-getter#protocol-specific-options-1). - -This is particularly useful when you co-locate helmfiles within your project repo but want to reuse the definitions in a global repo. - -### Environment values precedence -With the introduction of HCL, a new value precedence was introduced over environment values. -Here is the order of precedence from least to greatest (the last one overrides all others) -1. `yaml` / `yaml.gotmpl` -2. `hcl` -3. `yaml` secrets - -Example: - ---- - -```yaml -# values1.yaml -domain: "dev.example.com" -``` - -```terraform -# values2.hcl -values { - domain = "overdev.example.com" - env = "dev" - willBeOverridden = "override_me" -} -``` - -```terraform -# values3.hcl -values { - env = "local" -} -``` - -```yaml -# secrets.yml (assuming this one has been encrypted) -willBeOverridden: overridden -``` - -``` -# helmfile.yaml.gotmpl -environments: - default: - values: - - values1.yaml - - values2.hcl - - values3.hcl - secrets: - - secrets.yml ---- -releases: -- name: random-release - [...] - values: - domain: "{{ .Values.domain }}" # == "overdev.example.com" - env: "{{ .Values.env }}" # == "local" - willBeOverridden: "{{ .Values.willBeOverridden }}" # == "overridden" -``` -## DAG-aware installation/deletion ordering with `needs` - -`needs` controls the order of the installation/deletion of the release: - -```yaml -releases: -- name: somerelease - needs: - - [[KUBECONTEXT/]NAMESPACE/]anotherelease -``` - -Be aware that you have to specify the kubecontext and namespace name if you configured one for the release(s). - -All the releases listed under `needs` are installed before(or deleted after) the release itself. - -For the following example, `helmfile [sync|apply]` installs releases in this order: - -1. logging -2. servicemesh -3. myapp1 and myapp2 - -```yaml - - name: myapp1 - chart: charts/myapp - needs: - - servicemesh - - logging - - name: myapp2 - chart: charts/myapp - needs: - - servicemesh - - logging - - name: servicemesh - chart: charts/istio - needs: - - logging - - name: logging - chart: charts/fluentd -``` - -Note that all the releases in a same group is installed concurrently. That is, myapp1 and myapp2 are installed concurrently. - -On `helmfile [delete|destroy]`, deletions happen in the reverse order. - -That is, `myapp1` and `myapp2` are deleted first, then `servicemesh`, and finally `logging`. - -### Selectors and `needs` - -When using selectors/labels, `needs` are ignored by default. This behaviour can be overruled with a few parameters: - -| Parameter | default | Description | -|---|---|---| -| `--skip-needs` | `true` | `needs` are ignored (default behavior). | -| `--include-needs` | `false` | The direct `needs` of the selected release(s) will be included. | -| `--include-transitive-needs` | `false` | The direct and transitive `needs` of the selected release(s) will be included. | - -Let's look at an example to illustrate how the different parameters work: - -```yaml -releases: -- name: serviceA - chart: my/chart - needs: - - serviceB -- name: serviceB - chart: your/chart - needs: - - serviceC -- name: serviceC - chart: her/chart -- name: serviceD - chart: his/chart -``` - -| Command | Included Releases Order | Explanation | -|---|---|---| -| `helmfile -l name=serviceA sync` | - `serviceA` | By default no needs are included. | -| `helmfile -l name=serviceA sync --include-needs` | - `serviceB`
- `serviceA` | `serviceB` is now part of the release as it is a direct need of `serviceA`. | -| `helmfile -l name=serviceA sync --include-transitive-needs` | - `serviceC`
- `serviceB`
- `serviceA` | `serviceC` is now also part of the release as it is a direct need of `serviceB` and therefore a transitive need of `serviceA`. | - -Note that `--include-transitive-needs` will override any potential exclusions done by selectors or conditions. So even if you explicitly exclude a release via a selector it will still be part of the deployment in case it is a direct or transitive need of any of the specified releases. - -## Separating helmfile.yaml into multiple independent files - -Once your `helmfile.yaml` got to contain too many releases, -split it into multiple yaml files. - -Recommended granularity of helmfile.yaml files is "per microservice" or "per team". -And there are two ways to organize your files. - -* Single directory -* Glob patterns - -### Single directory - -`helmfile -f path/to/directory` loads and runs all the yaml files under the specified directory, each file as an independent helmfile.yaml. -The default helmfile directory is `helmfile.d`, that is, -in case helmfile is unable to locate `helmfile.yaml`, it tries to locate `helmfile.d/*.yaml`. - -By default, multiple files in `helmfile.d` are processed in **parallel** for better performance. If you need files to be processed **sequentially in alphabetical order** (e.g., for dependency ordering where databases must be deployed before applications), use the `--sequential-helmfiles` flag. - -For example, you can use a `-.yaml` naming convention to control the sync order when using `--sequential-helmfiles`: - -* `helmfile.d`/ - * `00-database.yaml` - * `01-backend.yaml` - * `02-frontend.yaml` - -```bash -# Process files sequentially in alphabetical order -helmfile --sequential-helmfiles sync -``` - -> **Note:** When processing multiple helmfile.d files, both parallel and sequential modes resolve paths without changing the process working directory, so relative environment variables like `KUBECONFIG` work correctly. - -### Glob patterns - -In case you want more control over how multiple `helmfile.yaml` files are organized, use `helmfiles:` configuration key in the `helmfile.yaml`: - -Suppose you have multiple microservices organized in a Git repository that looks like: - -* `myteam/` (sometimes it is equivalent to a k8s ns, that is `kube-system` for `clusterops` team) - * `apps/` - * `filebeat/` - * `helmfile.yaml` (no `charts/` exists because it depends on the stable/filebeat chart hosted on the official helm charts repository) - * `README.md` (each app managed by my team has a dedicated README maintained by the owners of the app) - * `metricbeat/` - * `helmfile.yaml` - * `README.md` - * `elastalert-operator/` - * `helmfile.yaml` - * `README.md` - * `charts/` - * `elastalert-operator/` - * `` - -The benefits of this structure is that you can run `git diff` to locate in which directory=microservice a git commit has changes. -It allows your CI system to run a workflow for the changed microservice only. - -A downside of this is that you don't have an obvious way to sync all microservices at once. That is, you have to run: - -```bash -for d in apps/*; do helmfile -f $d diff; if [ $? -eq 2 ]; then helmfile -f $d sync; fi; done -``` - -At this point, you'll start writing a `Makefile` under `myteam/` so that `make sync-all` will do the job. - -It does work, but you can rely on the Helmfile feature instead. - -Put `myteam/helmfile.yaml` that looks like: - -```yaml -helmfiles: -- apps/*/helmfile.yaml -``` - -So that you can get rid of the `Makefile` and the bash snippet. -Just run `helmfile sync` inside `myteam/`, and you are done. - -All the files are sorted alphabetically per group = array item inside `helmfiles:`, so that you have granular control over ordering, too. - -#### selectors - -When composing helmfiles you can use selectors from the command line as well as explicit selectors inside the parent helmfile to filter the releases to be used. - -```yaml -helmfiles: -- apps/*/helmfile.yaml -- path: apps/a-helmfile.yaml - selectors: # list of selectors - - name=prometheus - - tier=frontend -- path: apps/b-helmfile.yaml # no selector, so all releases are used - selectors: [] -- path: apps/c-helmfile.yaml # parent selector to be used or cli selector for the initial helmfile - selectorsInherited: true -``` - -* When a subhelmfile has explicit `selectors`, those selectors determine which releases from that subhelmfile are considered; parent and CLI selectors are not combined with them for release filtering. -* When CLI selectors are provided (e.g. `helmfile -l name=b sync`) and a subhelmfile has explicit selectors that are provably incompatible with them (same key, different value), that subhelmfile may be **skipped entirely** without loading or rendering it. For example, with `-l name=b`, a subhelmfile with `selectors: [name=a]` will be skipped since no release could match both. This optimization does not apply when `selectorsInherited: true` is set or when no CLI selectors are provided. Use `--debug` to see log messages about skipped subhelmfiles. -* When not selector is specified there are 2 modes for the selector inheritance because we would like to change the current inheritance behavior (see [issue #344](https://github.com/roboll/helmfile/issues/344) ). - * Legacy mode, sub-helmfiles without selectors inherit selectors from their parent helmfile. The initial helmfiles inherit from the command line selectors. - * explicit mode, sub-helmfile without selectors do not inherit from their parent or the CLI selector. If you want them to inherit from their parent selector then use `selectorsInherited: true`. To enable this explicit mode you need to set the following environment variable `HELMFILE_EXPERIMENTAL=explicit-selector-inheritance` (see [experimental](#experimental-features)). -* Using `selector: []` will select all releases regardless of the parent selector or cli for the initial helmfile -* using `selectorsInherited: true` make the sub-helmfile selects releases with the parent selector or the cli for the initial helmfile. You cannot specify an explicit selector while using `selectorsInherited: true` - -## Importing values from any source - -The `exec` template function that is available in `values.yaml.gotmpl` is useful for importing values from any source -that is accessible by running a command: - -A usual usage of `exec` would look like this: - -```yaml -mysetting: | -{{ exec "./mycmd" (list "arg1" "arg2" "--flag1") | indent 2 }} -``` - -Or even with a pipeline: - -```yaml -mysetting: | -{{ yourinput | exec "./mycmd-consume-stdin" (list "arg1" "arg2") | indent 2 }} -``` - -The possibility is endless. Try importing values from your golang app, bash script, jsonnet, or anything! - -Then `envExec` same as `exec`, but it can receive a dict as the envs. - -A usual usage of `envExec` would look like this: - -```yaml -mysetting: | -{{ envExec (dict "envkey" "envValue") "./mycmd" (list "arg1" "arg2" "--flag1") | indent 2 }} -``` - -## Hooks - -A Helmfile hook is a per-release extension point that is composed of: - -* `events` -* `command` -* `args` -* `showlogs` - -Helmfile triggers various `events` while it is running. -Once `events` are triggered, associated `hooks` are executed, by running the `command` with `args`. The standard output of the `command` will be displayed if `showlogs` is set and it's value is `true`. - -Hooks exec order follows the order of definition in the helmfile state. - -Currently supported `events` are: - -* `prepare` -* `preapply` -* `presync` -* `preuninstall` -* `postuninstall` -* `postsync` -* `cleanup` - -Hooks associated to `prepare` events are triggered after each release in your helmfile is loaded from YAML, before execution. -`prepare` hooks are triggered on the release as long as it is not excluded by the helmfile selector(e.g. `helmfile -l key=value`). - -Hooks associated to `presync` events are triggered before each release is synced (installed or upgraded) on the cluster. -This is the ideal event to execute any commands that may mutate the cluster state as it will not be run for read-only operations like `lint`, `diff` or `template`. - -`preapply` hooks are triggered before a release is uninstalled, installed, or upgraded as part of `helmfile apply`. -This is the ideal event to hook into when you are going to use `helmfile apply` for every kind of change. Note that preapply hooks will only run if at least one release has changes to apply. Be sure to make each `preapply` hook command idempotent. Otherwise, rerunning `helmfile apply` on a transient failure may end up either breaking your cluster, or the hook that runs for the second time will never succeed. - -`preuninstall` hooks are triggered immediately before a release is uninstalled as part of `helmfile apply`, `helmfile sync`, `helmfile delete`, and `helmfile destroy`. - -`postuninstall` hooks are triggered immediately after successful uninstall of a release while running `helmfile apply`, `helmfile sync`, `helmfile delete`, `helmfile destroy`. - -`postsync` hooks are triggered after each release is synced (installed or upgraded) on the cluster, regardless if the sync was successful or not. -This is the ideal place to execute any commands that may mutate the cluster state as it will not be run for read-only operations like `lint`, `diff` or `template`. - -`cleanup` hooks are triggered after each release is processed. -This is the counterpart to `prepare`, as any release on which `prepare` has been triggered gets `cleanup` triggered as well. - -The following is an example hook that just prints the contextual information provided to hook: - -```yaml -releases: -- name: myapp - chart: mychart - # *snip* - hooks: - - events: ["prepare", "cleanup"] - showlogs: true - command: "echo" - args: ["{{`{{.Environment.Name}}`}}", "{{`{{.Release.Name}}`}}", "{{`{{.HelmfileCommand}}`}}\ -"] -``` - -Let's say you ran `helmfile --environment prod sync`, the above hook results in executing: - -``` -echo {{Environment.Name}} {{.Release.Name}} {{.HelmfileCommand}} -``` - -Whereas the template expressions are executed thus the command becomes: - -``` -echo prod myapp sync -``` - -Now, replace `echo` with any command you like, and rewrite `args` that actually conforms to the command, so that you can integrate any command that does: - -* templating -* linting -* testing - -Hooks expose additional template expressions: - -`.Event.Name` is the name of the hook event. - -`.Event.Error` is the error generated by a failed release, exposed for `postsync` hooks only when a release fails, otherwise its value is `nil`. - -You can use the hooks event expressions to send notifications to platforms such as `Slack`, `MS Teams`, etc. - -The following example passes arguments to a script which sends a notification: - -```yaml -releases: -- name: myapp - chart: mychart - # *snip* - hooks: - - events: - - presync - - postsync - showlogs: true - command: notify.sh - args: - - --event - - '{{`{{ .Event.Name }}`}}' - - --status - - '{{`{{ if .Event.Error }}failure{{ else }}success{{ end }}`}}' - - --environment - - '{{`{{ .Environment.Name }}`}}' - - --namespace - - '{{`{{ .Release.Namespace }}`}}' - - --release - - '{{`{{ .Release.Name }}`}}' -``` - -For templating, imagine that you created a hook that generates a helm chart on-the-fly by running an external tool like ksonnet, kustomize, or your own template engine. -It will allow you to write your helm releases with any language you like, while still leveraging goodies provided by helm. - -### Hooks, Kubectl and Environments - -Hooks can also be used in combination with small tasks using `kubectl` directly, -e.g.: in order to install a custom storage class. - -In the following example, a specific release depends on a custom storage class. -Further, all enviroments have a default kube context configured where releases are deployed into. -The `.Environment.KubeContext` is used in order to apply / remove the YAML to the correct context depending on the environment. - -`environments.yaml`: - -```yaml -environments: - dev: - values: - - ../values/default.yaml - - ../values/dev.yaml - kubeContext: dev-cluster - prod: - values: - - ../values/default.yaml - - ../values/prod.yaml - kubeContext: prod-cluster -``` - -`helmfile.yaml`: - -```yaml -bases: - - ./environments.yaml - ---- -releases: - - name: myService - namespace: my-ns - installed: true - chart: mychart - version: "1.2.3" - values: - - ../services/my-service/values.yaml.gotmpl - hooks: - - events: ["presync"] - showlogs: true - command: "kubectl" - args: - - "apply" - - "-f" - - "./custom-storage-class.yaml" - - "--context" - - "{{`{{.Environment.KubeContext}}`}}" - - events: ["postuninstall"] - showlogs: true - command: "kubectl" - args: - - "delete" - - "-f" - - "./custom-storage-class.yaml" - - "--context" - - "{{`{{.Environment.KubeContext}}`}}" -``` - -### Global Hooks - -In contrast to the per release hooks mentioned above these are run only once at the very beginning and end of the execution of a helmfile command and only the `prepare` and `cleanup` hooks are available respectively. - -They use the same syntax as per release hooks, but at the top level of your helmfile: - -```yaml -hooks: -- events: ["prepare", "cleanup"] - showlogs: true - command: "echo" - args: ["{{`{{.Environment.Name}}`}}", "{{`{{.HelmfileCommand}}`}}\ -"] -``` - -### Helmfile + Kustomize - -Do you prefer `kustomize` to write and organize your Kubernetes apps, but still want to leverage helm's useful features -like rollback, history, and so on? This section is for you! - -The combination of `hooks` and [helmify-kustomize](https://gist.github.com/mumoshu/f9d0bd98e0eb77f636f79fc2fb130690) -enables you to integrate [kustomize](https://github.com/kubernetes-sigs/kustomize) into Helmfile. - -That is, you can use `kustomize` to build a local helm chart from a kustomize overlay. - -Let's assume you have a kustomize project named `foo-kustomize` like this: - -``` -foo-kustomize/ -├── base -│   ├── configMap.yaml -│   ├── deployment.yaml -│   ├── kustomization.yaml -│   └── service.yaml -└── overlays - ├── default - │   ├── kustomization.yaml - │   └── map.yaml - ├── production - │   ├── deployment.yaml - │   └── kustomization.yaml - └── staging - ├── kustomization.yaml - └── map.yaml - -5 directories, 10 files -``` - -Write `helmfile.yaml`: - -```yaml -- name: kustomize - chart: ./foo - hooks: - - events: ["prepare", "cleanup"] - command: "../helmify" - args: ["{{`{{if eq .Event.Name \"prepare\"}}build{{else}}clean{{end}}`}}", "{{`{{.Release.Ch\ -art}}`}}", "{{`{{.Environment.Name}}`}}"] -``` - -Run `helmfile --environment staging sync` and see it results in helmfile running `kustomize build foo-kustomize/overlays/staging > foo/templates/all.yaml`. - -Voilà! You can mix helm releases that are backed by remote charts, local charts, and even kustomize overlays. - -## Guides - -Use the [Helmfile Best Practices Guide](writing-helmfile.md) to write advanced helmfiles that feature: - -* Default values -* Layering - -We also have dedicated documentation on the following topics which might interest you: - -* [Shared Configurations Across Teams](shared-configuration-across-teams.md) - -Or join our friendly slack community in the [`#helmfile`](https://slack.sweetops.com) channel to ask questions and get help. Check out our [slack archive](https://archive.sweetops.com/helmfile/) for good examples of how others are using it. - -## Using .env files - -Helmfile itself doesn't have an ability to load .env files. But you can write some bash script to achieve the goal: - -```console -set -a; . .env; set +a; helmfile sync -``` - -Please see #203 for more context. - -## Running Helmfile interactively - -`helmfile --interactive [apply|destroy|delete|sync]` requests confirmation from you before actually modifying your cluster. - -Use it when you're running `helmfile` manually on your local machine or a kind of secure administrative hosts. - -For your local use-case, aliasing it like `alias hi='helmfile --interactive'` would be convenient. - -Another way to use it is to set the environment variable `HELMFILE_INTERACTIVE=true` to enable the interactive mode by default. -Anything other than `true` will disable the interactive mode. The precedence has the `--interactive` flag. - -## Running Helmfile without an Internet connection - -Once you download all required charts into your machine, you can run `helmfile sync --skip-deps` to deploy your apps. -With the `--skip-deps` option, you can skip running "helm repo update" and "helm dependency build". +Join our friendly slack community in the [`#helmfile`](https://slack.sweetops.com) channel to ask questions and get help. Check out our [slack archive](https://archive.sweetops.com/helmfile/) for good examples of how others are using it. ## Experimental Features Some experimental features may be available for testing in perspective of being (or not) included in a future release. Those features are set using the environment variable `HELMFILE_EXPERIMENTAL`. Here is the current experimental feature : -* `explicit-selector-inheritance` : remove today implicit cli selectors inheritance for composed helmfiles, see [composition selector](#selectors) +* `explicit-selector-inheritance` : remove today implicit cli selectors inheritance for composed helmfiles, see [composition selector](releases.md#selectors) If you want to enable all experimental features set the env var to `HELMFILE_EXPERIMENTAL=true` -## `bash` and `zsh` completion - -helmfile completion --help - ## Examples For more examples, see the [examples/README.md](https://github.com/helmfile/helmfile/blob/master/examples/README.md) or the [`helmfile`](https://github.com/cloudposse/helmfiles/tree/master/releases) distribution by [Cloud Posse](https://github.com/cloudposse/). -## Integrations - -* [renovate](https://github.com/renovatebot/renovate) automates chart version updates. See [this PR for more information](https://github.com/renovatebot/renovate/pull/5257). - * For updating container image tags and git tags embedded within helmfile.yaml and values, you can use [renovate's regexManager](https://docs.renovatebot.com/modules/manager/regex/). Please see [this comment in the renovate repository](https://github.com/renovatebot/renovate/issues/6130#issuecomment-624061289) for more information. -* [ArgoCD Integration](#argocd-integration) -* [Azure ACR Integration](#azure-acr-integration) - -### ArgoCD Integration - -Use [ArgoCD](https://argoproj.github.io/argo-cd/) with `helmfile template` for GitOps. - -ArgoCD has support for kustomize/manifests/helm chart by itself. Why bother with Helmfile? - -The reasons may vary: - -1. You do want to manage applications with ArgoCD, while letting Helmfile manage infrastructure-related components like Calico/Cilium/WeaveNet, Linkerd/Istio, and ArgoCD itself. - -* This way, any application deployed by ArgoCD has access to all the infrastructure. -* Of course, you can use ArgoCD's [Sync Waves and Phases](https://argoproj.github.io/argo-cd/user-guide/sync-waves/) for ordering the infrastructure and application installations. But it may be difficult to separate the concern between the infrastructure and apps and annotate K8s resources consistently when you have different teams for managing infra and apps. - -2. You want to review the exact K8s manifests being applied on pull-request time, before ArgoCD syncs. - -* This is often better than using a kind of `HelmRelease` custom resources that obfuscates exactly what manifests are being applied, which makes reviewing harder. - -3. Use Helmfile as the single-pane of glass for all the K8s resources deployed to your cluster(s). - -* Helmfile can reduce repetition in K8s manifests across ArgoCD application - -For 1, you run `helmfile apply` on CI to deploy ArgoCD and the infrastructure components. - -> helmfile config for this phase often reside within the same directory as your Terraform project. So connecting the two with [terraform-provider-helmfile](https://github.com/mumoshu/terraform-provider-helmfile) may be helpful - -For 2, another app-centric CI or bot should render/commit manifests by running: - -``` -helmfile template --output-dir-template $(pwd)/gitops//{{.Release.Name}} -cd gitops -git add . -git commit -m 'some message' -git push origin $BRANCH -``` - -> Note that `$(pwd)` is necessary when `helmfile.yaml` has one or more sub-helmfiles in nested directories, -> because setting a relative file path in `--output-dir` or `--output-dir-template` results in each sub-helmfile render -> to the directory relative to the specified path. - -so that they can be deployed by Argo CD as usual. - -The CI or bot can optionally submit a PR to be review by human, running: - -``` -hub pull-request -b main -l gitops -m 'some description' -``` - -Recommendations: - -* Do create ArgoCD `Application` custom resource per Helm/Helmfile release, each point to respective sub-directory generated by `helmfile template --output-dir-template` -* If you don't directly push it to the main Git branch and instead go through a pull-request, do lint rendered manifests on your CI, so that you can catch easy mistakes earlier/before ArgoCD finally deploys it -* See [this ArgoCD issue](https://github.com/argoproj/argo-cd/issues/2143#issuecomment-570478329) for why you may want this, and see [this helmfile issue](https://github.com/roboll/helmfile/pull/1357) for how `--output-dir-template` works. - -### Azure ACR Integration - -Azure offers helm repository [support for Azure Container Registry](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-helm-repos) as a preview feature. - -To use this you must first `az login` and then `az acr helm repo add -n `. This will extract a token for the given ACR and configure `helm` to use it, e.g. `helm repo update` should work straight away. - -To use `helmfile` with ACR, on the other hand, you must either include a username/password in the repository definition for the ACR in your `helmfile.yaml` or use the `--skip-deps` switch, e.g. `helmfile template --skip-deps`. - -An ACR repository definition in `helmfile.yaml` looks like this: - -```yaml -repositories: - - name: - url: https://.azurecr.io/helm/v1/repo -``` - -## OCI Registries - -In order to use OCI chart registries firstly they must be marked in the repository list as OCI enabled, e.g. - -```yaml -repositories: - - name: myOCIRegistry - url: myregistry.azurecr.io - oci: true -``` - -It is important not to include a scheme for the URL as helm requires that these are not present for OCI registries - -Secondly the credentials for the OCI registry can either be specified within `helmfile.yaml` similar to - -```yaml -repositories: - - name: myOCIRegistry - url: myregistry.azurecr.io - oci: true - username: spongebob - password: squarepants -``` - -or for CI scenarios these can be sourced from the environment with the format `_USERNAME` and ``, e.g. - -```shell -export MYOCIREGISTRY_USERNAME=spongebob -export MYOCIREGISTRY_PASSWORD=squarepants -``` - -If `` contains hyphens, the environment variable to be read is the hyphen replaced by an underscore., e.g. - -```yaml -repositories: - - name: my-oci-registry - url: myregistry.azurecr.io - oci: true -``` - -```shell -export MY_OCI_REGISTRY_USERNAME=spongebob -export MY_OCI_REGISTRY_PASSWORD=squarepants -``` - -### OCI Chart Caching - -OCI charts are automatically cached in the shared cache directory (`~/.cache/helmfile` by default, or the directory specified by `HELMFILE_CACHE_HOME`). This improves performance by avoiding redundant downloads. - -**Multi-Process Safety:** When running multiple helmfile processes in parallel (e.g., as an ArgoCD plugin), charts in the shared cache are not deleted or refreshed to prevent race conditions where one process might delete a chart that another is using. To force a cache refresh, run `helmfile cache cleanup` first. - -See the [cache](#cache) section for more details on cache management. - -## Attribution - -We use: - -* [semtag](https://github.com/pnikosis/semtag) for automated semver tagging. I greatly appreciate the author(pnikosis)'s effort on creating it and their kindness to share it! diff --git a/docs/integrations.md b/docs/integrations.md new file mode 100644 index 00000000..db7c6ad7 --- /dev/null +++ b/docs/integrations.md @@ -0,0 +1,136 @@ +# Integrations + +## Integrations + +* [renovate](https://github.com/renovatebot/renovate) automates chart version updates. See [this PR for more information](https://github.com/renovatebot/renovate/pull/5257). + * For updating container image tags and git tags embedded within helmfile.yaml and values, you can use [renovate's regexManager](https://docs.renovatebot.com/modules/manager/regex/). Please see [this comment in the renovate repository](https://github.com/renovatebot/renovate/issues/6130#issuecomment-624061289) for more information. +* [ArgoCD Integration](#argocd-integration) +* [Azure ACR Integration](#azure-acr-integration) + +### ArgoCD Integration + +Use [ArgoCD](https://argoproj.github.io/argo-cd/) with `helmfile template` for GitOps. + +ArgoCD has support for kustomize/manifests/helm chart by itself. Why bother with Helmfile? + +The reasons may vary: + +1. You do want to manage applications with ArgoCD, while letting Helmfile manage infrastructure-related components like Calico/Cilium/WeaveNet, Linkerd/Istio, and ArgoCD itself. + +* This way, any application deployed by ArgoCD has access to all the infrastructure. +* Of course, you can use ArgoCD's [Sync Waves and Phases](https://argoproj.github.io/argo-cd/user-guide/sync-waves/) for ordering the infrastructure and application installations. But it may be difficult to separate the concern between the infrastructure and apps and annotate K8s resources consistently when you have different teams for managing infra and apps. + +2. You want to review the exact K8s manifests being applied on pull-request time, before ArgoCD syncs. + +* This is often better than using a kind of `HelmRelease` custom resources that obfuscates exactly what manifests are being applied, which makes reviewing harder. + +3. Use Helmfile as the single-pane of glass for all the K8s resources deployed to your cluster(s). + +* Helmfile can reduce repetition in K8s manifests across ArgoCD application + +For 1, you run `helmfile apply` on CI to deploy ArgoCD and the infrastructure components. + +> helmfile config for this phase often reside within the same directory as your Terraform project. So connecting the two with [terraform-provider-helmfile](https://github.com/mumoshu/terraform-provider-helmfile) may be helpful + +For 2, another app-centric CI or bot should render/commit manifests by running: + +``` +helmfile template --output-dir-template $(pwd)/gitops//{{.Release.Name}} +cd gitops +git add . +git commit -m 'some message' +git push origin $BRANCH +``` + +> Note that `$(pwd)` is necessary when `helmfile.yaml` has one or more sub-helmfiles in nested directories, +> because setting a relative file path in `--output-dir` or `--output-dir-template` results in each sub-helmfile render +> to the directory relative to the specified path. + +so that they can be deployed by Argo CD as usual. + +The CI or bot can optionally submit a PR to be review by human, running: + +``` +hub pull-request -b main -l gitops -m 'some description' +``` + +Recommendations: + +* Do create ArgoCD `Application` custom resource per Helm/Helmfile release, each point to respective sub-directory generated by `helmfile template --output-dir-template` +* If you don't directly push it to the main Git branch and instead go through a pull-request, do lint rendered manifests on your CI, so that you can catch easy mistakes earlier/before ArgoCD finally deploys it +* See [this ArgoCD issue](https://github.com/argoproj/argo-cd/issues/2143#issuecomment-570478329) for why you may want this, and see [this helmfile issue](https://github.com/roboll/helmfile/pull/1357) for how `--output-dir-template` works. + +### Azure ACR Integration + +Azure offers helm repository [support for Azure Container Registry](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-helm-repos) as a preview feature. + +To use this you must first `az login` and then `az acr helm repo add -n `. This will extract a token for the given ACR and configure `helm` to use it, e.g. `helm repo update` should work straight away. + +To use `helmfile` with ACR, on the other hand, you must either include a username/password in the repository definition for the ACR in your `helmfile.yaml` or use the `--skip-deps` switch, e.g. `helmfile template --skip-deps`. + +An ACR repository definition in `helmfile.yaml` looks like this: + +```yaml +repositories: + - name: + url: https://.azurecr.io/helm/v1/repo +``` + +## OCI Registries + +In order to use OCI chart registries firstly they must be marked in the repository list as OCI enabled, e.g. + +```yaml +repositories: + - name: myOCIRegistry + url: myregistry.azurecr.io + oci: true +``` + +It is important not to include a scheme for the URL as helm requires that these are not present for OCI registries + +Secondly the credentials for the OCI registry can either be specified within `helmfile.yaml` similar to + +```yaml +repositories: + - name: myOCIRegistry + url: myregistry.azurecr.io + oci: true + username: spongebob + password: squarepants +``` + +or for CI scenarios these can be sourced from the environment with the format `_USERNAME` and ``, e.g. + +```shell +export MYOCIREGISTRY_USERNAME=spongebob +export MYOCIREGISTRY_PASSWORD=squarepants +``` + +If `` contains hyphens, the environment variable to be read is the hyphen replaced by an underscore., e.g. + +```yaml +repositories: + - name: my-oci-registry + url: myregistry.azurecr.io + oci: true +``` + +```shell +export MY_OCI_REGISTRY_USERNAME=spongebob +export MY_OCI_REGISTRY_PASSWORD=squarepants +``` + +### OCI Chart Caching + +OCI charts are automatically cached in the shared cache directory (`~/.cache/helmfile` by default, or the directory specified by `HELMFILE_CACHE_HOME`). This improves performance by avoiding redundant downloads. + +**Multi-Process Safety:** When running multiple helmfile processes in parallel (e.g., as an ArgoCD plugin), charts in the shared cache are not deleted or refreshed to prevent race conditions where one process might delete a chart that another is using. To force a cache refresh, run `helmfile cache cleanup` first. + +See the [cache](cli.md#cache) section for more details on cache management. + +## Attribution + +We use: + +* [semtag](https://github.com/pnikosis/semtag) for automated semver tagging. I greatly appreciate the author(pnikosis)'s effort on creating it and their kindness to share it! diff --git a/docs/releases.md b/docs/releases.md new file mode 100644 index 00000000..614c7d3b --- /dev/null +++ b/docs/releases.md @@ -0,0 +1,188 @@ +# Releases & DAG + +## DAG-aware installation/deletion ordering with `needs` + +`needs` controls the order of the installation/deletion of the release: + +```yaml +releases: +- name: somerelease + needs: + - [[KUBECONTEXT/]NAMESPACE/]anotherelease +``` + +Be aware that you have to specify the kubecontext and namespace name if you configured one for the release(s). + +All the releases listed under `needs` are installed before(or deleted after) the release itself. + +For the following example, `helmfile [sync|apply]` installs releases in this order: + +1. logging +2. servicemesh +3. myapp1 and myapp2 + +```yaml + - name: myapp1 + chart: charts/myapp + needs: + - servicemesh + - logging + - name: myapp2 + chart: charts/myapp + needs: + - servicemesh + - logging + - name: servicemesh + chart: charts/istio + needs: + - logging + - name: logging + chart: charts/fluentd +``` + +Note that all the releases in a same group is installed concurrently. That is, myapp1 and myapp2 are installed concurrently. + +On `helmfile [delete|destroy]`, deletions happen in the reverse order. + +That is, `myapp1` and `myapp2` are deleted first, then `servicemesh`, and finally `logging`. + +### Selectors and `needs` + +When using selectors/labels, `needs` are ignored by default. This behaviour can be overruled with a few parameters: + +| Parameter | default | Description | +|---|---|---| +| `--skip-needs` | `true` | `needs` are ignored (default behavior). | +| `--include-needs` | `false` | The direct `needs` of the selected release(s) will be included. | +| `--include-transitive-needs` | `false` | The direct and transitive `needs` of the selected release(s) will be included. | + +Let's look at an example to illustrate how the different parameters work: + +```yaml +releases: +- name: serviceA + chart: my/chart + needs: + - serviceB +- name: serviceB + chart: your/chart + needs: + - serviceC +- name: serviceC + chart: her/chart +- name: serviceD + chart: his/chart +``` + +| Command | Included Releases Order | Explanation | +|---|---|---| +| `helmfile -l name=serviceA sync` | - `serviceA` | By default no needs are included. | +| `helmfile -l name=serviceA sync --include-needs` | - `serviceB`
- `serviceA` | `serviceB` is now part of the release as it is a direct need of `serviceA`. | +| `helmfile -l name=serviceA sync --include-transitive-needs` | - `serviceC`
- `serviceB`
- `serviceA` | `serviceC` is now also part of the release as it is a direct need of `serviceB` and therefore a transitive need of `serviceA`. | + +Note that `--include-transitive-needs` will override any potential exclusions done by selectors or conditions. So even if you explicitly exclude a release via a selector it will still be part of the deployment in case it is a direct or transitive need of any of the specified releases. + +## Separating helmfile.yaml into multiple independent files + +Once your `helmfile.yaml` got to contain too many releases, +split it into multiple yaml files. + +Recommended granularity of helmfile.yaml files is "per microservice" or "per team". +And there are two ways to organize your files. + +* Single directory +* Glob patterns + +### Single directory + +`helmfile -f path/to/directory` loads and runs all the yaml files under the specified directory, each file as an independent helmfile.yaml. +The default helmfile directory is `helmfile.d`, that is, +in case helmfile is unable to locate `helmfile.yaml`, it tries to locate `helmfile.d/*.yaml`. + +By default, multiple files in `helmfile.d` are processed in **parallel** for better performance. If you need files to be processed **sequentially in alphabetical order** (e.g., for dependency ordering where databases must be deployed before applications), use the `--sequential-helmfiles` flag. + +For example, you can use a `-.yaml` naming convention to control the sync order when using `--sequential-helmfiles`: + +* `helmfile.d`/ + * `00-database.yaml` + * `01-backend.yaml` + * `02-frontend.yaml` + +```bash +# Process files sequentially in alphabetical order +helmfile --sequential-helmfiles sync +``` + +> **Note:** When processing multiple helmfile.d files, both parallel and sequential modes resolve paths without changing the process working directory, so relative environment variables like `KUBECONFIG` work correctly. + +### Glob patterns + +In case you want more control over how multiple `helmfile.yaml` files are organized, use `helmfiles:` configuration key in the `helmfile.yaml`: + +Suppose you have multiple microservices organized in a Git repository that looks like: + +* `myteam/` (sometimes it is equivalent to a k8s ns, that is `kube-system` for `clusterops` team) + * `apps/` + * `filebeat/` + * `helmfile.yaml` (no `charts/` exists because it depends on the stable/filebeat chart hosted on the official helm charts repository) + * `README.md` (each app managed by my team has a dedicated README maintained by the owners of the app) + * `metricbeat/` + * `helmfile.yaml` + * `README.md` + * `elastalert-operator/` + * `helmfile.yaml` + * `README.md` + * `charts/` + * `elastalert-operator/` + * `` + +The benefits of this structure is that you can run `git diff` to locate in which directory=microservice a git commit has changes. +It allows your CI system to run a workflow for the changed microservice only. + +A downside of this is that you don't have an obvious way to sync all microservices at once. That is, you have to run: + +```bash +for d in apps/*; do helmfile -f $d diff; if [ $? -eq 2 ]; then helmfile -f $d sync; fi; done +``` + +At this point, you'll start writing a `Makefile` under `myteam/` so that `make sync-all` will do the job. + +It does work, but you can rely on the Helmfile feature instead. + +Put `myteam/helmfile.yaml` that looks like: + +```yaml +helmfiles: +- apps/*/helmfile.yaml +``` + +So that you can get rid of the `Makefile` and the bash snippet. +Just run `helmfile sync` inside `myteam/`, and you are done. + +All the files are sorted alphabetically per group = array item inside `helmfiles:`, so that you have granular control over ordering, too. + +#### selectors + +When composing helmfiles you can use selectors from the command line as well as explicit selectors inside the parent helmfile to filter the releases to be used. + +```yaml +helmfiles: +- apps/*/helmfile.yaml +- path: apps/a-helmfile.yaml + selectors: # list of selectors + - name=prometheus + - tier=frontend +- path: apps/b-helmfile.yaml # no selector, so all releases are used + selectors: [] +- path: apps/c-helmfile.yaml # parent selector to be used or cli selector for the initial helmfile + selectorsInherited: true +``` + +* When a subhelmfile has explicit `selectors`, those selectors determine which releases from that subhelmfile are considered; parent and CLI selectors are not combined with them for release filtering. +* When CLI selectors are provided (e.g. `helmfile -l name=b sync`) and a subhelmfile has explicit selectors that are provably incompatible with them (same key, different value), that subhelmfile may be **skipped entirely** without loading or rendering it. For example, with `-l name=b`, a subhelmfile with `selectors: [name=a]` will be skipped since no release could match both. This optimization does not apply when `selectorsInherited: true` is set or when no CLI selectors are provided. Use `--debug` to see log messages about skipped subhelmfiles. +* When not selector is specified there are 2 modes for the selector inheritance because we would like to change the current inheritance behavior (see [issue #344](https://github.com/roboll/helmfile/issues/344) ). + * Legacy mode, sub-helmfiles without selectors inherit selectors from their parent helmfile. The initial helmfiles inherit from the command line selectors. + * explicit mode, sub-helmfile without selectors do not inherit from their parent or the CLI selector. If you want them to inherit from their parent selector then use `selectorsInherited: true`. To enable this explicit mode you need to set the following environment variable `HELMFILE_EXPERIMENTAL=explicit-selector-inheritance` (see [experimental](experimental-features.md)). +* Using `selector: []` will select all releases regardless of the parent selector or cli for the initial helmfile +* using `selectorsInherited: true` make the sub-helmfile selects releases with the parent selector or the cli for the initial helmfile. You cannot specify an explicit selector while using `selectorsInherited: true` + diff --git a/docs/templating.md b/docs/templating.md new file mode 100644 index 00000000..d994c8f1 --- /dev/null +++ b/docs/templating.md @@ -0,0 +1,236 @@ +# Templating + +Helmfile uses [Go templates](https://godoc.org/text/template) for templating your helmfile.yaml. While go ships several built-in functions, we have added all of the functions in the [Sprig library](https://godoc.org/github.com/Masterminds/sprig). + +We also added the following functions: + +* [`env`](templating_funcs.md#env) +* [`requiredEnv`](templating_funcs.md#requiredenv) +* [`exec`](templating_funcs.md#exec) +* [`envExec`](templating_funcs.md#envexec) +* [`readFile`](templating_funcs.md#readfile) +* [`readDir`](templating_funcs.md#readdir) +* [`readDirEntries`](templating_funcs.md#readdirentries) +* [`toYaml`](templating_funcs.md#toyaml) +* [`fromYaml`](templating_funcs.md#fromyaml) +* [`setValueAtPath`](templating_funcs.md#setvalueatpath) +* [`get`](templating_funcs.md#get) (Sprig's original `get` is available as `sprigGet`) +* [`getOrNil`](templating_funcs.md#getornil) +* [`tpl`](templating_funcs.md#tpl) +* [`required`](templating_funcs.md#required) +* [`fetchSecretValue`](templating_funcs.md#fetchsecretvalue) +* [`expandSecretRefs`](templating_funcs.md#expandsecretrefs) +* [`include`](templating_funcs.md#include) + +More details on each function can be found at the ["Template Functions" page in our documentation](templating_funcs.md). + +## Using environment variables + +Environment variables can be used in most places for templating the helmfile. Currently this is supported for `name`, `namespace`, `value` (in set), `values` and `url` (in repositories). + +Examples: + +```yaml +repositories: +- name: your-private-git-repo-hosted-charts + url: https://{{ requiredEnv "GITHUB_TOKEN"}}@raw.githubusercontent.com/kmzfs/helm-repo-in-github/master/ +``` + +```yaml +releases: + - name: {{ requiredEnv "NAME" }}-vault + namespace: {{ requiredEnv "NAME" }} + chart: roboll/vault-secret-manager + values: + - db: + username: {{ requiredEnv "DB_USERNAME" }} + password: {{ requiredEnv "DB_PASSWORD" }} + set: + - name: proxy.domain + value: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com + - name: proxy.scheme + value: {{ env "SCHEME" | default "https" }} +``` + +### Note + +If you wish to treat your enviroment variables as strings always, even if they are boolean or numeric values you can use `{{ env "ENV_NAME" | quote }}` or `"{{ env "ENV_NAME" }}"`. These approaches also work with `requiredEnv`. + +### Useful internal Helmfile environment variables + +Helmfile uses some OS environment variables to override default behaviour: + +* `HELMFILE_DISABLE_INSECURE_FEATURES` - disable insecure features, expecting `true` lower case +* `HELMFILE_DISABLE_RUNNER_UNIQUE_ID` - disable unique logging ID, expecting any non-empty value +* `HELMFILE_SKIP_INSECURE_TEMPLATE_FUNCTIONS` - disable insecure template functions, expecting `true` lower case +* `HELMFILE_USE_HELM_STATUS_TO_CHECK_RELEASE_EXISTENCE` - expecting non-empty value to use `helm status` to check release existence, instead of `helm list` which is the default behaviour +* `HELMFILE_EXPERIMENTAL` - enable experimental features, expecting `true` lower case +* `HELMFILE_ENVIRONMENT` - specify [Helmfile environment](environments.md), it has lower priority than CLI argument `--environment` +* `HELMFILE_TEMPDIR` - specify directory to store temporary files +* `HELMFILE_UPGRADE_NOTICE_DISABLED` - expecting any non-empty value to skip the check for the latest version of Helmfile in [helmfile version](cli.md#version) +* `HELMFILE_GO_YAML_V3` - use *go.yaml.in/yaml/v3* instead of *go.yaml.in/yaml/v2*. It's `false` by default in Helmfile v0.x, and `true` in Helmfile v1.x. +* `HELMFILE_CACHE_HOME` - specify directory to store cached files for remote operations +* `HELMFILE_FILE_PATH` - specify the path to the helmfile.yaml file +* `HELMFILE_INTERACTIVE` - enable interactive mode, expecting `true` lower case. The same as `--interactive` CLI flag +* `HELMFILE_RENDER_YAML` - force helmfile.yaml to be rendered as a Go template regardless of file extension, expecting `true` lower case. Useful for migrating from v0 to v1 without renaming files to `.gotmpl` +* `HELMFILE_AWS_SDK_LOG_LEVEL` - configure AWS SDK logging level for vals library. Valid values: `off` (default, secure, case-insensitive), `minimal`, `standard`, `verbose`, or custom comma-separated values like `request,response`. See issue #2270 for details +* `HELMFILE_VALS_FAIL_ON_MISSING_KEY_IN_MAP` - enable strict mode for vals secret references. When set to `true` (or any value accepted by Go's `strconv.ParseBool` like `TRUE`, `1`), vals will fail when a referenced key does not exist in the secret map. Invalid values will cause an error when vals is initialized (when secret refs are first evaluated). Default is `false` (when unset or empty) for backward compatibility. See issue #1563 for details + + +## Templates + +You can use go's text/template expressions in `helmfile.yaml` and `values.yaml.gotmpl` (templated helm values files). `values.yaml` references will be used verbatim. In other words: + +* for value files ending with `.gotmpl`, template expressions will be rendered +* for plain value files (ending in `.yaml`), content will be used as-is + +In addition to built-in ones, the following custom template functions are available: + +* `readFile` reads the specified local file and generate a golang string +* `readDir` reads the files within provided directory path. (folders are excluded) +* `readDirEntries` Returns a list of [https://pkg.go.dev/os#DirEntry](DirEntry) within provided directory path +* `fromYaml` reads a golang string and generates a map +* `setValueAtPath PATH NEW_VALUE` traverses a golang map, replaces the value at the PATH with NEW_VALUE +* `toYaml` marshals a map into a string +* `get` returns the value of the specified key if present in the `.Values` object, otherwise will return the default value defined in the function + +### Values Files Templates + +You can reference a template of values file in your `helmfile.yaml` like below: + +```yaml +releases: +- name: myapp + chart: mychart + values: + - values.yaml.gotmpl +``` + +Every values file whose file extension is `.gotmpl` is considered as a template file. + +Suppose `values.yaml.gotmpl` was something like: + +```yaml +{{ readFile "values.yaml" | fromYaml | setValueAtPath "foo.bar" "FOO_BAR" | toYaml }} +``` + +And `values.yaml` was: + +```yaml +foo: + bar: "" +``` + +The resulting, temporary values.yaml that is generated from `values.yaml.gotmpl` would become: + +```yaml +foo: + # Notice `setValueAtPath "foo.bar" "FOO_BAR"` in the template above + bar: FOO_BAR +``` + +## Refactoring `helmfile.yaml` with values files templates + +One of expected use-cases of values files templates is to keep `helmfile.yaml` small and concise. + +See the example `helmfile.yaml` below: + +```yaml +releases: + - name: {{ requiredEnv "NAME" }}-vault + namespace: {{ requiredEnv "NAME" }} + chart: roboll/vault-secret-manager + values: + - db: + username: {{ requiredEnv "DB_USERNAME" }} + password: {{ requiredEnv "DB_PASSWORD" }} + set: + - name: proxy.domain + value: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com + - name: proxy.scheme + value: {{ env "SCHEME" | default "https" }} +``` + +The `values` and `set` sections of the config file can be separated out into a template: + +`helmfile.yaml`: + +```yaml +releases: + - name: {{ requiredEnv "NAME" }}-vault + namespace: {{ requiredEnv "NAME" }} + chart: roboll/vault-secret-manager + values: + - values.yaml.gotmpl +``` + +`values.yaml.gotmpl`: + +```yaml +db: + username: {{ requiredEnv "DB_USERNAME" }} + password: {{ requiredEnv "DB_PASSWORD" }} +proxy: + domain: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com + scheme: {{ env "SCHEME" | default "https" }} +``` + +## Importing values from any source + +The `exec` template function that is available in `values.yaml.gotmpl` is useful for importing values from any source +that is accessible by running a command: + +A usual usage of `exec` would look like this: + +```yaml +mysetting: | +{{ exec "./mycmd" (list "arg1" "arg2" "--flag1") | indent 2 }} +``` + +Or even with a pipeline: + +```yaml +mysetting: | +{{ yourinput | exec "./mycmd-consume-stdin" (list "arg1" "arg2") | indent 2 }} +``` + +The possibility is endless. Try importing values from your golang app, bash script, jsonnet, or anything! + +Then `envExec` same as `exec`, but it can receive a dict as the envs. + +A usual usage of `envExec` would look like this: + +```yaml +mysetting: | +{{ envExec (dict "envkey" "envValue") "./mycmd" (list "arg1" "arg2" "--flag1") | indent 2 }} +``` + +## Using .env files + +Helmfile itself doesn't have an ability to load .env files. But you can write some bash script to achieve the goal: + +```console +set -a; . .env; set +a; helmfile sync +``` + +Please see #203 for more context. + +## Running Helmfile interactively + +`helmfile --interactive [apply|destroy|delete|sync]` requests confirmation from you before actually modifying your cluster. + +Use it when you're running `helmfile` manually on your local machine or a kind of secure administrative hosts. + +For your local use-case, aliasing it like `alias hi='helmfile --interactive'` would be convenient. + +Another way to use it is to set the environment variable `HELMFILE_INTERACTIVE=true` to enable the interactive mode by default. +Anything other than `true` will disable the interactive mode. The precedence has the `--interactive` flag. + +## Running Helmfile without an Internet connection + +Once you download all required charts into your machine, you can run `helmfile sync --skip-deps` to deploy your apps. +With the `--skip-deps` option, you can skip running "helm repo update" and "helm dependency build". + +## `bash` and `zsh` completion + +helmfile completion --help diff --git a/docs/writing-helmfile.md b/docs/writing-helmfile.md index 96c499b8..e0bc2f8c 100644 --- a/docs/writing-helmfile.md +++ b/docs/writing-helmfile.md @@ -1,6 +1,6 @@ -# The Helmfile Best Practices Guide +# Writing Helmfile -This guide covers the Helmfile's considered patterns for writing advanced helmfiles. It focuses on how helmfile should be structured and executed. +This guide covers patterns and best practices for writing helmfiles. It focuses on how helmfile should be structured and executed. **Before diving into advanced patterns, we strongly recommend reading [Values Merging and Data Flow](values-and-merging.md)** to understand how Helmfile merges values from various sources. This foundational knowledge is essential for writing effective helmfiles. diff --git a/mkdocs.yml b/mkdocs.yml index b4c92617..36cf6e08 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -16,17 +16,24 @@ docs_dir: docs nav: - Home: index.md - Getting Started: - - Paths Overview: paths.md - - Templating Funcs: templating_funcs.md - - HCL Funcs: hcl_funcs.md - - Built-in Objects: builtin-objects.md - - Core Concepts: + - Writing Helmfile: writing-helmfile.md - Values and Merging: values-and-merging.md - - Advanced Features: - - Best Practices Guide: writing-helmfile.md + - Environments: environments.md + - Releases & DAG: releases.md + - Configuration: + - helmfile.yaml Reference: configuration.md + - Templating: templating.md + - Template Functions: templating_funcs.md + - Built-in Objects: builtin-objects.md + - HCL Functions: hcl_funcs.md + - Paths Overview: paths.md + - CLI Reference: cli.md + - Advanced: - Advanced Features: advanced-features.md + - Hooks: hooks.md - Secrets: remote-secrets.md - - Shared Configuration Across Teams: shared-configuration-across-teams.md + - Shared Configuration: shared-configuration-across-teams.md + - Integrations: integrations.md - Experimental Features: experimental-features.md - About: - Users: users.md