Stanby Tech Blog

求人検索エンジン「スタンバイ」を運営するスタンバイの開発組織やエンジニアリングについて発信するブログです。

GitHub Actionsのご紹介と弊社での利用について

f:id:stanbyblog:20220218132027p:plain ※この情報は2021/12/17現在のものです。

はじめに

本記事は、これからGithub Actionsの導入を検討している方に向けて記載しております。

最近業務でGitHub Actionsを使うようになりましたので、その中で勉強してわかったことをつらつらとまとめます。

詳細な仕様につきましてはGitHub公式サイトのドキュメントが充実しておりますのでそちらをご確認ください。

背景

弊社スタンバイでは現在、CI/CDツールとしてJenkinsとAWS CodeBuildをメインに利用しており、JenkinsからCodeBuildをキックする構成としております。

しかし、この構成だと以下の問題点がございました。

  • ビルドの設定がJenkinsとAWS CodeBuildで分かれるため、運用コストがかかる
  • GitHubをトリガーとしてJenkinsジョブを起動する場合、Webhookを作成する必要がある
  • Serverless FrameworkなどをJenkinsから実行するためには、JenkinsのslaveサーバにNode.js/pythonなどをインストールする必要があり、環境競合発生の可能性がある

これらの問題があるため、Github Actionsの導入を検討しておりました。

現在、Serverless Frameworkのデプロイ及び一部のサービスのビルドにつきましてはGithub Actionsを実際に導入しております。

GitHub Actionsとは

GIthub Actionsとは、GitHubが提供するCI/CDシステムです。

ランナーとして提供されるOSはLinuxだけでなく、Windows/macOSも提供されています。

セルフホストランナーを自前環境に構築してGitHub Actionsを実行できますのでオンプレ環境でも使えます。

料金

料金はGitHubのサイトに詳細が書かれています。

パブリックリポジトリ及びセルフホストランナーの場合は無料、プライベートリポジトリの場合でも契約しているプランに応じて無料枠があるため、GitHubを既に利用している場合使い始めやすいのではないでしょうか。

GitHub Actionsの始め方

リポジトリ直下の .github/workflows ディレクトリに任意の名称のymlファイルを作成することによって、ワークフローを作成できます。

サンプルのワークフローを定義して実行結果を確認してみます。

.github/workflows/learn-github-actions.yml

name: learn-github-actions
on: [push]
jobs:
  check-bats-version:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: '14'
      - run: npm install -g bats
      - run: bats -v

GitHubにpushします。

git add .github/workflows/learn-github-actions.yml
git commit -m "first github actions workflow"
git push origin main

Actionsのタブを見ると、pushしたワークフローを確認できます。

今回サンプルで追加したワークフローはリポジトリへのpushをトリガーとして動くため、既に動いていることが確認できます。

グリーンのチェックが実行成功のマークです

f:id:stanbyblog:20220204140204p:plain

クリックして中身を確認すると、実行ログを確認できます。

f:id:stanbyblog:20220204140224p:plain

例では全てのブランチに対してのpushをトリガーとして動くワークフローを作成してみましたが、他にも色々なトリガーがあります。

もちろん特定のブランチに対するpushで動くワークフローも作成可能です。

GitHubと高度に統合されており、様々な操作をトリガーとしてワークフローを起動できるのはGitHub Actionsの強みではないでしょうか。

AWSとの連携

Github Actionsのランナー環境にはAWS CLIなど主要なCLIやモジュールがインストールされているので、わざわざインストールするステップを入れることなくAWSの各種リソースを操作できます。

https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-README.md

クレデンシャルの設定やECRログインなども、AWS公式から提供されているGitHub Actions用テンプレートがあるため、1ステップで簡単に行う事ができます。

クレデンシャルはアクセスキーだけではなく、OIDCにも対応しています。

今回はアクセスキーでの設定例を書きます。

.github/workflows/aws-actions-sample.yml

name: aws-actions-sample
on:
  workflow_dispatch:

jobs:
  test:
    name: aws test
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - 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: s3 list
      run: |
        aws s3 ls

AWSのアクセスキーとシークレットキーはGitHub

Settings→Secretsで設定できるRepository secretに入れておきます。

f:id:stanbyblog:20220218171340p:plain

今回はトリガーをworkflow_dispatchとしているので、Actionsのタブから手動で実行します。

f:id:stanbyblog:20220218171357p:plain

実行できていることが確認できます。(今回の例ではs3 lsコマンドが成功しています)

f:id:stanbyblog:20220218171453p:plain

また、AWSアカウントが開発と本番で分かれているなど、環境が分かれているケースではEnvironment secretsが利用できます。

ymlにenvironmentの記述(とついでにワークフロー実行時引数)を追加します。

.github/workflows/aws-actions-sample-environment.yml

name: aws-actions-environment-sample
on:
  workflow_dispatch:
    # ワークフロー実行時の引数
    inputs:
      env:
        type: choice
        options:  
        - dev
        - prod
        description: '環境'

jobs:
  test:
    # environment設定を追加
    # 値はワークフロー実行時の引数を設定
    environment: ${{ github.event.inputs.env }}
    name: aws test
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - 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: s3 list
      run: |
        aws s3 ls

Settings→Environmentsからenvironmentを作成し、その中にAWSのアクセスキーとシークレットキーを登録します。

今回はdevとprodのenvironmentを作成し、それぞれにAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYを設定しました。

なお、Repository secretにも同名のキーが設定されていた場合、Environment secretsが優先されます。

f:id:stanbyblog:20220204140422p:plain

ワークフロー実行時にenvを指定すると、指定したenvironmentからシークレットを取得してAWS CLIを実行できます。

f:id:stanbyblog:20220204140511p:plain

f:id:stanbyblog:20220204140545p:plain

f:id:stanbyblog:20220204140616p:plain

f:id:stanbyblog:20220204140639p:plain

なお、workflow_dispatchをトリガーとした場合、UIからの実行以外に、APIからも実行が可能です。

# OWNER: ワークフローを定義しているリポジトリのownerを指定
# REPO: ワークフローを定義しているリポジトリの名前を指定
curl -f \
  -X POST \
  -H "Accept: application/vnd.github.v3+json" \
  -H "Authorization: Bearer ${GITHUB_TOKEN}" \
  https://api.github.com/repos/${OWNER}/${REPO}/actions/workflows/aws-actions-sample-environment.yml/dispatches \
  -d "{\"ref\": \"main\", \"inputs\": {\"env\": \"prod\"}}"

Composite Action

ワークフローを書いていると、セットアップなどで同一ステップを複数のワークフローに書くことが増えてきます。

複数のステップをまとめて再利用可能なActionに定義できる機能として、Composite Actionが提供されています。

Composite Actionのファイル名は action.yml である必要があります。

Composite Actionは利用する側と同じリポジトリに定義することも、別リポジトリに定義もできます。

今回の例では利用する側と同じリポジトリに定義しています。

composite-action/init/action.yml

name: "setup library"
inputs:
  node-version:
    default: '14.x'
    required: false
    description: 'version of nodejs'
runs:
  using: "composite"
  steps:
    - name: Set up Node.js
      uses: actions/setup-node@v1
      with:
        node-version: ${{ inputs.node-version }}

Composite Action利用側はusesで呼び出します。

.github/workflows/composite-action-sample.yml

name: composite-action-sample
on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2
    - name: Initialize
      # Composite Actionを相対パスで指定
      # Composite Actionが別リポジトリにある場合は{owner}/{repo}/{path}@{ref}

      # owner: Composite Actionを定義しているリポジトリのownerを指定
      # repo: Composite Actionを定義しているリポジトリの名前を指定
      # path: Composite Actionを定義しているパスを指定
      # ref: Composite Actionのブランチまたはタグを指定(mainなど)
      uses: ./composite-action/init
      with:
        node-version: 16.x

f:id:stanbyblog:20220218171605p:plain

注意点

  • Composite Actionを利用側とは別リポジトリにする場合、そのリポジトリパブリックリポジトリ にする必要があります。
    プライベートリポジトリにする場合は、Composite Actionと利用側が同じリポジトリにいる必要があります。
    (この点が不便で、プライベートリポジトリにComposite Actionを集めたいケースもありますが、今のところそれができないです)
  • Composite Action側のログは1つのステップにまとめられて表示されるため、地味に見づらいです。
  • 利用側で設定した環境変数はComposite Action側でも参照できますが、シークレットは参照できないのでinputで渡す必要があります。
    なお、Composite Actionにシークレットを渡した場合でも、Composite Action側のログはちゃんとマスクされます。

Reusable Workflow

ワークフロー内のステップを共通化する方法としてComposite Actionを紹介しましたが、もう1つ共通化する方法としてResuable Workflowがあります。

こちらはワークフロー自体を他のワークフローから呼び出せる機能となります。

Composite Actionは一部処理を共通化するものですが、ビルド→デプロイなど一連のフローを共通化する際に利用できます。

また、Composite Actionと比べて処理内でcheckoutを実行すると以下の違いがあります。

  • Composite Action
    • Composite Actionを定義している側のリポジトリのリソースをcheckout
  • Reusable Workflow
    • Reusable Workflowを利用している側のリポジトリのリソースをcheckout

なのでcheckoutも含めて共通化して別リポジトリに定義する場合はReusable Workflowの方が使いやすいです。

実際にResuable Workflowを書いてみます。

Resuable Workflowはワークフローの一種なので、 .github/workflows の中に作る必要があります。

.github/workflows/reusable-workflow.yml

name: Reusable workflow example

on:
  # Reusable Workflowはworkflow_call
  workflow_call:
    inputs:
      command:
        required: true
        type: string
      env:
        required: true
        type: string
    # secretの設定
    secrets:
      access_key_id:
        required: true
      secret_access_key:
        required: true

jobs:
  example_job:
    # Environment Secretを使う場合はReusable Workflow側で設定
    environment: ${{ inputs.env }}
    name: exec aws command
    runs-on: ubuntu-latest
    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.access_key_id }}
          aws-secret-access-key: ${{ secrets.secret_access_key }}
          aws-region: ap-northeast-1

      - name: aws ${{ inputs.command }}
        run: |
          aws ${{ inputs.command }}

.github/workflows/call-reusable-workflow.yml

name: Call a reusable workflow

on:
  workflow_dispatch:
    inputs:
      env:
        type: choice
        options:  
        - dev
        - prod
        description: '環境'

jobs:
  call-workflow:
    # owner: Reusable Workflowを定義しているリポジトリのownerを指定
    # repo: Reusable Workflowを定義しているリポジトリの名前を指定
    # path: Reusable Workflowを定義しているパスを指定
    # filename: Reusable Workflowのファイルの名称を指定
    # ref: Reusable Workflowのブランチまたはタグを指定(mainなど)
    uses: {owner}/{repo}/{path}/{filename}@{ref}
    with:
      env: ${{ github.event.inputs.env }}
      command: s3 ls
    # Resuable Workflowで使うsecretを渡す
    secrets:
      access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

f:id:stanbyblog:20220204140821p:plain

f:id:stanbyblog:20220204140843p:plain

Reusable Workflow側のログはそれぞれのステップごとに分かれるので見やすいです。

注意点

  • Composite Actionと同じく利用側とは別リポジトリにする場合、そのリポジトリパブリックリポジトリ にする必要があります。
  • Resuable Workflow呼び出し側で設定した環境変数はResuable Workflow側には反映されません。
    なので引数でResuable Workflow側に渡してあげる必要があります。

ワークフローの配置戦略

Composite Action/Reusable Workflowの注意点に記載した通り、別リポジトリに定義する場合はパブリックリポジトリにする必要があります。

弊社では全てのリポジトリをプライベートリポジトリとして運用しているため、パブリックリポジトリとすることは許容できません。

なので、弊社では1つのリポジトリに主要なワークフローを集める方針としました。

  1. GitHub Actionsのワークフロー用リポジトリを作成
    そこにデプロイなどのワークフローを作成
  2. ワークフロー用リポジトリに定義した各ワークフローで使う共通処理(ビルドなど)をComposite Actionとして同リポジトリに定義
  3. 各ワークフローでは各アプリケーションリポジトリをcheckoutしてビルドを実行
  4. 各アプリケーションのリポジトリには、必要に応じてPRのマージなどをトリガーとして起動するワークフローを作成 ワークフロー用リポジトリに定義されたワークフローをAPIでcall

f:id:stanbyblog:20220204140955p:plain

これで各アプリケーションリポジトリに同じワークフローが分散することを防ぎつつ、Composite Actionで共通化ができます。

他にも、そもそも同じワークフローが必要なアプリケーションは1つのリポジトリにまとめてしまうなどの案もありましたが、移行工数などの観点から断念しました。

その他Tips

デバッグロギング

https://docs.github.com/ja/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging

Repository secretACTIONS_STEP_DEBUGをtrueで設定すれば詳細なログを出力できます。

f:id:stanbyblog:20220218171649p:plain

ローカルでワークフローを実行する

https://github.com/nektos/act

GitHubの公式ツールではありませんが、上記のようなツールがあります。

まとめ

GitHub Actionsはテンプレートも充実しており、簡単に、かつパブリックリポジトリなら無料で実装できるのでかなり便利だと思いました。

ただ、Composite Action/Reusable Workflowのパブリックリポジトリにしか配置できないなど、若干痒いところに手が届かない的な部分もまだまだあります。

どんどん新しい機能が追加されて使いやすくなっていってるようですので、是非皆さんも試してみてください。

本記事が、これからGitHub Actionsを始めようとされている方の理解の一助になれば幸いです。

スタンバイのプロダクトや組織について詳しく知りたい方は、気軽にご相談ください。

www.wantedly.com