🏎️

GitHub Actionsの実行時間を短縮!カスタムイメージでapt-getの遅延問題を解決しよう

に公開

はじめに

GitHub Actionsでワークフローを実行していると、「あれ、apt-get installが妙に遅いな…」なんて感じたことはありませんか?普段なら10〜15秒くらいで終わるはずのパッケージインストールが、なぜか1分以上かかってしまう…。地味にストレスですよね。また、privateリポジトリで実行している場合には、ワークフローの実行時間が増えると現在のプランの上限にその分だけ近づきやすくなってしまいます。その点から考えても極力実行時間が伸びないようにしたいはずです。

この記事では、そんなapt-getの気まぐれな実行時間にサヨナラして、カスタムDockerイメージを使ってワークフローの実行時間を安定させる方法をご紹介します。

問題点:apt-getの実行時間が安定しない…

GitHub Actionsのランナーでパッケージをインストールするとき、apt-get installの実行時間が結構ブレちゃうことがあります。特にたくさんのパッケージを入れたり、CI/CDパイプラインを頻繁に回したりしていると、この遅延はじわじわと効いてきます。

今回は、例としてsocatというツールをインストールするワークフローで、どれくらい時間が変わるのか見てみました。

どうやって比べたか?

2つのやり方で実行時間を比べてみました。

  1. いつものやり方: ワークフローの中でapt-get updateしてapt-get install socatを実行する。
  2. カスタムイメージ作戦: socatをあらかじめインストールしておいた自作のDockerイメージを使う。

それぞれのやり方でワークフローを10回ずつ実行して、socatコマンドが使えるようになるまでの時間を測ってみました。

いつものやり方(apt-getを使う)

こんな感じのワークフローですね。

name: Socat Custom normal install Workflow

on:
  push:
    branches: [ main ]
  workflow_dispatch:

jobs:
  run-with-custom-image:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install socat
        run: |
            echo "Installing socat..."
            sudo apt-get update
            sudo apt-get install -y socat
            echo "Socat installation complete!"

      - name: Verify socat installation
        run: |
            echo "Checking socat version..."
            socat -V
            echo "Checking socat path..."
            which socat
            echo "Socat is available!"

(補足: こちらではinstall socatにかかった時間を測定)

カスタムイメージを使用する

こちらではcontainerディレクティブを使って自作イメージを指定しています。

name: Socat Custom Image Workflow

on:
  push:
    branches: [ main ]
  workflow_dispatch:

jobs:
  run-with-custom-image:
    runs-on: ubuntu-latest

    container:
      image: ghcr.io/yuukilion/my-socat-image:latest
      credentials:
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Verify socat installation
        run: |
          echo "Checking socat version..."
          socat -V
          echo "Checking socat path..."
          which socat
          echo "Socat is available!"

(補足: こちらでは、コンテナがセットアップされ、最初のステップ (Checkout code) が実行されるまでの時間を「初期化時間」として測定)

今回使用したカスタムイメージ

FROM ubuntu:latest

# apt-get update でパッケージリストを更新し、socat をインストール
# -y オプションで確認なしでインストールを実行
# 最後の行は、キャッシュをクリーンアップしてイメージサイズを小さくするためのもの
RUN apt-get update && \
    apt-get install -y socat && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

ポイントはapt-get installの後にapt-get cleanとrm -rf /var/lib/apt/lists/*を実行しているところ。これでインストール時に使った一時ファイルとかキャッシュを消して、イメージサイズを小さく保つことができます。

このDockerfileを使ってイメージをビルドして、GitHub Container Registry(ghcr.io)みたいなレジストリにプッシュしておけば、ワークフローからいつでも呼び出せます。

結果発表!

さて、それぞれのやり方で10回ずつ実行した結果を見てみましょう!

いつものやり方(apt-get)のインストール時間

ここでは Install socat ステップにかかった時間を計測しました。

実行 インストール時間(秒)
1 11
2 15
3 96(1分36秒)
4 16
5 13
6 14
7 13
8 15
9 16
10 17
平均 22.6秒
中央値 15.0秒

見てください、この実行#3!なんと1分半以上かかっています…。他は10秒台なのに、すごい差ですよね。これがapt-getの気まぐれなところ。

カスタムイメージ作戦のコンテナ初期化時間

こっちは、コンテナが準備できて最初のステップが始まるまでの時間です。

実行 インストール時間(秒)
1 4
2 3
3 3
4 3
5 4
6 4
7 3
8 3
9 3
10 3
平均 3.3秒
中央値 3.0秒

めちゃくちゃ速いし、安定してる!毎回3〜4秒で安定しています。

結果を分析

この結果からはっきり分かることがありますね。

  • めっちゃ速くなった!: カスタムイメージを使うと、平均で 19.3秒(約85%)も短縮 できました!
  • 時間が安定した!: いつものやり方だと11秒〜96秒とバラバラだったのが、カスタムイメージなら 3〜4秒で安定。安心感が違います。
  • 最悪のケースが劇的に改善: いつものやり方で一番遅かった96秒と比べると、カスタムイメージ(最悪4秒)は 約96%も短縮。あの異常な待ち時間がなくなりました!
  • 予測しやすくなった: 実行時間のブレがほぼないので、ワークフロー全体がどれくらいで終わるか、かなり正確に見積もれるようになります。

気をつけること・おすすめのやり方
カスタムイメージを使う上で、ちょっとだけ気にしておきたいことやおすすめのやり方です。

  • イメージサイズは小さく: Dockerfileに書いたように、本当に必要なものだけ入れて、インストール後にはキャッシュ削除 (apt-get cleanなど) を忘れずに!イメージが軽いと起動も速くなります。
  • セキュリティも大事: ベースイメージやインストールしたパッケージは、定期的に最新版に更新して、セキュリティホールがないかチェックしましょう。
  • 認証情報は安全に: GitHub Container Registryを使うなら、ワークフローのsecrets.GITHUB_TOKENを使うのが定石。個人のトークンをベタ書きしないように注意!

まとめ

GitHub Actionsのワークフローでapt-get installを使っているなら、代わりに必要なツールをあらかじめ入れたカスタムDockerイメージを使うことで、実行時間をめちゃくちゃ短縮できて、しかも安定させられる、というお話でした。
今回の僕の検証だと、平均で85%短縮、あのイライラする一番遅いケース(96秒!)と比べると96%も改善しました。これは大きい!
特にすごいのは、たまに起きてた「なんでこんなに時間かかってるの!?」っていう極端な遅延が完全になくなったこと。これでCI/CDパイプラインの実行時間が読みやすくなって、開発全体のスピードアップにも繋がりそうですね。
こんなケースでは、特にカスタムイメージ作戦が効果を発揮すると思います。

  • CI/CDパイプラインを頻繁に回している
  • ワークフローで入れるパッケージがいくつかある
  • 実行時間がある程度一定じゃないと困る

最初にカスタムイメージを作ったり管理したりする手間は少しかかりますが、その後の実行時間短縮と安定性アップを考えれば、長い目で見ると絶対お得だと思います。
皆さんのGitHub Actionsワークフローも、カスタムイメージを使って、もっと快適にしてみませんか?
この記事が少しでもお役に立てたら嬉しいです!

Discussion