DockerHub でイメージを自動ビルドする際の Tips


DockerHub で GitHub や BitbucketGitHub と連携して Docker イメージを自動ビルドすること自体は、既に先人たちが道を切り開いてくださっているので、そちらを参照されたし。

本稿では、ちょっと捻くれたことをしている自分が、作業を進める中で得た知見を Tips として共有する。

Dockerfile がソースリポジトリのトップではなく、サブディレクトリの下にある場合

一つのソースリポジトリにディレクトリを掘って、複数の Dockerfile を管理している構成で、例えば directory1 の下にある Dockerfile を自動ビルドしたい場合、

├─ LICENSE
├─ README.md
├─ directory1
│   └─ Dockerfile ← これを自動ビルドしたい
└─ directory2
    └─ Dockerfile

BUILD RULE の Build Context の欄に /directory1 と入力すれば良い。以下に例を示す。

Source Type Source Docker Tag Dockerfile location Build Context
Branch dir1_dev latest Dockerfile /directory1

ただし、directory2 など他のディレクトリの Dockerfile を編集した場合に自動ビルドが暴発しないよう、Source Type 欄や Source 欄の設定内容は注意すること。この例だと、ソースリポジトリの dir1_dev ブランチに push した時だけ自動ビルドが発動する。

ちなみに、自動ビルドすると DockerHub におけるイメージの紹介ページの Overview の内容が、ソースリポジトリにある README.md の内容で強制的に上書きされる。もし、ソースリポジトリのトップに README.md ファイルが一つだけある構成だったりすると、そのファイルが参照されてしまう。
それだと困る場合の対応策としては、各ディレクトリそれぞれに README.md を保存しておけば良い。Dockerfile と同じディレクトリ内に README.md があれば、そちらが優先して参照される。

├─ LICENSE
├─ README.md ← 同じディレクトリ内になければ、これが参照される
├─ directory1
│   ├─ Dockerfile
│   └─ README.md ← これが優先的に参照される
└─ directory2
    ├─ Dockerfile
    └─ README.md

一度の自動ビルドで複数のタグをつける

例えば、毎回の自動ビルド結果に対して個別のタグを付けると同時に、最新のものは常に latest タグを付けたい…ということを実現したい場合は、BUILD RULE の Docker Tag 欄にカンマ区切りで複数設定すると良い。以下に例を示す。

Source Type Source Docker Tag Dockerfile location Build Context
Tag /^[0-9.]+$/ latest,{sourceref} Dockerfile /directory1

この例だと、1.0 というタグを打ってソースリポジトリに push した場合、ビルド結果に対して 1.0latest のタグが付けられる。

参考: https://github.com/docker/hub-feedback/issues/341#issuecomment-263705074

hooks/build を上書きした上で、一度の自動ビルドで複数のタグをつける

Dockerfile 内の ARG に動的に変化する値を渡せるように、自動ビルドのスクリプトを上書きできる仕組みがあるのだが、上述の「一度の自動ビルドで複数のタグをつける」と組み合わせる場合、以下のようなスクリプトではうまくいかない。1

.../hooks/build
#!/bin/bash
docker build --build-arg CUSTOM=$VAR -f $DOCKERFILE_PATH -t $IMAGE_NAME .

エラーの内容から考察すると、恐らく、環境変数 DOCKER_TAG には latest,1.0 という文字列が設定されていると考えられるので、for 文を利用して複数のイメージ名を指定するように細工する。加えて、ネットで調べたところ、どうも環境変数 DOCKERFILE_PATH が空になるケースがあるようなので、念のためその対策もしておく。

以下にスクリプトの例を示す。

.../hooks/build
#!/bin/bash

set -eu

if [ -z "$DOCKERFILE_PATH" ]
then
    file_path_arg=""
else
    file_path_arg="-f $DOCKERFILE_PATH"
fi

image_name_arg=""
tags=`echo "$DOCKER_TAG" | sed -e 's/,/ /g'`
for tag in $tags
do
    image_name_arg="$image_name_arg -t $DOCKER_REPO:$tag"
done

docker build --build-arg CUSTOM=$VAR $file_path_arg $image_name_arg .

MicroBadger と連携

MicroBadger を利用することで、以下のようなバッジを README.md などに貼り付けることができる。2

イメージのタグ名は、URL 内に埋め込まれているのでそれはそれとして、そのタグを付けたイメージをビルドした際の、ソースリポジトリにおける commit ID を取得するためには、
Dockerfile に適切にラベルを設定しておく必要がある。
また、イメージのサイズについては、対象の Docker イメージが更新されたタイミングで webhook を呼び出すように設定しておき、メタ情報の更新の契機を与える必要がある。

…のだが、ちゃんと webhook の設定をしたつもりなのに、イメージのサイズがいつまで経っても "0B" の表示のまま変化しない。MicroBadger のイメージ詳細情報ページを見ても、レイヤ情報の欄が "No matching base image" と表示されてしまう。何故だ!?

公式サイトの "Support" のリンク先となっている GitHub ページの Issues を覗いたら、昨年(2019年)からレイヤ情報やサイズ情報の更新がうまくできていないっぽい。なんてこった。

どうにかならないかと調べた結果、shields.io を利用することで、レイヤ情報だけのバッジを作れるようなので、仕方がないのでそれで代用する。
URL の例: https://img.shields.io/microbadger/layers/obono/arduboy-env:latest.svg


  1. そもそも、build スクリプトを上書きしなかった場合は、どんなスクリプトで処理してるのだろうか? どこかに情報は無いものか。 

  2. MicroBadger のイメージ詳細情報ページの右側にある "Get the badges" からマークダウン記述例を取得できる。