.NET, Docker, and Swarm OH MY! – Pt 2

This is the second post of a two part series on ASP.NET Core, Docker, and Docker Swarm. In our previous post, we created an ASP.NET Core Docker container and pushed it to Docker Hub. Along the way, we took a look at a couple third party tools, such as Yeoman. To continue our journey, we will take the container we previously created and host it in a highly available Docker Swarm cluster.

Our Docker environment will contain three nodes which will be set up as a Docker Swarm cluster. In this demo, we will be using Docker Toolbox in a Windows environment.

Creating Docker Machines

Using Docker Swarm wouldn’t benefit us much without having a couple hosts. Lets get started by creating those. The Docker Toolbox comes equipped with docker-machine for managing your local docker hosts. We can use the create command to create our new hosts.

λ docker-machine create --driver virtualbox swarm-demo-1
λ docker-machine create --driver virtualbox swarm-demo-2
λ docker-machine create --driver virtualbox swarm-demo-3

After the commands have completed, if you open VirtualBox Manager you will see our three hosts running.

Swarm Virtual Machines

You can also run the following command to see a list of all your docker machines and their status.

λ docker-machine ls

NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
swarm-demo-1 - virtualbox Running tcp://192.168.99.100:2376 v1.13.1
swarm-demo-2 - virtualbox Running tcp://192.168.99.101:2376 v1.13.1
swarm-demo-3 - virtualbox Running tcp://192.168.99.102:2376 v1.13.1

Setting up the Cluster

To create the swarm cluster, lets ssh into the machine that we want to be the master node.

λ docker-machine ssh swarm-demo-1

Now we want to run the swarm init command. The init command takes the –advertise-addr parameter to which we will want to supply our nodes public IP address. In my case, this is 192.168.99.100.

docker@swarm-demo-1:~$ docker swarm init --advertise-addr 192.168.99.100

Swarm initialized: current node (syer49bixi68zkw5tdebej4by) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join \
--token SWMTKN-1-452450rx24myaxaac49y67qijz5e3zoa84li5vvioy2sbrorhb-3cv994lxh25419huwynze0d0u \
192.168.99.100:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

Note the results from the command. We will use the docker swarm join command to join other nodes to the swarm cluster.

Creating Workers

We are going to create the swarm-demo-2 node as a backup manager. To do this, we will first ssh into this node.

λ docker-machine ssh swarm-demo-2

Then run the docker swarm join command.

docker@swarm-demo-2:~$ docker swarm join --token SWMTKN-1-452450rx24myaxaac49y67qijz5e3zoa84li5vvioy2sbrorhb-3cv994lxh25419huwynze0d0u 192.168.99.100:2377

This node joined a swarm as a worker.

These steps should also be repeated on the swarm-demo-3 virtual machine.

Review the Cluster

We now have a fully functional docker swarm cluster created. If we ssh into the swarm manager, we can use the docker node commands to manage the nodes in the cluster.

Usage: docker node COMMAND

Manage Swarm nodes

Options:
--help Print usage

Commands:
demote Demote one or more nodes from manager in the swarm
inspect Display detailed information on one or more nodes
ls List nodes in the swarm
promote Promote one or more nodes to manager in the swarm
ps List tasks running on one or more nodes, defaults to current node
rm Remove one or more nodes from the swarm
update Update a node

Run 'docker node COMMAND --help' for more information on a command.

Lets run the docker node ls command to see the status of the cluster.

docker@swarm-demo-1:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
4nz4qdk1ebkccgeyoa58xq4hf swarm-demo-2 Ready Active
6mkvtubrpxxfrp9zdos134e87 * swarm-demo-1 Ready Active Leader
n8vmt6pkq1s670h12pcv13tev swarm-demo-3 Ready Active

Deploy to the Swarm Cluster

Applications can be deployed to the swarm cluster using the docker service create command. When we create our service, we first will specify which image to use. In our case, we will be using the image that was created in the previous post – jrob5756/swarm-demo. To run multiple instances of the image, the --replicas parameter can be used.

λ docker-machine ssh swarm-demo-1
docker@swarm-demo-1:~$ docker service create --name swarm-demo --publish 5000:5000 jrob5756/swarm-demo

v6o00hfu3fptdmt26bzi04r1t

We can now see that our service was created and is running!

docker@swarm-demo-1:~$ docker service ls
ID NAME MODE REPLICAS IMAGE
v6o00hfu3fpt swarm-demo replicated 1/1 jrob5756/swarm-demo:latest

To make sure everything is working, browse to http://192.168.99.100:5000/api/values which gives us the same output as before. To see the node our service is running on, we can run the docker service ps command.

docker@swarm-demo-1:~$ docker service ps swarm-demo
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
yrv9hi5kbhw2 swarm-demo.1 jrob5756/swarm-demo:latest swarm-demo-2 Running Running 7 minutes ago

Now the fun part, lets shut down swarm-demo-2 and see what happens! We could run the docker-machine stop command but, lets simulate a hardware failure. From the VirtualBox Manager, the machine can be powered off directly. Once this is done, our api endpoint becomes unavailable. After about a minute, we can see the service gets switched over to the swarm-demo-1 machine and the site is available again. The docker node ls command now shows that swarm-demo-2 is in a down status.

docker@swarm-demo-1:~$ docker service ps swarm-demo
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
u8pihel1kb6o swarm-demo.1 jrob5756/swarm-demo:latest swarm-demo-1 Running Running 8 seconds ago
yrv9hi5kbhw2 \_ swarm-demo.1 jrob5756/swarm-demo:latest swarm-demo-2 Shutdown Running 18 minutes ago

docker@swarm-demo-1:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
4nz4qdk1ebkccgeyoa58xq4hf swarm-demo-2 Down Active
6mkvtubrpxxfrp9zdos134e87 * swarm-demo-1 Ready Active Leader
n8vmt6pkq1s670h12pcv13tev swarm-demo-3 Ready Active

Shortly after starting swarm-demo-2 back up, the machine is automatically returned to the cluster and we are back to normal. That said, we did have a bit of down time. What if we want to avoid any downtime all together? In this case, we can increase the number of replicas that are running of the service. This is done with the docker service update command.

docker@swarm-demo-1:~$ docker service update swarm-demo --replicas 2
swarm-demo

docker@swarm-demo-1:~$ docker service ls
ID NAME MODE REPLICAS IMAGE
v6o00hfu3fpt swarm-demo replicated 2/2 jrob5756/swarm-demo:latest

The service is now running on both swarm-demo-1 and swarm-demo-2. Lets again stop swarm-demo-2 by powering off the Virtual Machine. This time… NO WAITING!!! I suppose this isn’t a surprise but, it does highlight the importance of scaling critical services across nodes. Furthermore, we see first hand that not only does Docker Swarm provide High-Availability and Failover but, it also provides the ability to easily scale out our services.

To summarize, one of the most powerful aspects of ASP.NET Core is its interoperability. This allows us to run on Linux and take advantage of containerization platforms like Docker. Docker comes equipped with Docker Swarm which provides native clustering capabilities.

Happy Coding!!!