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

# 概要

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

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

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

```shell: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/build` に `env` コマンドを仕込んで、どのような環境変数がセットされるか見てみました。
Github repoは https://github.com/tuttieee/docker-cuda-python3 、`exper/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": "highland@docker.com", "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:Dockerfile
ARG BASE_TAG
FROM nvidia/cuda:${BASE_TAG}

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

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

```shell: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を以下のように設定します。
<img width="1268" alt="スクリーンショット 2018-09-19 1.42.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/65141/86a6c7c3-499f-99dc-ed37-a23e2722dec8.png">

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

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