Table of contents
Container Orchestration
Container orchestration is the automatic process of managing or scheduling the work of individual containers for applications based on micro-services within multiple clusters. The widely deployed container orchestration platforms are based on open-source versions like Kubernetes, Docker Swarm or the commercial version from Red Hat Open-shift.
If you want to manage tens, hundreds, or even thousands of containers, you don't want to do that manually of course! That's why we need container orchestration.
Multi-Container Apps
If you have multiple containers to run your app, for example, you have the database in one container, another back-end container, and a front-end container, you need to run all of these and connect them using networks and map the right ports and volumes and all that stuff! That sounds like a lot of work right ?! Here is where Docker Compose comes into the picture, it allows you to set everything in a YAML file and then run only one command to start your multi-container app!
Docker Compose
Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration. To learn more about all the features of Compose, see the list of features.
It's composing the parts of the application and configuring them to work beautifully together with one command!
It simplifies the managing from multiple repeated commands to a YAML file and one command.
Install Docker Compose on Linux
In recent Docker versions compose is already installed with Docker!
Docker Compose YAML File
DOCKER COMPOSE YAML FILE CHEAT SHEET
version: "3.9" services: db: image: postgres volumes: - ./data/db:/var/lib/postgresql/data environment: - POSTGRES_DB=postgres - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres # docker run -v ./data/db:/var/lib/postgresql/data -e k=v postgres web: build: . command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/code ports: - "8000:8000" depends_on: - db # docker build -t tag . # docker run tag -v .:/code -p 8000:8000 python manage.py runserver 0.0.0.0:8000
This is a simple docker-compose YAML file for a sample Django app that uses Postgres database.
so let's break it down!
version: "3.9"
Specifies the version of Docker compose
services: db: web:
it means we have two services, which kinda means we have two docker images to build, one called db and the other called web
let's dive into the DB service
db: image: postgres volumes: - ./data/db:/var/lib/postgresql/data environment: - POSTGRES_DB=postgres - POSTGRES_USER=postgres - POSTGRES_PASSWORD=postgres
image
Defines the image we want to build from, and the same asdocker run
command, if the image doesn't exist locally it'll get downloaded from docker-hub, so here the image name is postgresvolumes
Define the volume mapping rules so in this example we're saying map ./data/db in the local host to/var/lib/postgresql/data
in the container. It's the same as running your container with docker run -venvironment
Sets the environment variables for the container, the same as using -e when running your container with docker run, and it gets an array of key value pairs
so to wrap it up, the DB service says to run a container from the image Postgres, and map ./data/db
in the host to /var/lib/postgresql/data
in the container and set POSTGRES_DB=postgres
, POSTGRES_USER=postgres
, POSTGRES_PASSWORD=postgres
as env variables.
if we want to translate it to a docker command it'll be like this
# create a env.list file contains all the env variables
echo "POSTGRES_DB=postgres \nPOSTGRES_USER=postgres\nPOSTGRES_PASSWORD=postgres" > env.list
docker run -v $(pwd)/data/db:/var/lib/postgresql/data --env-file env.list postgres
now for the other service web, let's break it down
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
build
Gets a path to the directory containing the docker file to build, so the difference between build and image is that the image specifies an already built image, and build specifies the Dockerfile to build an image from.command
Gets a Linux command, which overwrites the CMD command inside the docker filevolumes
Maps a host directory to a container directoryports
Maps/binds a host port to a container-exposed port, so here we're mapping port 8000 in the host machine to port 8000 in the containerdepends_on
Specifies which services must be already running before running this container
so let's translate this service to a docker command
# build the image
docker build -t img .
# run the container with the mapped port and volume
docker run -p 8000:8000 -v $(pwd):/code img python manage.py runserver 0.0.0.0:8000
And there is so much more you can do with docker-compose YAML files.
Run Docker Compose Containers
now that we have a docker-compose.yaml
file we can run them using one command without paying attention to any mapping, and can get a specific service to start it only as an argument, if no arguments are specified all the services will start
# change your directory to where the yaml file is
cd docker compose-test
docker compose up
# thats it really!
an important option of the up command is —scale=n this option will scale (i.e. will create more than 1 container from a specified service)
# docker compose up --scale $service=$n
docker compose up --scale web=5
and here is one of the powerful features of docker-compose!
Stop/Remove Docker Compose Containers
this will stop all the running containers and remove containers, networks, volumes, and images created by up.
docker compose down
List Running Docker Compose Containers
docker compose ps
Stop Docker Compose Containers
this will stop all the containers created by up but will not remove anything, and can get a specific service to start it only as an argument, if no arguments are specified all the services will stop
docker compose stop
Start Docker Compose Containers
this will start a docker compose existing containers and can get a specific service to start it only as an argument, if no arguments are specified all the services will start
docker compose start
Pause Docker Compose Containers
this will pause all the containers created by up and can get a specific service to start it only as an argument, if no arguments are specified all the services will pause
docker compose pause
Un-pause Docker Compose Containers
this will un-pause all the containers created by up and can get a specific service to start it only as an argument, if no arguments are specified all the services will un-pause
docker compose unpause # [service, ...]