Introduction
When deploying applications in Kubernetes, you will eventually encounter the need to run multiple containers within a single pod. Kubernetes pods are designed to support multiple containers to run in a shared context, which can be critical for supporting sidecar, adapter, or ambassador patterns among others. This tutorial will take you through managing multi-container pods including their creation, communication, and managing their resources.
Understanding Multi-Container Pods
In Kubernetes, a Pod is the smallest deployable unit that can be created, scheduled, and managed. It’s common to have a Pod running just a single container, but Kubernetes also allows you to run multiple containers within the same Pod. These co-located containers can share resources, synchronize their execution, and communicate seamlessly, leveraging the same network and storage.
All containers inside a single pod:
- Share the same Network IP – they can communicate with each other using localhost.
- Have access to the same volumes – allowing them to share files.
- Are scheduled on the same physical or virtual machine.
Basic Pod with Multiple Containers
To get started, let’s create a basic Pod YAML definition that includes two containers:
apiVersion: v1
kind: Pod
metadata:
name: multi-container-pod
spec:
containers:
- name: app-container
image: busybox
command: ['sh', '-c', 'echo "Hello from the app container" && sleep 3600']
- name: sidecar-container
image: busybox
command: ['sh', '-c', 'echo "Hello from the sidecar container" && sleep 3600']
To apply this configuration and create the pod in Kubernetes, use:
kubectl apply -f multi-container-pod.yaml
Once the Pod is running, you can check the logs of each container:
kubectl logs multi-container-pod -c app-container
kubectl logs multi-container-pod -c sidecar-container
You should see the “Hello” messages from both containers.
Inter-container Communication
The containers within a pod can communicate using ‘localhost’, as they share the network namespace. Here’s an example of two containers communicating over a local socket:
apiVersion: v1
kind: Pod
metadata:
name: intercom-pod
spec:
containers:
- name: server
image: busybox
command:
- sh
- -c
- 'nc -lk -p 12345 -e echo "Hello World!"'
- name: client
image: busybox
command:
- sh
- -c
- 'sleep 30; nc localhost 12345'
To verify communication between the containers, check the logs after applying the configuration:
kubectl logs intercom-pod -c client
The client container should output “Hello World!” received from the server container.
Managing Resources for Containers
In multi-container pods, you may need to allocate resources differently for each container. Here is an example of how to specify resource requests and limits:
apiVersion: v1
kind: Pod
metadata:
name: resources-pod
spec:
containers:
- name: primary-container
image: nginx
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: secondary-container
image: redis
resources:
requests:
memory: "32Mi"
cpu: "100m"
limits:
memory: "64Mi"
cpu: "200m"
Apply the pod definition to see the resources in effect. Kubernetes will ensure that requests are guaranteed and limits are enforced.
Advanced: Using Init Containers
Init containers are specialized containers that run before app containers and are part of a pod’s initialization. Here’s an example of using an init container:
apiVersion: v1
kind: Pod
metadata:
name: init-container-pod
spec:
initContainers:
- name: init-myservice
image: busybox
command: ['sh', '-c', 'echo init container started; sleep 5']
containers:
- name: myservice
image: nginx
- name: mysidecar
image: redis
Apply this and then check the status of the pod. The init container must complete before the other containers start.
Sharing Volumes between Containers
You can share data between containers in a Pod using shared volumes. Here is how you can define a Pod with shared volumes:
apiVersion: v1
kind: Pod
metadata:
name: shared-volume-pod
spec:
volumes:
- name: shared-data
emptyDir: {}
containers:
- name: producer
image: busybox
volumeMounts:
- name: shared-data
mountPath: /usr/share/data
command: ['sh', '-c', 'echo "Data from producer" > /usr/share/data/index.html']
- name: consumer
image: busybox
volumeMounts:
- name: shared-data
mountPath: /usr/share/data2
command: ['sh', '-c', 'cat /usr/share/data2/index.html']
To test the shared volume, create the pod and then check the logs of the consumer container to see the data written by the producer container.
Conclusion
Managing multi-container pods in Kubernetes provides powerful ways to structure applications. By using shared volumes, network spaces, and careful resource allocation syntax, we can build complex, efficient, and tightly coupled systems that work harmoniously in a single pod. With the provided examples, you should be well on your way to mastering multi-container pods in Kubernetes.