Closed14

GitHub CI/CD実践ガイドの感想メモ

ぱんだぱんだ

2章 GitHub Actionsの概念

  • GitHub Actionsは何かしらのトリガーで自動実行されるもののみと思い込んでいたがworkflow_dispatchを指定することで手動実行のワークフローを作成できる
  • 無理に自動化させようとして無駄に複雑になることがあったので手動実行のワークフローという引き出しが増えたのは嬉しい
  • cronによる定期実行も可能。昔やったことがあるがけっこう起動時間ずれた記憶があるが、やはりだいぶずれるらしいので厳密な定期実行は避けたほうが無難。逆に1日一回みたいなざっくりな定期実行なら問題ない
  • GitHub Actionsはランナーはジョブを起動するときに開始し終了時に破棄される。そのため、毎回クリーンな環境でジョブを実行できる。この特性をエフェメラルと言う。
  • 同じジョブ内ではステップ間でワークスペースを共有しているので前段のステップで作成したファイルを後続のステップで使うなどはできる。
  • パフォーマンスなどを考えるとキャッシュやアーティファクトを検討したほうがいいかもしれない

リソースの共有について

  • GitHub Actionsはランナー単位で実行環境が用意される
  • 実行環境はジョブ内の各ステップで共有のため前段で作成したファイルを後続のステップで使うなどはできる
  • ツールのインストールなどをするのであればキャッシュを使うことを検討するとパフォーマンスがよくなるかもしれない
  • ステップ間で出力された値を共有したいとかでれば$GITHUB_OUTPUTSkey=valueの形式で出力することで${{ steps.current.outputs.message }}のような形式で参照できる
  • ジョブをまたいでファイルを共有したい場合などにはアーティファクトが使用できる
ぱんだぱんだ

3章 ワークフロー構文の基礎

  • GitHub Actionsではいくつかのコンテキストが使えgihubコンテキストrunnerコンテキストなどがある。
  • デフォルトの環境変数はコンテキストをそのまま環境変数にしたもので、置き換えが可能
  • コンテキストの使用も一度環境変数に入れてから使用したほうがいい。これは後述のセキュリティ的な観点から

環境変数の扱い

  • GitHub Actionsの構文というかシェルの構文
  • $TEST${TEST}の違いについて
  • {}をつけた方が明示的に変数を区切れるので予期せぬ挙動を防げそう
  • 基本的には{}ありで環境変数を使っておいた方が無難そう
  • シェル以外の場所で環境変数を使いたい場合、${{ env.TEST }}のような形式で使える
  • ダブルクォーテーションで変数は囲っておかないと変数が展開されないことがある
  • なので基本的にはダブルクォーテーションで囲ったほうがいい
  • また、後半のセキュリティのところで出てくるがスクリプトインジェクションのように展開されることで良きせぬコマンドを実行してしまうこともあるので、基本的にはinputの値は一度環境変数に設定してから使うと良い

オブジェクトフィルター

  • コンテキスト参照の特殊記法
  • 配列やオブジェクトから指定したプロパティのみ抜き出し、配列を作成する
  • ${{ github.event.*.html_url }} のようにアスタリスクを使って書く
  • オブジェクトフィルターは関数と一緒に使われることが多い
  • jsonの組み込み関数と合わせて以下のように使ってみた
      - name: Output Json
        id: json
        run: echo "json=[{\"name\":\"user1\"},{\"name\":\"user2\"}]" >> "${GITHUB_OUTPUT}"

      - name: Json Function
        run: |
          echo "${NAMES}"
        env:
          NAMES: ${{ toJson(fromJson(steps.json.outputs.json).*.name) }}
  • 最初envでfromJson()の結果を変数に設定しようとしてエラーになった
  • 環境変数に配列型のデータを設定しようとしてエラーになってた
  • なのでtoJsonで文字列に戻して環境変数に設定した

条件分岐

  • ifで条件分岐
  • ステータスチェックの組み込み関数を使うことで前段のステップのステータスによって条件分岐ができる
    steps:
      - name: Success
        run: exit 0
      - name: Echo success
        if: ${{ success() }}
        run: echo success!!

      - name: Failure
        run: exit 1
      - name: Echo failure
        if: ${{ failure() }}
        run: echo failure!!

      - name: Echo always
        if: ${{ always() }}
        run: echo always!

permission

  • デフォルトではcontentsのread権限が与えられているのでpermissionを設定しなくてもリポジトリのソースコードを参照できる
  • しかし、何かしらのpermissionを設定して、contentsのpermissionを設定しないとcontentsのread権限がない状態になってしまうので注意が必要
ぱんだぱんだ

4章 継続的インテグレーションの実践

actionlint

https://github.com/rhysd/actionlint/tree/main

GitHub Actionsのワークフローの静的解析ができる。インストール方法はいろいろあるが以下はdockerで実行する例。

name: Actionlint

on: workflow_dispatch

defaults:
  run:
    shell: bash

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  lint:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v4
      - name: Lint
        run: docker run --rm -v "$(pwd):$(pwd)" -w "$(pwd)" rhysd/actionlint:latest

  • actionlintは関係ないがdockerで実行すると毎回docker imageのpullが発生するのでキャッシュを使いたい気がする
  • ただ、pullしてきたimageをキャッシュする方法はあんまりなさそう
  • dockerのレイヤーデータは/var/lib/dockerにあるようだがこれをキャッシュするのはあまりやりたくない
  • go installでもインストールできるようなので実行バイナリを配置した一時ディレクトリを指定してキャッシュを取った方が簡単そう

同時実行のキャンセル

以下のようにすると古いワークフローの実行をキャンセルできる。

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

タイムアウト

  • タイムアウトは基本的に全てのワークフローに設定したほうがいい
  • デフォルトでは6時間に設定されているので最悪6時間動き続ける
jobs:
  lint:
    runs-on: ubuntu-latest
    timeout-minutes: 5

シェル

  • 基本的には全てのワークフローでデフォルトシェルを指定した方が良い
defaults:
  run:
    shell: bash
  • シェルの指定を省略してもbashで起動するが、パイプエラーを拾えない
  • なので、全てのワークフローで明示的に指定した方が良い
ぱんだぱんだ

第5章 運用しやすいワークフロー

  • デバッグログを有効化すればデバッグがだせる
  • ::<ワークフローコマンド>::をechoで出力すると自分でも見やすいログを出力できる
  • 使い方の例は以下の記事を

https://dev.classmethod.jp/articles/decorate-github-actions-log-by-workflow-command/

  • bashのset -xでコマンドの実行結果を見れるようにするのも簡単
  • GITHUB_STEP_SUMMARY環境変数にマークダウン形式で出力することでサマリーも出せる
  • これはサードパーティーのactionとか使ってるとサマリー出してくれるやつがそれだと思う
  • slackの通知はslack公式のactionがあったようだが今はGitHub Appsを使った方が簡単そう
  • 以下の記事が参考になる
    https://zenn.dev/k_saito7/articles/notification-github-actions-workflow-to-slack
  • environmentsを指定することで環境別のvariablesとsecretを使うことができる。
  • GitHub Actionsで使えるvariablesとsecretsはenvironmentsとrepositoryに設定するのとOrganizationとで3つある
ぱんだぱんだ

第6章 アクションによるモジュール化

  • GitHub Actionsの実装方法には3種類あり、compositとJavaScriptとDockerがある。
  • GitHub Actionsはリモートアクションとして公開するだけでなくローカルに配置して使う、ローカルアクションとして使うこともできる。
  • GitHub Actionsを作成する場合、インターフェースとしてメタデータファイルを作成する必要があり、これに入力と出力の定義などを記載する
ぱんだぱんだ

第10章 GitHub Pacakages

  • GitHub のリポジトリと合わせてパッケージを管理できるので楽
  • Javaのgradleプラグインやnpm, Docker imageなどがサポートされている
  • GitHub Pacagesの話ではないがdocker login ghcr.ioのようにdocker loginコマンドの後には使用するレジストリサービスのドメインを指定できる
  • デフォルトではDocker Hubだがghcr.ioを指定するとGitHub Pacagesを使うしgcr.ioを指定するとGoogle Container Registryを使える。

docker/metadata-action

  • GitHub Pacagesの話ではないがGitHub Actionsでdocker imageをビルドしレジストリにpushするとき、バージョンタグやメタデータを簡単に付与できるアクション。
  • あんまり気にしたことなかったけどdocker imageにはタグの他にラベルというメタデータを付与することができるようになっている。

docker/login-action

  • ついでにdocker loginを簡単にできるやつ

docker/build-push-action

  • docker buildとdocker pushが簡単にできるアクション
  • cache-fromやcache-toを指定することでキャッシュを有効化してビルド時間を短縮することも可能

docker/setup-buidx-action

  • 前述したbuild-push-actionがbuildxに依存しているらしく使用するのにセットアップが必要らしい

buildxについて

  • あんまり理解してなかったので
  • まずMobyというDocker社が作ったOSSプロジェクトがある
  • そのMobyのなかにBuildKitというコンテナビルドを高速化させるようなさまざまな機能がありbuildxはBuidKitをDockerから使えるようにする拡張のよう
  • buildxを使うことでマルチプラットフォームビルドや分散ビルド、キャッシュ機能の性能向上などのメリットがある
  • GitHub Actionsでは上述したように公式からactionが提供されているので全て使ってビルドプッシュするようにすると必然的にbuidxのセットアップもしているはず
  • buildxによるビルドで通常のビルドよりも性能が上がっている可能性もあるが、よりビルド時間を短縮させたければ--cache-from, --cache-toを使いレジストリに保存したレイヤーキャッシュを使えるようにするとビルド時間が短縮できそう
  • しかし、レジストリに保存するキャッシュはもう一つキャッシュ用のイメージを保存するような感じらしいのでレジストリの容量を圧迫することになる
  • なのでもしキャッシュまで有効にするならそこらへんも考えて有効にしたほうがいいかもしれない

参考

公式dockerのactionへの置き換えのまとめ
https://qiita.com/_kei_s/items/15c067090d5142648aac

BuildKit周辺の用語説明
https://zenn.dev/fraim/articles/98ad17f9ed140e#buildkit

ぱんだぱんだ

第11章 OIDC

  • AWSのようなクラウドベンダーの長命なクレデンシャルを直接使うのはアンチパターン
  • セキュアに運用するならば一時クレデンシャルを使用する
  • 一時クレデンシャルの取得にはOIDCの技術が使われ、GitHub ProviderのようなID Providerから取得したOIDCトークンを一時クレデンシャルと交換する
  • これを実現するには以下の2つが必要
    • クラウドプロバイダー側でOIDCに必要なコンポーネントを作成する
    • GitHub Actionsのワークフローにクラウドプロバイダーが提供する認証アクションを組み込む

OIDC TrustとCloud Roles

  • 前述した一時クレデンシャルの交換にはAWSのようなクラウドプロバイダーがGitHub Providerを信用している必要がある。
  • その仕組みがOIDC Trust
  • 一時クレデンシャルのアクセス元とアクセス先を管理するのがCloud Roles

認証アクション

主要なクラウドベンダーからは認証アクションが提供されている

AWS

  • AWSでGitHub Actionsのワークフローから一時クレデンシャルを取得するにはOIDC TrustとしてOpen ID Connect Provider、Cloud RolesとしてIAMロールを作成することで実現できる。

Google Cloud

  • Google Cloudの例はこちらの記事を参考にすると良さそう
  • ぱっと見AWSより複雑そうに見えちゃう

https://paper2.hatenablog.com/entry/2024/06/29/143947

ぱんだぱんだ

第13章 アクションのオープンソース化

  • GitHub Actionsのワークフロー内で以下の記事にあるように特定のメールアドレスとユーザー名を指定することで非公式ではあるもののGitHub botアカウントを使うことができる

https://qiita.com/marurusan/items/604f8655083154aa6fa1

  • GitHub Actionsもテストを書こうと思えば書けるので書けるときは書いていこうと思います。
ぱんだぱんだ

第14章 GitHub Actionsの高度な使い方

Reusable Workflows

  • actionを作成することでGitHub Actionsのワークフローをモジュール分割するようなやり方を学んだがReusable Workflowsを使うとより大きな括りで再利用できる処理を切り出す
  • 具体的に言うとワークフロー自体を切り出して再利用する
  • 利用側は独立したジョブとして扱う。アクションのようにステップで呼び出すことはできない。
  • Reusable Workflowsはリモートに配置することも可能なためリポジトリを跨いだジョブの共通化を実現させることができる

型変換

  • fromJson()を使うことで文字列をbooleanやnumber型に変換して使うことができる
  • これはGitHub Actionsの構文内で文字列以外の型の指定が必要なときに役立ちそう
このスクラップは4ヶ月前にクローズされました