ハロー!フロントエンドのテックリードをやってます、みゅーとん(@_mew_ton)です。
今回は小ネタです。
最近 GitHub Actions の使いすぎで料金がかかりすぎてしまい、情シスから怒られてしまったので、節約のための対策をやってみました。
TL;DR
3行でまとめ
- renovate の設定で labels を活用しよう
- GitHub Actions 側で、label を条件にすると、実行する Actions を制限できる
- (1行余り)
本記事で解説しないこと
- renovate とはなにか
- GitHub Actions とはなにか
- GitHub Actions の実行条件の記述方法
背景
うちで管理している GitHub の Repository では、 Renovate を導入し、依存するライブラリ・パッケージのバージョンアップを自動で行うようにしています。
また、Pull Request を作れば、自動でテストや lint が動作するように GitHub Actions を組んでいました。
この2つが悪く噛み合ってしまったのが、GitHub Actions の使いすぎの原因の一つとなってしまったようです。
Renovate タスクの実行頻度を上げ、ひたすらバージョン更新の実施しようとしており、これによりそれぞれの PullRequest で GitHub Actions がひたすら回っていました。
GitHub Actions は実行するマシンのOS、スペック、実行時間で料金が決まります。最低額となるスペックの選択をしていても、実行時間が圧倒的に多ければ、当然予算を食いつぶしてしまいます。
そこで、 GitHub Actions の実行時間を少なくする対応が求められました。
要件
うちの repository では、 renovate は以下のパッケージについてバージョンアップのための PullRequest を作成します
- node_modules
- yarn
- node
- GitHub Actions
- pre-commiit
- docker image
また、 node_modules の内訳として、製品の品質担保に直接作用する / しないパッケージがあり、ざっくり以下のようになっています。
- vite, typescript, nuxt .. 製品の品質に直接影響する (ビルドまわりのため)
- vitest, storybook .. 製品の品質に直接影響する (テストコードとしての利用のため)
- eslint, prettier .. 製品の品質に直接影響しない (コードの整形やコーディングルールのため)
対応する、実行すべき最小のタスクを考えると以下のようになりました。
- vite, typescript, nuxt .. テスト実行、ビルドがコケないか確認したい
- vitest, storybook .. テスト実行のみ
- eslint, prettier .. コード解析のみ
Renovate による PullRequest に自動でラベルをつける
renovate の config にて、 label をつけることができます。以下は renovate config の必要な部分だけ掲載しています。
{ "$schema": "https://docs.renovatebot.com/renovate-schema.json", // すべての renovate による Pull Request に "renovate" ラベルがつく "labels": ["renovate"], "npm": { // npm package update 関連の Pull Request に "renovate:npm" ラベルがつく "labels": ["renovate", "renovate:npm"], "packageRules": [ { "groupName": "eslint and prettier", "matchPackageNames": ["eslint", "prettier"], "matchPackagePrefixes": ["eslint-", "@eslint", "prettier-"], // パターンにマッチする package update の Pull Request に以下のラベルがつく "labels": ["renovate", "renovate:npm", "renovate:lint"] } ] } }
labels パラメータで Pull Request に追加したいラベルを設定することが出来ます。
また、パッケージの名前ごとにラベルを分けたい場合は、 packageRules を使用します。
ここでは、 eslint, prettier 系のライブラリが対象である場合に renovate:linter
ラベルが追加されます。
packageRules を指定すると、 renovate が PullRequest を作る際に、マッチするライブラリをひとつの PR にまとめてくれます。また、今回の設定では同時にラベルがつきます。
実際の Pull Request をみると、ちゃんとラベルがついていることがわかります。
ラベルの有無で、実行する GitHub Actions を制限する
GitHub Actions のほうで、制御した job に以下のように記載することで、ラベルの有無を実行条件にすることができます。
--- name: Lint Code Base (ESLint) run-name: "Lint code base on \"${{ github.event.pull_request.title }}\" by ${{ github.actor }}" jobs: eslint: name: "Lint: ESLint" # lint 系パッケージの更新か、renovate 以外での Pull Request 作成の場合実施する if: | (contains(github.event.pull_request.labels.*.name, 'renovate') && contains(github.event.pull_request.labels.*.name, 'renovate:lint')) || !contains(github.event.pull_request.labels.*.name, 'renovate') runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ./.github/actions/init-node - name: eslint uses: reviewdog/action-eslint@v1 with: eslint_flags: '--cache --ext .ts,.tsx,.js,.jsx,.mdx,.vue .' github_token: ${{ secrets.GITHUB_TOKEN }}
lint 系の場合に テストを実施したくないので、テスト実行の条件には、以下のように記載します。
--- name: Test run-name: "Test on \"${{ github.event.pull_request.title }}\" by ${{ github.actor }}" jobs: test: if: | (contains(github.event.pull_request.labels.*.name, 'renovate') && contains(github.event.pull_request.labels.*.name, 'renovate:lint')) || !contains(github.event.pull_request.labels.*.name, 'renovate')
まとめ
かなりニッチなネタですが、renovate を使って package の update を高い頻度で実施する場合に効いてくる話かと思います。
GitHub Actions はどうしても愚直な実装になるから大変ですが、こういった細かい節約の対応を積み重ねていくのが大切なのでしょうか。
余談
実は、弊社で使っている renovate config は public repository で管理しています。
今回の記事の内容もちゃんと反映されています。気になる方は見てみてください。
株式会社hacomonoでは一緒に働く仲間を募集しています!
採用情報や採用ウィッシュリストも是非ご覧ください!