Skip to main content

Stack versioning

DFE is made of independently released parts: the Rust data plane, dfe-engine, dfe-ui, dfe-hyperdx, the schemas, the charts and operators, and the deploy-repo template. "DFE X.Y.Z" selects the component versions recorded in versions.yaml at that release tag, and each stack release tests that combination. A deployment pins one number and can move individual components off the set, visibly and at its own risk.

Where the set is defined​

versions.yaml in dfe-infra is the one place every pinned version is set: bootstrap components, operators, data services and every dfe-* image. A drift check (scripts/check_versions_drift.py) fails the build when a chart, ApplicationSet or bootstrap manifest disagrees with it.

A stack release is a dfe-infra tag, so versions.yaml frozen at tag X.Y.Z is the manifest for DFE X.Y.Z. semantic-release cuts the tag and nobody hand-edits a version number. dfe-schemas and dfe-deploy carry content rather than images. They're tagged in step with each stack release and recorded in versions.yaml like any other component.

The deploy repo's pins.yaml carries base.dfe-infra, the one version that selects the stack, and a channel (alpha, beta, rc or release). Bumping the pin moves charts, operators and every app image in one reviewed commit and leaves values/ and config/ alone (state and repositories).

There's no dfe-schemas pin. The wheel rides inside the engine image, so the engine pin already selects the schema release.

Overrides and upgrades​

Need one component ahead of the set, or held behind it? List it under overrides in pins.yaml.

overrides:
apps:
dfe-receiver: "v1.16.0@sha256:..."

An override beats the certified manifest, and everything not listed stays on the certified version. It must be a tag@sha256 digest, and dfe-stack resolve rejects a floating tag.

Every override prints a support-drift notice, from dfe-stack resolve and again from dfe-engine at startup. The drift sits outside the certified-set guarantee until a later stack release absorbs it, because HyperI tests the manifest combination and not arbitrary cross products.

To apply an override, --emit-values writes per-service fragments (image.tag and image.digest, which the thin chart joins into tag@digest). Merge them into the service's existing values/{service}-{instance}-values.yaml. A new file would become an Argo application of its own.

Each release's versions.yaml carries stack.previous, the verified from-versions for that release. dfe-stack graph derives the whole upgrade graph from those entries, so no graph file needs curating. dfe-stack check-upgrade --from A --to B gives the verdict. A declared previous list is authoritative for its own release. Otherwise the rule is sequential minors with free patch hops.

stack.upgrade-order sets the rollout order between component groups: schemas, engine, data plane, then UI. Upgrades walks an upgrade and rollback undoes one.

Patches are cumulative. The components of one stack are tested together and move together. A patch can move an API between dfe-engine, dfe-ui and dfe-hyperdx, so upgrade all three at once.

Cutting a release​

Component repositories release on their own lines, each with a semantic-release tag and a GHCR image. A stack release is a dfe-stack cut against versions.yaml (cutting a stack). The drift check and the integrated test suites, which drive data from the receiver to ClickHouse, check it, and then it's tagged.

On the tag, the stack-manifest workflow renders the manifest and a flat image list for air-gap mirroring. It publishes both as a cosign-signed OCI artifact beside the images, so a mirror verifies offline. The deploy tooling's own version is in the manifest, because an unpinned installer makes a build impossible to reproduce. A component can be dropped from the set when keeping it costs more than it's worth, and the release notes say so.

scripts/dfe-stack does all of it:

SubcommandDoes
renderThe rendered manifest: image pins as tag@sha256, content repos, everything
imagesThe flat DFE-owned image list for air-gap mirroring
graphThe upgrade graph from the in-file stack.previous entries
check-upgrade --from A --to BThe verdict on an upgrade path
resolve --pins pins.yamlThe effective component set for a deployment, with support-drift per override
verifyCompares versions.yaml digests with the registry
cut, bump-app, release-gateCut a stack, move one app, and gate a release