Solving the routing mess for services using Docker

Luis Herrera Benítez
DevOpsion
Published in
17 min readAug 9, 2016

--

“It’s not the load that breaks you down; it’s the way you carry it.” — Lou Holtz

Co-authored with Emmet O’Grady ( Founder of NimbleCI and Docker Ninja).

In Franz Kafka’s book “The Metamorphosis”, a man wakes up one morning to find he’s been transformed into a giant insect-like creature. As DevOps engineers, we have our surreal moments too. We find exotic bugs under the rug or get attacked by worms and other nasty creatures. If you have been doing this long enough, you’ll have your horror story or two (share it with us!). In those moments we can’t sit back and wait for the crisis to pass, we need to act fast. Against the clock, we have to deploy new instances or roll out new versions of our services fixing the issue.

How about this for another surreal moment: your application gets featured in the media, a crowded slack channel or your internal message board. The users come fast and furious to your site, your service gets pushed to its limits and beyond. In a frenzied race against 502 errors, you need to find the servers, launch new instances, and re-configure your network and your load balancers. You’re frantically trying to put all the pieces together. You feel like sometimes you are taking a spoon to a knife fight. Wishfully you think “this should be portable and automated.” Maybe then I’d have more time to relax and read the classics!

Feel it no more. Here’s Docker 1.12 to help you. This release ships with a set of new features ensures a level playing field:

  • Roll out and roll back services quickly
  • Automate load balancing
  • Enable the scaling-out of services and the infrastructure in which they run
  • Tackle service or node failures automatically

And as you have learned to expect from Docker, they are easy to use.

Routing Mesh

Docker 1.12 introduces a whole set of new terms. One of them is a new feature called “routing mesh.” Mesh networks and their routing algorithms are not a new thing, the genius of Docker engineering team has been to use this approach to simplify software changes delivery and service discovery in Micro-services architectures. The “mesh” is simply the new way of routing and balancing the traffic to the containers in Docker 1.12. The new routing strategy allows a service to be reached by the same port on all nodes in the swarm, even if the node does not have the service deployed on it. The routing mesh also transparently balances requests across all available services in the swarm, detecting node failures.

Does your network looks like this today?

This new approach makes it very easy to set-up load balancing of services: imagine a three node swarm with seven different services spread out over the swarm. From the outside, we can send the request to any one of the nodes, and it will be routed to a random service automatically. Or we can always send the request to one single node and Docker will internally load balance between the services. So we get load balancing of services natively.

Routing mesh allows us to treat the containers truly transparently, in the sense that we don’t care how many containers are serving our app, the cluster handles all networking and load balancing for us. Where before we had to put a reverse proxy in front of the services to act as a load balancer, now we can relax and let docker do the load balancing for us. Because Docker handles all the dirty work for us, the difference between having one container and having 100 containers is now trivially small; it’s merely a matter of having enough computing resources to be able to scale and then running one command to scale up. No more do we have to think about architectural considerations before scaling since Docker handles it all. When it comes to scaling we can relax knowing that Docker will handle it transparently, one container is the same as 100.

You might be wondering why we’ve been using the terminology “services” instead of “containers.” That’s something else new in Docker 1.12, let’s take a look.

Services and tasks

Docker 1.12 has introduced a new abstraction, “services”. Services define the desired state of the containers in a cluster. Internally the engine uses this new concept to ensure that the containers are running, handle failures, and route traffic to the containers.

Let’s dive in a bit deeper and discuss the new concept of tasks. Services are composed of tasks which represent one instance of a container that should be running. The swarm schedules these tasks across nodes. Services mostly define the amount of running container instances (tasks) which should be up at any time as well as how they should be run (the configuration and flags for each container) and also how to update them (e.g. rolling updates). All that together represents the desired state of the service, and the Docker engine continuously monitors the current condition of the cluster and makes changes to ensure it matches the state you want.

Here’s a sneak preview of a redis service that we will start later in this article. To start it we might use a command like this:

$ docker service create --name redisdb --replicas=3 redis:alpine

Routing mesh in action

Enough of the theory, let’s see all this in action. We’ll start with small nodejs service that will help show the inner workings of the routing mesh. You’ll find the code on Github here. Let’s have a look at the most important file: webapp.js

// A sample webserver that responds with version, hostname, IPs used and number of visitsvar http = require(‘http’);
var os = require(“os”);
var redis = require(‘redis’);
var server = http.createServer(function (request, response) {// We start building building an “OK” response
response.writeHead(200, {“Content-Type”: “text/plain”});
// and also log the variables we are going to use in our response
var version = “2.0”;
var log = {};
log.header = ‘webapp’;
log.name = os.hostname();
log.version = version;
// We iterate over network interfaces to obtain IPv4 addresses
var interfaces = os.networkInterfaces();
var addresses = [];
for (var k in interfaces) {
for (var k2 in interfaces[k]) {
var address = interfaces[k][k2];
if (address.family === ‘IPv4’ && !address.internal) {
addresses.push(address.address);
}
}
}
log.nics = addresses;
// We try to reach our redis server (redisdb) by NAME
var client = redis.createClient(‘6379’, ‘redisdb’);
client.on(‘connect’, function(err,reply) {
if (err) return next(err);
console.log(‘Connected to Redis server’);
client.incr(‘counter’, function(err, reply) {
if(err) return next(err);
console.log(‘This page has been viewed ‘ + reply + ‘ times!’);
console.log(JSON.stringify(log));
response.end(“ Hello, I’m version “+ log.version +”.My hostname is “+ log.name +”, this page has been viewed “+ reply +”\n and my ip addresses are “ + log.nics + “\n” );
}); // client.incr
}); // client.on
}); // http.createHttpServer// Let's wait for http request on port 8000
server.listen(8000);

The service just returns the hostname , the IPs addresses of the container running it, and a counter with the number of visits.

So that’s our application. Before we jump in let’s make sure we’ve upgraded to Docker 1.12.0!

$ docker version
Client:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 21:04:48 2016
OS/Arch: darwin/amd64
Experimental: true
Server:
Version: 1.12.0
API version: 1.24
Go version: go1.6.3
Git commit: 8eab29e
Built: Thu Jul 28 21:04:48 2016
OS/Arch: linux/amd64
Experimental: true

We start by creating a cluster of three nodes using docker-machine:

$ docker-machine create --driver virtualbox swarm-1
Running pre-create checks…
Creating machine…

Setting Docker configuration on the remote daemon…
Checking connection to Docker…
Docker is up and running!
$ docker-machine create --driver virtualbox swarm-2

Docker is up and running!
$ docker-machine create --driver virtualbox swarm-3

Docker is up and running!
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
swarm-1 — virtualbox Running tcp://192.168.99.106:2376 v1.12.0
swarm-2 — virtualbox Running tcp://192.168.99.107:2376 v1.12.0
swarm-3 — virtualbox Running tcp://192.168.99.108:2376 v1.12.0

We’ve shortened the output of some commands for clarity. Next, we’ll set up the swarm. Docker 1.12 has made this very easy to do:

$ eval $(docker-machine env swarm-1)
$ docker swarm init --advertise-addr $(docker-machine ip swarm-1)
Swarm initialized: current node (bihyblm2kawbzd3keonc3bz0l) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \
--token SWMTKN-1–1n7gtfmvvrlwo91pv4r59vsdf73bwuwodj3saq0162vcsny89l-5zige8u81ug5adk3o4bsx32fi \
192.168.99.106:2377

Now, we copy & paste the command that the previous command outputted for the “worker” node in the other two nodes:

$ eval $(docker-machine env swarm-2)
$ docker swarm join \
--token SWMTKN-1–1n7gtfmvvrlwo91pv4r59vsdf73bwuwodj3saq0162vcsny89l-5zige8u81ug5adk3o4bsx32fi \
192.168.99.106:2377

This node joined a swarm as a worker.
$ eval $(docker-machine env swarm-3)
$ docker swarm join \
--token SWMTKN-1–1n7gtfmvvrlwo91pv4r59vsdf73bwuwodj3saq0162vcsny89l-5zige8u81ug5adk3o4bsx32fi \
192.168.99.106:2377


This node joined a swarm as a worker.

Note: When you initialize a new swarm the command will output two commands that you can use to join other nodes to the swarm. Don’t worry about losing these commands, though; you can get them again by running “docker swarm join-token worker|manager” at any time.

Before continuing, let’s make sure our swarm cluster is operational. We’ll point our Docker client to the manager node and check its status:

$ eval $(docker-machine env swarm-1)
$ docker node ls

ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
5jqsuf8hsemi7bfbwzfdxfcg5 swarm-2 Ready Active
93f0ghkpsh5ru7newtqm82330 swarm-3 Ready Active
b2womami9n2t8tti1acvz6v5j * swarm-1 Ready Active Leader
$ docker info

Swarm: active
NodeID: b2womami9n2t8tti1acvz6v5j
Is Manager: true
ClusterID: bimg9n2ti2tnsprkdjqg07tdm
Managers: 1
Nodes: 3
Orchestration:
Task History Retention Limit: 5
Raft:
Snapshot interval: 10000
Heartbeat tick: 1
Election tick: 3
Dispatcher:
Heartbeat period: 5 seconds
CA configuration:
Expiry duration: 3 months
Node Address: 192.168.99.106

We’re going to create a new network which we’ll use for all our examples:

$ docker network create --driver overlay webnet
a9j4al25hzhk2m7rdfv5bqt54

So we are now ready to launch a new service to the Swarm. We’re going to start a Redis database and a container “lherrera/webapp” which saves page visits in Redis and outputs other interesting details like the hostname and the IP address of the container.

When we deploy our webapp, it will be able to connect to the Redis database using the name of the Redis service, “redisdb”. We don’t need to use IP addresses because the swarm mode has an internal DNS that assigns automatically each service a DNS entry. Easy!

We can only deploy services from manager nodes. Since our Docker client is already pointing towards the manager node we can just type in the command “docker service create”:

$ docker service create --name webapp --replicas=3 --network webnet --publish 80:8000 lherrera/webapp:1.0
avq41soybmtw2jamdus0m3pg
$ docker service create --name redisdb --network webnet --replicas 1 redis:alpine
bmotumdr8bcewcfj6zqkws97x
$ docker service ls
ID NAME REPLICAS IMAGE COMMAND
avq41soybmtw webapp 3/3 lherrera/webapp:1.0
bmotumdr8bce redisdb 1/1 redis:alpine

In the service create command we need to specify at least an image (in our case, lherrera/webapp). For convenience, we are also providing a name (webapp). We could have also specified the command to run inside the containers just after the image. In the previous command, we also specified we want three replicas of the container running at any given time. Using the flag “ — replicas” implies we don’t care on which node they are put on, if we want one service per node we can use “ — mode=global” instead.

You can see that we’re using the “webnet” network that we created earlier. To make our service accessible from outside the Swarm, we need to publish the port where the Swarm listens for web requests. In our example, we “publish” port 8000 inside the service to port 80 on all the nodes. Because of the routing mesh, this will reserve port 80 on all nodes and Docker Engine will load balance the traffic on that port between port 8000 in all the replica containers.

The Swarm will take this service description as the desired state for our application and start deploying the application to nodes to achieve and maintain this desired state. We could specify more service parameters to complete our description, like restart policies, memory and CPU limits, node constraints, etc. For a full list of the available flags, you can use with “docker service create”, see here.

At this point, we make sure that our webapp is connected correctly to the new webnet network:

$ docker network ls
NETWORK ID NAME DRIVER SCOPE
df19a5c87d90 bridge bridge local
7c5762c8c6ff docker_gwbridge bridge local
eb0bd5a4920b host host local
bqqh4te5f5tf ingress overlay swarm
3e06a1616b7b none null local
a9j4al25hzhk webnet overlay swarm
$ docker service inspect webapp

“VirtualIPs”: [
{
“NetworkID”: “7i9t9uhtr7x0hybsvnsheh92u”,
“Addr”: “10.255.0.6/16”
},
{
“NetworkID”: “a9j4al25hzhk2m7rdfv5bqt54”,
“Addr”: “10.0.0.4/24”

}
]
},

Now let’s continue with our example and make sure our service it’s up and running:

$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
bb8n4iagxcjv4rn2oc3dj6cvy webapp.1 lherrera/webapp:1.0 swarm-1 Running Preparing about a minute ago
chndeorlvglj45alr4vhy50vg webapp.2 lherrera/webapp:1.0 swarm-3 Running Preparing about a minute ago
4txay0gj6p18iuiknacdoa91x webapp.3 lherrera/webapp:1.0 swarm-2 Running Preparing about a minute ago

One thing to be aware of is that although the docker service creates command returns quickly with an id, the actual scaling of the service may take some time, especially if the image has to be pulled on the nodes. If so, just run “docker service ps webapp” a few times until all replicas are providing service.

When the services are running (this make take a few minutes, grab a coffee in the meantime), we can check to see what our services respond to requests. First, we need to get the IP of the first node:

$ NODE1=$(docker-machine ip swarm-1)

Then we’ll hit port 80 on that IP address since we published the service on port 80 on the swarm. We’re using curl in the examples below, but you can also put the IP into your browser to see the same thing.

Now, we are ready to test our new service:

$ curl $NODE1
Hello, I’m version 1.0.My hostname is 5a557d3ed474, this page has been viewed 1
and my ip addresses are 10.255.0.9,10.255.0.6,172.18.0.3,10.0.0.7,10.0.0.4
$ curl $NODE1
Hello, I’m version 1.0.My hostname is 4e128c8af4ae, this page has been viewed 2
and my ip addresses are 10.255.0.7,10.255.0.6,172.18.0.3,10.0.0.5,10.0.0.4
$ curl $NODE1
Hello, I’m version 1.0.My hostname is eaa73f01996c, this page has been viewed 3
and my ip addresses are 10.255.0.8,10.255.0.6,172.18.0.4,10.0.0.6,10.0.0.4

We can see that the first request has gone to the container “5a557d3ed474.” If you hit refresh enough times, or you call “curl” repeatedly from the command line, you will see the request being sent to all of the three replica containers that we created.

To demonstrate the other aspect of the routing mesh, try hitting port 80 of the IPs of the other two docker machine nodes. You’ll see the same as before, which means that it doesn’t matter which node you ask; the request is always load balanced internally among the three containers.

Rolling updates

As part of the service description, you can specify the upgrade strategy for your service. For example, you can use the ` — update-delay` flag to configure the delay between updates to a service task (container) or sets of tasks. Or you can use the ` — update-parallelism` flag to change the default behavior of updating one container at a time. You can set all these flags during the service creation or later use the “docker service update” command as we are going to see in the following example. The update command takes nearly identical parameters as “docker service create” but some flags have different names in the update command. Anything you can set in the create command you can change in the update command, though, so you have complete freedom to update any part of the service description at any time.

Applying a rolling update manually: running downhill, realising you’re out of control

Let’s update our webapp service to see how the “rolling update” mechanism works. The team has been working hard to improve the webapp, and we have released a new tag called “2.0.” We’re going to update our service to this new image now.

$ docker service update --update-parallelism 1 --update-delay 5s --image lherrera/webapp:2.0 webapp

Notice how we’ve also indicated that we want the update to take place one at a time and with five seconds between each update. This rolling approach means that we will have no downtime!

While the update is happening, see it in real time by running “docker service ps webapp” every few seconds. You will see the old images being shut down one by one and being replaced by the new one:

$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 43 seconds ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 Shutdown Shutdown 44 seconds ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-2 Running Running 30 seconds ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3 Shutdown Shutdown 30 seconds ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 57 seconds ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-2 Shutdown Shutdown 57 seconds ago

Yes, this is simply awesome!

Since our application also prints the version of the image, another way to see the update in real time is to hit the services endpoint repeatedly during the upgrade. When the service is being updated, you will slowly see more and more requests returning “version 2.0” until the update completes and all the services return version 2.0.

$ curl $NODE1
Hello, I’m version 1.0.My hostname is 5a557d3ed474, this page has been viewed 4
and my ip addresses are 10.255.0.9,10.255.0.6,172.18.0.3,10.0.0.7,10.0.0.4
$ curl $NODE1
Hello, I’m version 2.0.My hostname is e0899324d9df, this page has been viewed 5
and my ip addresses are 10.255.0.10,10.255.0.6,172.18.0.4,10.0.0.8,10.0.0.4
$ curl $NODE1
...

You’ll notice that the Redis count continues unaffected since we haven’t changed the Redis service, only the webapp images.

Tackling the growing pains

A swarm of honey bees is a familiar sight in early summer. Honey bees instinctively handle the colony’s survival by swarming when it’s getting crowded. And so we do in our container clusters.

Let’s swarm…

So let’s say that our node is reaching capacity and we need to add another node to our cluster. It’s so easy you can do it with only four commands! For the sake of clarity though we are going to use a few more to ensure it clears what’s going on.

Let’s add a new node to our swarm cluster:


$ docker-machine create -d virtualbox swarm-4

Docker is up and running!
Join the node the swarm as a worker as before:$ eval $(docker-machine env swarm-4)
$ docker swarm join \
--token SWMTKN-1–1n7gtfmvvrlwo91pv4r59vsdf73bwuwodj3saq0162vcsny89l-5zige8u81ug5adk3o4bsx32fi \
192.168.99.106:2377

This node joined a swarm as a worker.

Now we check that both the new node and the webapp service is up and running:

$ eval $(docker-machine env swarm-1)$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
93f0ghkpsh5ru7newtqm82330 swarm-3 Ready Active
e9rxhj0w1ga3gz89g927qvntd swarm-4 Ready Active
5jqsuf8hsemi7bfbwzfdxfcg5 swarm-2 Ready Active
b2womami9n2t8tti1acvz6v5j * swarm-1 Ready Active Leader
$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 5 minutes ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 Shutdown Shutdown 5 minutes ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-2 Running Running 5 minutes ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3 Shutdown Shutdown 5 minutes ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 6 minutes ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-2 Shutdown Shutdown 6 minutes ago
luis@aurelio [13:14:27] [~/webapp] [2.0]

Now let’s ramp up our webapp service to four replicas:

$ docker service update --replicas=4 webapp

We might need to wait a few minutes for the image to be download on the new node.

$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 10 minutes ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 Shutdown Shutdown 10 minutes ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-2 Running Running 10 minutes ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3 Shutdown Shutdown 10 minutes ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 10 minutes ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-2 Shutdown Shutdown 10 minutes ago
81xbk0j61tqg76wcdi35k1bxv webapp.4 lherrera/webapp:2.0 swarm-4 Running Running 20 seconds ago

Simple, eh?. Bees in a swarm are always in a good mood!

For global services (as opposite to replicated ones, like the one we’ve seen in the example), the swarm runs a new task automatically for the service on the newly available node.

Routing Resilience

As if all this wasn’t good enough, the cluster will manage the state of these services (e.g. replicas running) and in the case of failure, reconcile the service to the desired state. In this scenario, new containers and IP addresses are popping in and disappearing. Thankfully, the new embedded service discovery mechanism will help us our services adapt to these situations and container failures, or even complete node failures will now pass unnoticed.

Network routing in traditional HA enviroments

To see this in action, we’re going to continue with our example and simulate a node of our small cluster failing.

Let’s make sure that our webapp is still running on our cluster:

$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 10 minutes ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 Shutdown Shutdown 10 minutes ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-2 Running Running 10 minutes ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3 Shutdown Shutdown 10 minutes ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 10 minutes ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-2 Shutdown Shutdown 10 minutes ago
81xbk0j61tqg76wcdi35k1bxv webapp.4 lherrera/webapp:2.0 swarm-4 Running Running 20 seconds ago

And the nodes:

$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
21z5m0vik76msi90icrf8prvf swarm-3 Ready Active
7zyckxuwsruehcfosgymwiucm swarm-4 Ready Active
9aso727d8c4vc59cxu0e8g778 swarm-2 Ready Active
bihyblm2kawbzd3keonc3bz0l * swarm-1 Ready Active Leader

Here comes the fun bit, who doesn’t like taking down live nodes to see what happens :D

$ docker-machine stop swarm-2

Let’s see how our service reacted:

$ docker service ps webapp
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
7bdpfbbjok78zt32xd9e2mqlt webapp.1 lherrera/webapp:2.0 swarm-3 Running Running 11 minutes ago
bb8n4iagxcjv4rn2oc3dj6cvy \_ webapp.1 lherrera/webapp:1.0 swarm-1 Shutdown Shutdown 11 minutes ago
af2rlu0laqhrj3uz8brym0f8r webapp.2 lherrera/webapp:2.0 swarm-4 Running Running 11 minutes ago
chndeorlvglj45alr4vhy50vg \_ webapp.2 lherrera/webapp:1.0 swarm-3 Shutdown Shutdown 11 minutes ago
0xjt6gib1hql10iqj6866q4pe webapp.3 lherrera/webapp:2.0 swarm-1 Running Running 11 minutes ago
4txay0gj6p18iuiknacdoa91x \_ webapp.3 lherrera/webapp:1.0 swarm-4 Shutdown Shutdown 11 minutes ago
15pxa5ccp9fqfbhdh76q78aza webapp.4 lherrera/webapp:2.0 swarm-3 Running Running 4 seconds ago
81xbk0j61tqg76wcdi35k1bxv \_ webapp.4 lherrera/webapp:2.0 swarm-2 Shutdown Running about a minute ago

Great! Docker has spun up a new container on node swarm-3 after we killed node swarm-2. As you can see, we still have three replicas running ( 2 in node “swarm-3”) ….

$ curl $NODE1
Hello, I’m version 2.0.My hostname is 0d49c828b675, this page has been viewed 7
and my ip addresses are 10.0.0.7,10.0.0.4,172.18.0.4,10.255.0.10,10.255.0.6
$ curl $NODE1
Hello, I’m version 2.0.My hostname is d60e1881ac86, this page has been viewed 8
and my ip addresses are 10.0.0.7,10.0.0.4,172.18.0.4,10.255.0.10,10.255.0.6

And traffic is automatically routed to the newly created container!.

Swarming up

Software changes fast. Software breaks. Failures happen, and they inevitably happen when least desired. The new “services” abstraction introduced in Docker 1.12 simplifies updates and prevent service downtime on failures. Not only that, this new approach make scheduling and maintaining long-running services like web servers much simpler. You can now deploy replicated, distributed, load balanced services on a swarm of Docker Engines with a few commands. The cluster will manage the state of your services and even reconcile the service to the desired state in case a node or container fails.

Solomon Hykes describes nicely how he hopes to make developers lives easier: “With advancements in our orchestration tooling, networking, and security, Docker is enabling developers to build more complex applications that can be delivered at scale from the desktop to the cloud, regardless of the underlying infrastructure.”

With the release of Docker 1.12, we think he’s certainly delivering on his promise. Docker is making things much easier, hopefully to the point where those surreal moments that we mentioned at the beginning will disappear! Do you have any DevOps surreal moments? Share them with us!

More info and links on Docker 1.12

Not enough for you? Follow us on Twitter (@lherrerabenitez and @EmmetOGrady ) for similar content! Interested in CI for Docker, check out NimbleCI.

--

--

Luis Herrera Benítez
DevOpsion

AI & Big Data aficionado. Redis enthusiast. Xoogler. Fomer Docker Captain and AWS Ambassador. Everybody has a plan until they get punched in the face.