Every few years, the software development industry experiences a paradigm shift. One of these phenomena can be recognized as the growing interest in the concept of microservices. Although microservices are not the newest technology, only recently its popularity has literally skyrocketed.
Large monolithic services are now being replaced by independent stand-alone microservices. A microservice can be thought of as an application that serves a single and very specific purpose. For example, it can be a relational DBMS, an Express application, a Solr service.
Nowadays it is difficult to imagine the development of a new software system without the use of microservices. And this situation, in turn, leads us to the Docker platform.
Docker
Platform
Docker Compose
Technology
When working with Docker Compose, a YAML file is used to configure application services and organize their interaction with each other. Docker Compose is thus a tool for describing and running multi-container Docker applications.
Two containers running on a host system
GNU Make
Program make
, in essence, is a tool for automating the assembly of programs and libraries from source code. In general, it can be said that make
applicable to any process that involves the execution of arbitrary commands to transform some source material to some end result, to some purpose. In our case, the commands docker-compose
will be converted to abstract targets (
To tell the program make
about what we want from her, we need a file Makefile
.
In our Makefile
will contain the usual commands docker
ΠΈ docker-compose
which are designed to solve many problems. Namely, we are talking about assembling a container, starting it, stopping it, restarting it, organizing a user entry into the container, working with container logs, and solving other similar tasks.
Typical use cases for Docker Compose
Imagine a typical web application that has the following components:
- TimescaleDB (Postgres) database.
- Express.js application.
- Ping (just a container that doesn't do anything special).
This application will need 3 Docker containers and a file docker-compose
A containing instructions for managing these containers. Each of the containers will have different interaction points. For example, with a container timescale
it will be possible to work approximately the same as working with databases. Namely, it allows you to do the following:
- Login to the Postgres shell.
- Import and export of tables.
- Creation
pg_dump
tables or databases.
Express.js application container, expressjs
, may have the following features:
- Issuance of fresh data from the system log.
- Entering a shell to execute certain commands.
Interaction with containers
Now that we've set up communication between containers using Docker Compose, it's time to communicate with these containers. Within the Docker Compose system, there is a command docker-compose
, supporting the option -f
, which allows you to transfer the file to the system docker-compose.yml
.
Using the capabilities of this option, you can limit interaction with the system only to those containers that are mentioned in the file docker-compose.yml
.
Let's take a look at what interactions with containers look like when using commands docker-compose
. If we imagine that we need to enter the shell psql
, then the corresponding commands might look like this:
docker-compose -f docker-compose.yml exec timescale psql -Upostgres
The same command, which is not used to execute docker-compose
, docker
, might look like this:
docker exec -it edp_timescale_1 psql -Upostgres
Note that in such cases it is always preferable not to use the command docker
, and the command docker-compose
, as it eliminates the need to remember container names.
Both of the above commands are not that complicated. But if we used the "wrapper" in the form Makefile
, which would give us an interface in the form of simple commands and would itself call such long commands, then the same results could be achieved like this:
make db-shell
It is clear that the use Makefile
greatly simplifies the work with containers!
Working example
Based on the above project scheme, we will create the following file docker-compose.yml
:
version: '3.3'
services:
api:
build: .
image: mywebimage:0.0.1
ports:
- 8080:8080
volumes:
- /app/node_modules/
depends_on:
- timescale
command: npm run dev
networks:
- webappnetwork
timescale:
image: timescale/timescaledb-postgis:latest-pg11
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
command: ["postgres", "-c", "log_statement=all", "-c", "log_destination=stderr"]
volumes:
- ./create_schema.sql:/docker-entrypoint-initdb.d/create_schema.sql
networks:
- webappnetwork
ping:
image: willfarrell/ping
environment:
HOSTNAME: "localhost"
TIMEOUT: 300
networks:
webappnetwork:
driver: bridge
To manage the Docker Compose configuration and to interact with the containers it describes, let's create the following file Makefile
:
THIS_FILE := $(lastword $(MAKEFILE_LIST))
.PHONY: help build up start down destroy stop restart logs logs-api ps login-timescale login-api db-shell
help:
make -pRrq -f $(THIS_FILE) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$'
build:
docker-compose -f docker-compose.yml build $(c)
up:
docker-compose -f docker-compose.yml up -d $(c)
start:
docker-compose -f docker-compose.yml start $(c)
down:
docker-compose -f docker-compose.yml down $(c)
destroy:
docker-compose -f docker-compose.yml down -v $(c)
stop:
docker-compose -f docker-compose.yml stop $(c)
restart:
docker-compose -f docker-compose.yml stop $(c)
docker-compose -f docker-compose.yml up -d $(c)
logs:
docker-compose -f docker-compose.yml logs --tail=100 -f $(c)
logs-api:
docker-compose -f docker-compose.yml logs --tail=100 -f api
ps:
docker-compose -f docker-compose.yml ps
login-timescale:
docker-compose -f docker-compose.yml exec timescale /bin/bash
login-api:
docker-compose -f docker-compose.yml exec api /bin/bash
db-shell:
docker-compose -f docker-compose.yml exec timescale psql -Upostgres
Most of the commands described here apply to all containers, but using the c=
allows you to limit the scope of the command to a single container.
After Makefile
ready, you can use it like this:
make help
- issuing a list of all commands available formake
.
Help for available commands
make build
- building an image fromDockerfile
. In our example, we used existing imagestimescale
ΠΈping
. But the imageapi
we want to build locally. This is exactly what will be done after executing this command.
Building a Docker container
make start
- start all containers. To run only one container, you can use a command likemake start c=timescale
.
Running the timescale container
Running a ping container
make login-timescale
- login to the bash session of the containertimescale
.
Running bash in a timescale container
make db-shell
- entrance topsql
in a containertimescale
to execute SQL queries against the database.
Running psql in a timescaledb container
make stop
- stop containers.
Stopping the timescale container
make down
- stopping and deleting containers. To remove a specific container, you can use this command, specifying the desired container. For example -make down c=timescale
ormake down c=api
.
Stop and delete all containers
Results
Even though the Docker Compose system gives us a rich set of commands for managing containers, sometimes these commands become long and hard to remember as a result.
Method of use Makefile
helped us establish a quick and easy interaction with containers from a file docker-compose.yml
. Namely, we are talking about the following:
- The developer interacts only with the project containers described in
docker-compose.yml
, other running containers do not interfere with work. - In the event that a certain command is forgotten, you can execute the command
make help
and get help on available commands. - You don't have to remember long lists of arguments to perform things like getting fresh log entries or logging in. For example, a command like
docker-compose -f docker-compose.yml exec timescale psql -Upostgres
turns intomake db-shell
. - File
Makefile
You can, as the project grows, flexibly adjust to it. For example, it is easy to add a command to it to create a database backup or to perform any other action. - If a large development team uses the same
Makefile
, this streamlines collaboration and reduces errors.
PS In our
Dear Readers, How do you automate work with Docker Compose?
Source: habr.com