Create a Nodejs Application that responds GET requests with its Hostname.

We will be using Docker Swarm to create a Stack of our Nodejs application, which will sit beind a HAProxy Load Balancer, we are mounting the docker.sock from the host to the container on a node that has a manager role, so as we scale our web application, our load balancer is aware of the changes, and scales as we scale our web application.

Stack Overview:

  • HAProxy Service (1 Replica)
  • Nodejs Application (10 Replica's)

Creating the Application:

Our nodejs application: app.js

var http = require('http');
var os = require('os');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.end(`My Hostname: ${os.hostname()}\n`);
}).listen(8080);

Our Dockerfile:

FROM node:alpine
ADD app.js /app.js
CMD ["node", "/app.js"]

Build and Push to your registry, or you could use my image on Dockerhub: hub.docker.com/r/rbekker87/node-containername

$ docker login
$ docker build -t <username>/<repo>:<tag> .
$ docker push  <username>/<repo>:<tag>

Creating the Compose file:

Create the compose file that will define our services:

version: '3'

services:
  node-app:
    image: rbekker87/node-containername
    networks:
      - nodenet
    environment:
      - SERVICE_PORTS=8080
    deploy:
      replicas: 10
      update_config:
        parallelism: 5
        delay: 10s
      restart_policy:
        condition: on-failure
        max_attempts: 3
        window: 120s

  loadbalancer:
    image: dockercloud/haproxy:latest
    depends_on:
      - node-app
    environment:
      - BALANCE=leastconn
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    ports:
      - 80:80
    networks:
      - nodenet
    deploy:
      placement:
        constraints: [node.role == manager]

networks:
  nodenet:
    driver: overlay

Create the Stack:

Deploy the Stack by specifying the compose file and name of our stack:

$ docker stack deploy -c docker-compose.yml node

Creating network node_nodenet
Creating service node_node-app
Creating service node_loadbalancer

List the Services in the Stack:

$ docker stack ls
NAME                SERVICES
node                2

List the Tasks in the Stack:

$ docker stack ps node
ID                  NAME                  IMAGE                                 NODE     DESIRED STATE       CURRENT STATE            ERROR               PORTS
l5ryfaedzzaq        node_loadbalancer.1   dockercloud/haproxy:latest            dsm-01   Running             Running 40 minutes ago
c8nrrcvek79h        node_node-app.5       rbekker87/node-containername:latest   dsm-01   Running             Running 40 minutes ago
dqii18b2q5nn        node_node-app.10      rbekker87/node-containername:latest   dsm-01   Running             Running 40 minutes ago
vkpw2rugy0ah        node_node-app.11      rbekker87/node-containername:latest   dsm-01   Running             Running 40 minutes ago
mm88nvnvy5lg        node_node-app.12      rbekker87/node-containername:latest   dsm-01   Running             Running 40 minutes ago
oyx8rfqc1xl2        node_node-app.16      rbekker87/node-containername:latest   dsm-01   Running             Running 41 minutes ago

Test out our Application:

Test out the Service:

$ curl -XGET 127.0.0.1/
My Hostname: a6e34246e73b

$ curl -XGET 127.0.0.1/
My Hostname: 5de71278be38

$ curl -XGET 127.0.0.1/
My Hostname: e0b7316fdd51

Scaling:

Scale our Application out to 30 replica's

$ docker service scale node-app=30

Scale our Application down to 5 replica's

$ docker service scale node-app=5

Cleanup:

Remove the Stack:

$ docker stack rm node
Removing service node_loadbalancer
Removing service node_node-app
Removing network node_nodenet

Resources: