Skip to content

proposal: Kustomize post-renderer for generated manifests #31

Description

@atkrad

Problem

Teams need last-mile changes to Deployah-generated objects (extra labels, sidecar env, tolerations, annotation tweaks, JSON6902 patches) that profiles and the spec cannot express. Today:

  • Extras (.deployah/manifests/) only append YAML via extras.PostRenderer; colliding with a generated object is an error by design.
  • There is no supported way to mutate the rendered Deployment/Service/Ingress stream short of forking the chart or fighting the collision rule.

Helm's answer is a post-renderer; the common tool for that is Kustomize. Deployah already wires postrenderer.PostRenderer through plan/deploy/render; it just needs a Kustomize implementation in the chain.

Goals

  • Optional Kustomize overlay that runs as a Helm post-renderer on the rendered release (plan + deploy + offline plan).
  • Support strategic-merge / JSON6902 patches (and normal kustomization.yaml features) against generated resources.
  • Keep "one binary" where practical: prefer embedding Kustomize (library / krusty) over requiring a host kustomize binary.
  • Clear layout under .deployah/ with per-environment overlays (same env-dir idea as manifests).
  • Compose with existing extras: defined pipeline order and collision rules.
  • Preserve Deployah identity labels/annotations after Kustomize (re-assert or validate; do not allow stripping reserved deployah.dev/* ownership).

Non-goals

  • Replacing the Deployah chart with a user-owned chart.
  • Replacing extras entirely (literal additive YAML stays useful).
  • Arbitrary executable post-renderers (--post-renderer ./script.sh) in v1 (security + portability; follow-up).
  • Full GitOps Kustomize app-of-apps / multi-base repos.
  • Letting Kustomize delete Deployah-managed identity keys without error.

Proposed design

Pipeline

Helm chart render
  -> Kustomize post-renderer (optional)   # transform / patch generated objects
  -> extras append post-renderer          # current .deployah/manifests behavior
  -> install / plan diff

Kustomize may add resources too (via resources: / generators). Prefer patches-first UX; document that additive YAML can stay in extras for simpler authorship.

Layout

.deployah/
  kustomize/
    kustomization.yaml          # base overlays applied to every env
    patches/
      add-labels.yaml
    production/
      kustomization.yaml        # env-specific; merges/chains from parent
      patches/
        replicas.yaml
  manifests/                    # existing extras (unchanged)
  crds/

Env subdirectory rules mirror manifests (production matches production and related wildcard envs per existing Deployah conventions).

Minimal kustomization.yaml mental model (implementation detail: stdin/resources file is staged in a temp dir, as Kustomize does not take Helm stdin natively):

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - all.yaml          # written by Deployah from Helm render
patches:
  - path: patches/add-labels.yaml
    target:
      kind: Deployment

Spec / flags

No required spec field if presence of .deployah/kustomize/ enables it. Optional knobs:

# deployah.yaml or platform (pick one owner)
# kustomize:
#   enabled: true
#   path: .deployah/kustomize

CLI escape: deployah deploy --skip-kustomize / deployah plan --skip-kustomize for debugging.

Identity and safety

After Kustomize runs:

  1. Re-apply or verify reserved labels/annotations on objects that still match generated identities.
  2. Fail if a patch removes deployah.dev/managed-by / project / environment keys Deployah requires.
  3. Extras collision check runs on the post-Kustomize stream (extras still cannot clobber an object that exists after patches).

Implementation sketch

  • New extras.KustomizePostRenderer (or internal/kustomize) implementing postrenderer.PostRenderer.
  • Chain: Chain{Kustomize, Extras} or a small composite runner.
  • Embed sigs.k8s.io/kustomize/api / krusty; pin version; no shell kustomize in v1.
  • Temp dir per render: write all.yaml + copy overlay; krusty.MakeKustomizer(...).Run.

Failure modes

  • Invalid kustomization.yaml / patch target miss → render error with Kustomize message.
  • Patch deletes required Deployah metadata → validation error.
  • Extras collide with post-Kustomize object → same error as today.
  • Empty / absent .deployah/kustomize/ → no-op; present but broken → error.

Alternatives considered

  1. Extras only (status quo). Cannot patch generated objects.
  2. Allow extras to overwrite chart objects. Loses clear ownership; ad-hoc YAML merge is weaker than Kustomize patches.
  3. Shell out to kustomize / user --post-renderer. Flexible; breaks one-binary and is harder to secure; follow-up.
  4. Profiles for every possible tweak. Does not scale; profiles stay for platform policy.

Compatibility and migration

Test plan

  • Unit: patch adds a label on Deployment; plan/render reflects it
  • Unit: JSON6902 patch; strategic merge patch
  • Unit: stripping reserved labels fails
  • Unit: extras still append; collision with patched object fails
  • Scenario under scenarios/ with .deployah/kustomize/
  • Offline plan works without cluster
  • Docs: layout, pipeline order, when to use kustomize vs extras vs profiles

Checklist

  • I searched existing issues and discussions
  • This includes enough design detail for implementation (not only a wish)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/extrasCustom manifests and CRDs under .deployah/area/helmChart render, release, post-renderkind/proposalDesign discussion before or during implementationneeds-triageNew, not yet categorized

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions