Introducing Pods in Kubernetes - II: Pod YAML Manifest
💬 “天地不仁,以万物为刍狗。(Heaven and Earth are impartial, they regard all things as straw dogs.)”
— Laozi
In my previous post, we introduced the concept of Pods in Kubernetes—what they are, how they fit into the Kubernetes architecture, and why they are the smallest deployable unit in a cluster. Now, we’ll transition from theory to practice by exploring the YAML manifest used to define a Pod and focus on several important container-level configurations.
To start a pod in Kubernetes, you may use kubectl run
(imperative way) with an exposed port:
kubectl run nginx-pod --image=nginx:1.25 --port=80
This creates a Pod named nginx-pod
running the nginx:1.25
image and opens port 80. It is useful for quick testing, but for production or repeatable deployments, YAML manifests are preferred.
For example, imagine you need to recreate the same Pod after a crash, or you want to deploy the same Pod across multiple environments like dev, staging, and production. If you only used kubectl run, you’d need to remember or script out all the command-line options, which can be error-prone and hard to maintain. Therefore, instead of manually creating Pods using kubectl run
or other imperative commands, Kubernetes encourages the use of declarative configuration via YAML files. This approach provides better reproducibility, version control, and consistency across environments.
In this post, we’ll walk through a complete Pod manifest and break down key sections commonly used in production deployments. These configurations ensure your containers are healthy, efficient, and secure. We’ll cover:
- Pod Metadata and Spec
- Readiness Probe
- Liveness Probe
- CPU/Memory Requests and Limits
- Volumes and VolumeMounts
- Environment Variables from Secrets
Sample Pod YAML Manifest
Here’s a complete sample YAML manifest demonstrating best practices for configuring a container inside a Pod:
apiVersion: v1
kind: Pod
metadata:
name: sample-app
namespace: default
labels:
app: sample
environment: production
spec:
containers:
- name: sample-container
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 15
periodSeconds: 20
failureThreshold: 3
volumeMounts:
- name: app-config
mountPath: /etc/config
readOnly: true
envFrom:
- secretRef:
name: app-secret
env:
- name: API_KEY
valueFrom:
secretKeyRef:
name: app-secret
key: api-key
volumes:
- name: app-config
configMap:
name: app-config
Pod Metadata and Spec
The top-level fields of a Pod YAML define its identity and structure.
apiVersion: v1
kind: Pod
metadata:
name: sample-app
namespace: default
labels:
app: sample
environment: production
spec:
...
- apiVersion: Specifies the Kubernetes API version (e.g.,
v1
for core resources like Pods). - kind: Defines the resource type, here a
Pod
. - metadata: Contains identifying information:
- name: A unique name for the Pod within its namespace.
- namespace: The Kubernetes namespace (e.g.,
default
). If omitted, the Pod is created in thedefault
namespace. - labels: Key-value pairs for organization and selection (e.g., by Services or Deployments). Here,
app: sample
andenvironment: production
help identify the Pod’s purpose and environment.
- spec: The specification of the Pod’s desired state, including its containers, volumes, and other configurations.
Why it matters: Proper metadata ensures the Pod is uniquely identifiable and can be targeted by other Kubernetes resources like Services or HorizontalPodAutoscalers. Incorrect or missing metadata can lead to naming conflicts or Pods being unselectable by controllers.
Readiness Probe
The readiness probe determines when a container is ready to accept traffic. Until the probe passes, the Pod is excluded from Service endpoints, preventing traffic from reaching an unready container.
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3
- httpGet: Probes the container by sending an HTTP GET request to
/
on port 80. - initialDelaySeconds: Waits 5 seconds after container startup before starting probes, allowing the application time to initialize.
- periodSeconds: Checks every 10 seconds.
- failureThreshold: Requires 3 consecutive failures to mark the container as not ready.
What happens if it fails?: If the probe fails (e.g., the endpoint returns a non-2xx HTTP status), Kubernetes marks the container as “Not Ready,” and the Pod is removed from Service endpoints. This prevents traffic from being routed to an unhealthy container, ensuring reliability. Once the probe succeeds, the Pod is added back to the Service.
Use case: Useful for applications that need time to load configurations or establish database connections before handling requests.
Liveness Probe
The liveness probe checks if a container is still healthy. If it fails, Kubernetes restarts the container to recover it.
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 15
periodSeconds: 20
failureThreshold: 3
- httpGet: Sends an HTTP GET request to
/
on port 80. - initialDelaySeconds: Waits 15 seconds before starting probes, giving the container time to stabilize.
- periodSeconds: Checks every 20 seconds.
- failureThreshold: Marks the container as unhealthy after 3 consecutive failures.
What happens if it fails?: If the probe fails (e.g., due to a crashed application or unresponsive endpoint), Kubernetes restarts the container. This is useful for recovering from deadlocks, memory leaks, or other issues that cause the application to become unresponsive.
Use case: Essential for long-running applications where temporary failures (e.g., a stuck process) can be resolved by restarting the container.
CPU and Memory: Requests and Limits
Resource requests and limits help Kubernetes schedule Pods and manage resource contention.
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- requests: Specifies the minimum resources guaranteed to the container:
- memory: “64Mi”: Ensures 64 mebibytes of memory.
- cpu: “250m”: Guarantees 0.25 CPU cores (250 milliCPU).
- limits: Caps the maximum resources the container can use:
- memory: “128Mi”: Limits memory to 128 mebibytes.
- cpu: “500m”: Limits CPU to 0.5 cores.
What happens if limits are exceeded?:
- Memory: If the container exceeds the memory limit, it is terminated with an OutOfMemory (OOM) error, and Kubernetes restarts it. This prevents a single container from starving the node of memory.
- CPU: If the CPU limit is exceeded, the container is throttled, meaning it gets less CPU time, but it won’t be terminated. This ensures fair CPU sharing among Pods.
Why it matters: Requests help Kubernetes schedule Pods on nodes with sufficient resources, while limits prevent resource hogging, ensuring cluster stability.
Volumes and VolumeMounts
Volumes provide persistent or shared data to containers, such as configuration files or persistent storage.
volumes:
- name: app-config
configMap:
name: app-config
volumeMounts:
- name: app-config
mountPath: /etc/config
readOnly: true
- volumes: Defines a volume named
app-config
sourced from a ConfigMap namedapp-config
. ConfigMaps store key-value pairs or files that can be mounted into containers. - volumeMounts: Mounts the
app-config
volume at/etc/config
inside the container. ThereadOnly: true
ensures the mounted files cannot be modified by the container.
What is it used for?: Volumes like ConfigMaps are ideal for injecting configuration files, such as Nginx server configs or application settings, without modifying the container image. They decouple configuration from code, making applications more portable and easier to update.
What happens if misconfigured?: If the ConfigMap doesn’t exist or the mount path conflicts with existing files, the container may fail to start or behave unexpectedly. Always ensure the referenced ConfigMap exists in the same namespace.
Environment Variables from Secrets
Secrets securely store sensitive data like API keys or passwords and can be injected as environment variables.
envFrom:
- secretRef:
name: app-secret
env:
- name: API_KEY
valueFrom:
secretKeyRef:
name: app-secret
key: api-key
- envFrom: Automatically sets all key-value pairs from the
app-secret
Secret as environment variables in the container. For example, ifapp-secret
containsusername: admin
andpassword: secret123
, these become environment variablesusername
andpassword
. - env: Selectively retrieves a specific key (
api-key
) from theapp-secret
Secret and assigns it to the environment variableAPI_KEY
.
What if I want a specific secret?: Use the env
field with secretKeyRef
(as shown) to retrieve only specific keys from a Secret, rather than exposing all key-value pairs. This is more secure and avoids cluttering the environment with unnecessary variables. By the way, the env
field is not necessary if all the envs are already populated by envFrom
. It is just for demonstration here.
What happens if misconfigured?: If the Secret app-secret
doesn’t exist or the api-key
key is missing, the container will fail to start. Ensure the Secret exists in the same namespace and contains the expected keys.
Why it matters: Secrets provide a secure way to manage sensitive data, reducing the risk of exposing credentials in logs or container images.
Deploying and Exploring the Pod
Apply the YAML
kubectl apply -f sample-pod.yaml
Check Pod Status
kubectl get pods
kubectl describe pod sample-app
View Logs
kubectl logs sample-app
Port Forward (to test readiness/liveness endpoints)
kubectl port-forward pod/sample-app 8080:80
curl http://localhost:8080/
Check Probes
kubectl get endpoints
# -A5: include 5 lines After match. -i: ignore cases
kubectl describe pod sample-app | grep -A5 -i "Readiness"
Summary
This post walked through a detailed Pod manifest and highlighted key configuration options at the container level that are critical for observability, reliability, and resource management. Mastering these configurations helps ensure your application runs efficiently and is easier to manage in production.
For further reading, check out the official Kubernetes documentation on Pods.