GitHub Actions - セルフホステッド ランナー（AWS CodeBuild）

# 内容

GitHub Actions WorkflowのJob実行に使われる環境にセルフホステッド ランナー（AWS CodeBuild）を使用する  
今回は、セルフホステッド ランナーを使ったJobでRDSクラスターの操作を行う  
また、CodeBuildのデプロイにはCFNを使用する  

# セルフホステッド ランナー

ランナーはJob実行に使用する環境で、  
GitHub ホステッド ランナーとして、Linux、Windows、macOSが用意されており、  
以下のように `runs-on` で指定する  

```yaml
jobs:
  check-bats-version:
    runs-on: ubuntu-latest
```

セルフホステッド ランナーも使用することができ、一つの方法としてAWS CodeBuildでランナーを作成することができる  
以下のように各種カスタマイズが可能  
※VPC等EC2でのみ設定可能な項目あり

![2024-07-14-12-41-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/d245b5e8-09f8-62b5-96b2-6e2bd50ca139.png)
![2024-07-14-12-43-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/27367762-2a52-6d46-c228-28fdb1090cdb.png)

AWS CodeBuild用に用意されているイメージは[ドキュメント](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-available.html#lambda-compute-images)参照  
例えば、Lambda用のイメージ `aws/codebuild/amazonlinux-x86_64-lambda-standard:python3.11` の中身は[Dockerfile](https://github.com/aws/aws-codebuild-docker-images/blob/master/al-lambda/x86_64/python3.11/Dockerfile)で確認できる  
GitHub ホステッド ランナーのLinuxとはインストールされているツール、ライブラリが異なるため注意が必要  
（GitHub ホステッド ランナーLinuxで使える `jq` がLambdaでは使用できない等）  

また、[料金](https://docs.github.com/ja/actions/learn-github-actions/usage-limits-billing-and-administration)に違いがあり、  
プライベート リポジトリの場合、GitHub ホステッド ランナーの使用時間（分）に応じて料金が発生するが、  
セルフホステッド ランナーは料金が発生しない（AWS料金は発生する）  

# CodeBuild設定内容

使用するコンピューティング環境のイメージやスペックの設定、  
GitHubの認証、リポジトリ指定、GitHubからCodeBuild環境を呼び出すためのWebhook登録等を行う  

以下AWS CodeBuildに必要な主な設定

## ソース

![2024-07-14-16-12-16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/6ec16506-217a-d5a3-493f-e57981f791f8.png)

対象のGitHubリポジトリの接続を行う  
OAuthを使用した接続（username, passwordでサインイン）か、個人用アクセストークン（PAT）を登録して接続する  
GitHub Apps で生成した[トークン](https://docs.github.com/ja/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app)は使用できなかった  
今回は、OAuthを使用した接続を行った  

> [!IMPORTANT]
> Githubの認証情報はAWSアカウント×リージョンに対して1個しか登録できない  
> そのため、同アカウント、リージョンの他CodeBuildプロジェクトで別のGithub認証を行うと先に登録した認証情報が消えてしまう

## Webhook登録

![2024-07-14-16-12-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/3edf8a86-00a5-b813-8535-a6c7399c8421.png)

GitHubからCodeBuild環境を呼び出すためのWebhook登録を行う  
イベントタイプには `WORKFLOW_JOB_QUEUED` を選択する  
この登録行うと、以下のようにGitHubにWebhookが登録される  
そのため、GitHubの認証が通っている状態でなければこの設定はできない

![2024-07-14-16-36-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/34f6775d-e5d4-7a46-78e2-0b7ddf3d12da.png)

## コンピューティング環境

![2024-07-14-16-13-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/9b605faa-f2a8-cc23-6fcb-35dcded13db0.png)

今回は処理時間の都合上EC2を選択  
指定するロールにRDSの操作権限を付与する

# CFN 実装

```yaml
Resources:
  CodebuildGitHubActionsLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /aws/codebuild/CodebuildGitHubActions
      RetentionInDays: 30
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete

  CodebuildGitHubActionsRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: CodebuildGitHubActionsRole
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - codebuild.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: CodebuildGitHubActionsRolePolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              # RDS操作用権限
              - Effect: Allow
                Action:
                  - rds:DescribeDBClusters
                  - rds:StartDBCluster
                  - rds:StopDBCluster
                Resource: !Ref RdsClusterArn

              # CDKでは以下権限不要
              - Effect: Allow
                Action:
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource:
                  - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/CodebuildGitHubActions
                  - !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/CodebuildGitHubActions:*
              - Effect: Allow
                Action:
                  - codebuild:CreateReportGroup
                  - codebuild:CreateReport
                  - codebuild:UpdateReport
                  - codebuild:BatchPutTestCases
                  - codebuild:BatchPutCodeCoverages
                Resource:
                  - !Sub arn:${AWS::Partition}:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/CodebuildGitHubActionsProject-*

  CodebuildGitHubActionsProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Artifacts:
        Type: NO_ARTIFACTS
      Environment:
        ComputeType: BUILD_GENERAL1_SMALL
        Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0
        PrivilegedMode: false
        Type: LINUX_CONTAINER
      LogsConfig:
        CloudWatchLogs:
          GroupName: !Ref CodebuildGitHubActionsLogGroup
          Status: ENABLED
      Name: CodebuildGitHubActionsProject
      ServiceRole: !GetAtt CodebuildGitHubActionsRole.Arn
      Source:
        GitCloneDepth: 1
        Location: https://github.com/xxxxxx.git
        ReportBuildStatus: false
        Type: GITHUB
      TimeoutInMinutes: 30
```

CDKで実装した場合、
CodeBuildで使用するロールに付与しているRDS操作用権限以外は自動的に付与される

今回、GitHubの認証、Webhookの登録は手動で行うようにした  
（認証情報登録を手動で行うと、認証を前提としているWebhook登録も手動になる）

PATをSecretsManagerに登録してよい場合等は、
CFNの場合、[AWS::CodeBuild::SourceCredential](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-codebuild-sourcecredential.html)、CDKの場合、[GitHubSourceCredentials](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_codebuild.GitHubSourceCredentials.html)を使用して認証情報を登録できる  

このGithub認証情報はAWSアカウント×リージョンに対して1個の独立したリソースのため、  
実装上、CodeBuildプロジェクトとの関連付けするようなことはない

# GitHub Actions 実装

```yaml
jobs:
  describe_rds_cluster:
    name: Start Rds Cluster
    runs-on: codebuild-CodebuildGitHubActionsProject-${{ github.run_id }}-${{ github.run_attempt }}
    timeout-minutes: 30
    outputs:
      cluster_status: ${{ steps.get_cluster_status.outputs.status }}
    steps:
      - name: Get Cluster Status
        id: get_cluster_status
        shell: bash
        run: |
          status=$(aws rds describe-db-clusters \
            --db-cluster-identifier ${{ inputs.clusterName }} \
            --query DBClusters[0].Status)
          status=$(echo $status | tr -d '"')
          echo $status
          echo "status=${status}" >> $GITHUB_OUTPUT
```

AWS CodeBuildのランナーを使用する場合、`runs-on` は、  
`codebuild-{CodeBuild Project Name}-${{ github.run_id }}-${{ github.run_attempt }}`  
となる、`{CodeBuild Project Name}` 部分はデプロイしたCodeBuildのプロジェクト名  

この`runs-on`のJobが実行される際にCodeBuildに対するWebhookが実行されるが、  
CodeBuild側の権限不足によりエラーが発生した場合等、Webhookにエラー応答が返ってきた場合、  
Jobが即時エラーとはなってくれず、いつ終了するのか不安になるので、  
`timeout-minutes` は一応設定しておいたほうが良い

# ログ

CodeBuildはもちろんCloudWatch Logsにログを出力するが、  
GitHubからWebhookを実行された際にCodeBuild側の権限不足によりエラーが発生した場合等、AWS側にログが残らない  
その場合、エラーはGithub側のWebhook履歴で確認できる  
ただし、Webhookが登録されていると、`runs-on: ubuntu-latest`等、  
セルフホステッド ランナー以外でもWebhookが実行され、エラーログが多数残るため、ほとんどのエラーログは無関係

![2024-07-15-11-33-59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/695430/8426fc97-39a5-1916-490f-c7bd5086f9d1.png)

# 参考

- [AWS CodeBuildのGitHub Actions runnerサポートでLambdaが実行できるようになったので検証しました](https://developers.cyberagent.co.jp/blog/archives/47677/)
- [GitHub Self-hosted Runner in AWS CodeBuildを試す](https://qiita.com/k-kojima-yumemi/items/1930a4c2fb183ba63ba3)
- [CodeBuildがGitHub ActionランナーをサポートしたのでDBマイグレーションを試してみた](https://zenn.dev/yuta28/articles/codebuild-support-github-action-runners)
- [AWS CDKでAWS CodeBuildのGitHub Webhookを設定する](https://kakakakakku.hatenablog.com/entry/2024/01/23/221814)