Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions docs/howto/charts_tips_and_tricks.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,51 @@ existing release will be upgraded.
```console
$ helm upgrade --install <release name> --values <values file> <chart directory>
```

## Build Reproducible Chart Archives

By default, the files inside a packaged chart archive (`.tgz`)
carry the modification times of the source files on disk.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documented that Helm honors SOURCE_DATE_EPOCH to stamp chart archive file modification times, based on PR #32162 which added sourceDateEpochFromEnv() in pkg/cmd/source_date_epoch.go and StampModTimes in pkg/chart/v2/chart.go, applied before archiving in pkg/action/package.go.

Source: helm/helm#32162

As a result, repackaging the same chart produces archives that differ from one build to the next.
To make chart archives reproducible,
Helm honors the `SOURCE_DATE_EPOCH` environment variable defined by the
[Reproducible Builds](https://reproducible-builds.org/docs/source-date-epoch/) project.
When you set it,
Helm stamps every file in the archive with the modification time you provide
instead of the build time.

Set `SOURCE_DATE_EPOCH` to a Unix timestamp,
the number of whole seconds since 1970-01-01 in UTC,
and run `helm package`:

```console
$ SOURCE_DATE_EPOCH=1609459200 helm package ./mychart
```

Helm stamps every file in the resulting archive with 2021-01-01T00:00:00Z,
so packaging the same source again produces the same timestamps.
To track your source history,
derive the timestamp from your last commit:

```console
$ SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) helm package ./mychart
```

Keep the following in mind when you use `SOURCE_DATE_EPOCH`:

- The value must be a non-negative integer.
Helm interprets it as whole seconds in UTC and does not support sub-second precision.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Value semantics come from sourceDateEpochFromEnv() in pkg/cmd/source_date_epoch.go: it parses the value with strconv.ParseInt as whole seconds and converts via time.Unix(epoch, 0).UTC(), returns nil for unset/empty, and errors with invalid SOURCE_DATE_EPOCH for non-numeric or negative values.

Source: https://github.com/helm/helm/pull/32162/files

A non-numeric or negative value fails the command with an `invalid SOURCE_DATE_EPOCH` error.
- When the variable is unset or empty,
Helm keeps the default behavior,
where archive entries reflect the actual file modification times.
- When you package a chart that contains a `Chart.lock` file,
Helm also stamps that file's `generated:` timestamp with the `SOURCE_DATE_EPOCH` value,
normalized to UTC and whole seconds.
As a result, charts that declare dependencies produce byte-identical archives across builds and machines
when you use the same `SOURCE_DATE_EPOCH`,
because the `Chart.lock` content matches, not just the file modification times.
- `helm install`, `helm upgrade`, `helm dependency build`, and `helm dependency update`

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file://-only scope for install/upgrade/dependency build/dependency update reflects pkg/downloader/manager.go, where the epoch is passed into the download Manager but only applied inside tarFromLocalDir when re-archiving dependencies from a local file:// repository; remotely fetched dependency archives are stored unchanged.

Source: https://github.com/helm/helm/pull/32162/files

also honor `SOURCE_DATE_EPOCH`,
but only when they re-archive a dependency sourced from a local `file://` repository.
Helm stores remotely downloaded dependencies as it fetched them.
Loading