Declarative Object Configs
Manage resources with YAML and a reviewable change workflow.
Declarative config means you describe the desired state in files and manage everything through kubectl apply. It keeps changes reviewable, repeatable, and safer than ad-hoc imperative commands.
This quick start expands on the workflow with diff/preview, labels, patching, and GitOps-style practices.
Why it works
- Changes are reviewable in git.
- Rollbacks are simple by reapplying history.
- Reapplying the same file is safe and idempotent.
Multi-object example
apiVersion: v1
kind: Namespace
metadata:
name: demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: demo
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: nginx:1.25
Common flow
kubectl apply -f app.yaml
kubectl diff -f app.yaml
kubectl delete -f app.yaml
Order of operations
Start with namespaces, then RBAC, then workloads and services. This avoids dependency errors when applying multiple resources.
Labels and selectors
Use consistent labels so Services, Deployments, and monitors can discover Pods:
metadata:
labels:
app: api
tier: backend
Server-side apply
Server-side apply makes field ownership explicit and helps avoid conflicts:
kubectl apply --server-side -f app.yaml
If you see conflicts, use field managers and avoid multiple systems writing the same fields.
Field ownership and managers
Server-side apply tracks which tool owns which fields. If you use multiple tools (for example, kubectl and a GitOps controller), define a clear owner for each field to avoid fights.
You can specify a field manager explicitly:
kubectl apply --server-side --field-manager=dev-cli -f app.yaml
Diff and preview
Use kubectl diff before applying to inspect changes. For CI, you can run:
kubectl diff -f app.yaml || true
Apply ordering by files
If you split manifests across files, consider a predictable naming scheme (e.g., 00-namespace.yaml, 10-rbac.yaml, 20-app.yaml) so CI and operators apply them in the correct order.
Patch vs apply
Use kubectl apply for full desired state. Use kubectl patch for small, targeted edits:
kubectl patch deploy api -p '{"spec":{"replicas":3}}'
In production, prefer commit + apply so the desired state stays in git.
Apply with prune
If you want to delete resources removed from your manifests, use prune with labels:
kubectl apply -f ./manifests -l app=api --prune
This keeps the cluster aligned with your repo.
Namespaces and resource scope
Remember that most resources are namespace-scoped. If you apply a manifest without a namespace set, it goes to the default namespace. Make namespaces explicit in your YAML or use -n when applying.
Dry-run
Validate changes without applying:
kubectl apply -f app.yaml --dry-run=server
Validation and linting
You can validate schemas with tools like kubeconform or kubectl apply --dry-run=server in CI to catch errors early. Even basic validation prevents broken manifests from reaching production.
Kustomize basics
Kustomize is built into kubectl and helps manage environments:
kubectl apply -k overlays/prod
Use it to manage image tags and environment-specific settings without copying YAML.
GitOps workflow
In GitOps, git is the source of truth and a controller applies changes automatically. This reduces manual drift and ensures every change is reviewed.
Even without a GitOps controller, you can follow the same idea by enforcing reviews and applying only from the main branch.
Example Kustomize overlay
A minimal structure:
# kustomization.yaml
resources:
- ../../base
images:
- name: nginx
newTag: "1.26"
Apply it with:
kubectl apply -k overlays/prod
Immutable fields
Some fields cannot be updated (like selectors). If you need to change them, you must recreate the resource. Plan selectors carefully from day one.
Naming and directory structure
Organize manifests by app or environment. A common structure is:
base/for shared resources.overlays/dev,overlays/prodfor environment overrides.
This keeps changes clear and reduces duplication.
Promotion workflow
Promote changes by merging to main, then applying from a CI pipeline or GitOps controller. This ensures the same change that was reviewed is what reaches production.
Drift and reconciliation
If manual changes happen, kubectl apply will bring resources back to the desired state. This is why declarative config pairs well with GitOps controllers.
Secrets and config separation
Keep secrets out of the main manifests. Use external secret managers or separate secret manifests with restricted access. This reduces the risk of accidental leaks during reviews. Never paste secrets into issue trackers or chat logs.
Practical tips
- Use
kubectl diffin CI to review changes. - Keep manifests small and focused.
- Version your manifests with git tags to make rollback easy.
- Use consistent indentation to avoid formatting noise.
- Keep configs modular so teams can own their components.
Change review checklist
- Are labels and selectors consistent?
- Are resource requests set?
- Are secrets handled separately?
- Is a rollback path documented?
Policy and guardrails
Consider using admission controllers (like Gatekeeper or Kyverno) to enforce naming conventions, label requirements, and security constraints. This prevents invalid configs from reaching the cluster.
Ownership and handoff
If multiple teams share a repo, document ownership of each folder so reviews route to the right people. Clear ownership reduces merge conflicts and accidental overrides.
Common issues
- Apply conflicts: multiple tools manage the same fields.
- Missing namespace: resource applied before namespace exists.
- Immutable fields: selectors or service types cannot be changed.
Diff hygiene
Normalize YAML formatting and key order to keep diffs clean. This makes reviews faster and reduces accidental noise.
State of the world vs desired state
Declarative workflows assume the manifests describe the source of truth. Avoid “fixing” production by hand; instead, change the manifest and reapply. This keeps your cluster reproducible.
Split configs by concern
Keep RBAC, config, and workloads in separate files. This makes reviews clearer and reduces the risk of accidental cross-cutting changes.
Auditing changes
Keep a changelog in git or use PR descriptions to capture the intent of each change. During incidents, this context saves time.
Consistency checks
Use pre-commit hooks or CI checks to enforce basic schema and formatting rules across the repo. Consistent validation reduces runtime surprises.
Debug workflow
kubectl get -f app.yaml
kubectl describe -f app.yaml
kubectl diff -f app.yaml
Apply from directory
You can apply a directory of manifests:
kubectl apply -f ./manifests
Combine with labels to target a subset in larger repos.
Practical notes
- Start with a quick inventory:
kubectl get nodes,kubectl get pods -A, andkubectl get events -A. - Compare desired vs. observed state;
kubectl describeusually explains drift or failed controllers. - Keep names, labels, and selectors consistent so Services and controllers can find Pods.
Quick checklist
- The resource matches the intent you described in YAML.
- Namespaces, RBAC, and images are correct for the target environment.
- Health checks and logs are in place before promotion.
- Changes are reviewed and applied through version control.
Field checklist
When you move from a quick lab to real traffic, confirm the basics every time. Check resource requests, readiness behavior, log coverage, alerting, and clear rollback steps. A checklist prevents skipping the boring steps that keep services stable. Keep it short, repeatable, and stored with the repo so it evolves with the service and stays close to the code.
Troubleshooting flow
Start from symptoms, not guesses. Review recent events for scheduling, image, or probe failures, then scan logs for application errors. If traffic is failing, confirm readiness, verify endpoints, and trace the request path hop by hop. When data looks wrong, validate the active version and configuration against the release plan. Always record what you changed so a rollback is fast and a postmortem is accurate.
Small exercises to build confidence
Practice common operations in a safe environment. Scale the workload up and down and observe how quickly it stabilizes. Restart a single Pod and watch how the service routes around it. Change one configuration value and verify that the change is visible in logs or metrics. These small drills teach how the system behaves under real operations without waiting for an outage.
Production guardrails
Introduce limits gradually. Resource quotas, PodDisruptionBudgets, and network policies should be tested in staging before production. Keep backups and restore procedures documented, even for stateless services, because dependencies often are not stateless. Align monitoring with user outcomes so you catch regressions before they become incidents.
Documentation and ownership
Write down who owns the service, what success looks like, and which dashboards to use. Include the on-call rotation, escalation path, and basic runbooks for common failures. A small amount of documentation removes a lot of guesswork during incidents and helps new team members ramp up quickly.
Quick validation
After any change, validate the system the same way a user would. Hit the main endpoint, check latency, and watch for error spikes. Confirm that new pods are ready, old ones are gone, and metrics are stable. If the change touched storage, verify disk usage and cleanup behavior. If it touched networking, confirm DNS names and endpoint lists are correct.
Release notes
Write a short note with what changed, why it changed, and how to roll back. This is not bureaucracy; it prevents confusion during incidents. Even a few bullets help future you remember intent and context.
Capacity check
Compare current usage to requests and limits. If the service is close to limits, plan a small scaling adjustment before traffic grows. Capacity planning is easier when it is incremental rather than reactive.
Final reminder
Keep changes small and observable. If a release is risky, reduce scope and validate in staging first. Prefer frequent small updates over rare large ones. When in doubt, pick the option that simplifies rollback and reduces time to detect issues. The goal is not perfect config, but predictable operations.