Kubernetes Adapter Pattern

Overview:

In this tutorial, I would like to demonstrate the use of Kubernetes Adapter Pattern with a simple example.

Kubernetes Adapter Pattern:

Design Patterns are repeatable & reusable solutions for commonly occurring problems in the software/architectural design and they encourage the developers to design a highly cohesive and loosely coupled applications. Design patterns can be used for the infrastructure/deployment design as well in this modern Microservices era!

Lets consider an application in our Kubernetes cluster. One of the APIs of the application is not compatible with a client which is trying to consume the API.

Kubernetes Adapter Pattern allows us to run a sidecar container along with main application container to convert the API as the client expects without any application code change!

This adapter pattern is a special case of Kubernetes Sidecar Pattern which we had discussed here.

Sample Application:

Let’s consider a simple Microservice for cars in which we get information about a car model based on the given id. The application is successfully deployed and all the clients which are consuming this API are happy except one!

{
   "id":1,
   "make":"honda",
   "model": "civic",
   "topSpeed" : 60
}

The unhappy client realized that the topSpeed in the above response is in miles/hour. But the client expectation was to get that information in the kilometers/hour. The Microservice developers are afraid that they do not want to make a change in the code just for 1 client. [This is a simple example to explain the issue. But hopefully you get the idea].

Let’s see how we could make the client happy with Kubernetes Adapter Pattern.

Car Service – Application Container:

  • Lets’s create a simple DB using json file for the cars-service as shown here. I have this content in a file called db.json
{
   "cars":[
      {
         "id":1,
         "make":"honda",
         "model": "civic",
         "topSpeed" : 60
      },
      {
         "id":2,
         "make":"honda",
         "model": "accord",
         "topSpeed" : 80
      },
      {
         "id":3,
         "make":"nissan",
         "model": "370z",
         "topSpeed" : 100
      }
   ]
}
  • Lets first create a ConfigMap with the json file for the cars-service to use later
kubectl create configmap carsdb --from-file=db.json
  • Lets deploy the app using the below deployment.yaml
    • The docker container will be injected with the above db.json during deployment.
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: car-service
  name: car-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: car-service
  template:
    metadata:
      labels:
        app: car-service
    spec:
      containers:
      - image: clue/json-server
        name: car-service
        ports:
        - containerPort: 80
        volumeMounts:
        - name: db
          mountPath: /data/
      volumes:
      - name: db
        configMap:
          name: carsdb
  • Then Lets create a service to expose the app.
apiVersion: v1
kind: Service
metadata:
  labels:
    app: car-service
  name: car-service
spec:
  ports:
  - name: 8080-80
    port: 8080
    protocol: TCP
    targetPort: 80
  selector:
    app: car-service
  type: LoadBalancer
  • At this point, We should be able to access the application using the loadbalancer URL.

Kubernetes Adapter Pattern Implementation:

Now let’s work on the 1 specific client requirements of converting the topSpeed to km/h unit without touching the main car-service app. We are going to achieve that by attaching nginx to the main car-service app as a sidecar.

  • Lets create another config file for nginx.
    • Here we process the response from the car-service, convert the topSpeed from miles to kilometers
upstream backend  {
  server localhost;
}

server {

    listen 8080;

    default_type application/json;

    location /cars_backend {
        internal;
        proxy_pass http://backend$request_uri;
        proxy_redirect off;
    }

    location /cars {

        content_by_lua_block {

            -- forward to backend
            local a = ngx.location.capture("/cars_backend")

            -- convert to diff unit
            local func = function (v)
                return '"topSpeed": ' .. v[1] * 1.6;
            end

            -- find a match and replace
            local newstr, n, err = ngx.re.sub(a.body, '"topSpeed": ([0-9]+)', func)

            -- final response
            ngx.say(newstr)

        }
    }

}
kubectl create configmap nginxconf --from-file=default.conf
  • The deployment yaml spec is updated to include the sidecar as shown here
spec:
      containers:
      - image: openresty/openresty:alpine
        name: car-adapter
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: conf
          mountPath: /etc/nginx/conf.d/     
      - image: clue/json-server
        name: car-service
        ports:
        - containerPort: 80
        volumeMounts:
        - name: db
          mountPath: /data/
      volumes:
      - name: db
        configMap:
          name: carsdb
      - name: conf
        configMap:
          name: nginxconf
  • The nginx sidecar is exposing its own port for anyone to access.
  • Service yaml is updated as shown here to include additional nginx port
apiVersion: v1
kind: Service
metadata:
  labels:
    app: car-service
  name: car-service
spec:
  ports:
  - name: 8080-80
    port: 8080
    protocol: TCP
    targetPort: 80
  - name: 8081-80
    port: 8081
    protocol: TCP
    targetPort: 8080
  selector:
    app: car-service
  type: LoadBalancer

Now we have included a special client requirement as a separate sidecar without modifying the original application.

kubernetes adapter pattern

By using the same uri patterns and using different port, we are able to change the response based on the requirements.

Summary:

We were able to successfully demonstrate the use of Kubernetes Adapter Pattern. We could modify the application response behavior by adding additional container as a sidecar based on the consumer requirements.

Read more about Kubernetes Cloud Design Patterns.

The source code is available here.

Happy learning 🙂

 

Share This:

1 thought on “Kubernetes Adapter Pattern

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.