Running new apps in Kubernetes is straightforward.
But what happens when you have legacy apps that:
- Log to file instead of stdout?
- Has no support for Prometheus?
- Has no support for HTTPS?
First, let's cover the basics.
In Kubernetes, a pod is a collection of containers.
Containers are isolated using two Linux primitives: control groups and namespaces.
- Control groups are for limiting resources (max 256MB of memory).
- Namespaces are for isolation (you can only see this folder).
All the containers in a Pod are isolated except for the network.
The network is shared, and a single IP address is assigned to all containers in a Pod (Pod's IP address).
Why would you need to run more than a container in a Pod?
If you can't (or don't want to) change the code in your app, you might need to adjust its functionality in other ways.
Let's have a look at an example.
Recent versions of Elasticsearch support TLS, but it was a paid extra feature for a long time.
How did you secure traffic with TLS?
You could add a proxy to your pod as a container.
The (encrypted) traffic reaches the proxy first, then (unencrypted) Elasticsearch.
Another example is exposing your apps to the public internet without an Ingress.
Cloudflare tunnel runs an agent alongside the app and proxies all the traffic.
What happens when you want to use Prometheus, but your app has a custom format for exposing metrics?
There's no need to change the code if you use an adapter.
Example: Elasticsearch doesn't expose Prometheus metrics.
Adapter to the rescue!
When you have an extra container in the Pod to handle input, that's called the Ambassador pattern.
If it processes the output of the main container, it's an Adapter instead.
The default for apps in Kubernetes is to print the logs to stdout.
What if you have an app that logs to file instead?
How do you collect the logs?
You can use a container that retrieves the content of the log file and prints it to stdout.
Other sidecars include containers that inject secrets, reload the app when there's a change to ConfigMaps, caching, etc.
Any container that enhances your app is generally called a sidecar container.
Elasticsearch recommends setting the virtual memory to a higher value (i.e. mmap count) before the app starts.
How do you do that in Kubernetes?
You can use Init Containers, which are containers that run to completion before the "normal" containers start.
So if you're migrating existing apps into Kubernetes, you have four patterns at your disposal:
In this blog post, you can find more in-depth explanations about the multi-container patterns.
And finally, if you've enjoyed this thread, you might also like:
- The Kubernetes workshops that we run at Learnk8s https://learnk8s.io/training
- This collection of past threads https://twitter.com/danielepolencic/status/1298543151901155330
- The Kubernetes newsletter I publish every week, "Learn Kubernetes weekly" https://learnk8s.io/learn-kubernetes-weekly