Docker Compose: Simplify Using Makefile

Every few years, a paradigm shift occurs in the software development industry. One of these phenomena is the growing interest in the concept of microservices. Although microservices is not the latest technology, only recently has its popularity literally skyrocketed.

Large monolithic services these days are replaced by independent autonomous microservices. A microservice can be considered as an application that serves a single and very specific purpose. For example, it can be a relational DBMS, Express application, 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


The Docker platform , in the development and deployment of microservices, has become an almost industry standard. On the project’s website, you can find out that Docker is the only independent containerization platform that allows organizations to effortlessly create any applications, as well as distribute and run them in any environment - from hybrid clouds to border systems.

Docker compose


Docker Compose technology is designed to configure multi-container applications. A Docker Compose project can include as many Docker containers as the creator of this project needs.

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 Docker multi-container applications.


Two containers running on the host system

GNU Make


A program makeis essentially a tool for automating the assembly of programs and libraries from source code. In general, we can say that it is makeapplicable to any process that includes the execution of arbitrary commands for converting certain source materials to a certain resulting form, to a certain goal. In our case, the teams docker-composewill be converted to abstract goals ( Phony targets ).

In order to tell the program makewhat we want from it, we need a file Makefile.

Ours Makefilewill contain the usual commands dockeranddocker-composethat are designed to solve many problems. Namely, we are talking about assembling a container, about starting, stopping, restarting it, about organizing a user’s login to the container, about working with container logs and about solving other similar problems.

Typical Uses for Docker Compose


Imagine a regular web application that has the following components:

  • TimescaleDB Database (Postgres).
  • Express.js application.
  • Ping (just a container that does nothing special).

This application will need 3 Docker containers and a file docker-composecontaining instructions for managing these containers. Each of the containers will have different points of interaction. For example, timescaleyou can work with a container in much the same way that you work with databases. Namely, it allows you to perform the following actions:

  • Login to Postgres shell.
  • Import and export tables.
  • Create a pg_dumptable or database.

The container of an Express.js application,, expressjsmay have the following features:

  • The output of fresh data from the system log.
  • Enter the shell to execute certain commands.

Container Interaction


After we configured the connection between containers using Docker Compose, it's time to establish interaction with these containers. As part of the Docker Compose system, there is a command docker-composethat supports an option -fthat allows you to transfer a 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.

Take a look at how container interactions look when using commands docker-compose. If we imagine that we need to enter the shell psql, then the corresponding commands may look like this:

docker-compose -f docker-compose.yml exec timescale psql -Upostgres

The same command for which not docker-compose, but is used docker, may look like this:

docker exec -it  edp_timescale_1 psql -Upostgres

Please note that in such cases it is always preferable to use not a command docker, but a command docker-compose, since this eliminates the need to remember the names of the containers.

Both of the above commands are not so complicated. But if we used the “wrapper” in a form Makefilethat would give us an interface in the form of simple commands and call such long commands ourselves, then the same results could be achieved like this:

make db-shell

It is obvious that the use Makefilegreatly simplifies the work with containers!

Working example


Based on the above project diagram, 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 that it describes, 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 option c=allows you to limit the scope of the command to one container.

Once Makefileready, you can use it like this:

  • make help- issuing a list of all the commands available for make.


Available Commands Help

  • make build- assembly of the image from Dockerfile. In our example, we used existing images timescaleand ping. But apiwe want to collect the image locally. This is exactly what will be done after executing this command.


Docker container assembly

  • make start- launch of all containers. To start only one container, you can use the command of the form make start c=timescale.


Launch timescale container


Launch ping container

  • make login-timescale- entry into the bash session of the container timescale.


Running bash in timescale container

  • make db-shell- Log in psqlto the container timescaleto execute SQL queries to the database.


Running psql in timescaledb container

  • make stop - stopping containers.


Stopping the timescale container

  • make down- stop and remove containers. To delete a specific container, you can use this command with the specified container. For example - make down c=timescaleor make down c=api.


Stop and delete all containers

Summary


Despite the fact that the Docker Compose system gives us an extensive set of commands designed to manage containers, sometimes these commands become long, and as a result they can be difficult to remember.

The methodology of use Makefilehelped us establish quick and easy interaction with containers from the file docker-compose.yml. Namely, we are talking about the following:

  • , docker-compose.yml, .
  • , , make help .
  • , . , docker-compose -f docker-compose.yml exec timescale psql -Upostgres make db-shell.
  • Makefile , , . , .
  • Makefile, .

PS In our marketplace there is a Docker image , which is installed in one click. You can check the operation of containers on VPS . All new customers are given 3 days free of charge for testing.

Dear readers! How do you automate work with Docker Compose?

Source: https://habr.com/ru/post/undefined/


All Articles