I recently started playing with Kubernetes and deployed a simple Express app as practice. You can follow along after you have installed minikube for your OS.

You can then follow along this tutorial after cloning the my github repo.

Node applications

We are going to build two Express apps: the main app responds with Hello World and the health app responds to /health and /readiness requests.

node-app:

GET /
=> Hello World

health-app

GET /health
=> 200

GET /readiness
=> 200

The official NodeJS site has a great little article about building a node docker image so I will not go over that again here.

Let's just take a look at the two server.js files for our main and health apps.

// ~/learn/kubernetes/app/health/server.js

'use strict';

const express = require('express');

// Constants
const PORT = 8081;

// App
const app = express();
app.get('/health', function (req, res) {
  res.sendStatus(200);
});

app.get('/readiness', function (req, res) {
  res.sendStatus(200);
});

app.listen(PORT);
console.log('Running on http://localhost:' + PORT);
// ~/learn/kubernetes/app/main/server.js

'use strict';

const express = require('express');

// Constants
const PORT = 8080;

// App
const app = express();
app.get('/', function (req, res) {
  res.send('Hello world\n');
});

app.listen(PORT);
console.log('Running on http://localhost:' + PORT);

Docker images

Let's build, tag and push the docker images for both applications:

~ app/main$ docker build -t tzumby/node-web-app .
~ app/health$ docker build -t tzumby/node-health .
~ app/health$ docker images
REPOSITORY                                            TAG                 IMAGE ID            CREATED             SIZE
tzumby/node-web-app                                   1.0.0               ba16f4d69b5c        2 hours ago         649.3 MB
tzumby/node-health                                    latest              9f6d6f6b8f78        About an hour ago   649.3 MB

You will need to create an account on hub.docker.com and push your images there:

~$ docker login
~$ docker push tzumby/node-web-app:latest
~$ docker push tzumby/node-health:latest

Kubernetes pods

A pod is a group of one or more Docker containers that run in a shared context. That means they share the same IP address and port space, same volumes attached to the pod etc.

Our pod will start two containers for each of the Docker images we built in the previous step.

apiVersion: v1
kind: Pod
metadata:
  name: node-app
  labels:
    app: node-app
spec:
  containers:
    - name: node-app
      image: tzumby/node-web-app:1.0.0
      ports:
        - name: http
          containerPort: 8080
      resources:
        limits:
          cpu: 0.2
          memory: "10Mi"
    - name: node-health
      image: tzumby/node-health:latest
      ports:
        - name: health
          containerPort: 8081
      livenessProbe:
        httpGet:
          path: /health
          port: 8081
          scheme: HTTP
        initialDelaySeconds: 5
        periodSeconds: 15
        timeoutSeconds: 5
      readinessProbe:
        httpGet:
          path: /readiness
          port: 8081
          scheme: HTTP
        initialDelaySeconds: 5
        timeoutSeconds: 1

Notice how we're exposing different ports for each app, namely 8080 and 8081.

Let's create the pod now using the kubectl tool:

~ kubernetes$ kubectl create -f pods/node-app.yaml
~ kubernetes$ kubectl get pods
NAME       READY     STATUS    RESTARTS   AGE
node-app   2/2       Running   0          1h

It may take a few second for the pod to run both containers because docker will have to download the two images from the Docker hub.

Let's setup an ad-hoc port forwarding from our host machine to the kubernetes cluster in order to test the main app.

~ kubernetes$ kubectl port-forward node-app 10080:8080

Open another terminal and let's curl the root url:

~ kubernetes$ curl http://127.0.0.1:10080
Hello world

Next

I'm very excited about using Kubernetes for a real-world setup and over the next few posts I will more concepts such as Services, Deployments and Volumes in a future post.