Kubernetes is the go-to tool for managing containers, making it easier to deploy and run applications across different environments. At its heart is the pod, the smallest unit in Kubernetes, which groups one or more containers to work together.
If you're new to Kubernetes, learning the basics of pods is a good starting point. But to use Kubernetes effectively, it’s important to explore advanced pod features.
These advanced features, like using multiple containers in a pod, Init Containers, and managing resources, can help improve how your applications perform and stay stable.
In this article, we'll break down these concepts and give you the knowledge you need to better manage and grow your container-based apps.
Definition:
A pod in Kubernetes is a logical unit representing one or more tightly coupled containers that share storage and network resources. Each pod has its own IP address and can contain multiple containers, although most simple applications only need a single container per pod.
Basic Pod Architecture
Containers: Each pod can host one or more containers, often with a shared purpose.
Networking: Containers in a pod share the same network namespace, meaning they can communicate with each other via
localhost
.Storage: Pods can share storage volumes between containers, making it easier to manage persistent data.
Example of Creating a Single Container Pod:
---
apiVersion: v1
kind: Pod
metadata:
name: pod-1
spec:
containers:
- name: cont-1
image: nginx
ports:
- containerPort: 80
apiVersion
What it does: It tells Kubernetes what version of the API to use for this file.
Simple example: Think of it as the version of a recipe you're following.
kind
What it does: Specifies what type of Kubernetes object you're creating.
In this case: You’re creating a
Pod
.Simple example: Like saying, "I want to build a house" (here, the house is the Pod).
metadata
What it does: Contains extra information about the object, like its name.
In this case: The Pod's name is
pod-1
.Simple example: Like labelling your lunchbox with your name.
spec
What it does: Describes the specifications of the Pod—what's inside and how it behaves.
Simple example: Like listing what ingredients go into your sandwich and how to make it.
containers
What it does: Lists the containers that will run inside the Pod.
Simple example: Imagine each container as a mini-app packed in your Pod (like a box with compartments).
- name
What it does: Gives the container a name.
In this case: The container is named
cont-1
.Simple example: It's like naming your pet to identify it.
image
What it does: Specifies the container image to use.
In this case: It uses the
nginx
image (a web server).Simple example: Like choosing a meal from a menu; here, you're picking "nginx."
ports
What it does: Defines which port inside the container will be used.
In this case: The container listens on port
80
.Simple example: Think of it as the door number to access the container.
containerPort
What it does: Specifies the port number used by the container.
In this case: The container is ready to serve content on port
80
.Simple example: Like telling someone which doorbell to ring when they visit your house.
This YAML file essentially creates a simple Kubernetes Pod that runs an Nginx server.
Multi-Container Pod:
A multi-container pod in Kubernetes is a Pod that has more than one container inside it. These containers share the same network and storage, so they can easily communicate and work together.
Why Multi-Container Pods?
Single-container Pods work well for simple apps, but for more complex tasks, using multiple containers in a Pod can be better. When a Pod has multiple containers, they can work together in helpful ways. This makes your app more efficient, easier to manage, and better at handling different tasks.
In these multi-container pods, just assume that we have 2 containers in a single pod. One container acts as main container and another one is helper container.
Common Pod Patterns
Sidecar Pattern: Here helper containers are used for logging, monitoring, or proxying and Main container runs the application.
Example: A web app container with a sidecar container that collects logs.
Ambassador Pattern: The ambassador pattern adds a helper container to manage network traffic for the main container
Example: If the main app needs to talk to a database, the ambassador container handles the connection, making things easier and more secure.
Adapter Pattern: A helper container modifies or transforms data for the main container.
Example: A container that changes log formats before sending them to a monitoring system.
Init Container Pattern: A container that runs first to set things up before the main app starts.
Example: A container that downloads data before the app container starts running.
Example Configuration File: Multi-Container Pod with Sidecar Pattern:
Here’s a YAML example showing a multi-container pod with a sidecar container to handle logging for the main application container:
apiVersion: v1
kind: Pod
metadata:
name: multi-container-pod
spec:
containers:
- name: main-app
image: nginx
- name: log-agent
image: busybox
args: ["/bin/sh", "-c", "while true; do echo $(date) >> /var/log/nginx/access.log; sleep 5; done"]
volumeMounts:
- name: log-volume
mountPath: /var/log/nginx
volumes:
- name: log-volume
emptyDir: {}
Sample YAML Configuration: Pod with Init Container
apiVersion: v1
kind: Pod
metadata:
name: init-container-pod
spec:
initContainers:
- name: init-db
image: busybox
command: ['sh', '-c', 'until nslookup database; do echo waiting for database; sleep 2; done']
containers:
- name: main-app
image: nginx
The Init Container (init-db
) checks if a service named database
is accessible. Only once this check is complete does the main application container (nginx
) start.
Pod Lifecycle and States: Managing Pod Behaviour
Pod Lifecycle Phases
Understanding the pod lifecycle is key to troubleshooting and managing Kubernetes applications. The primary phases in the lifecycle are:
Pending: The pod is accepted by the Kubernetes system but is waiting for resources to be allocated.
Running: The pod has been scheduled, and all containers are in a running state.
Succeeded: All containers in the pod have exited successfully.
Failed: All containers in the pod have terminated, with at least one container failing.
CrashLoopBackOff: One or more containers in the pod are repeatedly crashing.
Handling Pod Failures
Kubernetes provides various tools for managing and troubleshooting pod states. For example, the kubectl describe
command can be used to examine the status of a pod and identify reasons for failures.
kubectl describe pod <pod-name>
Common Commands On Pods
To get all the pods:
kubetctl get pods (or) kubectl get pod (or) kubectl get po
To delete a pod:
kubectl delete pod pod_name
To get IP of a pod:
kubectl get po pod_name -o wide
To get IP of all pods:
kubectl get po -o wide
To get all details of a pod:
kubectl describe pod podname
To get all details of all pods:
kubectl describe po
To get the pod details in YAML format:
kubectl get pod pod-1 -o yaml
To get the pod details in JSON format:
kubectl get pod pod-1 -o json
To enter into a pod:
kubectl exec -it pod_name -c cont_name bash
To get the logging info of our pod:
kubectl logs pod_name
To get the logs of containers inside the pod:
kubectl logs pod_name -c cont-name
Conclusion
In Kubernetes, using multi-container Pods and common patterns like the Ambassador, Sidecar, and Adapter can make applications more efficient, modular, and easier to manage. Each pattern has a specific role to solve different challenges, helping your containers work together seamlessly. By understanding and applying these patterns, you can design robust, scalable, and flexible applications tailored to your needs.
If you enjoy stories that help you learn, live, and work better, consider subscribing. If this article provided you with value, please support my work — only if you can afford it. You can also connect with me on Linkedin. Thank you!