Docker Hubにある非公式のイメージを使用する場合、それがどうやって作られているか気になりますよね?Automated Buildsであれば、Dockerfileから生成されているので、何をやっているかがわかりますが、直接イメージがpushされている場合、なにが含まれているかわかりません。Automated Buildsなら確実に信用できるというわけではありませんが、ビルド手順を公開し自動的に構築することで利用者の不安を軽減することが出来ます。
Automated Buildsにしていなかった理由
私は基本的にAutomated Buildsにしているのですが、これまでしていなかったのがOpenWrtのDockerイメージのビルドです。私はshellspecというシェルスクリプトのテスティングフレームワークを開発しているのですが、そのテスト環境の一つとしてOpenWrtを使用しています。Docker HubにはOpenWrtが公開しているイメージがあるのですが最新バージョンしかありません。古いバージョンでもテストしたかったので独自でイメージを作成しています。
OpenWrtが公開している手順にも書いてありますが、手元でやるならファイルをダウンロードしてdocker import
で簡単にイメージが作れます。
$ docker import http://downloads.openwrt.org/attitude_adjustment/12.09/x86/generic/openwrt-x86-generic-rootfs.tar.gz openwrt-x86-generic-rootfs
しかし、Automated BuildsではDockerfileから生成します。DockerfileのFROM
にtar.gzは指定できませんし、ADD
にURLを指定した場合、tar.gzは展開されません。(ローカルファイルからtar.gzをADDした場合は展開されます。以前はバグでURLからADDした場合も展開されていたようで、OpenWrtのサイトにはその手順が残っていますが今はこのやり方はできません。)そのため今までは手元で作成したdockerイメージをpushしていました。
どうやってAutomated Buildsにしたか?
2020-01-22 実装方法を変更しました。 (古いやり方は下の方に残しています。)
この記事を最初に投稿した時はDocker Hubのフックの機能していたのですが、マルチステージビルドを使用した方法に変更しました。フックを使用した場合に比べてDockerfile一つで完結するのでローカルでもいつも通りのやり方でビルドできるというメリットがあります。またその際にハッシュチェックも行いより安心して使えるようにしています。
実装
まずマルチステージビルドの一段目で.tar.gz
ファイルを取得してディレクトリに展開します。その際にハッシュチェックも行います。マルチステージビルドの二段目でFROM scratch
から始めて一段目のディレクトリをコピーしています。
FROM alpine as builder
ENV base=https://downloads.openwrt.org/releases/19.07.0-rc2/targets/x86/64/
ENV file=openwrt-19.07.0-rc2-x86-64-generic-rootfs.tar.gz
ENV sha256=0910f4c4c0aa009117ecd97bb0d047d53229f58a889c905525f62b64595ab666
RUN wget -q "$base$file" && echo "$sha256 $file" | sha256sum -c
RUN mkdir /rootfs && tar xf "$file" -C /rootfs
FROM scratch
COPY --from=builder /rootfs/ /
CMD ["/bin/sh"]
以下は古いやり方です。
どうやってAutomated Buildsにしたか?(旧)
使用した機能はCustom build phase hooksです。Docker HubのAutomated Buildsはbuildやpushの前後等にフックを入れることが出来ます。またビルド処理(docker build
コマンドの実行)そのものを入れ替えることも出来ます。これを利用してビルドの前(hooks/pre_build
)でtar.gzファイルをダウンロードして、このファイルをDockerfileでADD
しています。
実装
Automated BuildsはGitHubやBitbucketと連携してソースコードをpushしたタイミングで、ソースコードのDockerfileを元にDocker HubがDockerイメージをビルドします。フックスクリプトも同じくソースコードのリポジトリに含めます。今回必要なのはビルド前のフックなので(Dockerfileと同じ階層に)hooks/pre_build
を作成します。
まず先にDockerfile
の内容です。
# IMPORT https://downloads.openwrt.org/releases/19.07.0/targets/x86/64/openwrt-19.07.0-x86-64-generic-rootfs.tar.gz
FROM scratch
ADD imports/openwrt-19.07.0-x86-64-generic-rootfs.tar.gz /
CMD /bin/sh
#IMPORT
で始まる行を参照し、そのURLからファイルをダウンロードしてimports
ディレクトリに保存するという処理をhooks/pre_build
で行っています。(マルチステージビルドの事も考えて#IMPORT
は複数記述できるようにしています。)
# !/bin/sh -eu
while read -r cmd path; do
[ "$cmd" = "#IMPORT" ] || continue
curl -vsSfL "$path" -o "imports/${path##*/}"
done < "$DOCKERFILE_PATH"
フックについて
フックではファイルをダウンロードするだけでなくapt-get
も使用できたので自由度はかなり高いです。ディストリは現時点ではUbuntu 16.04 xenialが使われていました。フックを利用することで複雑なビルドでもAutomated Buildsにすることができるでしょう。