Masteries

技術的なことや仕事に関することを書いていきます.

GitHub Actionsでactions/cacheを使わずS3で必要なファイルをキャッシュする

papix.hatenablog.com

先日, 「GitHub Actionsの知見ご紹介」でactions/cacheが意図通り動作しないケースがある, ということをご紹介しました. 今回は, actions/cacheの代わりにS3を使ってキャッシュを実現する方法をご紹介します. ...まあ, ご紹介しますというか, まあ普通にawsコマンドを使って必要なファイルをS3に置いたり引っ張ってきたりするだけなのですが.

ここでは, 例としてcpanfile.snapshotを元にして, Perlのモジュールがインストールされるディレクトリ(local)をS3でキャッシュする例をご紹介します. Node.jsであれば, cpanfile.snapshotpackage.json, localnode_modulesと読み替えればOKです.

前提として, 適当なS3バケット(以下の例では, sample-cache-bucketという名前としました)を用意しておいてください. また, S3への読み書きが可能なIAMアカウントを用意して, そのAccess Key IDとSecret Access KeyをGitHubのSecrets(リポジトリのSettingsSecrets)で, それぞれAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYという名前で登録しておく必要があります.

env:
  cache-bucket: sample-cache-bucket
  cache-directory: perl

jobs:
  prepare:
    runs-on: ubuntu-latest
    steps:

    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-1

    - name: Fetch cached perl modules
      run: |
        if [[ $(aws s3 ls s3://${{ env.cache-bucket }}/${{ env.cache-directory }}/${{ hashFiles('cpanfile.snapshot') }}.tar.gz | wc -l) > 0 ]]; then
          aws s3 cp --no-progress s3://${{ env.cache-bucket }}/${{ env.cache-directory }}/${{ hashFiles('cpanfile.snapshot') }}.tar.gz perl-modules.tar.gz
          tar -zxf perl-modules.tar.gz
        else
          echo "Cache not found"
        fi

    # ここで必要に応じてライブラリのインストール(carton install, npm installなど)を実行する

    - name: Cache perl modules
      run: |
        if [[ $(aws s3 ls s3://${{ env.cache-bucket }}/${{ env.cache-directory }}/${{ hashFiles('cpanfile.snapshot') }}.tar.gz | wc -l) > 0 ]]; then
          echo "Cache already exists"
        else
          tar -zcf perl-modules.tar.gz local
          aws s3 cp --no-progress perl-modules.tar.gz s3://${{ env.cache-bucket }}/${{ env.cache-directory }}/${{ hashFiles('cpanfile.snapshot') }}.tar.gz
        fi

...少なくとも, runs-onubuntu-latestの場合, デフォルトでawsコマンドが/usr/local/bin/awsに用意されています. 2020年5月現在バージョンは1.18.37となっているようで, 最新の2系ではないのですが, 例なので今回はこれをそのままを使うことにしましょう(より新しいバージョンのawsコマンドが必要であれば, 別途インストールしてください).

後はaws-actions/configure-aws-credentials@v1を利用して適切にAWSアカウントの認証(ここでSecretsで設定したAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYを利用します)をした上で, awsコマンドを使って S3からファイルを撮ってくる/ファイルを設置するだけです.

これで,

  • cpanfile.snapshotに対応するキャッシュがあれば...
    • S3からこれをダウンロードして利用する
    • 必要なライブラリは全てキャッシュから復元されているはずなので, ライブラリのインストールをしても差分なしですぐに完了する
  • cpanfile.snapshotが書き換えられるなどしており, 対応するキャッシュがないなら...
    • ライブラリのインストールを実行して, その結果を最後にS3にアップロードする
    • 2回目以降はキャッシュが利用されるようになる

...という挙動が実現できます.

S3を使えば, 前のエントリで紹介したactions/cacheのハマりポイントを意識する必要はありませんし(2〜3週間運用していますが, キャッシュの取得にミスした事例はほぼほぼなくなった), 必要があればAWSのWebコンソールなどを使って, キャッシュを削除したりできるので, 適切なS3バケットが用意できるのであればむしろこちらの方が便利なのでは...? という気がしています.

一方で, 当然ながら別途S3の料金が必要になるのはデメリットですね. なるべく料金を節約できるよう, ライフサイクルルールを設定するなどしつつ利用すると良さそうです.