Software Design 202407
Github Actions
基本
- 料金
- パブリックリポジトリでは無料
- プライベートリポジトリでは有料だが無料枠あり
- Windows は Linux の 2 倍、Mac は 10 倍
- 手軽さ
- Webhook の設定が不要なので簡単
- イベント / ワークフローをキックする
- ワークフロー / 1 つ以上のジョブを実行する自動化されたプロセス
- ジョブ / 同一のランナー内で実行される一連のステップのまとまり / 逆に言えばジョブが違えば全く異なるまっさらな環境で実行される
- ステップ / 最小の単位 / 以下の 2 つが可能
run
によるスクリプトの実行uses
によるアクション(事前定義された処理のプリセット)の実行- このとき
with
でパラメータを渡すことができる
- このとき
- ステップ / 最小の単位 / 以下の 2 つが可能
- ジョブ / 同一のランナー内で実行される一連のステップのまとまり / 逆に言えばジョブが違えば全く異なるまっさらな環境で実行される
- ワークフロー / 1 つ以上のジョブを実行する自動化されたプロセス
ハンズオン
${{}}
という書式は、GihHub Actions 上で利用できる変数にアクセスするための書式- e.g.
${{ github.actor }}
で実行した Github のユーザー名を取得できる - e.g.
${{ secrets.GITHUB_TOKEN }}
で GitHub Actions で使えるデフォルトのトークンを取得できる
- e.g.
- 以下ような用途には専用の actions が用意されているのでそれを使うと吉
- docker コマンドを使った認証
- docker コマンドを使ったレジストリへのプッシュ
- Amazon ECS や Google Cloud Run などのデプロイ
実運用
- コンテキスト
- github コンテキスト
- ワークフローをトリガーしたイベントやリポジトリに関する情報を持つ
- ブランチ名
${{ github.head_ref }}
- PR の番号
${{ github.event.pull_request.number }}
- PR の作成者
${{ github.event.pull_request.user.login }}
- ブランチ名
- ワークフローをトリガーしたイベントやリポジトリに関する情報を持つ
- job, steps コンテキスト
- 現在のジョブやステップに関する情報を持つ
- ジョブの実行結果
${{ job.status }}
- ステップの実行結果
${{ steps.<step-id>.conclusion }}
- ジョブの実行結果
- 現在のジョブやステップに関する情報を持つ
- vars, secrets
- あらかじめリポジトリや Organization に登録した、変数やシークレット情報
${{ vars.SOME_VALUE }}
${{ secrets.SOME_SECRET }}
- vars と secrets の違いは、secrets はログで
*
でマスクされる点
- あらかじめリポジトリや Organization に登録した、変数やシークレット情報
- github コンテキスト
- アーティファクト
- 成果物を保存するための仕組み
- 専用の action が用意されている
- 複数のジョブ間でのデータの受け渡しのためや、人間が結果を利用するために使う
- 複数 job の順番制御
needs
に依存先のジョブ名を書くことで行う
- 成否による処理分岐
- ステップやジョブに
if: ${{ always() }}
を指定することで、前段の処理が失敗しても必ず処理が実行されるようになる - その他、成功時のみ実行する
if: ${{ success() }}
、失敗時のみ実行するif: ${{ failure() }}
もある
- ステップやジョブに
- キャッシュ
actions/setup-***
などにおいて、キャッシュを有効にするオプションが用意されているactions/cache
を使うことで、任意のフォルダを自由にキャッシュすることも可能- この場合、key の設定には注意。ファイル のハッシュに加えて OS の種類を含める必要がある場合もある。
- トリガーの種類
- label トリガー
- コストが高い処理について、手動でトリガーをかけるときなどに使う
- スケジュール実行
- バッチ処理や、不要リソースの定期削除などに使う
- 最小間隔は 5 分
- 必ずその時間に実行されるわけではなくベストエフォートなので、確実な実行が必要であれば自前でスケジューラを立てて、workflow を API を介して dispatch するなどの方法が必要
- 手動トリガー(workflow_dispatch)
- Github の Web 画面や API を介して、手動実行が可能になる。手元から
gh workflow run
も可能になる。 - 対象のブランチを指定できる。また、あらかじめ指定したパラメータも指定できる。
- 通常のトリガーと併用可能なので、転ばぬ先の杖として使える
- Github の Web 画面や API を介して、手動実行が可能になる。手元から
- label トリガー
- トリガーのフィルタ
- 特定のブランチでのみ実行する
on.push.branches
- 特定のフォルダ内に変更があったときのみ実行する
on.pull_request.paths
- ファイルのフォルダに加え、ワークフローの yaml も含めないと、ワークフロー自体の変更時にトリガーされないので注意
- 特定のブランチでのみ実行する
- 権限
GITHUB_TOKEN
- GihHub Actions が GitHub の特定リソースを扱うための権限
- 特に設定無しで使える
- contents, packages, metadata の 3 つがある
- contents: read(規定), write, none
- packages: read(規定), write, none
- metadata: 常に読み取り許可で固定
- 明示する場合は、contents と packages の両方を列挙しないと書かなかったものは none になるので注意
- OIDC を用いたクラウドサービス連携
- ワークフロー実行時に、GitHub から発行された OIDC トークンをクラウドプロバイダーに投げ、アクセストークンを得る方法
- クラウド側では OIDC トークンの subject claim を見て、許可を判断する
- subject claim の例:
repo:<OWNER>/<REPO>:refs/heads/main
- subject claim の例:
- クラウド側では、事前に以下の設定を済ませておく必要がある
- 受け入れる subject claim の形式(≒ 対象のリポジトリとブランチ)
- 与える権限
- セキュリティ対策
- 特にパブリックなリポジトリではインジェクションに注意
- なるべく actions を使うこと
- 文字列をコンテキストから取る場合は、一度環境変数に入れてから使うなどの対策が必要
- 特にパブリックなリポジトリではインジェクションに注意
大規模開発での Actions の課題と解法
- コンテナを使う方法
- ジョブコンテナ
- ジョブを実行するコンテナ
runs-on
の階層でcontainer
を指定する
- サービスコンテナ
- ジョブの開始時に起動する任意のコンテナ
- DB を立ち上げてテストを実行する際などに使う
runs-on
の階層でservices
を指定する
- ジョブコンテナ
credentials
プロパティにレジストリの認証情報を書くことができる- docker のパブリックイメージを使う場合でも、pull rate limit を防ぐ意味で書いておくとよい
- ランナーの種類
- GitHub-hosted (larger) runner
- Self-hosted runner
- matrix strategy
- ジョブの実行を複数の変数の組み合わせで行うための機能
- ユースケース 1: テストの分割実行
- 例えば jest は shared オプションを使うことで並列実行が可能
- ユースケース 2: テストの動的実行
- JSON を入力として受け取れるので、前段のジョブで条件の組み合わせ一覧を JSON で生成し、それを使って後段で複数のテストを実行することが可能
- GITHUB_TOKEN の制約
- 別のワークフローの実行や、別のプライベートリポジトリへのアクセスはできない
- かといって PAT の利用は非推奨
- GitHub Apps の仕組みに乗る方法がよい(詳細はドキュメント参照)
- キャッシュ
- 上限は 10GB で、超えたら GitHub のお気持ちにより削除される
actions/cache/(save/restore)
を使うことで、キャッシュするしないをコントロールできる- 例えば Dependabot の PR ではキャッシュ読み込みはするけど保存はしないなどの設定はよい取り組み