company_banner

Docker Compose: упрощение работы с использованием Makefile

Автор оригинала: Khushbu Adav
  • Перевод
Каждые несколько лет в индустрии разработки ПО происходит смена парадигмы. Одним из таких явлений можно признать рост интереса к концепции микросервисов. Хотя микросервисы — это технология не самая новая, лишь в последнее время её популярность буквально взлетела до небес.

Большие монолитные сервисы в наши дни заменяют независимыми автономными микросервисами. Микросервис можно рассматривать как приложение, которое служит единственной и очень специфической цели. Например — это может быть реляционная СУБД, Express-приложение, Solr-сервис.



В наши дни сложно представить себе разработку новой программной системы без применения микросервисов. А эта ситуация, в свою очередь, ведёт нас к платформе Docker.

Docker


Платформа Docker, в деле разработки и развёртывания микросервисов, стала практически индустриальным стандартом. На сайте проекта можно узнать о том, что Docker — это единственная независимая платформа контейнеризации, которая позволяет организациям без особых усилий создавать любые приложения, а также распространять и запускать их в любых средах — от гибридных облаков, до пограничных систем.

Docker Compose


Технология Docker Compose предназначена для конфигурирования многоконтейнерных приложений. В Docker Compose-проект может входить столько контейнеров Docker, сколько нужно создателю этого проекта.

При работе с Docker Compose для настройки сервисов приложения и организации их взаимодействия друг с другом используется YAML-файл. Docker Compose, таким образом, это инструмент для описания и запуска многоконтейнерных приложений Docker.


Два контейнера, работающие на хост-системе

GNU Make


Программа make, по существу, представляет собой инструмент для автоматизации сборки программ и библиотек из исходного кода. В целом, можно говорить о том, что make применима к любому процессу, который включает в себя выполнение произвольных команд для преобразования неких исходных материалов к некоему результирующему виду, к некоей цели. В нашем случае команды docker-compose будут преобразовываться в абстрактные цели (Phony targets).

Для того чтобы сообщить программе make о том, чего мы от неё хотим, нам понадобится файл Makefile.

В нашем Makefile будут содержаться обычные команды docker и docker-compose, которые предназначены для решения множества задач. А именно, речь идёт о сборке контейнера, о его запуске, остановке, перезапуске, об организации входа пользователя в контейнер, о работе с логами контейнера и о решении других подобных задач.

Типичные варианты использования Docker Compose


Представим себе обычное веб-приложение, в котором имеются следующие компоненты:

  • База данных TimescaleDB (Postgres).
  • Express.js-приложение.
  • Ping (просто контейнер, ничего особенного не делающий).

Этому приложению понадобится 3 контейнера Docker и файл docker-compose, содержащий инструкции по управлению этими контейнерами. Каждый из контейнеров будет обладать разными точками взаимодействия. Например, с контейнером timescale можно будет работать примерно так, как работают с базами данных. А именно, он позволяет выполнять следующие действия:

  • Вход в оболочку Postgres.
  • Импорт и экспорт таблиц.
  • Создание pg_dump таблицы или базы данных.

Контейнер Express.js-приложения, expressjs, может обладать следующими возможностями:

  • Выдача свежих данных из системного журнала.
  • Вход в оболочку для выполнения неких команд.

Взаимодействие с контейнерами


После того, как мы настроили связь между контейнерами с использованием Docker Compose, пришло время налаживания взаимодействия с этими контейнерами. В рамках системы Docker Compose имеется команда docker-compose, поддерживающая опцию -f, которая позволяет передавать системе файл docker-compose.yml.

Используя возможности этой опции, можно ограничить взаимодействие с системой только теми контейнерами, которые упомянуты в файле docker-compose.yml.

Взглянем на то, как выглядят взаимодействия с контейнерами при использовании команд docker-compose. Если представить, что нам нужно войти в оболочку psql, то соответствующие команды могут выглядеть так:

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

Та же команда, для выполнения которой используется не docker-compose, а docker, может выглядеть так:

docker exec -it  edp_timescale_1 psql -Upostgres

Обратите внимание на то, что в подобных случаях всегда предпочтительнее использовать не команду docker, а команду docker-compose, так как это позволяет избавиться от необходимости помнить имена контейнеров.

Обе приведённых выше команды не так уж и сложны. Но если бы мы воспользовались «обёрткой» в виде Makefile, которая давала бы нам интерфейс в виде простых команд и сама бы вызывала подобные длинные команды, то тех же результатов можно было бы добиться так:

make db-shell

Совершенно очевидно то, что использование Makefile значительно упрощает работу с контейнерами!

Рабочий пример


На основе вышерассмотренной схемы проекта создадим следующий файл 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

Для управления конфигурацией Docker Compose и для взаимодействия с контейнерами, которые она описывает, создадим следующий файл 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

Большинство описанных здесь команд применяются ко всем контейнерам, но использование опции c= позволяет ограничить область действия команды до одного контейнера.

После того, как Makefile готов, пользоваться им можно так:

  • make help — выдача перечня всех команд, доступных для make.


Справка по доступным командам

  • make build — сборка образа из Dockerfile. В нашем примере мы использовали существующие образы timescale и ping. Но образ api мы хотим собрать локально. Именно это и будет сделано после выполнения данной команды.


Сборка контейнера Docker

  • make start — запуск всех контейнеров. Для запуска лишь одного контейнера можно воспользоваться командой вида make start c=timescale.


Запуск контейнера timescale


Запуск контейнера ping

  • make login-timescale — вход в bash-сессию контейнера timescale.


Запуск bash в контейнере timescale

  • make db-shell — вход в psql в контейнере timescale для выполнения SQL-запросов к базе данных.


Запуск psql в контейнере timescaledb

  • make stop — остановка контейнеров.


Остановка контейнера timescale

  • make down — остановка и удаление контейнеров. Для удаления конкретного контейнера можно использовать эту команду с указанием нужного контейнера. Например — make down c=timescale или make down c=api.


Остановка и удаление всех контейнеров

Итоги


Несмотря на то, что система Docker Compose даёт в наше распоряжение обширный набор команд, предназначенных для управления контейнерами, иногда эти команды становятся длинными, в результате их бывает сложно запомнить.

Методика использования Makefile помогла нам наладить быстрое и простое взаимодействие с контейнерами из файла docker-compose.yml. А именно, речь идёт о следующем:

  • Разработчик взаимодействует только с контейнерами проекта, описанными в docker-compose.yml, работе не мешают другие запущенные контейнеры.
  • В том случае, если некая команда забыта, можно выполнить команду make help и получить справку по доступным командам.
  • Не нужно запоминать длинных списков аргументов для выполнения таких действий, как получение свежих записей журнала или вход в систему. Например, команда вида docker-compose -f docker-compose.yml exec timescale psql -Upostgres превращается в make db-shell.
  • Файл Makefile можно, по мере роста проекта, гибко под него подстраивать. Например, в него несложно добавить команду для создания резервной копии базы данных или для выполнения любого другого действия.
  • Если большая команда разработчиков пользуется одним и тем же Makefile, это упорядочивает совместную работу и снижает количество ошибок.

P.S. В нашем маркетплейсе имеется образ Docker, который устанавливается в один клик. Вы можете проверить работу контейнеров на VPS. Всем новым клиентам бесплатно предоставляются 3 дня для тестирования.

Уважаемые читатели! Как вы автоматизируете работу с Docker Compose?

RUVDS.com
RUVDS – хостинг VDS/VPS серверов

Комментарии 40

    +3

    В данном примере make целиком бесполезная зависимость. Ничем не отличается от файлов в папке bin.
    ./bin/up
    ./bin/restart
    ./bin/psql
    и тп.

      +1
      Я тоже использую make для docker-compose, но у меня в Makefile еще прописаны зависимости, что помогает в работе за счет экономии мозговой энергии.
      +3

      эмм забавно конечно, но что мешает добавить все эти команды как alias в .bashrc / .zshrc?
      В этом случае даже не нужно make писать. Если проектов много можно даже и так:


      dc-<project>-up
      dc-<project>-down
      dc-<project>-build
        +3
        Ничего не мешает. Но Makefile можно положить в репозиторий, например, рядом с docker-compose.yaml и всё будет работать у всех разработчиков без каких либо дополнительных действий.
          +2
          Ну и в Makefile можно прописать зависимости от Docker файлов и других, и тогда нужно будет меньше думать при пересборке имиджей.
            0

            Ну если процесс сборки очень хитрый с кастомными образами, кучей скриптов — то почему бы и нет, но ping + db так собирать это по моему перебор немного...

              0
              плюсом ко всему выше будет то, что make — довольно распространенная в индустрии утилита — новые разработчики, придя на проект, уже ожидают стандартные
              make build, make stop, make start -> знают как развернуть и поднять проект
                0

                Это от проекта зависит. На php, js/ts, например, makefile точно редкий гость. Или баш-скрипты, или composer/npm/yarn или их комбинация. Иногда какой-нибудь таск-раннер на родном для проекта языке.

          0

          Чтобы можно было включить его в репозиторий

            0
            Можно использовать direnv и добавлять папку с скриптами в PATH при cd в папку проекта. И в репозиторий совать удобно, и окружение остальное не затрагивает.
            Таже автозапуск nix-shell поддерживает, который может docker-compose подтянуть и вот это вот всё.
              0
              Забавно, что сам direnv имеет Makefile с кучей .PHONY алиасов.
            +5
            И много людей используют Makefile как алиасы для команд?
            Как по мне это как то не правильно
              +1
              В опенсорс проектах для установки и удаления — очень много.
                +1
                Строго говоря, алиасы для команд это вся суть Makefile. Даже если учитывать команды для компиляции и сборки бинарников, в типичном Makefile почти всегда алиасы общего назначения (PHONY).
                make install классический пример.
                +4
                Главная фича Make, отслеживание изменённий в зависимостях здесь не используется. Всё тоже самое можно сделать с помощью обычного Баш скрипта со свитчем команд. Было бы даже по красивее. Синтаксис Make файлов мягко говоря не инуитивный.
                  +3
                  Выглядит, как дичь. Можно еще один уровень абстракции сделать в на py/go/..., чтобы дергать make, чтобы дергать docker-compose. Странный подход.
                  Вот есть человек, который привык к дефолтным ключам, а вы ему — не, запускай давай make.
                  Костыли.
                    +2
                    Это не дичь, а использование уже готового инструмента.
                    Часто, в работе требуется выполнять разные команды с параметрами в зависимости от настроек конкретного окружения. Постоянно вспоминать команды — напрягает, хочется как-то это упростить и автоматизировать.
                    Это удобно использовать при переключении между ветками проекта: выполнить миграции, подтянуть новые зависимости или запустить установку заново.

                    Конечно же обертку можно написать на любом языке, но Make уже дает готовый инструмент.
                    Как пример, список команд в одном наших из проектов:

                    === Application ===
                    make configure — Настройка конфигов
                    make reinstall — полная переустановка сервиса (сборка контейнера, сброс БД, composer install)
                    make install — первоначальная установка или обновление сервиса (сборка контейнера, composer install)
                    make status — статус приложения
                    make clean — удаление всех файлов, которые созданы во время установки
                    make cache-clear — прогрев кэша (через приложение)
                    === Tests ===
                    make app-ok — проверка всего сервиса
                    make cc — прогон тестов
                    === Docker ===
                    make up — поднять сервис
                    make stop — остановить сервис
                    make down — остановка с удалением контейнера
                    make php-cli — войти в shell сервиса php
                    make nginx-cli — войти в shell сервиса nginx
                    make php-log — stdout сервиса php
                    make nginx-log — stdout сервиса nginx
                    === DB ===
                    make migrate — накатка миграций
                    make remigrate — Очистка БД и выполнение миграций
                    +1

                    Нда, какой-то дикий изврат.
                    Совершенно согласен с предыдущими коментами, что проще это всё запихать в алиасы. Причём, не обязательно в .bashrc, а в любой другой файл, который может быть подключен через .bashrc.
                    Да и что мешает накатать банальный container_control.sh, для которого, как минимум, не надо знать синтаксиса make.
                    Грустнее этого может быть только запуск системного сервиса через samopalny_service.sh & при загрузке системы.
                    Вот программисты переживают за код, который будут разбирать другие после них, хотелось бы чтобы и админы переживали за конфигурацию серверов.

                      +3
                      Когда проектов много, в альясах или шелл скриптах утонешь. Лучше, чтобы все было в проекте. В Makefile можно сделать зависимости на докерфайлы, файлы конфигурации и т.д.
                      Поверьте старому линуксоводу, это — лючше.
                      0
                      В наши дни сложно представить себе разработку новой программной системы без применения микросервисов. А эта ситуация, в свою очередь, ведёт нас к платформе Docker.

                      Ну не знаю. К платформе Докер нас ведёт, в первую очередь, то что не требуется настраивать инстансы каждый раз, а пользоваться имейджами. Ну и стопицот дополнительных плюшек.
                      А микросервисы так вообще спорная вещь…
                        –2
                        упрощение работы с использованием Makefile

                        Это не упрощение. Это усложнение — лишний слой абстракции, скрывающий под капотом реальные аргументы команды. За это придется платить.


                        По сути, мысль можно свести к следующему: для удобства каждый разработчик должен завернуть все линуксовые команды [а чего на docker-compose то остановились? давайте make ls вместо ls -Altr] в свой удобный враппер, которым привык пользоваться.
                        C-программисты — в make, Java — в maven goal, JS — в scripts в package.json, а питонисты пусть для manage.py модули пишут.


                        Только вот под лишним слоем абстракции всегда теряется понимание внутренних процессов и во время траблшутинга наступает час расплаты.. Я уже это в мире Windows видел, где люди управляют серверами мышкой и не отдупляют, что у них вообще происходит.

                          0
                          Это не упрощение. Это усложнение — лишний слой абстракции, скрывающий под капотом реальные аргументы команды. За это придется платить.

                          Всё смешалось: люди, кони. Речь идёт о предоставлении единого интерфейса к разным сервисам — или упрощении интерфейса. Был ли упрощён интерфейс? Был.


                          Ценой чего был упрощён интерфейс? Верно, ценой абстракции — усложнения реализации
                          А вот мысль "За это придется платить." прошу пояснить: за годы работы в саппорте понял, что игра в угадайку — неблагодарное занятие


                          По сути, мысль можно свести к следующему...

                          По сути, так любую здравую мысль можно свести к абсурду. Гротеск такой гротеск.


                          C-программисты — в make, Java — в maven goal, JS — в scripts в package.json, а питонисты пусть для manage.py модули пишут.

                          Перевожу на русский язык: "я не знаю, зачем нужен make, maven, package.json и manage.py, но соберу в одну кучу и покажу, какой я дофига умный". Возможно, повезёт в следующий раз


                          Только вот под лишним слоем абстракции всегда теряется понимание внутренних процессов и во время траблшутинга наступает час расплаты… Я уже это в мире Windows видел, где люди управляют серверами мышкой и не отдупляют, что у них вообще происходит.

                          И снова всё смешалось. Абстракция не есть сокрытие реализации, и сравнение с Windows ошибочно.


                          А давайте откажемся от файловых систем — они скрывают реализацию хранения данных на носителях. Давайте к каждому носителю обращаться напрямую — ведь за слои абстракций над носителями приходится платить! Давайте обращаться к цилиндрам на HDD. К чёрту файловые системы — эти абстракции так легко рушатся, а при траблшутинге никто дупля не отрезает, что на самом деле происходит и где на самом деле данные хранятся на диске


                          Вы прослушали миниатюру "Гротеск". Или, может, не всё ли равно, как носители работают внутри, если нам важен интерфейс — хранилище?




                          Выводы:


                          • Абстракции не всегда есть "зло, за которое придётся платить"
                          • Абстракции хороши, будучи применёнными к месту и в нужном объёме
                            +1
                            А вот мысль "За это придется платить." прошу пояснить

                            Поторопились вопрос задавать. Ниже по тому же тексту объяснено, чем платить — непониманием, куда двигаться во время траблшутинга.


                            По сути, так любую здравую мысль можно свести к абсурду

                            Вот тут вы точно ошибаетесь. Если мысль можно свести к абсурду, значит она и была неверна изначально. Правильную мысль свести к абсурду без нарушения логики не получится. Подробнее тут.


                            я не знаю, зачем нужен make, maven, package.json и manage.py, но соберу в одну кучу и покажу, какой я дофига умный

                            Опаньки, переход на личности пошел. Ну ок, правила игры усвоены.
                            Я знаю, зачем нужен make и все остальное перечисленное. И уверен, что знаю лучше вас ;-)
                            Если вы не знаете, что объединяет эти столь непохожие инструменты, то подтянуть знания надо вам, а не мне. Откройте пожалуйста package.json, убедитесь, что секция scripts — ни что иное, как алиасы к другим командам, о которых тут в комментах не написал только ленивый.


                            А давайте откажемся от файловых систем

                            Единственное, где согласен и где вопрос спорный.


                            Вы прослушали миниатюру "Гротеск"

                            Сразу после знакомства с package.json пожалуйста ознакомьтесь с термином "гротеск", который вы примеряете не по смыслу.

                          +1

                          Забавно, но я недели полторы назад провел коллегам лекцию на тему использования build-tools на примере Make для похожих задач.


                          Вообще make не обязателен, можно использовать любую приблуду из списка софта для автоматизации сборки


                          У меня, например, Terraform в make завёрнут.
                          У одного из коллег деплой Kafka в k8s, причем мы пришли к такому решению независимо.


                          В статье не раскрыто в каком случае такая заморочка становится нужной.
                          Для меня это имеет простой и понятный смысл.


                          После выхода проекта из стадии активной разработки я Operations отдаю менее квалифицированным "условным индусам", которые разбираться в кишках проекта не станут и для них, что короткая строка команды, что длинная одинаково непонятны.
                          Но в короткой вероятность ошибки в разы ниже.


                          К тому-же у нас разворачиваются десятки однотипных сред, TF код построен таким образом, что отличие в значении пары переменных позволяет деплоить совсем другое окружение в неслольких географически разнесенных зонах.
                          Таким образом:


                          make apply PROJECT=blabla ENV=test APPROVE=yes

                          За счет chain commands превращается в:


                          terraform workspace select blabla_test && \
                          terraform fmt && \
                          terraform validate && \
                          terraform apply -lock=true -input=false -refresh=true -var project=blabla -var env=test -var-file=blabla_test.tfvars -auto-approve

                          Причем файл переменных подхватывается только если он существует и есть ешё пара несущественных (но приятных) плюшек.
                          Вроде того что у каждой среды есть свой независимый стейт.


                          Как это удобно и, в особенности, переносимо сделать на алиасах в Bash я не представляю.
                          Хотя алиасов и функций у меня в ~/.bashrc немало.


                          Теперь по тексту статьи, хочу автора немного пожурить.


                          Если используете самодокументируемые Makefile то нужно в них документацию добавлять.


                          На примере Makefile из статьи


                          build: ## Buids docker compose file in this directory
                                  docker-compose -f docker-compose.yml build $(c)

                          Тогда make help будет не только список команд выдавать, но и справку по ним.

                            +2

                            Ах ты досада какая, зря я автора журил…
                            В статье обычный Makefile не самодокументируемый.
                            Тогда вот пример как добавить документацию в Makefile.


                            help:
                                    @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
                            
                            build: ## Buids docker compose file in this directory
                                    docker-compose -f docker-compose.yml build $(c)
                              +1

                              Класс, спасибо за идею!


                              Вообще make не обязателен, можно использовать любую приблуду из списка софта для автоматизации сборки

                              Только make среди них самая распространённая, переносимая и простая. Да, после shell-скриптов непривычно, но, когда вникнешь, понимаешь весь дзен.

                                0

                                Насчёт простой это очень спорно, особенно если шелл-скриптов не писал никогда. Да и сейчас встретить человекапрограммиста, никогда не слышавшего о нём вообще, куда проще, чем того, кто его хотя бы читает свободно

                            0
                            Главное не забыть это все завернуть в контейнер и покрыть еще одним docker-compose.
                              0
                              Больше бойлерплейта ради бога бойлерплейта
                                +1
                                Давно использую taskfile.dev — выглядит проще и понятней, особенно учитывая что львиная часть функционала в Make нужна только многоэтапной ленивой компиляции программ на языках вроде C/C++.
                                И help там есть из коробки, если добавлять к каждой команде description.
                                  0

                                  Интересно, спасибо, я его не находил, когда искал замену make. А можете поделиться нетривиальным примером использования из своей практики?

                                0

                                Трудно придумать что-то ещё более бесполезное. Если надо что-то добавить в репо, так добавьте свой файл с алиасами. source my-aliases и вперед. Но тут даже трудно придумать на что алиас сделать, на docker-compose up?? Используйте completions в конце концов.

                                  +2

                                  Когда, в начале своей девопс-карьеры, увидел связку docker-compose + Makefile в соседнем проекте, вот так же, как большинство комментаторов тут плевался и обещал, что у меня никогда ничего такого не будет. А в итоге пришёл год спустя к тому же самому.


                                  Разработчики, кстати, въехали моментально, вопросов почти не возникало. И то, что у всех наших проектов похожий интерфейс: make up|down|clean|shell|dbshell и т.п. — большой плюс.


                                  Пробовал то же самое сделать в виде bash-скрипта — тоже вариант, но Makefile даже проще и компактнее. А алиасы слишком ограничены, и их, опять же, нужно в своём профиле прописывать.


                                  Кстати, где-то читал, что .PHONY, в 99% случаев указывать вовсе не обязательно, что делает его ещё проще.

                                    0

                                    Начинал тоже с набора скриптов в директории ./bin, но когда их стало больше 10 — начал искать альтернативу, и ей стал как раз Makefile. Надо лишь чуть "въехать" в его синтаксис, и после этого дальнейшую разработку без него представить уже становится сложно.


                                    Один из примеров того как можно его использовать можно найти тут (golang проект-болванка).


                                    Ах да, ещё и документирование поддерживаемых целей возможна таким способом:


                                    .DEFAULT_GOAL : help
                                    
                                    # This will output the help for each task. thanks to https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
                                    help: ## Show this help
                                        @printf "\033[33m%s:\033[0m\n" 'Available commands'
                                        @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "  \033[32m%-14s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

                                    image

                                      +1
                                      Выше уже советовали Task. Он тоже умеет выводить список задач и конфиг у него в привычном Yaml формате.
                                        +1

                                        К сожалению, он является дополнительной зависимостью, что должна быть на тачке каждого разработчика, а make с 99% вероятностью уже стоит "по умолчанию".


                                        Но yaml читать многократно удобнее, тут спорить сложно. В сторону таскера посмотрю тоже обязательно, быть может зайдет созданием скрипта с именем ./task с примерным содержанием docker run --rm -v "$(pwd):/rootfs" -w '/rootfs' task:image $@

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                    Самое читаемое