dockerhubのautomated buildで任意のdocker buildコマンドを利用し、単一のDockerfileから設定を動的に変えて複数イメージをビルドする


概要

dockerhubにはautomated buildという機能があります。
Dockerfileを含んだgithub repositoryを関連付けておくと、dockerhubのビルドサーバでCI的に自動でイメージをビルドしてくれます。

このrepositoryにhooks/buildファイルをおいておくと、ビルドを任意のコマンドでオーバーライドできます。
また、その際にいろいろな環境変数を参照できるので、それを--build-argにわたすことで、生成するイメージに動的にパラメータを設定できます。

ビルドフックについて

hooks/build を作成しておくと、automated build時にフックしてビルドの挙動をオーバーライドできます。

hooks/build
#!/bin/bash
set -eu

docker build -t $IMAGE_NAME .

(↑この hooks/build の例だとデフォルト挙動と特に違いはありませんが)

この機能について、Docker Cloudのドキュメントには記述があります( https://docs.docker.com/docker-cloud/builds/advanced/ )。
Docker Hubについてのドキュメントは見つかりませんでしたが、同様に動作するようです。
ただし、一部環境変数がDocker Cloudのドキュメント通りにならないようです。
(また、このドキュメントによると、hooks/build 以外にもフックポイントがあるようです(試していません))

ビルドフックで参照できる環境変数

hooks/buildenv コマンドを仕込んで、どのような環境変数がセットされるか見てみました。
Github repoは https://github.com/tuttieee/docker-cuda-python3exper/echo-env というブランチに add env to hooks/build というコミットをして、automated buildを走らせた状況です(2018-09-18)↓。

いろいろな環境変数が得られることがわかります。

HOSTNAME=287ed2d96aaa

DOCKER_REPO=index.docker.io/tuttieee/cuda-python3

DOCKER_HOST=unix:///var/run/docker.sock

SOURCE_BRANCH=exper/echo-env

PYTHONUNBUFFERED=1

PUSH=true

GIT_SHA1=3c8f459ac08b2c4c5a7e3fbf74d9f8b44d2cf621

BUILD_PATH=/

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

SIGNED_URLS={"post": {"debug": {"url": "https://docker-highland-p1-debug-logs.s3.amazonaws.com/", "fields": {"policy": "eyJjb25kaXRpb25zIjogW1siY29udGVudC1sZW5ndGgtcmFuZ2UiLCAwLCA2NzEwODg2NF0sIHsiYnVja2V0IjogImRvY2tlci1oaWdobGFuZC1wMS1kZWJ1Zy1sb2dzIn0sIHsia2V5IjogImI5dnFxaXRwdmdoa2NwZHc3eGp2OXdtLmxvZyJ9XSwgImV4cGlyYXRpb24iOiAiMjAxOC0wOS0xOVQxNjoxNjowOVoifQ==", "AWSAccessKeyId": "AKIAIA35NOZ7FSTHT73Q", "key": "b9vqqitpvghkcpdw7xjv9wm.log", "signature": "6oUI+zAq8ZUDnepttUsvySwYIUU="}}, "metrics": {"url": "https://docker-highland-p1-metrics-logs.s3.amazonaws.com/", "fields": {"policy": "eyJjb25kaXRpb25zIjogW1siY29udGVudC1sZW5ndGgtcmFuZ2UiLCAwLCA2NzEwODg2NF0sIHsiYnVja2V0IjogImRvY2tlci1oaWdobGFuZC1wMS1tZXRyaWNzLWxvZ3MifSwgeyJrZXkiOiAiYjl2cXFpdHB2Z2hrY3Bkdzd4anY5d20ubG9nIn1dLCAiZXhwaXJhdGlvbiI6ICIyMDE4LTA5LTE5VDE2OjE2OjA5WiJ9", "AWSAccessKeyId": "AKIAIA35NOZ7FSTHT73Q", "key": "b9vqqitpvghkcpdw7xjv9wm.log", "signature": "z2wmXnjeua6ahyvuf1ZJSPzK9kg="}}, "readme": {"url": "https://docker-highland-p1-readmes.s3.amazonaws.com/", "fields": {"policy": "eyJjb25kaXRpb25zIjogW1siY29udGVudC1sZW5ndGgtcmFuZ2UiLCAwLCA2NzEwODg2NF0sIHsiYnVja2V0IjogImRvY2tlci1oaWdobGFuZC1wMS1yZWFkbWVzIn0sIHsia2V5IjogImI5dnFxaXRwdmdoa2NwZHc3eGp2OXdtLm1kIn1dLCAiZXhwaXJhdGlvbiI6ICIyMDE4LTA5LTE5VDE2OjE2OjA5WiJ9", "AWSAccessKeyId": "AKIAIA35NOZ7FSTHT73Q", "key": "b9vqqitpvghkcpdw7xjv9wm.md", "signature": "xdomB7XZmq1DZ8x58BbirJZEMAc="}}, "dockerfile": {"url": "https://docker-highland-p1-dockerfiles.s3.amazonaws.com/", "fields": {"policy": "eyJjb25kaXRpb25zIjogW1siY29udGVudC1sZW5ndGgtcmFuZ2UiLCAwLCA2NzEwODg2NF0sIHsiYnVja2V0IjogImRvY2tlci1oaWdobGFuZC1wMS1kb2NrZXJmaWxlcyJ9LCB7ImtleSI6ICJiOXZxcWl0cHZnaGtjcGR3N3hqdjl3bS5Eb2NrZXJmaWxlIn1dLCAiZXhwaXJhdGlvbiI6ICIyMDE4LTA5LTE5VDE2OjE2OjA5WiJ9", "AWSAccessKeyId": "AKIAIA35NOZ7FSTHT73Q", "key": "b9vqqitpvghkcpdw7xjv9wm.Dockerfile", "signature": "hHB0CYrXcOxmcQwba6f2FP7A66A="}}, "logs": {"url": "https://s3.amazonaws.com/docker-highland-p1-build_logs", "fields": {"policy": "eyJjb25kaXRpb25zIjogW1siY29udGVudC1sZW5ndGgtcmFuZ2UiLCAwLCA2NzEwODg2NF0sIHsiYnVja2V0IjogImRvY2tlci1oaWdobGFuZC1wMS1idWlsZF9sb2dzIn0sIHsia2V5IjogImI5dnFxaXRwdmdoa2NwZHc3eGp2OXdtLmxvZyJ9XSwgImV4cGlyYXRpb24iOiAiMjAxOC0wOS0xOVQxNjoxNjowOVoifQ==", "AWSAccessKeyId": "AKIAIA35NOZ7FSTHT73Q", "key": "b9vqqitpvghkcpdw7xjv9wm.log", "signature": "lkuVdZEd4UOX2wUNZKIy02v6R6M="}}}, "get": {}}

DOCKER_TAG=exper_echo-env

GIT_MSG=add env to hooks/build



COMMIT_MSG=add env to hooks/build



PWD=/src/b9vqqitpvghkcpdw7xjv9wm

BUILD_CODE=b9vqqitpvghkcpdw7xjv9wm

IMAGE_NAME=index.docker.io/tuttieee/cuda-python3:exper_echo-env

HOME=/root

SHLVL=1

DOCKERCFG={"https://index.docker.io/v1/": {"email": "[email protected]", "auth": "dHV0dGllZWU6ZTc4ODRjMWYtNWUyOS00MmFhLThhNmItMjBiOGYzNTNjZjkx"}}

DOCKERFILE_PATH=

DEBIAN_FRONTEND=noninteractive

CACHE_TAG=

SOURCE_TYPE=git

MAX_LOG_SIZE=67108864

以上の仕組みを実際に利用してみました。

ここでは、nvidia/cudaをベースイメージとして、python3をインストールしただけのDockerイメージを作りました。
https://github.com/tuttieee/docker-cuda-python3

nvidia/cudaは、tagによって色々なバリエーションのイメージを使い分けられます( https://hub.docker.com/r/nvidia/cuda/ )。
ここでは各tagをベースにビルドした各種のイメージを作りたいとします(nvidia/cuda:9.2-runtime-ubuntu16.04をベースにtuttieee/cuda-python3:9.2-runtime-ubuntu16.04をビルド、nvidia/cuda:9.1-base-ubuntu17.04をベースにtuttieee/cuda-python3:9.1-base-ubuntu17.04をビルド、……のように)。

ベースイメージのtagごとに別々のDockerfileを作って管理するのは大変なので避けたいところです(独自でやることはpython3とpipのインストールだけですし)。

そこで、FROM(ベースイメージ)をARGで動的に変更できるようにしたDockerfileを一つだけ作り、ビルド時に動的に設定するようにします。
※ Docker 17.05から ARG で設定した変数を FROM で参照できるようになっています: https://www.jeffgeerling.com/blog/2017/use-arg-dockerfile-dynamic-image-specification

Dockerfile
ARG BASE_TAG
FROM nvidia/cuda:${BASE_TAG}

# Python3のインストールなど
# ...
# ...

次に、hooks/buildを用意し、環境変数をベースに--build-argを設定します。

hooks/build
#!/bin/bash
set -eu

if [ "$DOCKERFILE_PATH" = "" ]; then
    DOCKERFILE_PATH_ARG=""
else
    DOCKERFILE_PATH_ARG="-f $DOCKERFILE_PATH"
fi

docker build --build-arg BASE_TAG=${DOCKER_TAG} ${DOCKERFILE_PATH_ARG} -t $IMAGE_NAME .

以上をGithubにpushし、repoと関連づいたautomated buildを作成します。
この例では https://hub.docker.com/r/tuttieee/cuda-python3/ です。
そしてBuild Settingsを以下のように設定します。

たとえばDocker Tag Name = 9.2-runtime-ubuntu16.04の設定からは、tuttieee/cuda-python3:9.2-runtime-ubuntu16.04がビルドされます。
このときにhooks/buildDockerfileのARGの設定により、ベースイメージとしてnvidia/cuda:9.2-runtime-ubuntu16.04が使われます。

この調子で各Tagを設定していけば、nvidia/cudaの各Tagをベースにした、複数のオリジナルのDockerイメージが自動でビルドされるようになります。