Containerized Tooling

В своей работе мы постоянно используем различные инструменты: protoc, golangci-lint, allure и многие другие.

Чтобы избежать ситуации, в которой версия или конфигурация инструмента у одного разработчика отличается от того, что уже установлено у другого, или от того, что настроено в CI, наши инструменты “запечены” в контейнеры.

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

Мы системно подошли к вопросу контейнеризации нашего тулинга:

  • Создан базовый шаблон репозитория инструмента (boilerplate);
  • Выделена отдельная группа проектов под названием tooling;
  • Внутри группы tooling на каждый инструмент создан отдельный репозиторий.

Все репозитории имеют единый общий пайплайн сборки и публикации во внутреннем реестре образов.

Группа проектов может иметь такой вид:

tree -a -C -L 2 tooling
tooling
├── golangci-lint
│   ├── .env
│   ├── .git
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── entrypoint.sh
│   └── golangci.yaml
├── protoc
│   ├── .env
│   ├── .git
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
...

За конфигурацию отвечает файл .env, обычно в нём задаётся имя образа:

IMAGE_NAME=internal-registry.dmz/dx/tooling/cowsay

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

include .env

.DEFAULT_GOAL := build

.PHONY: build
build:
	docker build --tag ${IMAGE_NAME} .

Собственно, Dockerfile не требует какого-то отдельного описания, приведу здесь максимально простой пример:

# syntax=docker/dockerfile:1

FROM ubuntu

RUN <<EOF
apt-get update
apt-get upgrade -y

apt-get install -y cowsay
EOF

WORKDIR /workdir

ENTRYPOINT ["/usr/games/cowsay"]

Следует обратить внимание на две вещи, которые могут быть неочевидными:

  • Комментарий в первой строке # syntax=docker/dockerfile:1 включает возможность использовать HEREDOC — он использован в директиве RUN;
  • Вместо директивы CMD используется ENTRYPOINT — это даёт возможность передавать аргументы для этой команды при запуске контейнера.

Благодаря подходу к контейнеризации инструментов моя команда получила:

  • Прозрачность и простоту “установки” и запуска инструментов в локальной среде;
  • Единообразие версий инструментов в локальной среде и на CI;
  • Общую и единую конфигурацию инструментария для всех проектов.

Ссылки