Use Docker Services to Scale Your App – How to Tutorial πŸ‹

1. Overview

In a previous introductory tutorial about docker-compose we have seen how to create a service that is described with a simple docker-compose.yml file.

Now, we want to leverage the inherent scaling capabilities of docker. In order to demonstrate this we use the example of a server setup (as seen previously).

We already have an image to create the server-service from the respective docker image. This time however, we want to scale the server side 5 times and enable load balancing on our network for port 80.

2. Scaling our services

At the beginning our docker-compose.yml looks like this:

version: "2"
services:
 server:
  image: pushcommit/myveryfirstimageserver
  ports:
   - "80:80"

There is only minimal information, just the two image to be pulled and the port to be exposed.

We get the following output when we start it up:

root@uservirt-VirtualBox:/home/uservirt/Docker-ServerScalin# docker-compose up
Creating network “dockerserverscalin_default” with the default driver
Creating dockerserverscalin_server_1 …
Creating dockerserverscalin_server_1 … done
Attaching to dockerserverscalin_server_1
server_1 | Server listening on 80
server_1 | /

We extend our docker-compose.yml file to get a scaled version of our service

version: "3"
services:
 server:
  image: pushcommit/myveryfirstimageserver
  deploy:
   replicas: 5
   resources:
    limits:
     cpus: "0.1"
     memory: 50M
  ports:
   - "80:80"

There is a deploy directive that states we want to have 5 replicas of our server container that are resource-constrained. Each container is limited to 10% of of our CPU and 50M of RAM.

We also changed the docker-compose file version to 3. In order to get the application up and running we will use docker stack deploy, since our compose file contains deployment information.

5. Running the distributed application

Before we can run our compose file we first need to init a swarm and then run the prospective docker-compose file. We will also give it a name (myfirstscaledserver).

docker swarm init
docker stack deploy -c docker-compose.yml myfirstscaledserver

Let’s see what happens:

root@uservirt-VirtualBox:/home/uservirt/Docker-ServerScalin# docker swarm init
Swarm initialized: current node (gmgvcmg020fh14hjns5is8rem) is now a manager.

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

docker swarm join –token SWMTKN-1-613ve48qo4yjj9zwexui70nkjbar6zs27vugrqqulgkde5by0u-41ht5gash9psu3djfxi0lj0ij 10.0.2.15:2377

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

Ok, that means our swarm is ready for use. Let us deploy our app now.
root@uservirt-VirtualBox:/home/uservirt/Docker-ServerScalin# docker stack deploy -c docker-compose.yml myfirstscaledserver
Creating network myfirstscaledserver_default
Creating service myfirstscaledserver_server
Looks good. We should see the running containers now:
root@uservirt-VirtualBox:/home/uservirt/Docker-ServerScalin# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
60b0f9f115a9 pushcommit/myveryfirstimageserver:latest “/bin/sh -c ‘node /d…” 22 seconds ago Up 15 seconds myfirstscaledserver_server.1.q0decbx6j0bbd7xx2mvdrhub6
24f73a0cb970 pushcommit/myveryfirstimageserver:latest “/bin/sh -c ‘node /d…” 23 seconds ago Up 14 seconds myfirstscaledserver_server.4.i8jbo87dhuykzp9pgu0ltzb5l
db550fdcc744 pushcommit/myveryfirstimageserver:latest “/bin/sh -c ‘node /d…” 23 seconds ago Up 17 seconds myfirstscaledserver_server.2.tzfsszqqqatuht2sd6lsoc1iz
c713f304f472 pushcommit/myveryfirstimageserver:latest “/bin/sh -c ‘node /d…” 23 seconds ago Up 16 seconds myfirstscaledserver_server.5.xq9o4kijfdqh746acbiyy5xi6
00efb649c95d pushcommit/myveryfirstimageserver:latest “/bin/sh -c ‘node /d…” 23 seconds ago Up 19 seconds myfirstscaledserver_server.3.ngpfjkfwf92p9swqsuv9dt1ed
There are five identical containers up and running. Note that our containers have to ports exposed but our service does:
root@uservirt-VirtualBox:/home/uservirt/Docker-ServerScalin# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
11q44causujw myfirstscaledserver_server replicated 5/5 pushcommit/myveryfirstimageserver:latest *:80->80/tcp

Listing the networks confirms we have a new swarm network that connects those five containers.

root@uservirt-VirtualBox:/home/uservirt/Docker-ServerScalin# docker network ls
NETWORK ID NAME DRIVER SCOPE
1ef179ee0a83 bridge bridge local
66c7947eb897 docker_gwbridge bridge local
36feb5d5276a dockerserverscalin_default bridge local
31548492caef host host local
rord59nsj340 ingress overlay swarm
lcajn2z2ipcz myfirstscaledserver_default overlay swarm
65c2a0d00e8f myveryfirstnetwork bridge local
1bd8390819fb none null local
root@uservirt-VirtualBox:/home/uservirt/Docker-ServerScalin# docker network inspect myfirstscaledserver_default
[
{
“Name”: “myfirstscaledserver_default”,
“Id”: “lcajn2z2ipczx1kqj06szw2zm”,
“Created”: “2018-05-21T11:37:03.196552813+02:00”,
“Scope”: “swarm”,
“Driver”: “overlay”,
“EnableIPv6”: false,
“IPAM”: {
“Driver”: “default”,
“Options”: null,
“Config”: [
{
“Subnet”: “10.0.0.0/24”,
“Gateway”: “10.0.0.1”
}
] },
“Internal”: false,
“Attachable”: false,
“Ingress”: false,
“ConfigFrom”: {
“Network”: “”
},
“ConfigOnly”: false,
“Containers”: {
“00efb649c95daea0d2974d65bf5bbf34f7df6209e48dc83b94feba9abfb5dec8”: {
“Name”: “myfirstscaledserver_server.3.ngpfjkfwf92p9swqsuv9dt1ed”,
“EndpointID”: “5cf451716262152803275ec5600565e6b1aa2c5541eb4d6e6212bb3ec5163a49”,
“MacAddress”: “02:42:0a:00:00:06”,
“IPv4Address”: “10.0.0.6/24”,
“IPv6Address”: “”
},
“24f73a0cb970f31133e51f8dabd24fc96b3b01b49ac9d43d030321d4a635f855”: {
“Name”: “myfirstscaledserver_server.4.i8jbo87dhuykzp9pgu0ltzb5l”,
“EndpointID”: “caa6268a16fb5288667a6944e853d3919f6ca8d690c96bc2d8904043b1f69b3f”,
“MacAddress”: “02:42:0a:00:00:07”,
“IPv4Address”: “10.0.0.7/24”,
“IPv6Address”: “”
},
“60b0f9f115a9e55f92194f5534a502f27ce975f1f2245d4cd1c92c9598130644”: {
“Name”: “myfirstscaledserver_server.1.q0decbx6j0bbd7xx2mvdrhub6”,
“EndpointID”: “a357e51c48495598b6fcd74527aa1668c49db6ccab27de023d98f630bcb974ae”,
“MacAddress”: “02:42:0a:00:00:04”,
“IPv4Address”: “10.0.0.4/24”,
“IPv6Address”: “”
},
“c713f304f4722ddd5ab29e0193dda16544fcd6935a2146d9c8cf138742ce540c”: {
“Name”: “myfirstscaledserver_server.5.xq9o4kijfdqh746acbiyy5xi6”,
“EndpointID”: “afc22b459d641e3b198efb9656641640e0457d36c9d271e4f50f846773c7f10f”,
“MacAddress”: “02:42:0a:00:00:08”,
“IPv4Address”: “10.0.0.8/24”,
“IPv6Address”: “”
},
“db550fdcc744b51ac634657fdd769c507d36890c16b6459a621c729b911fe58f”: {
“Name”: “myfirstscaledserver_server.2.tzfsszqqqatuht2sd6lsoc1iz”,
“EndpointID”: “f9850daa7c99fc0a83302dcc7b0526143d800391a6067905ee2937219f45c3a2”,
“MacAddress”: “02:42:0a:00:00:05”,
“IPv4Address”: “10.0.0.5/24”,
“IPv6Address”: “”
}
},
“Options”: {
“com.docker.network.driver.overlay.vxlanid_list”: “4097”
},
“Labels”: {
“com.docker.stack.namespace”: “myfirstscaledserver”
},
“Peers”: [
{
“Name”: “a2a8d9a46925”,
“IP”: “10.0.2.15”
}
] }
]
When we run request from the outside to port 80 we get a (load-balanced) server-response as expected:

root@uservirt-VirtualBox:/home/uservirt/MyDockerImages# curl localhost:80

Hello World!

Great! Now let’s conclude with stopping our docker service (that will also remove our network) and ending the swarm (that will stop the containers):
docker stack rm myfirstscaledserver
docker swarm leave --force

6. Conclusion

You can see that it is pretty easy to get a distributed and scaled web application up and running.

Based on the swarm capabilities of docker we can not only run multiple instances of an image on a single server but there is also the possibility to distribute the containers on multiple machines for even more stability.

Next, we will see how to use this full functionality of docker swarm and stacks.

Leave a Reply

Your email address will not be published. Required fields are marked *