Skip to content

proposal: custom Kubernetes manifests and CRDs via .deployah/ #4

Description

@atkrad

Problem

The generated Helm chart covers common app resources. Teams still need things Deployah does not generate (NetworkPolicy, PrometheusRule, app-owned CRDs, and similar). Today there is no first-class place for that YAML, so users fall back to out-of-band kubectl or custom charts.

Goals

  • Users can ship arbitrary Kubernetes manifests with a Deployah release
  • Extra CRDs can be installed before the chart, with a clear create vs create-replace policy
  • deployah plan shows extras in the diff and reports pending CRDs
  • DX-first layout under .deployah/; no backward-compatibility constraint

Non-goals

  • Helm templating or environment-variable substitution inside extras
  • Deleting or pruning CRDs on uninstall
  • A catalog / dependency manager for third-party charts (separate proposal)
  • Full GitOps reconciliation or replacing Helm

Proposed design

Layout

.deployah/
  manifests/
    common.yaml           # all environments
    prod/
      extra.yaml          # only for prod (and prod/* prefix matches)
  crds/
    my-crd.yaml           # shared; no per-env subdirs
  • deployah init scaffolds .deployah/manifests/ and .deployah/crds/ with short READMEs.
  • Only *.yaml / *.yml load; README/markdown and dotfiles are skipped; other visible files are errors.
  • Subdirectories under manifests/ must be declared environment keys. Nested dirs under an env dir (or under crds/) are not allowed.
  • CRDs must use apiVersion: apiextensions.k8s.io/v1 and live under .deployah/crds/ only.

Behavior

  • Manifests: loaded literally (no Helm templating, no env substitution). Identity labels/annotations are merged into metadata only; reserved deployah.dev/* keys the user does not own are stripped. Empty namespace is filled with the release namespace; a different namespace is an error. Objects are appended to the Helm release via a post-renderer.
  • CRDs: applied before the Helm install/upgrade; wait for Established (bounded by --timeout). Policy via --crds create (default) or --crds create-replace (server-side apply). Never pruned or deleted on uninstall.
  • Plan: extra manifests appear in the diff; CRDs are reported as pending, not applied.
  • Idle Helm plan: if the chart is unchanged but .deployah/crds/ is non-empty, still apply CRDs.
  • Safety: collide with a generated object -> fail; duplicate identities -> fail; unknown CR kinds need an in-repo CRD or cluster discovery (small offline allowlist for cert-manager / prometheus-operator); plan --offline allows unknown kinds for preview.

Labels and annotations

Object Labels Annotations
Generated (from the spec) deployah.dev/project, deployah.dev/environment, deployah.dev/component, ... deployah.dev/source=spec, ...
Extra manifests project + environment deployah.dev/source=manifests
Extra CRDs project only (no environment) deployah.dev/source=crds

Alternatives considered

  • Embed extras in deployah.yaml: worse for large YAML and for copy-paste from existing manifests.
  • Require a custom Helm chart: higher friction than a Bitnami-style escape hatch next to the spec.
  • Apply everything with raw kubectl outside Helm: splits ownership; extras would not share the release lifecycle.

Compatibility and migration

New feature. No migration path required. Existing projects without .deployah/ are unchanged.

Test plan

  • Unit tests for load, merge, scope, CRD apply policy, and post-renderer
  • Integration scenarios: manifests-only, env-scoped extras + CRDs, plan with extras
  • README documents the feature; CLI help includes --crds
  • deployah init scaffolds the directories
  • Idle Helm plan still applies pending CRDs

Checklist

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

Acceptance criteria

  • .deployah/manifests/ and .deployah/crds/ load with the rules above
  • Extras appear in deployah plan / deployah deploy (manifests in release; CRDs applied first)
  • --crds create|create-replace works; idle Helm + CRDs still applies CRDs
  • Identity merge, namespace rules, reserved-key stripping, collision checks
  • deployah init scaffolds the directories
  • README documents the feature; CLI help includes --crds
  • Integration scenarios cover manifests, env-scoped extras + CRD scope, and plan with extras

Metadata

Metadata

Assignees

Labels

area/deployDeploy and plan session flowarea/extrasCustom manifests and CRDs under .deployah/area/helmChart render, release, post-renderkind/proposalDesign discussion before or during implementationpriority/mediumImportant, not urgent

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions