Comprehensive toolkit for generating, validating, managing Kubernetes YAML resources. Use this skill when creating Kubernetes manifests (Deployments, Services, ConfigMaps, StatefulSets, etc.), working with Custom Resource Definitions (CRDs), generating production-ready K8s configurations.
68
82%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Mental Model: Kubernetes YAML generation is about translating application requirements into declarative infrastructure. Think in terms of desired state, not imperative commands. A manifest that merely "applies without error" is not the bar — it must also survive a node restart, a rolling update, and a resource crunch without silently degrading, so generation and validation are never separable steps. The recurring pitfall is generating a manifest that validates cleanly today but hits a gotcha under load six months later, because a default (an inferred imagePullPolicy, an unset resource limit) was never made explicit.
Decision Framework:
When to use this skill:
When NOT to use this skill:
k8s-yaml-validator directly instead.{{ }} expressions, _helpers.tpl) rather than the rendered resource — that is chart authoring, not resource generation.Generation philosophy: Generate correct, complete, validated YAML on first pass. Never output YAML that hasn't been validated — this is a mandatory, non-negotiable gate, not a suggestion.
Gather: resource type, target K8s version, app requirements (replicas, ports, volumes), namespace/labels/annotations, and CRD specifics (kind, apiVersion, version).
Query library documentation for CRD specifications:
tessl_query_library_docs: query: "<project-name> <CRD-kind> <version> specification"
# e.g. "argo-cd Application v1alpha1 specification"
# e.g. "istio VirtualService v1beta1 specification"
# e.g. "cert-manager Certificate v1 specification"The query should include:
If documentation is insufficient, fall back to web search:
WebSearch: "<CRD-name> <version> spec documentation"
# e.g. "ArgoCD Application v1alpha1 spec documentation"Always include the version in the query for compatibility.
Recommended labels (use consistently across all resources):
labels:
app.kubernetes.io/name: myapp
app.kubernetes.io/instance: myapp-prod
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/component: backend
app.kubernetes.io/part-of: myplatform
app.kubernetes.io/managed-by: claude-codeBest practices checklist:
securityContext; Pod Security StandardsDeployment template:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: default
labels:
app.kubernetes.io/name: myapp
app.kubernetes.io/instance: myapp-prod
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: myapp
app.kubernetes.io/instance: myapp-prod
template:
metadata:
labels:
app.kubernetes.io/name: myapp
app.kubernetes.io/instance: myapp-prod
spec:
containers:
- name: myapp
image: myapp:1.0.0
ports:
- containerPort: 8080
resources:
requests: { memory: "64Mi", cpu: "250m" }
limits: { memory: "128Mi", cpu: "500m" }
livenessProbe:
httpGet: { path: /health, port: 8080 }
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet: { path: /ready, port: 8080 }
initialDelaySeconds: 5
periodSeconds: 5Service template:
apiVersion: v1
kind: Service
metadata:
name: myapp-service
namespace: default
spec:
type: ClusterIP # or LoadBalancer, NodePort
selector:
app.kubernetes.io/name: myapp
app.kubernetes.io/instance: myapp-prod
ports:
- protocol: TCP
port: 80
targetPort: 8080
name: httpConfigMap template:
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
namespace: default
data:
app.properties: |
key1=value1
config.json: |
{ "setting": "value" }CRITICAL: Always validate using the k8s-yaml-validator workflow immediately after generation.
See: yaml-validator/SKILL.md (in this tile)The validator runs yamllint (syntax), kubeconform (schema/API compliance), best-practice checks, and optional cluster dry-run. Address all reported errors—fix, re-validate, repeat until clean.
Present the validated YAML with a brief summary, key configuration choices, and next steps:
kubectl apply -f ./<filename>.yaml
kubectl get <resource-type> <name> -n <namespace>
kubectl describe <resource-type> <name> -n <namespace>apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
labels:
app.kubernetes.io/managed-by: argocd
spec:
project: default
source:
repoURL: https://github.com/org/repo
targetRevision: HEAD
path: manifests
destination:
server: https://kubernetes.default.svc
namespace: myapp
syncPolicy:
automated:
prune: true
selfHeal: trueapiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp.example.com
gateways:
- myapp-gateway
http:
- route:
- destination:
host: myapp-service
port:
number: 8080apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: myapp-tls
namespace: default
spec:
secretName: myapp-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- myapp.example.comBAD:
containers:
- name: app
image: myapp:1.0
# No resources defined - pods can consume unlimited CPU/memoryGOOD:
containers:
- name: app
image: myapp:1.0
resources:
requests: { memory: "64Mi", cpu: "250m" }
limits: { memory: "128Mi", cpu: "500m" }WHY: Unlimited resources lead to noisy neighbor issues and OOMKilled pods.
BAD:
kind: ConfigMap
data:
DATABASE_PASSWORD: "my-secret-password" # Visible in etcdGOOD:
kind: Secret
type: Opaque
stringData:
DATABASE_PASSWORD: "my-secret-password" # Base64 encoded, separate RBAClatest Tag in ProductionBAD:
containers:
- name: app
image: myapp:latest # Non-deterministic, breaks rollbacksGOOD:
containers:
- name: app
image: myapp:1.2.3 # Immutable, traceable
imagePullPolicy: IfNotPresentBAD:
containers:
- name: app
image: myapp:1.0
# No probes - K8s can't detect failuresGOOD:
containers:
- name: app
image: myapp:1.0
livenessProbe:
httpGet: { path: /health, port: 8080 }
initialDelaySeconds: 30
readinessProbe:
httpGet: { path: /ready, port: 8080 }
initialDelaySeconds: 5BAD:
# Deployment
selector:
matchLabels: { app: myapp }
# Service
selector: { app: my-app } # Typo breaks routingGOOD:
# Deployment
selector:
matchLabels: { app: myapp, version: v1 }
# Service
selector: { app: myapp } # Matches all versionsNever output YAML without running it through the validation workflow:
# Use yaml-validator from this tile
tessl_query_library_docs: query: "kubernetes yaml validation kubeconform yamllint"metadata:
name: myapp
namespace: production # Never rely on default namespace--- separators if desiredextensions/v1beta1 to networking.k8s.io/v1 in K8s 1.19+Before delivering generated YAML, confirm:
latest| Issue | Solution |
|---|---|
| CRD docs not found | Try name variations; fall back to WebSearch with version-specific query |
| Validation failures | Read errors carefully; verify field names/types/required fields; re-validate |
| Wrong API version | Confirm target K8s version; check deprecation status; update apiVersion; re-validate |
Workflow summary: Understand → Fetch CRD Docs (if needed) → Generate → Validate → Deliver
resources: limits and requests from container specsresources: block.requests for scheduling and limits for protection: resources: {requests: {cpu: 100m, memory: 128Mi}, limits: {cpu: 500m, memory: 512Mi}}latest as the image tag in Kubernetes manifestsimagePullPolicy: Always with :latest makes every pod start non-deterministic; imagePullPolicy: IfNotPresent with :latest uses a stale local image silently.image: myapp:latestimage: myapp:v1.2.3 with a specific, immutable tag and imagePullPolicy: IfNotPresentenv value appears in pod descriptions, process listings, and logs; it bypasses Kubernetes RBAC for Secret objects.env: [{name: DB_PASSWORD, value: "mysecret"}]env: [{name: DB_PASSWORD, valueFrom: {secretKeyRef: {name: db-secret, key: password}}}]livenessProbe or readinessProbe.readinessProbe to control traffic routing and livenessProbe to trigger pod restarts on deadlocks.kubectl apply -f - <<EOF\nenv:\n value: $SECRET\nEOF| Topic | Reference | When to Use |
|---|---|---|
QoS classes, imagePullPolicy defaults, probe-threshold interaction, SIGTERM propagation to child processes | Production Readiness | Before generating any Deployment or Pod spec bound for a shared or production cluster |
a1083f4
Also appears in
last in sync Aug 28, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.