Multi-container Applications using Docker Compose and Swarm
Docker Compose to Orchestrate Containers shows how to run two linked Docker containers using Docker Compose. Clustering Using Docker Swarm shows how to configure a Docker Swarm cluster.
This blog will show how to run a multi-container application created using Docker Compose in a Docker Swarm cluster.
Updated version of Docker Compose and Docker Swarm are released with Docker 1.7.0.
Docker 1.7.0 CLI
Get the latest Docker CLI:
1 | curl https: //get .docker.com /builds/Darwin/x86_64/docker-latest > /usr/local/bin/docker |
and check the version as:
1 2 | docker - v Docker version 1.7.0, build 0baf609 |
Docker Machine 0.3.0
Get the latest Docker Machine as:
1 | curl -L https: //github .com /docker/machine/releases/download/v0 .3.0 /docker-machine_darwin-amd64 > /usr/local/bin/docker-machine |
and check the version as:
1 2 | docker-machine - v docker-machine version 0.3.0 (0a251fe) |
Docker Compose 1.3.0
Get the latest Docker Compose as:
1 2 | curl -L https: //github .com /docker/compose/releases/download/1 .3.0 /docker-compose- ` uname -s`-` uname -m` > /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose |
and verify the version as:
1 2 3 4 | docker-compose - v docker-compose version: 1.3.0 CPython version: 2.7.9 OpenSSL version: OpenSSL 1.0.1j 15 Oct 2014 |
Docker Swarm 0.3.0
Swarm is run as a Docker container and can be downloaded as:
1 | docker pull swarm |
You can learn about Docker Swarm at docs.docker.com/swarm or Clustering using Docker Swarm.
Create Docker Swarm Cluster
The key components of Docker Swarm are shown below:
and explained in Clustering Using Docker Swarm.
- The easiest way of getting started with Swarm is by using the official Docker image:1
docker run swarm create
This command returns a discovery token, referred as <TOKEN> in this document, and is the unique cluster id. It will be used when creating master and nodes later. This cluster id is returned by the hosted discovery service on Docker Hub.
It shows the output as:
0102030405060708091011121314docker run swarm create
Unable to
find
image
'swarm:latest'
locally
latest: Pulling from swarm
55b38848634f: Pull complete
fd7bc7d11a30: Pull complete
db039e91413f: Pull complete
1e5a49ab6458: Pull complete
5d9ce3cdadc7: Pull complete
1f26e949f933: Pull complete
e08948058bed: Already exists
swarm:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.
Digest: sha256:0e417fe3f7f2c7683599b94852e4308d1f426c82917223fccf4c1c4a4eddb8ef
Status: Downloaded newer image
for
swarm:latest
1d528bf0568099a452fef5c029f39b85
The last line is the <TOKEN>.
Make sure to note this cluster id now as there is no means to list it later. This should be fixed with#661.
- Swarm is fully integrated with Docker Machine, and so is the easiest way to get started. Let’s create a Swarm Master next:1
docker-machine create -d virtualbox --swarm --swarm-master --swarm-discovery token:
//
<TOKEN> swarm-master
Replace
<TOKEN>
with the cluster id obtained in the previous step.--swarm
configures the machine with Swarm,--swarm-master
configures the created machine to be Swarm master. Swarm master creation talks to the hosted service on Docker Hub and informs that a master is created in the cluster. - Connect to this newly created master and find some more information about it:12
eval
"$(docker-machine env swarm-master)"
docker info
This will show the output as:
01020304050607080910111213141516171819202122232425262728> docker info
Containers: 2
Images: 7
Storage Driver: aufs
Root Dir:
/mnt/sda1/var/lib/docker/aufs
Backing Filesystem: extfs
Dirs: 11
Dirperm1 Supported:
true
Execution Driver: native-0.2
Logging Driver: json-
file
Kernel Version: 4.0.5-boot2docker
Operating System: Boot2Docker 1.7.0 (TCL 6.3); master : 7960f90 - Thu Jun 18 18:31:45 UTC 2015
CPUs: 1
Total Memory: 996.2 MiB
Name: swarm-master
ID: DLFR:OQ3E:B5P6:HFFD:VKLI:IOLU:URNG:HML5:UHJF:6JCL:ITFH:DS6J
Debug mode (server):
true
File Descriptors: 22
Goroutines: 36
System Time: 2015-07-11T00:16:34.29965306Z
EventsListeners: 1
Init SHA1:
Init Path:
/usr/local/bin/docker
Docker Root Dir:
/mnt/sda1/var/lib/docker
Username: arungupta
Registry: https:
//index
.docker.io
/v1/
Labels:
provider=virtualbox
- Create a Swarm node:1
docker-machine create -d virtualbox --swarm --swarm-discovery token:
//
<TOKEN> swarm-node-01
Replace
<TOKEN>
with the cluster id obtained in an earlier step.Node creation talks to the hosted service at Docker Hub and joins the previously created cluster. This is specified by
--swarm-discovery token://...
and specifying the cluster id obtained earlier. - To make it a real cluster, let’s create a second node:1
docker-machine create -d virtualbox --swarm --swarm-discovery token:
//
<TOKEN> swarm-node-02
Replace
<TOKEN>
with the cluster id obtained in the previous step. - List all the nodes created so far:1
docker-machine
ls
This shows the output similar to the one below:
1234567docker-machine
ls
NAME ACTIVE DRIVER STATE URL SWARM
lab virtualbox Running tcp:
//192
.168.99.101:2376
summit2015 virtualbox Running tcp:
//192
.168.99.100:2376
swarm-master * virtualbox Running tcp:
//192
.168.99.102:2376 swarm-master (master)
swarm-node-01 virtualbox Running tcp:
//192
.168.99.103:2376 swarm-master
swarm-node-02 virtualbox Running tcp:
//192
.168.99.104:2376 swarm-master
The machines that are part of the cluster have the cluster’s name in the SWARM column, blank otherwise. For example, “lab” and “summit2015” are standalone machines where as all other machines are part of the “swarm-master” cluster. The Swarm master is also identified by (master) in the SWARM column.
- Connect to the Swarm cluster and find some information about it:12
eval
"$(docker-machine env --swarm swarm-master)"
docker info
This shows the output as:
010203040506070809101112131415161718192021222324> docker info
Containers: 4
Images: 3
Role: primary
Strategy: spread
Filters: affinity, health, constraint, port, dependency
Nodes: 3
swarm-master: 192.168.99.102:2376
└ Containers: 2
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.022 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.0.5-boot2docker, operatingsystem=Boot2Docker 1.7.0 (TCL 6.3); master : 7960f90 - Thu Jun 18 18:31:45 UTC 2015, provider=virtualbox, storagedriver=aufs
swarm-node-01: 192.168.99.103:2376
└ Containers: 1
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.022 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.0.5-boot2docker, operatingsystem=Boot2Docker 1.7.0 (TCL 6.3); master : 7960f90 - Thu Jun 18 18:31:45 UTC 2015, provider=virtualbox, storagedriver=aufs
swarm-node-02: 192.168.99.104:2376
└ Containers: 1
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.022 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.0.5-boot2docker, operatingsystem=Boot2Docker 1.7.0 (TCL 6.3); master : 7960f90 - Thu Jun 18 18:31:45 UTC 2015, provider=virtualbox, storagedriver=aufs
CPUs: 3
Total Memory: 3.065 GiB
There are 3 nodes – one Swarm master and 2 Swarm nodes. There is a total of 4 containers running in this cluster – one Swarm agent on master and each node, and there is an additional swarm-agent-master running on the master.
- List nodes in the cluster with the following command:1
docker run swarm list token:
//
<TOKEN>
This shows the output as:
1234> docker run swarm list token:
//1d528bf0568099a452fef5c029f39b85
192.168.99.103:2376
192.168.99.104:2376
192.168.99.102:2376
Deploy Java EE Application to Docker Swarm Cluster using Docker Compose
Docker Compose to Orchestrate Containers explains how multi container applications can be easily started using Docker Compose.
- Use the
docker-compose.yml
file explained in that blog to start the containers as:123docker-compose up -d
Creating wildflymysqljavaee7_mysqldb_1...
Creating wildflymysqljavaee7_mywildfly_1...
The
docker-compose.yml
file looks like:01020304050607080910111213mysqldb:
image: mysql:latest
environment:
MYSQL_DATABASE: sample
MYSQL_USER: mysql
MYSQL_PASSWORD: mysql
MYSQL_ROOT_PASSWORD: supersecret
mywildfly:
image: arungupta
/wildfly-mysql-javaee7
links:
- mysqldb:db
ports:
- 8080:8080
- Check the containers running in the cluster as:12
eval
"$(docker-machine env --swarm swarm-master)"
docker info
to see the output as:
010203040506070809101112131415161718192021222324docker info
Containers: 7
Images: 5
Role: primary
Strategy: spread
Filters: affinity, health, constraint, port, dependency
Nodes: 3
swarm-master: 192.168.99.102:2376
└ Containers: 2
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.022 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.0.5-boot2docker, operatingsystem=Boot2Docker 1.7.0 (TCL 6.3); master : 7960f90 - Thu Jun 18 18:31:45 UTC 2015, provider=virtualbox, storagedriver=aufs
swarm-node-01: 192.168.99.103:2376
└ Containers: 2
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.022 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.0.5-boot2docker, operatingsystem=Boot2Docker 1.7.0 (TCL 6.3); master : 7960f90 - Thu Jun 18 18:31:45 UTC 2015, provider=virtualbox, storagedriver=aufs
swarm-node-02: 192.168.99.104:2376
└ Containers: 3
└ Reserved CPUs: 0 / 1
└ Reserved Memory: 0 B / 1.022 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.0.5-boot2docker, operatingsystem=Boot2Docker 1.7.0 (TCL 6.3); master : 7960f90 - Thu Jun 18 18:31:45 UTC 2015, provider=virtualbox, storagedriver=aufs
CPUs: 3
Total Memory: 3.065 GiB
- “swarm-node-02” is running three containers and so lets look at the list of containers running there:1
eval
"$(docker-machine env swarm-node-02)"
and see the list of running containers as:
12345docker
ps
-a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b1e7d9bd2c09 arungupta
/wildfly-mysql-javaee7
"
/opt/jboss/wildfly/
38 seconds ago Up 37 seconds 0.0.0.0:8080->8080
/tcp
wildflymysqljavaee7_mywildfly_1
ac9c967e4b1d mysql:latest "
/entrypoint
.sh mysq 38 seconds ago Up 38 seconds 3306
/tcp
wildflymysqljavaee7_mysqldb_1
45b015bc79f4 swarm:latest "
/swarm
join
--addr 20 minutes ago Up 20 minutes 2375
/tcp
swarm-agent
- Application can then be accessed again using:1
curl http:
//
$(docker-machine ip swarm-node-02):8080
/employees/resources/employees
and shows the output as:
1<?<span class=
"pl-ent"
>xml<
/span
><span class=
"pl-e"
> version<
/span
>=<span class=
"pl-s"
><span class=
"pl-pds"
>
"</span>1.0<span class="
pl-pds
">"
<
/span
><
/span
><span class=
"pl-e"
> encoding<
/span
>=<span class=
"pl-s"
><span class=
"pl-pds"
>
"</span>UTF-8<span class="
pl-pds
">"
<
/span
><
/span
><span class=
"pl-e"
> standalone<
/span
>=<span class=
"pl-s"
><span class=
"pl-pds"
>
"</span>yes<span class="
pl-pds
">"
<
/span
><
/span
>?><<span class=
"pl-ent"
>collection<
/span
>><<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>
id
<
/span
>>1</<span class=
"pl-ent"
>
id
<
/span
>><<span class=
"pl-ent"
>name<
/span
>>Penny</<span class=
"pl-ent"
>name<
/span
>></<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>
id
<
/span
>>2</<span class=
"pl-ent"
>
id
<
/span
>><<span class=
"pl-ent"
>name<
/span
>>Sheldon</<span class=
"pl-ent"
>name<
/span
>></<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>
id
<
/span
>>3</<span class=
"pl-ent"
>
id
<
/span
>><<span class=
"pl-ent"
>name<
/span
>>Amy</<span class=
"pl-ent"
>name<
/span
>></<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>
id
<
/span
>>4</<span class=
"pl-ent"
>
id
<
/span
>><<span class=
"pl-ent"
>name<
/span
>>Leonard</<span class=
"pl-ent"
>name<
/span
>></<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>
id
<
/span
>>5</<span class=
"pl-ent"
>
id
<
/span
>><<span class=
"pl-ent"
>name<
/span
>>Bernadette</<span class=
"pl-ent"
>name<
/span
>></<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>
id
<
/span
>>6</<span class=
"pl-ent"
>
id
<
/span
>><<span class=
"pl-ent"
>name<
/span
>>Raj</<span class=
"pl-ent"
>name<
/span
>></<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>
id
<
/span
>>7</<span class=
"pl-ent"
>
id
<
/span
>><<span class=
"pl-ent"
>name<
/span
>>Howard</<span class=
"pl-ent"
>name<
/span
>></<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>employee<
/span
>><<span class=
"pl-ent"
>
id
<
/span
>>8</<span class=
"pl-ent"
>
id
<
/span
>><<span class=
"pl-ent"
>name<
/span
>>Priya</<span class=
"pl-ent"
>name<
/span
>></<span class=
"pl-ent"
>employee<
/span
>></<span class=
"pl-ent"
>collection<
/span
>>
- Latest instructions for this setup are always available at: github.com/javaee-samples/docker-java/blob/master/chapters/docker-swarm.adoc.
Enjoy!
Reference: | Multi-container Applications using Docker Compose and Swarm from our JCG partner Arun Gupta at the Miles to go 2.0 … blog. |