Skip to main content

Kubernetes Components

Define Kubernetes resources in stack manifests when you want Atmos to manage plain YAML or Kustomize overlays alongside Terraform, Helmfile, Packer, and Ansible components. A Kubernetes component describes what to render, which values to inject, and how the result should be deployed for each stack.

Available Configuration Sections

Kubernetes components use the same stack sections as other Atmos components, so the deployment can inherit values, run hooks, use Auth, and be included in affected runs.

metadata
Component behavior, inheritance, and component path selection.
vars
Variables available to stack template rendering and inline manifests.
env

Environment variables applied before Kubernetes clients are created, such as KUBECONFIG.

settings
Integration metadata and legacy dependency settings.
auth
Component-level Atmos Auth providers, identities, and integrations.
dependencies

Component, file, and folder dependencies used by affected detection and ordered multi-component runs.

hooks
Lifecycle event handlers using dotted Kubernetes events.
generate

Declarative file generation before Kubernetes operations when auto_generate_files is enabled.

source and provision
JIT source and workdir/provisioning behavior shared with other component types.

Kubernetes components do not support command in v1 because the provider names describe manifest behavior. Atmos does not execute kubectl or kustomize binaries for these operations.

Component Structure

stacks/catalog/argocd.yaml
components:
kubernetes:
argocd/defaults:
metadata:
type: abstract
component: argocd
provider: kustomize
paths:
- overlays/{{ .vars.cluster }}
vars:
namespace: argocd
cluster: dev
env:
KUBECONFIG: /tmp/kubeconfig

stacks/deploy/dev/argocd.yaml

import:
- catalog/argocd

vars:
stage: dev

components:
kubernetes:
argocd:
metadata:
inherits:
- argocd/defaults
vars:
cluster: dev

Component Directory Structure

Kubernetes components are located under components.kubernetes.base_path from atmos.yaml.

atmos.yaml

components:
kubernetes:
base_path: components/kubernetes
provider: kubectl

Example structure:

components/kubernetes/
├── argocd/
│ ├── base/
│ └── overlays/
│ ├── dev/
│ └── prod/
└── namespace/
└── namespace.yaml

Providers

kubectl
Loads plain YAML or JSON manifests from files, directories, and inline manifests entries.
kustomize
Renders Kustomize directories, then passes rendered objects to the Kubernetes client.

Provider names describe behavior. Atmos does not require the kubectl or kustomize binaries.

Paths And Manifests

paths is a list of files or directories relative to the component directory. Directories are walked recursively for .yaml, .yml, and .json files. With provider: kustomize, a directory containing a Kustomize file is rendered as a Kustomize root.

components:
kubernetes:
app:
provider: kubectl
paths:
- namespace.yaml
- workloads

manifests is a list of inline Kubernetes objects or YAML strings.

components:
kubernetes:
namespace:
provider: kubectl
manifests:
- apiVersion: v1
kind: Namespace
metadata:
name: "{{ .vars.namespace }}"

Render Output

atmos kubernetes render writes rendered manifests to stdout by default. Configure component-level output with render.output.

components:
kubernetes:
argocd:
render:
output:
path: rendered/clusters/{{ .vars.cluster }}/argocd
split: true

When split is true, path is treated as a directory and Atmos writes one file per object. Otherwise path is a single multi-document YAML file.

Delivery Targets

apply and deploy deliver the rendered manifests to a target. By default they apply to the cluster, but a component can declare named delivery targets under provision.targets and select one with --target. Each target has a kind:

  • kind: kubernetes — apply the manifests to the cluster (the default).
  • kind: git — render the manifests and commit them to a Git deployment repository (a GitOps source-of-truth reconciled by Argo CD or Flux).
# atmos.yaml declares the managed deployment repository:
git:
repositories:
deployments:
uri: https://github.com/acme/deployments.git
branch: main

# the component selects where apply/deploy delivers:
components:
kubernetes:
argocd:
provision:
default: cluster # used when --target is omitted
targets:
cluster:
kind: kubernetes
deployment-repo:
kind: git
repository: deployments # references git.repositories.<name>
path: "clusters/{{ .vars.cluster }}/argocd" # supports Go templates
auth:
identity: platform-admin # optional; else the repository default
commit:
message: "Render {{ .vars.app_name }} for {{ .vars.stage }}"
signing: auto # auto | always | never

The git target clones (or fast-forwards) the repository, replaces the managed path with the rendered manifests, commits that path with provenance trailers (Atmos-Stack, Atmos-Component), and pushes. Re-delivering identical manifests is a clean no-op. Credentials come from Atmos Auth (GitHub STS); no tokens are written into the manifests. Pull-request publishing is not yet supported.

When split is unset, Atmos infers delivery mode from path. A manifest filename writes one exact file, while other paths use directory delivery. Set split: true or split: false to override the inference. Single-file delivery is required whenever the consumer expects a specific filename, such as Kustomize's kustomization.yaml. See File vs. directory delivery and the walkthrough below.

Generating a Kustomize component for GitOps

A common pattern: inject a Terraform-derived value (a security group ID, a Route53 zone ID, an ARN) into an existing Kustomize/Argo CD deployment without hand-editing the Kustomize overlay. Atmos renders a Kustomize Component manifest — a JSON6902 patch, using atmos.Component/!terraform.state to pull the value — and commits it to the deployment repository as an exact kustomization.yaml, which the real overlay then includes as a remote component.

components:
kubernetes:
cert-manager-patch:
provision:
targets:
deployment-repo:
kind: git
repository: deployments
path: "kustomize/overlays/{{ .vars.environment }}/kustomization.yaml"
commit:
message: "Render manifests for {{ .vars.environment }}"
manifests:
- apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
patches:
- target:
kind: ClusterIssuer
name: letsencrypt-dns
patch: |
- op: add
path: /spec/acme/solvers
value:
- dns01:
cnameStrategy: Follow
route53:
region: "{{ .vars.aws_region }}"
hostedZoneID: "{{ atmos.Resolve \"!terraform.state route53 public_zone_id\" }}"
atmos kubernetes deploy cert-manager-patch -s plat-ue2-dev --target=deployment-repo

Two things make this work that are easy to miss:

  • No split is set. The path ends in kustomization.yaml, so Atmos infers split: false and writes it as a single file rather than a directory by that name — see File vs. directory delivery.
  • No metadata.name is needed on the Component object. Kustomize's own Kustomization/Component objects are not Kubernetes API resources — they are local input to the kustomize build tool — and Kustomize does not require a name on them. Atmos recognizes these two kinds specifically and does not require metadata.name for them; see atmos kubernetes validate for details, including the validate: false escape hatch for other cases.

The real Kustomize overlay then includes the generated file as a remote component:

# kustomize/overlays/prod/kustomization.yaml (hand-maintained, in the same repo)
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- github.com/acme/deployments//kustomize/overlays/prod?ref=main

Auth

Kubernetes operations use the kubeconfig and client configuration visible to Kubernetes Go clients. Atmos Auth can prepare that environment before the client is created.

For local clusters, an ambient identity can pass through the existing environment:

auth:
identities:
local:
kind: ambient

components:
kubernetes:
app:
env:
KUBECONFIG: /path/to/kubeconfig

For EKS, use an Atmos Auth identity with an aws/eks integration to write kubeconfig, then run the Kubernetes command with that identity.

Native CI Summaries

When ci.enabled: true and Atmos runs in a supported CI provider such as GitHub Actions, Kubernetes commands write a compact Markdown job summary to the provider summary file ($GITHUB_STEP_SUMMARY on GitHub Actions).

The summary includes the stack, component, command status, per-action object counts, object rows, and an error section when the command fails:

  • render: rendered objects
  • plan / diff: created, changed, and no-change objects, plus a collapsible Kubernetes Diff block with the per-object unified diff (Secret objects are omitted so their data is never written to the job summary)
  • apply / deploy: applied or delivered objects
  • delete: deleted and not-found objects
  • validate: valid and invalid objects

Kubernetes CI support is intentionally summary-only in v1. It does not emit $GITHUB_OUTPUT variables, commit statuses, PR comments, or stored artifacts.

Hooks

Kubernetes components support dotted lifecycle events:

components:
kubernetes:
argocd:
hooks:
notify:
events:
- after.kubernetes.apply
command: echo "applied argocd"

Supported events:

  • before.kubernetes.render
  • after.kubernetes.render
  • before.kubernetes.plan
  • after.kubernetes.plan
  • before.kubernetes.diff
  • after.kubernetes.diff
  • before.kubernetes.apply
  • after.kubernetes.apply
  • before.kubernetes.deploy
  • after.kubernetes.deploy
  • before.kubernetes.delete
  • after.kubernetes.delete
  • before.kubernetes.validate
  • after.kubernetes.validate

plan normalizes to the diff lifecycle for hook matching, and deploy normalizes to the apply lifecycle for hook matching, so hooks written for either spelling match the equivalent operation.

Bulk And Affected Runs

Kubernetes commands can process more than one component when you need a full environment rollout or a CI job scoped to changed files:

atmos kubernetes apply --all -s dev
atmos kubernetes plan --affected --base origin/main
atmos kubernetes deploy --affected --base origin/main --include-dependents

--all processes matching Kubernetes components in dependency order. --affected uses affected detection to select changed Kubernetes components, includes their dependencies by default, and includes downstream dependents when --include-dependents is set.