PLAY DEVELOPERS BLOG

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

HuluやTVerなどの日本最大級の動画配信を支える株式会社PLAYが運営するテックブログです。

GitHub Actionsをオートスケールするself-hosted runnersで動かしたくて

こんにちは、SaaSプロダクト開発部の松本です。 弊社プロダクト「PLAY VIDEO STORES」のエンジニアを担当しています。

最近は朝の布団との格闘が始まり、冬の幕開けを沸々と感じています。 寒い冬はMacBook Proで暖を取りましょう(?)


さて、本題に入ります。

GitHub Actionsを導入してプロダクトの開発運用を負荷軽減、効率化したい!!

と考えてから数ヶ月が経ち...ついに今年に入って実現することができました。

そこで今回は、GitHub Actionsの導入にあたり構築したself-hosted runnersについてご紹介します。

背景(もっと詳しく)

プロダクトの開発コードは全て社内のGitHub Enterprise Serverで管理をしていますが、 プロダクトの成長に伴って開発サイクルでいくつかの課題が上がっていました。

  1. 手動運用の増加:開発段階での MilestonePull RequestIssueの作成、本番デプロイ後の ReleaseTagの作成などの手動運用が増えてきた
  2. デプロイの手間:ステージング環境への反映頻度が増えてきたため、従来の bash のデプロイ用スクリプトを実行するのが手間になってきた
  3. 開発メンバーの増加:開発メンバーの増加及び入れ替え時に導入する運用ルールのボリュームが増えてきた

これらの課題を解決し、運用を改善するため、CI/CD環境を導入しワークフローを自動化することにしました。

AWS CodeBuild等の導入も検討していましたが、 GitHub上で完結できること、GitHubのイベントトリガーでワークフローを実行できることもあるため、GitHub Actionsを導入することにしました。

GitHub Actionsって何?

GitHub Actions(以下、Actions) はGitHubが提供するCI/CD(継続的インテグレーション/継続的デリバリー)を実現するための機能です。 GitHub上で管理しているリポジトリ内で設定できるワークフローを通じて、開発プロセスを自動化し、カスタマイズすることができます。

Actionsやワークフロー構文の解説は、こちらの過去記事で紹介されているため割愛します。 developers.play.jp

何と言ってもpushPull RequestIssueをトリガーとして、 自由にワークフローを組むことができるのが魅力の1つと言えます。

また、GitHub Marketplace で一般公開しているActionsを利用することもできます。

self-hosted runnersって何?

Actionsの利用にあたり第一の関門として、ワークフローの実行環境の準備が必要になります。

実行環境の選択肢として主に2つの方法があります。

  1. GitHub-hosted runners
    • GitHubがSaaS提供する実行環境
    • 手っ取り早くActionsを利用する場合におすすめ
    • 無料枠 + 従量課金 ※Publicリポジトリは無料
  2. self-hosted runners
    • 自前で構築する実行環境
    • 実行環境をカスタマイズし、好みのOSやパッケージを導入する場合におすすめ
    • 実行自体は無料

つまり、self-hosted runnersは実行環境のリソースは自身で管理する必要がありますが、特定のライブラリやツールが必要な場合は、要件に合わせた実行環境を柔軟に構築することができる点が大きなメリットと言えるでしょう。

実現・解決したいこと

さて、前置きが長くなりましたが本題に入っていきます。

前述の通り社内管理のGitHub Enterprise Serverを使用しているため、self-hosted runners以外に選択肢はありませんでした。

ひとまずActionsを始める取っ掛かりとしては、社内で共用のself-hosted runnersと連携するという手段もありましたが、 以下4つを実現したいこともあり、プロダクト専用でself-hosted runnersを構築することにしました。

  1. アプリケーションのbuild負荷に耐えられる実行環境にしたい
  2. 他システムで導入しているライブラリやツールの影響を受けないプライベートな実行環境にしたい
  3. 必要に応じてライブラリやツールを自由に増やせる実行環境にしたい
  4. ワークフローを実行していない時のランニングコストは極力抑えたい

self-hosted runnersの構築について

今回構築したself-hosted runnersの全体構成図です。

構成のポイントは以下です。

  • ECS on EC2を使用する
  • ホストのEC2にはECS最適AMIを使用する
  • ECS ClusterのCapacity ProviderにAuto Scaling Groupを使用して、オートスケールを可能にする

以下4ステップでself-hosted runnersの構築とGitHubへの連携を進めていきます。

  1. GitHubアクセストークンの発行
  2. インフラ環境の構築
  3. runner用コンテナイメージの作成
  4. Organization / リポジトリへのrunner登録

GitHubアクセストークンの発行

GitHub上にrunnerを登録するためのアクセストークンを発行します。

アカウント(右上)の「Settings」>「Developer settings」>「Personal access token」>「Generate new token」で新規アクセストークン発行の画面に遷移します。

scopeは repoworkflowadmin:org を選択し、「Generate token」でアクセストークンを発行します。

以下形式のアクセストークンが発行されます。(*の部分はマスクです。)

ghp_************************************

後述するタスク定義の環境変数に発行したアクセストークンを渡すため、保管しておきます。

インフラ環境の構築

AWSへのインフラ環境はAWS CloudFormationで構築しました。

各構成のセクションごとに解説します。 なお、例に記載するコードの変数(${SystemName}${ENV})、括弧書きは自身の環境に合わせて置き換えてください。

Amazon ECR (Elastic Container Registry)

Templateの例(クリックで展開)

template.yaml

  # ------------------------------------------------------------#
  # ECR
  # ------------------------------------------------------------#
  ECR:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Sub ${SystemName}-${ENV}

解説

  • 特筆はありません。任意の名前をつけましょう。

起動テンプレート / Auto Scaling Group

Templateの例(クリックで展開)

template.yaml

  # ------------------------------------------------------------#
  # LaunchTemplate
  # ------------------------------------------------------------#
  LaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: !Sub ${SystemName}-${ENV}-lt
      LaunchTemplateData:
        # 実行するAMI(ECS最適化AMIを使用する)
        ImageId: ami-0afd6c9431a9be6a9
        # インスタンスタイプ
        InstanceType: (EC2のインスタンスタイプ)
        # ECS用のインスタンスプロファイルをアタッチ
        IamInstanceProfile:
          Name: !Ref ECSInstanceProfile
        # EBSデバイスの設定
        BlockDeviceMappings:
          - DeviceName: '/dev/xvda'
            Ebs:
              VolumeType: 'gp3'
              VolumeSize: '30'
        # EBSをスループット最適化モードにするか
        EbsOptimized: false
        # EC2インスタンスのキーペア
        KeyName: (EC2インスタンスで使用するキーペア名)
        # EC2に紐づけるセキュリティグループ
        SecurityGroupIds:
          - (セキュリティグループのARN)
        # ECSクラスターに紐づけるためのユーザーデータ
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash
            echo "ECS_CLUSTER=${SystemName}-${ENV}" >> /etc/ecs/ecs.config
            echo "ECS_ENABLE_SPOT_INSTANCE_DRAINING=true" >> /etc/ecs/ecs.config

  # ------------------------------------------------------------#
  # Auto Scaling Group
  # ------------------------------------------------------------#
  AutoScaling:
    Type: AWS::AutoScaling::AutoScalingGroup
    # インスタンス更新時のアップデート設定
    UpdatePolicy:
      # ローリングアップデートの設定
      AutoScalingRollingUpdate:
        MaxBatchSize: (インスタンスの最小起動数)
        MinInstancesInService: (インスタンスの最小起動数)
    Properties:
      AutoScalingGroupName: !Sub ${SystemName}-${ENV}-asg
      # 次のスケーリングアクションまでの待機時間
      Cooldown: '300'
      # 実行するインスタンスの希望数
      DesiredCapacity: (インスタンスの最小起動数)
      # インスタンスの最小数
      MinSize: (インスタンスの最小起動数)
      # インスタンスの最大数
      MaxSize: (インスタンスの最大起動数)
      # インスタンスの起動設定
      MixedInstancesPolicy:
        InstancesDistribution:
          # オンデマンドインスタンスを最低1台実行
          OnDemandBaseCapacity: 1
          # インスタンスを追加するときにオンデマンドを起動する割合
          OnDemandPercentageAboveBaseCapacity: 50
        LaunchTemplate:
          # 起動テンプレートの設定
          LaunchTemplateSpecification:
            LaunchTemplateId: !Ref LaunchTemplate
            Version: !GetAtt LaunchTemplate.LatestVersionNumber
      # スケールインの際に古いインスタンスから順に削除
      TerminationPolicies:
        - OldestInstance
      VPCZoneIdentifier:
          - (サブネットのARN)

  # ------------------------------------------------------------#
  # IAM Role
  # ------------------------------------------------------------#
  # ECSで利用するためのロール
  ECSInstanceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${SystemName}-${ENV}-instance-role
      # ECSの基本的なポリシーとSSMを利用するためのポリシーをアタッチする
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
        - arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: 'Allow'
            Principal:
              Service:
                - 'ec2.amazonaws.com'
            Action:
              - 'sts:AssumeRole'

  # ------------------------------------------------------------#
  # InstanceProfile
  # ------------------------------------------------------------#
  ECSInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: '/'
      Roles:
        - !Ref ECSInstanceRole
      InstanceProfileName: !Sub ${SystemName}-${ENV}-instance-role

解説

  • 起動テンプレート(Launch Template)のAMIには、ECS最適AMIを指定します
  • ECS on EC2を使用するにあたり、ホストのEC2インスタンスへAmazonEC2ContainerServiceforEC2Roleのポリシーをアタッチします(必須)

Amazon ECS (Elastic Container Service)

Templateの例(クリックで展開)

template.yaml

  # ------------------------------------------------------------#
  # ECS CapacityProvider
  # ------------------------------------------------------------#
  ECSCapacityProvider:
    Type: AWS::ECS::CapacityProvider
    Properties:
      AutoScalingGroupProvider:
        # 使用するAuto Scaling Groupの設定
        AutoScalingGroupArn: !Ref AutoScaling
        ManagedScaling:
          MinimumScalingStepSize: (最小起動数)
          MaximumScalingStepSize: (最大起動数)
          Status: ENABLED
          TargetCapacity: 100
          InstanceWarmupPeriod: 60

  # ------------------------------------------------------------#
  # ECS Cluster
  # ------------------------------------------------------------#
  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Sub ${SystemName}-${ENV}
      ClusterSettings:
        - Name: containerInsights
          Value: !If [isProd, enabled, disabled]
      # 使用するCapacity Providerの設定
      CapacityProviders:
        - !Ref ECSCapacityProvider
      DefaultCapacityProviderStrategy:
        - Base: 0
          Weight: 1
          CapacityProvider: !Ref ECSCapacityProvider

  # ------------------------------------------------------------#
  # ECS TaskDefinition
  # ------------------------------------------------------------#
  ECSTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Sub ${SystemName}-${ENV}-task-definition
      RequiresCompatibilities:
        - EC2
      NetworkMode: awsvpc
      Cpu: !Ref ECSTaskDefinitionCPU
      Memory: !Ref ECSTaskDefinitionMemory
      ExecutionRoleArn:
        Fn::ImportValue: !Sub ${ServiceName}-${ENV}-ecs-task-execution-role-arn
      TaskRoleArn:
        Fn::ImportValue: !Sub ${ServiceName}-${ENV}-${TaskRoleOutputName}
      ContainerDefinitions:
        - Name: !Sub ${SystemName}-${ENV}-task-definition
          # 起動するECRにpushしたイメージのタグ名
          Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ECR}:${ENV}-latest
          PortMappings:
          - ContainerPort: !Ref ContainerPort
            HostPort: !Ref ContainerPort
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-create-group: true
              awslogs-group: !Sub "/ecs/${SystemName}-${ENV}"
              awslogs-region: ap-northeast-1
              awslogs-stream-prefix: ecs
          Environment:
            - Name: 'ACCESS_TOKEN'
              Value: (GitHubで発行したアクセストークン)
            - Name: 'ORGANIZATION'
              Value: (GitHubに連携するOrganization名)
            - Name: 'ENV'
              Value: (環境 prod / stg)
          # dockerを使用するためホストをマウントする
          MountPoints:
            - ReadOnly: false
              ContainerPath: "/var/run/docker.sock"
              SourceVolume: "docker"
      Volumes:
        - Name: "docker"
          Host:
            SourcePath: "/var/run/docker.sock"

  # ------------------------------------------------------------#
  # ECS Service
  # ------------------------------------------------------------#
  ECSService:
    Type: AWS::ECS::Service
    DependsOn:
      - ECSTaskDefinition
    Properties:
      ServiceName: !Sub ${SystemName}-${ENV}-service
      Cluster: !Ref ECSCluster
      # タスクの必要数
      DesiredCount: !Ref MinimumCount
      EnableECSManagedTags: true
      EnableExecuteCommand: true
      PropagateTags: TASK_DEFINITION
      TaskDefinition: !Ref ECSTaskDefinition
      NetworkConfiguration:
        AwsvpcConfiguration:
          Subnets:
            - (サブネットのARN)
          SecurityGroups:
            - (セキュリティグループのARN)  

解説

  • Auto Scaling GroupによりECS Taskをオートスケールするため、ECS ClusterにはCapacity Provider を設定します
  • TaskDefinition(タスク定義)では、Environmentに環境変数として ACCESS_TOKENORGANIZATIONENV の値を定義します ※この3つの環境変数値は後述のDockerイメージの作成で使用されます

無事に構築が完了すると、ECS ClusterのAWS マネジメントコンソールでは「インフラストラクチャ」にCapacity Providerの設定が紐付きます。

また、Auto Scaling GroupではCapacity Providerにより以下のようなポリシーが設定されます。

runner用コンテナイメージの作成

次に、runner本体をECS Task上で常駐起動させ、GitHubと連携するために以下2つを用意します。

  • ECS Task上で実行するrunner用コンテナのDockerイメージ
  • GitHub(Organization又はリポジトリ)にrunnerを登録するbashスクリプト

Dockerfileの例(クリックで展開)

Dockerfile

# base
FROM ubuntu:22.04

# GitHub Actions Runnerのバージョンを指定する
# https://github.com/actions/runner/releases
ARG RUNNER_VERSION="2.310.2"

SHELL ["/bin/bash", "-c"]

# baseパッケージの更新、dockerグループとユーザを追加する
RUN apt-get update -y \
    && apt-get upgrade -y \
    && groupadd -g 992 docker \
    && useradd -m -g 992 docker

# Pythonおよびコードの依存パッケージをインストールし、JSONを解析できるようにjqを追加する
# 必要に応じて追加のパッケージを追加する
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
    curl jq build-essential libssl-dev libffi-dev python3 python3-venv python3-dev python3-pip \
    ca-certificates gnupg lsb-release unzip

# voltaをインストールする
ENV VOLTA_HOME=${HOME}/.volta
ENV PATH=${VOLTA_HOME}/bin:$PATH

RUN curl https://get.volta.sh | bash - \
    && . ~/.bashrc \
    && chmod 777 -R .volta/
RUN volta install node

# gitをインストールする
RUN apt-get install -y git

# aws-cliをインストールする
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \
    && unzip awscliv2.zip \
    && ./aws/install -i /usr/local/aws-cli -b /usr/bin \
    && rm -f awscliv2.zip

# Docker CLIをインストールする
RUN mkdir -p /etc/apt/keyrings \
    && curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \
    && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
    && apt-get update \
    && apt-get install -y docker-ce-cli

# dockerユーザのディレクトリに移動し、GitHub Actions Runnerをダウンロード + 展開する
RUN cd /home/docker && mkdir actions-runner && cd actions-runner \
    && curl -O -L https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz \
    && echo "(ファイルのハッシュ値)  actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz" | shasum -a 256 -c \
    && tar xzf ./actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz

# dockerディレクトリ内の所有権をdockerに変更 + installdependencies.shを実行する
RUN chown -R docker ~docker && /home/docker/actions-runner/bin/installdependencies.sh

COPY ./scripts/register.sh ./register.sh

# register.shに実行権限を付与する
RUN chmod +x register.sh

# rootユーザーによる実行が許可されていないため、ユーザーを "docker" に設定し、以降のすべてのコマンドを "docker" ユーザーとして実行する
USER docker

# エントリーポイントをregister.shに設定する
ENTRYPOINT ["./register.sh"]

解説

  • ホストEC2の/var/run/docker.sockをrunnerコンテナが使用できるように、ホストと同一の992でdockerグループを作成し、さらにdockerユーザを所属させます
  • dockerユーザに register.sh の実行権限を付与します
  • Nodeのアプリケーションではvoltaを使用しているため、package.jsonにvolta pinしているバージョンに動的切り替えするようvolta本体をインストールします
  • コンテナのエントリポイントをregister.shに設定し、新規起動したタスク実行時にGitHub上にrunnerとして登録されるようにします

register.shの例(クリックで展開)

register.sh

#!/bin/bash

GITHUB_API_URL="https://(GitHub APIサーバのURL)"
ENV=$ENV
ACCESS_TOKEN=$ACCESS_TOKEN
ORGANIZATION=$ORGANIZATION
OWNER=$OWNER
REPO=$REPO

# ORGANIZATIONが指定されている場合は、organizationのアクセストークンを発行する
if [ -n "$ORGANIZATION" ]; then
  REG_TOKEN=$(curl -sX POST -H "Authorization: token ${ACCESS_TOKEN}" ${GITHUB_API_URL}/orgs/${ORGANIZATION}/actions/runners/registration-token | jq .token --raw-output)
  cd /home/docker/actions-runner
  echo "setup Organization Runner"
  ./config.sh --url ${GITHUB_URL}/${ORGANIZATION} --token ${REG_TOKEN} --labels ${ENV}
# それ以外は、リポジトリのアクセストークンを発行する
else
  REG_TOKEN=$(curl -sX POST -H "Authorization: token ${ACCESS_TOKEN}" ${GITHUB_API_URL}/repos/${OWNER}/${REPO}/actions/runners/registration-token | jq .token --raw-output)
  cd /home/docker/actions-runner
  echo "setup Repository Runner"
  ./config.sh --url ${GITHUB_URL}/${OWNER}/${REPO} --token ${REG_TOKEN}
fi

cleanup() {
    echo "Removing runner..."
    ./config.sh remove --token ${REG_TOKEN}
}

trap 'cleanup; exit 130' INT
trap 'cleanup; exit 143' TERM

./run.sh & wait $!

解説

  • Actions Runnerのソースコードを解凍すると以下階層のファイル群が格納されており、register.shではconfig.shrun.shを実行しています
    • config.sh: Actions Runner の設定と構成を定義するbashスクリプト
    • run.sh: ワークフローの各ステップ実行毎に呼び出されるbashスクリプト
├── bin
├── config.sh
├── env.sh
├── run-helper.cmd.template
├── run-helper.sh.template
├── run.sh
└── safe_sleep.sh
  • config.sh--labelsオプションを渡すことにより、prodstgの環境を区別するためのラベルを設定しています(AWSアカウントを本番とステージング環境で分けているため)
  • ECS Taskが終了した時、GitHubに登録したrunnerが定期的にお掃除されるように、INT(割り込み)とTERM(終了)のシグナルをキャッチしcleanup()でrunnerを削除します

Organization / リポジトリへのrunner登録

次に、ECRにbuildしたDockerイメージをpushし、ECS ServiceからECS Taskを起動します。

DockerイメージのbuildとECRへpushするコマンド例

readonly repository_uri="(AWSアカウントID).dkr.ecr.ap-northeast-1.amazonaws.com"
readonly repository="${repository_uri}/app"
readonly env="prod"
readonly git_commit_hash=`git log --pretty=oneline | head -n 1 | awk '{print $1}'`

# Ubuntuベースで動作させるため、linux/x86_64でbuidする
docker build --platform linux/x86_64 -t "${repository}:${env}-latest" -t "${repository}:${git_commit_hash}" .

# ECRレジストリに対してDockerを認証する
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ${repository_uri}

# コンテナイメージをECRにpushする
docker push ${repository}:${env}-latest ${repository}:${git_commit_hash}

ECS Taskでは以下内容でログが出力されおり、runnerの登録は無事に完了しているようです!

--------------------------------------------------------------------------------
|        ____ _ _   _   _       _          _        _   _                      |
|       / ___(_) |_| | | |_   _| |__      / \   ___| |_(_) ___  _ __  ___      |
|      | |  _| | __| |_| | | | | '_ \    / _ \ / __| __| |/ _ \| '_ \/ __|     |
|      | |_| | | |_|  _  | |_| | |_) |  / ___ \ (__| |_| | (_) | | | \__ \     |
|       \____|_|\__|_| |_|\__,_|_.__/  /_/   \_\___|\__|_|\___/|_| |_|___/     |
|                                                                              |
|                       Self-hosted runner registration                        |
|                                                                              |
--------------------------------------------------------------------------------
# Authentication
√ Connected to GitHub
# Runner Registration
Enter the name of the runner group to add this runner to: [press Enter for Default] 
Enter the name of runner: [press Enter for ip-10-44-29-3] 
√ Runner successfully added
√ Runner connection is good
# Runner settings
Enter name of work folder: [press Enter for _work] 
√ Settings Saved.
√ Connected to GitHub
Current runner version: '2.310.2'
2023-10-30 10:58:51Z: Listening for Jobs

念の為、GitHub上でOrganizationsの「Settings」>「Actions」>「Runners」を確認します。

無事にrunnerが登録されていることと、環境振り分け用のラベルが設定されていることが確認できました。 ここまででself-hosted runnersの構築と連携は完了です。(お疲れ様でした)

これでようやく Actions を実行できる環境が整いました。

ワークフローの実行

では早速、簡単なワークフローを用意して動作確認してみます。

actions/labelerを使用して、Pull Requestに自動でLabelを追加してみます。

.github/workflows/labeler.yaml

name: Labeler

on:
  - pull_request_target

jobs:
  labeler:
    runs-on: [self-hosted, prod]
    permissions:
      id-token: write
      contents: read
      pull-requests: write

    steps:
      - uses: actions/labeler@v4
        with:
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          sync-labels: true

解説

  • self-hosted runnersを実行環境として利用するためruns-onにはself-hostedを指定します。
  • 本番環境用のAWSアカウントで構築したrunnerで実行するため、runs-onに環境振り分け用ラベルのprodも追加します。

.github/labeler.yaml

# change-files
Config:
  - any: ['src/app/config/**']

解説

  • actions/labelerで使用されるラベル定義用のyamlファイルです。
  • src/app/config/以下のファイルが変更された時に、「Config」のLabelが付与されるように定義します。

src/app/config/以下のファイルに変更を加えリモートへのpush、Pull Requestを作成します。 リモートリポジトリ上の 「Actions」を開きワークフローの実行状態を確認します。

が付いていることが確認でき、無事に実行完了しています。

さらに、ステップを開きステップの実行ログを確認します。問題なさそうです。

Pull Request」を開くと対象のPull RequestにLabelが付与されていることが確認できました。完璧です。

これで構築したself-hosted runnersの動作に問題がないことも確認できました。

GitHub Actions の導入事例

最後に、プロダクト専用で構築したself-hosted runners の実行環境を利用し、 開発および運用の負担を軽減するために導入したいくつかの事例を紹介します。

リリースノート(Release) / Tagの自動生成

mainブランチへのpushをトリガーに前回作成されたTag とバージョン、修正差分を比較し、次版の作成を自動で実行しています。

↓実際にワークフローを通して作成されたリリースノート

GitHub-Backlog課題の連携

Backlog NotifyのActionsを使用し、 プロダクトのタスク管理で使用しているBacklogとGitを連携しています。

Backlog課題をPull Requestやcommitメッセージの先頭に XXX-100のように入れた場合、以下画像のようにBacklogのコメントに記録されます。

Backlog課題から修正内容を追うことが可能になるので、非常に便利です。

ドキュメントサイト(Amazon CloudFront + Amazon S3)のbuild、デプロイ

他の技術ブログ記事でもよく紹介されているワークフローですが、 VitePressで作成したドキュメントサイトのbuildとS3 Bucketへのsyncの実行を自動化しています。

こちらもmainブランチへのpushをトリガーにしており、修正が入るたびに自動で反映されるようにしています。

まとめ

本記事では、self-hosted runnersの構築により、 よりカスタマイズ性の高い実行環境で GitHub Actions を利用する方法について紹介しました。

self-hosted runnersは案外簡単に導入することができます。

皆さんもぜひ、自身のプロジェクトでself-hosted runnersの導入を検討してみてはいかがでしょうか?

手間な作業は自動化して減らし、開発ライフをEnjoyしましょう!