🤖

🤖

:gijutsu_burogu:

DockerイメージのビルドをBuildKitで並列実行し高速化する

なぜ、ビルドを早くする

  • デプロイ時間の短縮
  • AutoScaling 等でのインスタンスの追加時間の短縮
  • CI のビルド時間が短縮

どう、ビルドを早くする

  • 並列性を上げる
  • ビルドキャッシュを効かせる

並列性

本記事では、並列性のみに触れる。

BuildKit を使用する

Docker 18.09 のリリースにおいて行われたビルド機能の拡張は、ビルドアーキテクチャーの総見直しにより必要となる機能を導入しています。 BuildKit を統合したことによって、処理性能、ストレージ管理、ツール機能、セキュリティのどれをとっても改善が見られるはずです。 https://matsuand.github.io/docs.docker.jp.onthefly/develop/develop-images/build_enhancements/

$ DOCKER_BUILDKIT=1 docker build .のように環境変数にセットすることで Builtkit を利用したビルドをすることができる。 また、AWS CodeBuildでもBuildKitをサポートしている。

簡単な例

簡単な例で確かめてみる。 以下のDockerfileに対して、DOCKER_BUILDKIT=1 docker build .を実行すると、① が同時に実行される。

FROM alpine as test1
RUN sleep 1 # ①

FROM alpine as test2
RUN sleep 2 # ①

FROM alpine as test3
RUN sleep 3 # ①

FROM alpine as test4
RUN sleep 4 # ①

FROM alpine
RUN sleep 5 # ①

COPY --from=test1 /bin /bin
COPY --from=test2 /bin /bin
COPY --from=test3 /bin /bin
COPY --from=test4 /bin /bin

RUN sleep 6

前記事の例

修正前

Go製CLIツールを使うDockerイメージをダイエットしてみた - 🤖

前記事では、イメージサイズを意識したDockerfileを書くことはできたが、実行時間については意識していなかった。 前記事のDockerfile では Alpine のステージの最初で Builder のステージに依存しているため、並列実行を行うことができない。

FROM golang as builder

RUN CGO_ENABLED=0 go get github.com/tenntenn/qiitaexporter github.com/x-motemen/blogsync

FROM alpine

# ここで既にbuilderステージに依存しており並列実行できない
COPY --from=builder /go/bin/qiitaexporter /bin/qiitaexporter
COPY --from=builder /go/bin/blogsync /bin/blogsync

RUN apk --no-cache add libintl && \
    apk --no-cache add --virtual .gettext gettext && \
    cp /usr/bin/envsubst /usr/local/bin/envsubst && \
    apk del .gettext

WORKDIR /Documents
COPY blogsync.template /Documents
COPY setup.sh /Documents

RUN mkdir -p ~/.config/blogsync
COPY config.yaml.tmp /root/.config/blogsync

RUN chmod +x setup.sh
ENTRYPOINT ./setup.sh
修正後

修正後の Dockerfile では、① で示された三箇所は並列実行される。 しかしgo getを二つに分け並列処理を行ったが、ビルド時間を大きく減らすことはなかった。 それはおそらく、go get github.com/tenntenn/qiitaexporter github.com/x-motemen/blogsyncが内部では並列実行されているからではと思った。

FROM golang as qiitaexporter-builder
RUN CGO_ENABLED=0 go get github.com/tenntenn/qiitaexporter # ①

FROM golang as blogsync-builder
RUN CGO_ENABLED=0 go get github.com/x-motemen/blogsync # ①

FROM alpine

# ①Start
WORKDIR /Documents 
COPY blogsync.template /Documents
COPY setup.sh /Documents
RUN chmod +x setup.sh

RUN mkdir -p ~/.config/blogsync
COPY config.yaml.tmp /root/.config/blogsync

RUN apk --no-cache add libintl && \
    apk --no-cache add --virtual .gettext gettext && \
    cp /usr/bin/envsubst /usr/local/bin/envsubst && \
    apk del .gettext 
# ①End

# 以下はbuilderステージに依存しているため並列実行されない
COPY --from=qiitaexporter-builder /go/bin/qiitaexporter /bin/qiitaexporter
COPY --from=blogsync-builder /go/bin/blogsync /bin/blogsync

ENTRYPOINT ./setup.sh

おわりに

並列性の具体例を紹介していると、記事として分量が多くなったため、ビルド時のキャッシュについては今度改めて紹介する。

参考

qiita.com