Ponz Dev Log

ゆるくてマイペースな開発日記

BuildKitを使って docker build のビルド時間を半分以下にする

元ネタはAWS CodeBuildでBuildKitがサポートされたという話。

dev.classmethod.jp

BuildKitとは、Docker v18.06から搭載された "次世代 docker build" のようです。BuildKitを使わないよりも圧倒的にビルドパフォーマンスが高くなる&セキュアにビルドできるようなので試してみました。

BuildKit自体の説明は上の記事でも紹介されていたSlideShareが一番簡潔で分かりやすいので是非見ていただければと。

www.slideshare.net

実践

今回は以下のようなJavaのコードをGradleでJarに固めることを試します。 やっていることはSlackのWebhook URLにUUIDをメッセージとして投げつけているだけです。

package net.ponzmild;

import java.io.IOException;
import java.util.UUID;
import net.ponzmild.client.SlackClient;

/**
 * 処理のエントリーポイント
 * @author ponzmild
 */
public class Handler {

  public static void main(String[] args) {

    String uuid = UUID.randomUUID().toString();
    System.out.println("Message UUID is " + uuid);

    String webhookUrl = System.getenv("SLACK_URL");
    if (webhookUrl == null || webhookUrl.isEmpty()) {
      System.out.println("Environment variable 'SLACK_URL' doesn't set or is empty.");
      System.exit(1);
    }

    SlackClient slackClient = new SlackClient(webhookUrl);
    try {
      String responseStr = slackClient.postMsg(uuid);
      System.out.println("Response is " + responseStr);
    } catch (IOException e) {
      e.printStackTrace();
      System.exit(1);
    }
  }

}

また、Dockerfileは以下のようにマルチステージビルドで何もしなくても比較的高速でビルドされるようにします。

FROM openjdk:8-jdk-alpine as build
COPY . /usr
WORKDIR /usr
RUN ./gradlew build

FROM openjdk:8-jre-alpine
COPY --from=build /usr/build/libs/dck-slack-messenger-1.0.jar /app/
ENV SLACK_URL https://hooks.slack.com/services/xxxxxx/yyyyyyyyy/zzzzzzzzzzzz
CMD java -jar /app/dck-slack-messenger-1.0.jar

BuildKitを使わない場合

まずは BuildKitを使わないdocker buildから。以下のように見たことあるようなログが出ますね。(ログが長かったのでGradleのビルド部分しか見えませんが...) ビルド所要時間は 約90秒 でした。

f:id:accelerk:20190109015058p:plain
BuildKitを使わない場合の docker build

BuildKitを使った場合

お次は BuildKitを使った場合です。 BuildKitの使い方は簡単で、ターミナル上で export DOCKER_BUILDKIT=1 をセットするだけ!ビルドしてみましょう。

f:id:accelerk:20190109015322p:plain
BuildKitを使った場合の docker build

おお!全然ログが違いますね。。。ビルド時間は 41秒 !! BuildKitを使わない場合の半分以下じゃん! それと自分の設定によるものかもしれませんが、ログ出力の観点では以下のような違いもありました。

  • 各ステップの所要時間が出力されるようになった。上の画像の右端に1/10秒単位で吐かれていますね。
  • Dockerfileで指定した EVN がログに出力されなくなった。
  • Gradleのビルド途中経過のログが一切出力されなくなった。
  • マルチステージビルドの場合は、ステージ名も出力されるようになった。

環境変数がログに出なくなったのは個人的には嬉しいです。デバッグしづらいかもしれませんが、秘密鍵とかトークンがそのままログに出るとセキュアではないですしね。

AWS以外でもDockerのバージョンさえ満たしていれば、他のクラウドやCIサービスで大いに活用できそうです。CI時間が長いとお困りの方は使ってみてはいかかでしょうか?