Вход
Русский
USD
Цены в иностранной валюте приведены информационно

Сборка контейнеров docker с помощью контейнеров docker

Организация процесса сборки приложений, а также их упаковка в контейнера.

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

Что такое сборочный контейнер?

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

Чтобы проще было понять, рассмотрим вот такой пример: у нас есть абстрактный проект. Для его сборки и запуска необходимо выполнить некоторые действия:

  • поставить все нужные пакеты nmp;
  • инсталлировать все клиентские зависимости посредством bower;
  • использовать grunt для сборки проекта.

Для вышеописанной задачи лучше всего подойдет npm-builder. Это сборочный конвейер, включающий в себя npm, make, nodejs, g++. чтобы выполнить все три шага выше, наберите:

$ docker run --rm -v `pwd`:/data -w /data leanlabs/npm-builder npm install 
$ docker run --rm -v `pwd`:/data -w /data leanlabs/npm-builder bower install --allow-root 
$ docker run --rm -v `pwd`:/data -w /data leanlabs/npm-builder grunt build

Вот и все, получится собрать проект буквально с помощью 3 строк кода.

Давайте разбираться, что же мы сделали. Контейнер docker с npm-builder мы запускаем в корневой папке проекта. Потом текущая директория монтируется в /data, указывающаяся как рабочая. Это необходимо для того, чтобы в ней выполнялись все команды.

Первая команда выполняет установку всех модулей nodejs в папку node_modules. Поставятся модули, прописанные в файле package.json. Вторая строчка кода необходима для инсталляции в созданную папку bower_components всех зависимостей, которые прописаны в файле bower.json. Сборка с помощью grunt осуществляется последней строкой. Опция --rm указывается при запуске контейнера и помогает удалять его после инсталляции.

Используя проект на php, у нас получится применить сборочный контейнер komposer при установке зависимостей. Наберите:

$ docker run --rm -v `pwd`:/data imega/composer:1.1.0 install --no-dev

Для чего мы все это делали?

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

2. Проектный порог вхождения. Сборочные конвейеры дают возможность не заморачиваться над установкой разного ПО на компьютере разработчика. Для начала работы просто скопируйте репозиторий проекта, поставьте docker, docker-compose и сделать docker-compose up -d. А потом с docker hub сами подтянутся все контейнеры, которые нужны для сборки и установки проекта.

3. Повторное применение сборочных этапов. Если прописать в Dockerfile саму сборку, то все этапы придется прописать заново. Частично проблему получится решить за счет инструкции ONBUILD, но тогда уровень гибкости ухудшится. Это проявится когда потребуются дополнительные шаги сборки, которые придется все равно заново прописывать. Прозрачность сборки также может пострадать. Чтобы понять ход сборки, вам нужно будет смотреть на исходный файл родительского контейнера.

4. Единообразие среды, в которой происходит исполнение. Запуск приложения не зависит от этапа его сборки. А упаковка в контейнер является лишь копированием собранной программы. Что это значит? Если одни и те же приложения исполняются в контейнерах в разных средах, то в случае поломки летит всё везде одинаково.

5. Предсказуемость сборки. Не стоит проводить запуск grunt на хостовой машине, даже в самом начале применения docker.

6. Одинаковый процесс сборки. Docker не должен выступать средством управления конфигурациями. Его нужно использовать для упаковки, доставки и пуска программ. Если убрать из Dockerfile процесс сборки, они станут значительно проще и будут выглядеть так:

FROM leanlabs/nginx:1.0.1вк
COPY . /var/www/client/
COPY ./build/sites-enabled/client.conf /etc/nginx/sites-enabled/client.conf
CMD ["nginx", "-g", "daemon off;"] 

7. Применение уже имеющихся инструментов. Экосистема Docker уже включает в себя кучу инструментов вроде docker-compouse. Здесь сборочные контейнеры тоже подойдут.

Конвенции во время применения сборочных контейнеров

При использовании идеи сборочных контейнеров можно выделить несколько соглашений по применению и разработке.

  • Общим может быть «интерфейс». Для наглядности можно выделить volume / data в сборочных контейнерах. Они помогут вам смонтировать исходники программ. Кроме того, есть еще и / cache, способный помочь монтировать папки с кэшем сборочного контейнера. Это могут быть посторонние зависимости вроде bower, composer кэш, npm. Для сборочных контейнеров, применять лучше один базовый образ, выполняющий роль интерфейса.
  • Метод запуска. Контейнера можно разделить на one shot и long running. Первый вариант можно запустить только один раз. Контейнер выполнит задачу и закроется. Такой вариант подходит для инсталляции зависимостей, генерации документации к API или клонирования исходных файлов. Контейнера long running являются долгоживущими. Они способны отслеживать изменения в исходных файлах, а также пересобирать проект. Контейнера можете использовать для сборки JS-файлов, SCSS и много чего еще.
  • Сборочный контейнер является внешней зависимостью относительно приложения. Мы не применяем контейнера phpunit, ведь они подключаются через composer. Его наличие и версию определяет сама программа.
  • Названия контейнеров. В имени мы применяет суффикс -builder. Получается вот что: erlnag-builder, npm-builder.

Применение вместе с docker-compose

Контейнера выгодно использовать в среде разработчика в связке с docker-compose. Это может вам пригодится если нужно внести изменения в исходники. С docker-compose если некоторые нюансы. Применить одноразовый контейнер вы сможете только с опцией -d при выполнении docker-compose. Иначе после завершения его работы закроются и все остальные контейнера.

Вот так будет выглядеть инсталляция зависимостей с применением composer для php-приложений:

phpbuilder:
	image: imega/composer:1.1.0
	volumes:
		- "./:/data"
		- "$HOME/.composer:/cache"
	command: ["update"] 

Однако, долгоиграющие контейнеры работают без проблем. Например, вот так будет выглядеть инсталляция nodejs, зависимостей bower, а также запуск grunt:

clientbuilder:
	image: leanlabs/npm-builder
	volumes:
		- "./:/data"
		- "$HOME/.node_cache:/cache"
	command: ["/bin/sh", "-c", "npm install && bower install --allow-root && grunt"] 

Использование совместно с make

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

IMAGE = leanlabs/client
TAG = 1.1.9

build:
	@docker run --rm -v $(CURDIR):/data -v $$HOME/node_cache:/cache leanlabs/npm-builder npm install
	@docker run --rm -v $(CURDIR):/data -v $$HOME/node_cache:/cache leanlabs/npm-builder bower install —allow-root
	@docker run --rm -v $(CURDIR):/data -v $$HOME/node_cache:/cache leanlabs/npm-builder grunt build

release:
	@docker build -t $(IMAGE).
	@docker tag $(IMAGE):latest $(IMAGE):$(TAG)
	@docker push $(IMAGE):latest
	@docker push $(IMAGE):$(TAG)

.PHONY: build release

В качестве вывода

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

Опубликовано: Апрель 11, 2017