top of page

Kubernetes Structural Design Patterns

  • Writer: Vishakh Rameshan
    Vishakh Rameshan
  • Jan 7, 2021
  • 3 min read

With the introduction of microservices and containers, development, deployment and maintaining of applications on a production have greatly changed and brought lots of advantage and also problems like managing tens or thousands of containers. With Orchestration tools like Docker Swarm, Mesos, Kubernetes most of the problems were solved.


With Kubernetes being now a de-facto standard orchestration platform and being adopted by multiple cloud providers, the way to design the containers running on pods in Kubernetes are to looked upon very seriously to gain the full advantage of cloud nativeness.


In this blog we will be looking at some of the important, well known and very much implemented architectural design for laying your containers on a Kubernetes pod.


In a Microservice world, you would have already heard many saying "microservice is a unique entity that can survive alone and should have a single responsibility". This is very much true when application are deployed on containers. The container should be performing a single task and should not be overloaded with multiple features.


To give an example, say you had a monolithic e-commerce application which you dissected into purchase service, payment service, order service etc. Now each of those are a microservice built on your specific language and communicate to each other over REST/GRPC. When you take a payment service it should have just one responsibility and that is handling the payment. You should not overload it with say logging feature. That is something common for all the microservices and so should be created as another independent microservice and have other services communicate to this logging service. This way the business application remains separate from additional layers.


This is same when microservices are deployed into containers. The above payment service must be one container and the logging service must be another container. This way both remain independent and isolated and they communicate over webservice.

So with no further due let's jump into the design patterns to be followed when deploying the containers into a Kubernetes platform as a pod.


Init containers

Init containers are containers used for initializing tasks before the actual application container starts.


For example, say before your order service container starts and running, there should be a mechanism to connect to DB and create a table and perform some task or say for order service to start there should be some some shell scripts in that pod to be executed. So in those situation instead of burdening the application container, let there be an init container to perform that task.


The advantage that we get here is, init containers by default runs first and the application will start only once init containers have done their job.


Sidecar


Sidecar containers are kind of enhancement to an existing application, like say a younger brother (sidecar container) who takes some responsibility from his elder brother (application container) to look after his family and home (application task).


Here the application container can live without sidecar, but the sidecar is used just to minimize the work that the application container do.

The most famous one is envoy proxy in istio, that takes care of traffic management, mtls communication, service discovery etc.


Adapter


Adapter containers are used as an addon support to an application container. You can map this concept with that of a normal phone charging adapter, where the phone (application) to connect to the plug (external service) can be achieved using a charging adapter (adapter container).

The best example would be, say your application containers generates logs but to push to logstash and visualize on kibana, the application logs need to be formatted in logstash supported format. This instead of adding the format conversion logic on every microservice, we can have an adapter service which does the conversion. This way, even if the microservices are using different language, or if they are legacy codebase, still with this adapter you can achieve the use case.




Ambassador


There are situations in which the application container needs to communicate with an external service such as database. Now this can be achieved directly by the application code, but you may need to configure database ip or dns based on each env (dev, qa, stage, load, uat, prod etc). If tomorrow the database changes from say Oracle to MySQL, then you may need to alter your configuration in your application code.

With Ambassador, the application code just need localhost:port_number to communicate with the ambassador container, and the ambassador will take care of communicating to external service. This way the application/business never changes and wherever it's running, application just makes localhost call to the database.


Best example would be the cloud sql proxy which is an ambassador container that an application container can call using localhost:port_number to communicate to an external Google Cloud SQL database service.


Comments


bottom of page