Multi container pod
Pods can contain multiple containers, for some excellent reasons — primarily, the fact that containers in a pod get scheduled in the same node in a multi-node cluster. This makes communication between them faster and more secure, and they can share volume mounts and filesystems
There are three widely recognized, multi-container pod patterns
- Sidecar
- Ambassador
- Adapter
Sidecar
Sidecars derive their name from motorcycle sidecars. While your motorcycle can work fine without the sidecar, having one enhances or extends the functionality of your bike, by giving it an extra seat. Similarly, in Kubernetes, a sidecar pattern is used to enhance or extend the existing functionality of the container
our container works perfectly well without the sidecar, but with it, it can perform some extra functions. Some great examples are using a sidecar for monitoring and logging and adding an agent for these purposes.
# cat side-car-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: sidecar-pod
spec:
volumes:
- name: logs
emptyDir: {}
containers:
- name: app-container
image: alpine
command: ["/bin/sh"]
args: ["-c", "while true; do date >> /var/log/app.log; sleep 2;done"]
volumeMounts:
- name: logs
mountPath: /var/log
- name: log-exporter-sidecar
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: logs
mountPath: /usr/share/nginx/html
save and exit the yaml file
So, if we look at the manifest you’ll see we have two containers: app-container and log-exporter-sidecar. The app container continuously streams logs to /var/log/app.log, and the sidecar container mounts the logs to the Nginx HTML directory. This allows anyone to visualize the logs using a web browser.
Lets run the below command
# kubectl apply -f side-car-pod.yaml
pod/sidecar-pod created
once the pod is running
# kubectl get pod sidecar-pod
NAME READY STATUS RESTARTS AGE
sidecar-pod 2/2 Running 0 19m
# kubectl port-forward sidecar-pod 80:80
Forwarding from 127.0.0.1:80 -> 80
Forwarding from [::1]:80 -> 80
Ambassador
The ambassador pattern derives its name from an Ambassador, who is an envoy and a person a country chooses to represent their country and connect with the rest of the world. Similarly, in the Kubernetes perspective, an Ambassador pattern implements a proxy to the external world. Let me give you an example — If you build an application that needs to connect with a database server, the server configuration, etc, changes with the environment.
Now, the official recommendation to handle these is to use Config Maps, but what if you have legacy code that is already using another way of connecting to the database. Maybe, a properties file, or even worse, a hardcoded set of values. What if you want to communicate with localhost, and you can leave the rest to the admin? You can use the Ambassador pattern for these kinds of scenarios.
So, what we can do is create another container that can act as a TCP Proxy to the database, and you can connect to the proxy via localhost. The sysadmin can then use config maps and secrets with the proxy container to inject the correct connection and auth information.
#cat ambassador-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: ambassador-pod
labels:
app: ambassador-app
spec:
volumes:
- name: shared
emptyDir: {}
containers:
- name: app-container-poller
image: yauritux/busybox-curl
command: ["/bin/sh"]
args: ["-c", "while true; do curl 127.0.0.1:81 > /usr/share/nginx/html/index.html; sleep 10; done"]
volumeMounts:
- name: shared
mountPath: /usr/share/nginx/html
- name: app-container-server
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: shared
mountPath: /usr/share/nginx/html
- name: ambassador-container
image: bharamicrosystems/nginx-forward-proxy
ports:
- containerPort: 81
save and exit the file
# kubectl apply -f ambassdor-pod.yaml
pod/ambassdor-pod configured
# kubectl get pod ambassdor-pod
NAME READY STATUS RESTARTS AGE
ambassdor-pod 2/3 Running 0 19m
# kubectl port-forward ambassdor-pod 80:80
Forwarding from 127.0.0.1:80 -> 80
Forwarding from [::1]:80 -> 80
If you look carefully in the manifest YAML, you will find there are three containers. The app-container-poller continuously calls http://localhost:81
and sends the content to /usr/share/nginx/html/index.html
.
The app-container-server runs and listens on port 80 to handle external requests. Both these containers share a common mountPath
. That is similar to the sidecar approach.
There is an ambassador-container
running within the pod that listens on localhost:81
and proxies the connection to example.com
, so when we curl the app-container-server
the endpoint on port 80, we get a response from example.com
.
Adapter
The Adapter is another pattern that you can implement with multiple containers. The adapter pattern helps you standardize something heterogeneous in nature. For example, you’re running multiple applications within separate containers, but every application has a different way of outputting log files.
Now, you have a centralised logging system that accepts logs in a particular format only. What can you do in such a situation? Well, you can either change the source code of each application to output a standard log format or use an adapter to standardise the logs before sending it to your central server. That’s where the adapter pattern comes in.
#cat adapter-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: adapter-pod
labels:
app: adapter-app
spec:
volumes:
- name: logs
emptyDir: {}
containers:
- name: app-container
image: alpine
command: ["/bin/sh"]
args: ["-c", "while true; do date >> /var/log/app.log; sleep 2;done"]
volumeMounts:
- name: logs
mountPath: /var/log
- name: log-adapter
image: alpine
command: ["/bin/sh"]
args: ["-c", "tail -f /var/log/app.log|sed -e 's/^/Date /' > /var/log/out.log"]
volumeMounts:
- name: logs
mountPath: /var/log
In the manifest, we have an app-container
that outputs a stream of dates to a log file. The log-adapter
container adds a Date
prefix in front. Yes, it’s a very rudimentary example, but enough to get how the adapter works.
# kubectl apply -f adapter-pod.yaml
pod/adapter-pod configured
# kubectl get pod adapter-pod
NAME READY STATUS RESTARTS AGE
adapter-pod 2/2 Running 0 19m
# kubectl port-forward adapter-pod 80:80
Forwarding from 127.0.0.1:80 -> 80
Forwarding from [::1]:80 -> 80
And that's how we can deploy a multi-container pod into your Kubernetes cluster
Relevant Blogs:
Recent Comments
No comments
Leave a Comment
We will be happy to hear what you think about this post