Skip to main content

Native Kubernetes Components: Render, Apply, and Publish to GitOps Repos

· 4 min read
Erik Osterman
Founder @ Cloud Posse

Atmos now treats Kubernetes as a first-class component type. Define Kubernetes objects — inline manifests, files, directories, or Kustomize overlays — in your stack configuration, then render, diff, apply, and delete them through the Kubernetes Go SDK with server-side apply. No kubectl or kustomize binary required. And because Atmos owns rendering, lifecycle events, and credentials, an apply can publish the rendered manifests to a Git deployment repository instead of a cluster — the producer side of a GitOps workflow.

What Changed

components.kubernetes.<name> is a native component type with the same stack semantics as Terraform and Helmfile — vars, env, auth, metadata, settings, dependencies, hooks, inheritance, and overrides — plus Kubernetes-specific paths, manifests, and render sections:

components:
kubernetes:
argocd:
provider: kustomize
vars: { cluster: ue2-dev, namespace: argocd }
paths:
- bootstrap/argocd
manifests:
- apiVersion: v1
kind: Namespace
metadata: { name: "{{ .vars.namespace }}" }

Run it like any other component:

atmos kubernetes render argocd -s plat-ue2-dev    # print the manifests
atmos kubernetes diff argocd -s plat-ue2-dev # server-side diff
atmos kubernetes apply argocd -s plat-ue2-dev # server-side apply

--all and --affected run components in dependency order, so the same change detection that drives Terraform pipelines works for Kubernetes.

When native CI is enabled, Kubernetes commands now write a compact job summary to the CI provider summary file, such as $GITHUB_STEP_SUMMARY in GitHub Actions. The summary reports object actions for plan/diff, apply/deploy, delete, and validate, plus an error section on failure. For plan/diff it also includes a collapsible Kubernetes Diff block with the per-object unified diff (GitHub renders the +/- lines in green and red); the same diff appears in the terminal output. Secret objects are omitted from the diff so their data is never printed or written to the summary. This first CI slice is deliberately summary-only: Kubernetes commands do not emit $GITHUB_OUTPUT values, commit statuses, PR comments, or stored artifacts.

Deliver to a Cluster — or a GitOps Repository

By default apply/deploy applies to the cluster. But many teams don't apply directly: they commit rendered manifests to a deployment repository that Argo CD or Flux reconciles. Atmos models delivery destinations as provision targets, selected by kind:

git:
repositories:
deployments:
uri: https://github.com/acme/deployments.git
branch: main

components:
kubernetes:
argocd:
provision:
default: cluster
targets:
cluster:
kind: kubernetes
deployment-repo:
kind: git
repository: deployments
path: "clusters/{{ .vars.cluster }}/argocd"
commit:
message: "Render {{ .vars.app_name }} for {{ .vars.stage }}"
# apply to the cluster (default)
atmos kubernetes apply argocd -s plat-ue2-dev

# render and publish to the deployment repo instead
atmos kubernetes apply argocd -s plat-ue2-dev --target=deployment-repo

The git target clones (or fast-forwards) the repository, replaces the managed path with the freshly rendered manifests, commits that path with provenance trailers (Atmos-Stack, Atmos-Component), and pushes. Re-delivering identical manifests is a clean no-op. It is built on the reusable Atmos Git service, so credentials come from Atmos Auth (GitHub STS) and never land in the manifests.

This is the same target convention Atmos uses elsewhere for "where to put things," and the git target is component-agnostic: the rendered-artifact model that Kubernetes produces today is the same one future component types will use to publish to git, oci, and other destinations.

Why This Matters

GitOps pipelines have always needed glue: ad hoc scripts to render manifests into a deployment repo, commit them, survive push races, and wire credentials. Atmos already owns rendering, lifecycle events, and authentication — provision targets add the delivery step with centralized safety rules, so the same component configuration can apply to a cluster in dev and publish to a GitOps repo in prod with a single flag.

How to Use It

  • Add a components.kubernetes.<name> to a stack with paths/manifests.
  • Run atmos kubernetes render|diff|apply|delete <component> -s <stack>.
  • To publish to a deployment repo, declare a git.repositories.<name> and a provision.targets entry with kind: git, then apply ... --target=<name>.

See the Kubernetes component and atmos kubernetes documentation to get started.