Skip to content

#80_docker_compose

Andrew edited this page May 1, 2019 · 1 revision

Spike Number: Issue 80

Spike Title: Docker orchestration Investigation

Andrew Davis
1/5/19

Goals / Deliverables

A report investigating multiple orchestration frameworks and a comparison of them along with a recommendation of what will best suit our needs.

A guide on using the recommended framework.

Technologies, Tools and Resources Used

Docker Orchestration Explained blogpost Docker compose compose-file docs
YAML wikipedia page
Docker compose man page $man docker-compose

What we found out:

Docker-Compose

Docker compose reads a yaml configuration file, which is a superset of JSON. that describes 1-->many containers. Many parts of the dockerfile can instead be omitted in lieu of being included in the docker compose file. For example which ports are exposed internally and which are mapped to host ports, environment variables, cli arguments and host directories to be loopback mounted.

Docker compose handles setting up an internal virtual network between the containers including DNS. In the compose file, names for each container are defined which are then mapped to domain names.

For example for internal networking, assume we have a foo_service trying to connect to bar_service REST API. bar_service exposes port 5001 internally, foo_service can connect to bar_service on http://bar_service:5001/

For external networking, in contrast to use Docker alone, the internal port is described in the dockerfile and when the container is instantiated with docker run an argument is passed to map that container port to a host port. Docker compose allows this to be mapped inside the configuration file. In the compose file a port must be mapped HOST:CONTAINER eg a foo_service that opens port 80 on the container can be mapped to 8080 on the host 8080:80. To connect to the container using the internal networking over a REST api would be http://foo_service:80/ similar to the bar_service example above for internal networking. To connect to it externally would be based on the host address localhost:8080 or via the hosts public up eg 27.34.155.251:8080 (assuming the hosting providers firewall is set up correctly).

Example docker-compose.yml file with # denoting a comment

#First line specifies the configuration file version.  This is not the version of the docker compose config file format not Docker or Docker Compose version
version: "3.7" 

#Services is the top level list of the services to be configured in the file
services:
	#One or many services can be listed.  Note the name of the service is mapped for networking
	foo_service:	
		#Path to the dockerfile relative to the location of the docker-compose file
		build: ./path/to/dockerfile 
		
		#ports to be mapped to the container
		#if only a single port is listed on a line then that port is available internally
		#if two ports are listed on a line they are done so in $HOST:$CONTAINER format eg - 80:8080 then that indicates map host port 80 to container port 8080.   
		ports:
			- "8080:80"  
			- "500" 
		
		#Reminder, docker containers are stateless.  Anything written to their filesystem will vanish when the container is taken down.  
		#Therefore when a container needs to store state, it is possible to pass in a directory of the host to the contaienr
		#the format is $HOSTPATH:$CONTAINERPATH
		#One or more volumes can be used.
		volumes: 
			- ./path/to/host/directory:/path/to/mount/in/container		
	
	#Again, multiple containers can be listed
	bar_service:
		build: ./path/to/bar_service/
		ports:
			- "5001"
		#Depends defines some containers requiring others to be functional.  For example an API gateway might not work very well if the services backing it aren't up
		depends_on: 	
			- "foo_service" 	#state a dependency is foo_service.  
		#Command is optional and used to override the cmd in the dockerfile
			command: ["app", "arg1", "arg2", "etc"]

Kubernetes

Based on consultation with Paul who has tried (and failed) to set up Kubernetes it is a monster to set up yourself. Limiting us to paid hosting options which we can deploy too. Kubernetes is also primarily aimed at much larger organisations looking to scale to multiple nodes that need fail over and load balancing.

Kubernetes is intended to be set up using cluster.
Each node in the cluster runs a process called a kubelet that acts as a manager for that node, based on instructions from the control plane. The manager is responsible for starting, stopping the containers.
Nodes are then divided into pods, where each pod acts as a scheduling unit. Containers in a pod must be guaranteed to be on the same physical node.
Kubernetes master. The master is in charge of sending commands to the kublets, deploying pods to nodes. It does this via an open Kubernetes API.
Config files are described in yaml files, it also has a tool to convert docker compose files.

Docker Swarm

Swarm was Docker inc's product to handle orchestration. Swarm is similar to Kubernetes with some nomenclature differences. Instead of a cluster it's a swarm, instead of a master there is a manager node, instead of a kubelet there is a worker node.

At this stage, Kubernetes is where the world is going and Docker inc has now embraced reality that everyone prefers Kubernetes, so i stopped investigating at this stage.

Recommendations:

Which Framework

Docker Compose.

The complexity of setting up Kubernetes or Swarm is not worth the trouble. For our project we need only two boxes to represent our different organisations (blockchain consortium and data broker respectively). Thus we don't need the ability to manage a cluster.

Docker Compose files are simple and solve all of our configuration. With one yaml file per system is easily manageable at this scale.

Installing Docker-Compose

Assumptions are that you have root access (denoted with a #) for some commands and the host is Debian derived eg Ubuntu 18.04

Update packages and install Docker, Docker-Compose and git. We need git to pull down our project.

#apt update
#apt upgrade
#apt install docker.io git docker-compose

Some distros will autostart the Docker service and have it run automatically. In case it doesn't. We will first enable it which will make it autostart at boot and then start it to start it immediately.

#systemctl enable docker
#systemctl start docker

To test that docker is running try running the hello world container. This will pull down a hello-world container from docker-hub, run it and shut down.

#docker run hello-world

To use most Docker commands, such as starting and stopping containers requires root access. This can be worked around by adding a docker group and then adding your user to it. Eg to add my user andrew

#groupadd docker
#usermod -aG docker andrew

You have to log off. I've had some issues where this wasn't sufficient. In this case, bounce the box and it should be working. You can verify it has worked by running docker commands such as the hello world container as your regular user.

$docker run hello-world

Note. The officially supported method of using Docker on Ubuntu is to add a Docker (the organisation) package repository. If you'd rather do this it is available here

running docker-compose

Assumptions when building. The Docker service is running and the docker-compose.yml is in the current level and the services are in under it with their dockerfile's and src/ directories. This may be different depending on where the dockerfile is in your project directory. But for now assume this layout:

tree

From the current directory run

#docker-compose up

This will trigger docker-compose to perform actions based on your docker-compose.yml file. Eg build the containers, instantiate them etc.

To run them headless use the -d flag.

To destroy the containers run

#docker-compose down

Writing a compose file

See above for a compose file example with comments explaining the different tags and examples.

There are many more features in Docker compose such as setting up more detailed network information, ulimit (resource limiting), logging etc.

Extensive documentation can be found on Docker compose can be found here
For documentation on just the compose configuration file here

Clone this wiki locally