C.W.K.
Stream
Lesson 01 of 08 · published

Kubernetes Manifests — apiVersion, kind, spec

~12 min · yaml, kubernetes, manifests

Level 0Plaintext
0 XP0/64 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Every Kubernetes object is a YAML document with the same four keys

Kubernetes manifests follow a strict shape: apiVersion, kind, metadata, spec. The cluster API server reads the manifest, validates it against the OpenAPI schema for that kind, and reconciles state. Every Deployment, Service, ConfigMap, Ingress, Job, CronJob — all the same four-key envelope.

The four-key envelope

  • apiVersion — which API group + version owns this object (e.g., apps/v1 for Deployment, v1 for Service).
  • kind — the resource type (Deployment, Service, ConfigMap, …).
  • metadata — name, namespace, labels, annotations.
  • spec — the desired state. Shape varies per kind.

Multi-document files for one logical service

A typical service ships as Deployment + Service + ConfigMap + (optional) Ingress, four documents in one file separated by ---. kubectl apply -f stack.yaml applies them all in one shot.

Principle: manifests are desired state, not commands. The cluster reconciles toward what you wrote. This is why YAML — declarative, idempotent — is the right format for Kubernetes; an imperative shell script would be the wrong shape.

Code

A complete service in one file·yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: pippa-config
data:
  PORT: "8000"
  LOG_LEVEL: info
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pippa
  labels:
    app: pippa
spec:
  replicas: 3
  selector:
    matchLabels:
      app: pippa
  template:
    metadata:
      labels:
        app: pippa
    spec:
      containers:
        - name: api
          image: ghcr.io/cwk/pippa:1.0
          envFrom:
            - configMapRef:
                name: pippa-config
          ports:
            - containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
  name: pippa
spec:
  selector:
    app: pippa
  ports:
    - port: 80
      targetPort: 8000
Validate before applying·bash
# Schema-check against the cluster's actual API
kubectl apply --dry-run=server -f stack.yaml

# Schema-check offline (faster, catches typos)
kubeconform -summary stack.yaml

# Lint with kube-linter (best practices)
kube-linter lint stack.yaml
The 'string vs number' trap·yaml
# WRONG — port becomes integer 8000, ConfigMap rejects (must be string)
data:
  PORT: 8000

# RIGHT — port is the string "8000"
data:
  PORT: "8000"

External links

Exercise

Write a single YAML file that defines a one-replica Deployment plus a Service for any toy image (nginx is fine). Apply with kubectl apply -f stack.yaml --dry-run=server. Then deliberately omit a required field (selector, port) and re-run; read the error message — it points to the missing field. That round trip is how you'll learn every new resource kind.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.