In this tutorial I'll be walking you through the creation of a multicontainer pod with two apps: a NodeJS REST API, and another NodeJS API that serves as the backend. Everything running in Kubernetes. And more specifically, on GKE (Google Kubernetes Engine).
This tutorial is based on the awesome Deploying a containerized web application tutorial, which introduced me to Kubernetes. However, as I'll be leveraging multicontainer pod deployment model in future tutorials, I decided to write one with the purpose of augmenting it.
There are multiple reasons for this. Allow me to elaborate my reasons.
This tutorial has two NodeJS Express HTTP containers that aim to separate responsibilites of API Management and backend (business rules):
-
For the execution of certain API Management policies like validate a token, apply spike arrest, apply quota restrictions, etc. E.g. in the near future, I might want to use Apigee Microgateway. Stay tuned for another tutorial on this.
-
For the execution of the business rules perhaps payload transformations, mashups (calling multiple APIs and consolidating responses), etc.
Let me expand on the above, as I'll build on top of this tutorial for future content.
- To add API Management capabilities. In my case, I'm using a plain NodeJS app, for the sake of keeping this tutorial as simple as possible and reusable. However, you can use anything more sophisticated. For instance, Apigee Microgateway, which you can also run on Docker. Full disclosure, I work for Google Apigee, hence my familiarity with this product.
- To add transformation/mediation capabilities without increasing the complexity of my current codebase to either API management or Transformation/mediation layers. API Management is a separate responsibility, hence it should be separate container from transformation and mediation capabilities (another container).
- To leverage the same k8s cluster and pod that the REST API use. Adding transformation/mediation NodeJS app should not increase the complexity of my infrastructure (my cluster). If the REST API and transformation/mediation NodeJS API coexist in the same pod, Kubernetes will manage the pod and keep both containers healthy without adding a separate cluster for both containers. Some purists might be against this model, but I won't into that conversation at this point.
You can run these steps in Kubernetes GCP free-tier for a few bucks covered by the 300 credit. I recommend running on n1-standard-1 machines, since I noticed some pods getting into errors because of the lack of running Kubernetes on small footprint hardware such as micro VMs (06 GBs) ¯_(ツ)_/¯.
First things first, clone this repo either on your laptop or GCP CloudShell.
git clone https://github.com/dzuluaga/kubernetes-multicontainer-pod-lab.git
The folder structure:
├── kubernetes_nodejs_deployment.yaml -> deployment descript
├── nodejs-express-api -> REST API
│ ├── Dockerfile
│ ├── node_modules
│ ├── package.json
│ └── server.js
└── nodejs-express-backend -> Transformation/mediation API
├── Dockerfile
├── package.json
└── server.js
Open one terminal window to start NodeJS Express REST API server. This API will be exposed by Kubernetes LoadBalancer component through port 80.
cd nodejs-express-api
node server.js
curl http://localhost:8080/hello -H 'Skip-Backend: true'
Response:
Hello world-API
Note Skip-Backend
header will skip call to the backend.
Open another terminal window to start the server. And execute the following commands:
cd nodejs-express-backend
node server.js
curl http://localhost:8081
Response:
Hello world-backend
Execute
curl http://localhost:8080/hello
Response:
Hello world-backend
Note that response includes -backend
word in it. Therefore, nodejs-api is serving as api proxy to nodejs-express-backend.
In the next steps we will deploy a multicontainer pod with these two apps.
Create a cluster of 3 VMs n1-standard-1 for our two node.js apps.
gcloud container clusters create multi-container-pod --num-nodes=3 --machine-type=n1-standard-1 --zone=us-west1-a
This variable will be referenced from next steps. So, it's useful to keep it as variable instead of a hardcoded value.
export PROJECT_ID="$(gcloud config get-value project -q)"
cd nodejs-express-api
docker build -t gcr.io/${PROJECT_ID}/nodejs-express-api:v1 .
Push Docker build to your own private Google Container Registry in GCP:
gcloud docker -- push gcr.io/${PROJECT_ID}/nodejs-express-api:v1
cd ../nodejs-express-backend
docker build -t gcr.io/${PROJECT_ID}/nodejs-express-backend:v1 .
Push Docker build to Google Container Registry:
gcloud docker -- push gcr.io/${PROJECT_ID}/nodejs-express-backend:v1
Edit Kubernetes.yaml
and replace $GCP_PROJECT
token with your GCP project.
$ kubectl apply -f kubernetes_nodejs_deployment.yaml
This step will only expose port 8080 from nodejs-express-api container through standard http port 80, so it's accessible through your browser from a public IP address.
$ kubectl expose deployment multicontainer-nodejs-deployment --type=LoadBalancer --port=80 --target-port=8080
Get Public IP Address
$ kubectl get service
Response:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
multicontainer-nodejs-deployment LoadBalancer 10.35.249.82 35.230.95.143 80:32720/TCP 1m
From command get the public IP address and access your nodejs-express-api using a curl command. You can use your browser.
$ curl 35.230.63.8/hello
Response:
Hello world-backend
This response validates that nodejs-api can call nodejs-backend.
You can increase the number of replicas of your app by using kubectl scale
command. Increase 5 more replicas of your multicontainer pod.
$ scale deployment multicontainer-nodejs-deployment --replicas=6
deployment "multicontainer-nodejs-deployment" scaled
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
multicontainer-nodejs-deployment-66b758855c-6h27v 2/2 Running 0 18h
multicontainer-nodejs-deployment-66b758855c-9fpx6 2/2 Running 0 18h
multicontainer-nodejs-deployment-66b758855c-kb67r 2/2 Running 0 18h
multicontainer-nodejs-deployment-66b758855c-mnpsn 2/2 Running 0 8s
multicontainer-nodejs-deployment-66b758855c-nzjjp 2/2 Running 0 8s
multicontainer-nodejs-deployment-66b758855c-tsz4h 2/2 Running 0 8s
I want to know your feedback! You can reach out to me on twitter @dzuluaga.
$ kubectl exec -it kubernetes-multi-container-pod -- /bin/sh
or to ssh into a specific container:
kubectl exec -it kubernetes-multi-container-pod -c nodejs-express-backend -- /bin/sh
From here you can run requests to test connectivity:
$ curl http://localhost:8080/hello
Hello world-backend
To backend:
$ curl http://localhost:8081
Response
Hello world-backend