The Friction of Command-Line Infrastructure
When starting out with containers, you often configure everything using CLI flags. You run commands like:
docker run -d --name my-app -p 80:80 -v /var/data:/data --restart=always my-image:v2
While this is quick for local testing, it is difficult to manage in production. You cannot easily store CLI histories in a Git repository, run code reviews on them, or track who changed a parameter. If you need to rebuild your environment, you have to recreate the exact CLI commands from memory.
Managing infrastructure through interactive commands is prone to error and hard to replicate.
Structuring the Kubernetes YAML Schema
Kubernetes solves this by using declarative configuration files written in YAML.
Every Kubernetes resource definition file—whether it is a Pod, a Service, a ReplicaSet, or a Deployment—must contain four mandatory top-level fields:
apiVersion: Specifies the version of the Kubernetes API schema used to create the object. The API is divided into versions and groups (such asv1orapps/v1).kind: The type of resource you want to create (e.g.,Pod,Service,ReplicaSet,Deployment). This field is case-sensitive.metadata: A dictionary containing identifying data likename,namespace,labels, andannotations.labels: Key-value pairs used to identify and group resources (e.g.,app: nginx). Controllers use labels to find pods.annotations: Key-value pairs used to store non-identifying metadata, such as build versions, release dates, or contact emails. Kubernetes does not query annotations to select resources.spec: Declares the desired state of the resource. The configuration details underspecdiffer depending on the resourcekind(e.g., container images, ports, and storage volumes).
Here is a quick reference table for the apiVersion and kind pairings:
| Resource Type | apiVersion | kind (Case-Sensitive!) |
|---|---|---|
| Pod | v1 | Pod |
| Service | v1 | Service |
| ReplicaSet | apps/v1 | ReplicaSet |
| Deployment | apps/v1 | Deployment |
Writing and Deploying a Pod Spec
Let’s define a Pod using YAML and deploy it to the cluster. Save the following configuration as my-first-pod.yaml:
apiVersion: v1
kind: Pod
metadata:
name: nginx-webserver
labels:
app: web
tier: frontend
annotations:
owner: "kapil"
build-id: "20260605.1"
spec:
containers:
- name: nginx-container
image: nginx:1.25
ports:
- containerPort: 80
env:
- name: ENV_VAR_EXAMPLE
value: "production"
Before you deploy, you can validate your YAML syntax and schema against the API Server using the dry-run flag:
$ kubectl apply -f my-first-pod.yaml --dry-run=client
pod/nginx-webserver created (dry run)
If it succeeds, deploy the Pod to the cluster:
$ kubectl apply -f my-first-pod.yaml
pod/nginx-webserver created
To view the running Pods in the namespace:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-webserver 1/1 Running 0 15s
If you need to inspect the status, configuration details, and lifecycle events of a Pod, use the describe command:
$ kubectl describe pod nginx-webserver
This command prints a detailed report of the Pod’s lifecycle history:
Name: nginx-webserver
Namespace: default
Node: worker-node-1/192.168.49.3
Start Time: Fri, 05 Jun 2026 08:40:00 +0530
Labels: app=web
tier=frontend
Annotations: build-id: 20260605.1
owner: kapil
Status: Running
IP: 10.244.1.5
Containers:
nginx-container:
Container ID: containerd://1d7b32...
Image: nginx:1.25
Port: 80/TCP
State: Running
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 30s default-scheduler Successfully assigned default/nginx-webserver to worker-node-1
Normal Pulling 29s kubelet Pulling image "nginx:1.25"
Normal Pulled 25s kubelet Successfully pulled image "nginx:1.25" in 4.12s
Normal Created 25s kubelet Created container nginx-container
Normal Start 24s kubelet Started container nginx-container
The events log at the bottom is highly useful for troubleshooting. If your container fails to start because of an image download error or a configuration mistake, the exact reason will be shown here.

