4 container design patterns for Kubernetes
Tags: kubernetes, devops
Published: 2023-02-27 15:17:03

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.

1. Control groups are for limiting resources (max 256MB of memory).
2. Namespaces are for isolation (you can only see this folder).

![Control groups and Linux namespaces are the fundamental primitives of containers](https://res.cloudinary.com/learnk8s/image/upload/v1677479668/threads/container-patterns-2_tnrclf.png)

**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).

![Containers in the same pod share the same network namespace](https://res.cloudinary.com/learnk8s/image/upload/v1677479668/threads/container-patterns-3_zefcvo.png)

_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.

![The traffic is proxied by the NGINX container before reaching ElasticSearch](https://res.cloudinary.com/learnk8s/image/upload/v1677479668/threads/container-patterns-4_y36erb.png)

Another example is exposing your apps to the public internet without an Ingress.

[Cloudflare tunnel](https://developers.cloudflare.com/cloudflare-one/tutorials/many-cfd-one-tunnel/) runs an agent alongside the app and proxies all the traffic.

![The tunneld agent tunnels the traffic to the Cloudflare network](https://res.cloudinary.com/learnk8s/image/upload/v1677479668/threads/container-patterns-5_gg678c.png)

_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!**

![The container adapts the Elastic Search metrics to be compatible with Prometheus](https://res.cloudinary.com/learnk8s/image/upload/v1677479669/threads/container-patterns-6_g8e1bu.png)

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.

![Adapter vs Ambassador pattern](https://res.cloudinary.com/learnk8s/image/upload/v1677479669/threads/container-patterns-7_cfdcho.png)

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.**

![The sidecar container retrieves the content of the file and prints it to stdout](https://res.cloudinary.com/learnk8s/image/upload/v1677479669/threads/container-patterns-8_ryvj7j.png)

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.

Example include:

- [Injecting secrets.](https://www.vaultproject.io/docs/platform/k8s/injector)
- [Reloading ConfigMaps](https://github.com/jimmidyson/configmap-reload) when there's a change.
- [Caching.](https://thenewstack.io/tutorial-apply-the-sidecar-pattern-to-deploy-redis-in-kubernetes/)

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.

![Init containers in Kubernetes](https://res.cloudinary.com/learnk8s/image/upload/v1677479669/threads/container-patterns-10_ysmcbs.png)

So if you're migrating existing apps into Kubernetes, you have four patterns at your disposal:

- Ambassador
- Adapter
- Sidecar
- Init

[Those are from the original Google paper.](https://static.googleusercontent.com/media/research.google.com//en/pubs/archive/45406.pdf)

In this blog post, you can find more in-depth explanations about the [multi-container patterns.](https://learnk8s.io/sidecar-containers-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