Pods Basics
This page is a hands-on introduction to Pods: creating them, inspecting them, and running multi-container Pods when they are justified. Every example uses kubectl against a cluster where containerd runs the containers.
Prerequisites
- Kubernetes 1.36.2 cluster access (minikube, kind, or a managed cluster).
- kubectl matching the cluster minor version (skew of one minor is supported).
- Docker Engine 29.6.1 only for building images locally; the cluster runs them via containerd.
- A container registry you can push to, or use public images for practice.
Quick check that your client and cluster are healthy:
kubectl version
kubectl get nodesBasic Examples
1. Run a one-off Pod imperatively
The fastest way to get a Pod running for a quick test.
kubectl run web --image=nginx:1.27 --port=80- Creates a single-container Pod named
web. --imagepins the image; prefer a specific tag overlatest.- Good for experiments; not for production, where you use a Deployment.
- Delete it with
kubectl delete pod web.
2. Declare a Pod with YAML
Declarative manifests are reviewable, versionable, and repeatable.
apiVersion: v1
kind: Pod
metadata:
name: web
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80apiVersion: v1andkind: Podidentify the object.labelslet Services and controllers select this Pod later.containerPortdocuments the port; it does not open firewall rules.- Apply with
kubectl apply -f web.yaml.
3. Inspect a Pod
Reading Pod state is the core debugging skill.
kubectl get pod web -o wide
kubectl describe pod webget -o wideshows node placement, Pod IP, and readiness.describeshows events, container states, and restart counts.- The Events section at the bottom explains scheduling or image-pull failures.
- Restart counts above zero signal crashes or failed probes.
4. View container logs
Logs are the first place to look when a container misbehaves.
kubectl logs web
kubectl logs web --previous- Default
logsshows the current container instance's stdout/stderr. --previousshows the last terminated instance after a crash.- Add
-fto follow logs live. - For multi-container Pods, add
-c <container>.
5. Exec into a running container
Interactive access helps confirm config and connectivity from inside.
kubectl exec -it web -- sh-itattaches an interactive terminal.- Everything after
--runs inside the container. - Use it to check env vars, mounted files, or DNS resolution.
- Distroless images may lack a shell; plan debugging tooling accordingly.
6. Set environment variables and a command
Containers often need config through env vars and an explicit entrypoint.
apiVersion: v1
kind: Pod
metadata:
name: printer
spec:
restartPolicy: Never
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c"]
args: ["echo Hello $GREETING; sleep 3600"]
env:
- name: GREETING
value: "world"commandoverrides the image ENTRYPOINT;argsoverrides CMD.envinjects variables the process can read.restartPolicy: Neversuits one-shot tasks.- The
$GREETINGexpansion happens in the shell, not in Kubernetes.
7. Add labels and read them
Labels are the glue between Pods and the controllers and Services that manage them.
kubectl get pods --show-labels
kubectl label pod web tier=frontend
kubectl get pods -l tier=frontend--show-labelslists all labels on each Pod.labeladds or updates a label on the fly.-lfilters Pods by a label selector.- Selectors power Services, Deployments, and NetworkPolicies.
Intermediate Examples
8. A multi-container Pod with a shared volume
Use a second container only when it must share the Pod's network or storage.
apiVersion: v1
kind: Pod
metadata:
name: web-logs
spec:
volumes:
- name: logs
emptyDir: {}
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: logs
mountPath: /var/log/nginx
- name: log-tailer
image: busybox:1.36
command: ["sh", "-c", "tail -F /var/log/nginx/access.log"]
volumeMounts:
- name: logs
mountPath: /var/log/nginx- The
emptyDirvolume is shared by both containers for the Pod's lifetime. - The app writes logs; the tailer reads the same files with no network hop.
- Read the tailer's output with
kubectl logs web-logs -c log-tailer. - This is a justified multi-container Pod: the helper needs shared storage.
9. Add resource requests, limits, and a probe
Production Pods declare what they need and how health is measured.
apiVersion: v1
kind: Pod
metadata:
name: api
spec:
containers:
- name: api
image: registry.example.com/api:1.4.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
memory: "256Mi"
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 5requestsdrive scheduling;limitscap usage (memory over limit is OOM-killed).- Setting requests and memory limit, and leaving CPU uncapped, is a common starting posture.
- The
readinessProbegates traffic until/healthzreturns 200. - Set these on the Pod template of a Deployment for real workloads.
10. Wrap a Pod in a Deployment
You rarely run bare Pods in production; a Deployment manages replicas and rollouts.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80- The
templateis a Pod spec; the Deployment creates and heals Pods from it. replicas: 3keeps three Pods running and reschedules failures.- The
selectormust match the template labels. - Roll out changes with
kubectl applyand watchkubectl rollout status deployment/web.
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).