Blue-Green Deployment in Docker Cloud
Introduction
This post is part of my series about implementing a CI/CD pipeline. Please refer to this post for an introduction and a full table of content. In this post I want to demonstrate step by step how to create a simple Node JS application and run it as a stack in Docker Cloud. This includes creating a repository in GitHub and linking it to a repository in Docker Cloud where we will use the auto build feature to create Docker images of the application. I will also show how to scale and load balance the application for high availability and even discuss how we can exercise blue-green deployment to achieve zero down time deployments.
The Application
To not over complicate things we create a simple node JS application consisting of a package.json
file and a server.js
file. The content of the package.json
file is
And the content of the server.js
file looks like this
The test
command is not important at this point. We will come back to it later down. We can now test this application locally by running
npm start
on the command line. If we navigate to localhost in the browser we should see something along this
Note that we are listening on port 80! This is important as we move along.
The Dockerfile
If we want to Docker-ize the application we need a Dockerfile. The content looks like this
Specifically note how we expose port 80. This will be important once we use a load balancer in front of the sample application in the cloud.
We can now build this Docker Image locally
docker build -t blue-green .
and run an instance (container) of it
docker run -dt --name bg -p 80:80 blue-green
If in the browser we now navigate to 192.168.99.100 (or whatever the IP address of your Docker host is) then we should see something like this
Pushing the code to GitHub
Push the code to a new GitHub repository. In my case I called it BlueGreen
. The repo I use can be found here: https://github.com/gnschenker/BlueGreen I have added a simple .gitignore
file which makes sure node modules are not pushed to GitHub. I also added a Readme.md
for documentation purposes.
Creating a Repository in Docker Cloud
Create a new repository in Docker Cloud and link it to the above GitHub repository. Try to build the repo in Docker Cloud. It should take a minute or so and succeed.
Create a Stack in Docker Cloud
Create a new stack in Docker Cloud and name it appropriately. The content of the Stackfile
should look like this
Here we have a definition for the two services lb
and web
. The former one represents our load balancer and the latter our node JS application. The web service will be scaled to 3 instances and since we are using high availability strategy the instances will be put on different nodes of our cluster. We use self-healing in the sense as we require the service instances to restart automatically in case of failure. We also need to assign the role global
to the load balancer such as that the service is able to query the Docker Cloud API.
Running the Stack
We can now deploy and run the stack we just defined. As soon as all services are up and running we can access the endpoint of the stack. Please use the Service endpoint and not the Container endpoint.
If everything went as supposed we should then see something like this
If we refresh the browser a few times we will see that the from server: changes between web-1
, web-2
and web-3
which shows us that our node JS application is indeed load balanced.
High Availability for the Load Balancer
We can now also scale our load balancer such as that it is highly available. For that we should change our Stackfile
to look like this
Note line 3 and 4 that have been added. The former guarantees us that the instances of the load balancer are distributed to different cluster nodes while the latter tells us how many load balancer instances we want to run. After we have redeployed the whole stack we can see in the Node dashboard that indeed every node has now 2 containers on it, one for the load balancer and one for the node application.
Blue-Green Deployment
Now we want to try to realize zero-downtime or non destructive deployment. This is called blue-green deployment. It basically means that we install the new version of a service in parallel to the current existing one. Once the new version is ready we reroute all traffic to the new version and can then decommission the previous version of the service.
Installing the Docker Cloud CLI
First we need to install the Docker Cloud CLI as described here. With this CLI we can script everything in Docker Cloud. Please note that if you are on a Windows machine it is a bit more complicated than just typing pip install docker-cloud
. We first need to have Python installed on our system. We can do that using Chocolatey.
choco install python2
Now create a folder where you want to install Docker Cloud CLI. Navigate to this folder. And then I had to use the full path to pip.exe
c:\python27\scripts\pip.exe install docker-cloud
Now we need to add the path to docker-cloud to our path variable. Do this in the Advanced System Settings. Once this is done open a new (Bash) console and verify that everything is OK
Tagging Images
Now we want to start to work with tagged Docker images. For this we have to adjust our repository. If we want to have a tagged image generated then we need to either use branches or tags in GitHub. I prefer to use tags. Let’s say we have a version v1
and a version v2
we want to play with then we can just create tags in Git as follows
$ git tag -a v1 -m "Version 1"
This creates a tag v1
with a description Version 1
at the current commit. We can then push this tag to origin by using
$ git push origin v1
Now we can modify our repository in Docker Cloud. We can add image tags that refer to Git branches or tags (in our case it is tags)
The Stackfile
If we want to introduce blue-green deployment (also called non-destructive deployment) we need to modify our Stackfile
as follows
Here we have instead of one service called web
two services called web-blue
and web-green
. Only one of the two services is active at a given time (that is the load balancer is routing the traffic to it). At the beginning the load balancer is wired to web-blue
. We are starting with both services being in version v1
. We can then redeploy the whole stack and once it is up and running we can test it. We should see this
Upgrade green to v2
Use this command to upgrade web-green
to version v2
$ docker-cloud service set --image clearmeasure/blue-green:v2 --redeploy --sync web-green
The service will be automatically redeployed. Now we can scale up web-green
to also use 3 instances
$ docker-cloud service scale web-green 3
While we are doing this the application still happily uses v1
of our node js image.
Switch blue to green
Now it is time to switch from web-blue to web-green
and reroute the load balancer. We can do this using this command
$ docker-cloud service set --link web-green:web-green lb
And then we need to redeploy the load balancer service using this command
$ docker-cloud service redeploy lb
And we’ll have this outcome
Rollback
If something goes terribly wrong we can just rollback by linking the load balancer again with web-blue
and redeploying it.
Summary
In this post I have shown how Docker Cloud can be used to provide CI as well as scalability, high availability and blue-green deployment to us with a few simple operations. Everything can be automated through the docker-cloud CLI.