GitHub Actionsをpush・PR・手動実行で使い分ける【GitHub Actions実践記録 #2】
はじめに
こんにちは。
なかのひとカンパニーの archer です。
前回は、GitHub Actionsの基本として、
- Workflow
- Job
- Step
- Action
- Runner
について整理しました。
今回は、
Workflowをいつ動かすか
について書きます。
GitHub Actionsを使い始めたころは、
on:
push:
としておけば、とりあえず動くので便利でした。
ただ、使うWorkflowが増えてくると、
「この処理、本当に毎回pushするたびに必要なのか」
と思うようになります。
PRで確認したい処理。
mainへ入ったときだけ動かしたい処理。
必要なときだけ手動で動かしたい処理。
毎日決まった時間に動かしたい処理。
それぞれ目的が違います。
今回は、よく使うTriggerを整理します。
on がWorkflowの入口
GitHub Actionsでは、
on:
でWorkflowを実行するきっかけを指定します。
たとえば、
on:
push:
ならpushされたとき。
on:
pull_request:
ならPull Requestに関するイベントが発生したときです。
自分の中では、
Workflowで何をするかを考える前に、いつ動かすべきかを考える
ようにしています。
pushで実行する
一番分かりやすいのが push です。
on:
push:
これならRepositoryへpushされたときにWorkflowが実行されます。
ただし、このままだとさまざまなブランチへのpushで動きます。
本番デプロイなら、
on:
push:
branches:
- main
のようにmainへ限定します。
たとえば、
featureブランチへpush
↓
本番Deployしない
mainへpush
↓
本番Deploy
という形です。
Cloudflare連載で作ったDeploy Workflowも、この考え方でした。
pushは何に向いているか
自分の場合、push は、
mainへのMerge後
↓
本番Deploy
のような用途で使うことが多いです。
ほかにも、
mainへ入ったコードに対する最終Build
などにも使えます。
逆に、
コードを書く
↓
何度もpush
する作業ブランチですべて重いWorkflowを動かすと、無駄な実行も増えます。
そのため、
どのブランチへのpushで動かすのか
まで考えるようにしています。
Pull Requestで実行する
コードをmainへ入れる前に確認したい処理には、
on:
pull_request:
を使えます。
たとえば、
on:
pull_request:
branches:
- main
とすると、mainを対象とするPull RequestでWorkflowを実行できます。
ここで、
lint
test
build
などを実行します。
流れとしては、
featureブランチ
↓
Pull Request
↓
CI
↓
レビュー
↓
Merge
です。
つまり、
問題がないことを確認してからmainへ入れる
ためのWorkflowです。
pushとPRの役割を分ける
自分がよく使うのは、
Pull Request
→ 確認
mainへのpush
→ Deploy
という分け方です。
たとえば、
ci.yml
on:
pull_request:
branches:
- main
ここでは、
lint
test
build
を実行します。
deploy.yml
on:
push:
branches:
- main
こちらでは、
本番Deploy
を実行します。
役割としては、
PR
↓
この変更を入れて大丈夫か確認する
main
↓
確認済みの変更を本番へ出す
となります。
Workflowを一つにまとめることもできますが、自分は役割が違うなら分ける方が理解しやすいと感じています。
手動で実行する
自動化したいけれど、
勝手には動いてほしくない
処理もあります。
そこで使えるのが、
on:
workflow_dispatch:
です。
これを設定すると、GitHub上からWorkflowを手動実行できます。
たとえば、
データ再取得
本番データ更新
一時的なメンテナンス
特定処理の再実行
などです。
自分の場合、
実行すると本番データに影響する処理
は、何でも自動化するより手動実行にした方がよい場合があると考えています。
手動実行時に値を入力する
workflow_dispatch では、実行時の入力値も定義できます。
たとえば、
on:
workflow_dispatch:
inputs:
target:
description: "実行対象"
required: true
type: choice
options:
- staging
- production
のようにできます。
Workflowでは、
${{ inputs.target }}
として利用できます。
これなら、
Run workflow
↓
targetを選択
↓
実行
という操作ができます。
単純な手動実行よりも、何を実行するのか明示しやすくなります。
gh から手動実行する
GitHubの画面だけでなく、GitHub CLIからもWorkflowを実行できます。
たとえば、
gh workflow run deploy.yml
です。
入力値があるなら、
gh workflow run deploy.yml \
-f target=staging
のように渡せます。
自分は普段 gh を使うことが多いので、Workflowもターミナルから実行できるのは便利です。
定期実行する
決まった時間に動かしたい場合は、
on:
schedule:
を使います。
たとえば、
on:
schedule:
- cron: "0 9 * * *"
timezone: "Asia/Tokyo"
のように設定できます。
用途としては、
定期データ取得
古いデータの削除
日次バッチ
定期チェック
などです。
Webサービスを作っていると、
ユーザーからのアクセスとは関係なく、
定期的に実行したい処理
も出てきます。
そういう場合に便利です。
定期処理は「毎時0分」を避ける
定期Workflowでは、一つ注意点があります。
指定時刻ぴったりに必ず開始するとは限りません。
GitHub Actions側が混雑している場合、実行が遅れることがあります。
特に毎時ちょうどは負荷が高くなりやすいため、
cron: "0 * * * *"
より、
cron: "17 * * * *"
のように少しずらす考え方もあります。
「9:00:00ちょうどに絶対実行されないと困る」
という処理なら、GitHub Actionsのscheduleだけに依存する設計は考え直した方がよさそうです。
一つのWorkflowに複数Triggerも書ける
もちろん、
on:
push:
branches:
- main
workflow_dispatch:
のように複数指定することもできます。
この場合、
mainへpush
または
手動実行
で同じWorkflowが動きます。
たとえば、
通常
↓
mainへのMergeで自動Deploy
障害対応
↓
必要なら手動で再Deploy
という使い方もできます。
Pathでさらに絞る
Monorepoなどでは、
「このファイルを変更したときだけWorkflowを動かしたい」
ということがあります。
たとえば、
on:
push:
branches:
- main
paths:
- "app/**"
とすれば、
app/
配下に関係する変更があった場合だけ実行できます。
逆に、
paths-ignore:
- "docs/**"
として、
README修正だけならCIしない
ということもできます。
Workflowの実行時間を減らしたい場合にも使えます。
「自動化できる」と「自動化すべき」は違う
GitHub Actionsを使っていると、
push
↓
test
↓
DB Migration
↓
Deploy
↓
本番データ更新
まで全部自動化できます。
技術的には便利です。
ただ、
自動化できるから、自動化する
では少し危ないと思っています。
たとえば、
lint
test
build
は自動で問題ありません。
一方、
大量の本番データ更新
破壊的Migration
外部サービスへの大量リクエスト
などは、
workflow_dispatch
で明示的に実行する方がよい場合があります。
自動化すると安全になる処理もあれば、
危険な処理が高速で実行されるだけ
の場合もあります。
今の使い分け
現在の自分の考え方をかなり単純化すると、
| Trigger | 用途 |
|---|---|
pull_request |
lint / test / build |
push + main |
Deploy |
workflow_dispatch |
本番操作・再実行 |
schedule |
定期処理 |
という感じです。
つまり、
コードの確認
↓
pull_request
公開
↓
push
人間の判断が必要
↓
workflow_dispatch
時間で動かす
↓
schedule
と考えています。
もちろんRepositoryによって変わります。
大事なのは、
とりあえずpushではなく、処理の目的からTriggerを決めること
だと思っています。
不要なWorkflowを減らす
Triggerを整理すると、GitHub Actionsの実行回数も減らせます。
たとえば、
README修正
↓
lint
test
build
deploy
まで毎回動かす必要があるか。
Pull Requestですでにtestしたのに、
同じcommitに対して何度も同じ処理を実行していないか。
Workflowが増えてくると、
動かすことより、動かさない設計
も重要になります。
GitHub Actionsには利用時間や料金の考え方もあります。
無駄なWorkflowを減らすことは、
CIが速くなる
ログが見やすくなる
利用時間を減らせる
というメリットがあります。
まとめ
今回は、GitHub Actionsをいつ実行するかについて整理しました。
よく使うのは、
push
pull_request
workflow_dispatch
schedule
です。
自分の中では、
Pull Request
→ コードを確認する
mainへのpush
→ 本番へ出す
workflow_dispatch
→ 人間が実行を決める
schedule
→ 時間で動かす
と分けています。
GitHub Actionsを使い始めたころは、
on:
push:
で十分だと思っていました。
でもWorkflowが増えてくると、
何を自動化するかより、いつ自動化するか
もかなり重要でした。
必要なときだけ動かす。
危険な処理は人間が開始する。
定期処理はscheduleへ任せる。
Triggerを整理するだけでも、GitHub ActionsのWorkflowはかなり分かりやすくなります。
次回は、
GitHub ActionsのJobを分ける理由
について書きます。
lint、test、buildを一つのJobへ全部入れる場合と、別々のJobへ分ける場合で何が変わるのか、needs や並列実行も含めて整理する予定です。
