Why Docker Compose
Docker Compose is a tool for running multi-container Dockerized applications. Given a YAML configuration file which describes all your services and a single command you can create and start your application, drastically improving the flow compared to building and running each container individually as we learned in the previous article.
To prove the claim above, let's take a real example. Say we want to build a nodeJs application which connects to a database and we want to have the ability to scale it.
FROM node:11 LABEL maintainer="Darius Cupsa <firstname.lastname@example.org> RUN mkidr -p /usr/src/app WORKDIR /usr/src/app EXPOSE 80 COPY package.json /usr/src/app/package.json COPY package-lock.json /usr/src/app/package-lock.json RUN npm install COPY . /usr/src/app CMD ["npm", "run", "start"]
Considering the Dockerfile above, to accomplish the requirements we set we would have to go through a couple of steps, as follow:
- Create a bridge network to which the containers should connect and communicate through.
docker network create -d bridge demo-network
- Start a reverse proxy that would route and balance the traffic inside the network
docker run -d --name proxy \ -p 80:80 -p 8080:8080 \ -v /var/run/docker.sock:/var/run/docker.sock \ -network demo-network \ traefik:latest \ --web --docker --docker.domain=demo-app.dkr
- Create a storage volume for the database
docker volume create demo-app-db
- Start a database container
docker run -d --name mysql \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=secret \ -v demo-app-db:/var/lib/mysql \ --network demo-network \ mysql:5
- Build the actual application
docker build -t demo-app:latest .
- Start the application
docker run -d --name demo-app_1 \ --network demo-network \ -e MYSQL_HOST=mysql \ -e MYSQL_USER=root \ -e MYSQL_PASSWORD=secret \ -e PORT=80 \ -l "traefik.port=80" \ -l "traefik.backend=app" \ -l "traefik.frontend.rule=Host:demo-app.dkr;PathPrefixStrip:/" \ -l "traefik.network=demo-network" \ demo-app:latest
Now if for whatever reason we need to scale this up, we would just need to run the last command but with a different name, traefik should know once the container is ready to route traffic towards it.
On a quick glance it looks way more complicated than it should be and you would be correct as all this can be accomplished with just a configuration file and one simple command as we shall see now.
Considering that all commands will be ran from inside the nodeJs app folder, the
docker-compose.yml file should look something like this:
version: '3.7' services: proxy: image: traefik:latest ports: - 80:80 - 8080:8080 volumes: - /var/run/docker.sock:/var/run/docker.sock networks: - demo-network command: --web --docker --docker.domain=demo-app.dkr mysql: image: mysql:5 ports: - 3306:3306 environment: MYSQL_ROOT_PASSWORD: secret volumes: - demo-app-db:/var/lib/mysql networks: - demo-network app: build: context: . image: demo-app:latest environment: MYSQL_HOST: mysql MYSQL_USER: root MYSQL_PASSWORD: secret PORT: 80 labels: - "traefik.port=80" - "traefik.backend=app" - "traefik.frontend.rule=Host:demo-app.dkr;PathPrefixStrip:/" - "traefik.network=demo-network" networks: - demo-network volumes: demo-app-db: driver: local networks: demo-network: driver: bridge
If we take a deeper look we see that every argument given to the commands we used above is in a way or another reflected in the configuration file.
As for the almighty one liner command we use to run this is just this:
docker-compose up -d
This will read the configuration file, create the
demo-network network, create the
demo-app-db persistent volume and it will start booting up containers and if we ever need to scale this, docker-compose has a handy way of doing that by just telling it how many containers of one type do you want to run.
docker-compose scale app=3
Thank you for sticking up with me up until this point and I hope something out of this article was helpful to you.