こんにちは、SaaSプロダクト開発部の松本です。 弊社プロダクト「PLAY VIDEO STORES」のエンジニアを担当しています。
最近は朝の布団との格闘が始まり、冬の幕開けを沸々と感じています。 寒い冬はMacBook Proで暖を取りましょう(?)
さて、本題に入ります。
GitHub Actionsを導入してプロダクトの開発運用を負荷軽減、効率化したい!!
と考えてから数ヶ月が経ち...ついに今年に入って実現することができました。
そこで今回は、GitHub Actionsの導入にあたり構築したself-hosted runnersについてご紹介します。
- 背景(もっと詳しく)
- GitHub Actionsって何?
- self-hosted runnersって何?
- 実現・解決したいこと
- self-hosted runnersの構築について
- ワークフローの実行
- GitHub Actions の導入事例
- まとめ
背景(もっと詳しく)
プロダクトの開発コードは全て社内のGitHub Enterprise Serverで管理をしていますが、 プロダクトの成長に伴って開発サイクルでいくつかの課題が上がっていました。
- 手動運用の増加:開発段階での
Milestone
、Pull Request
、Issue
の作成、本番デプロイ後のRelease
、Tag
の作成などの手動運用が増えてきた - デプロイの手間:ステージング環境への反映頻度が増えてきたため、従来の bash のデプロイ用スクリプトを実行するのが手間になってきた
- 開発メンバーの増加:開発メンバーの増加及び入れ替え時に導入する運用ルールのボリュームが増えてきた
これらの課題を解決し、運用を改善するため、CI/CD環境を導入しワークフローを自動化することにしました。
AWS CodeBuild等の導入も検討していましたが、 GitHub上で完結できること、GitHubのイベントトリガーでワークフローを実行できることもあるため、GitHub Actionsを導入することにしました。
GitHub Actionsって何?
GitHub Actions(以下、Actions) はGitHubが提供するCI/CD(継続的インテグレーション/継続的デリバリー)を実現するための機能です。 GitHub上で管理しているリポジトリ内で設定できるワークフローを通じて、開発プロセスを自動化し、カスタマイズすることができます。
Actionsやワークフロー構文の解説は、こちらの過去記事で紹介されているため割愛します。 developers.play.jp
何と言ってもpush
やPull Request
、Issue
をトリガーとして、
自由にワークフローを組むことができるのが魅力の1つと言えます。
また、GitHub Marketplace で一般公開しているActionsを利用することもできます。
self-hosted runnersって何?
Actionsの利用にあたり第一の関門として、ワークフローの実行環境の準備が必要になります。
実行環境の選択肢として主に2つの方法があります。
- GitHub-hosted runners
- GitHubがSaaS提供する実行環境
- 手っ取り早くActionsを利用する場合におすすめ
- 無料枠 + 従量課金 ※Publicリポジトリは無料
- self-hosted runners
- 自前で構築する実行環境
- 実行環境をカスタマイズし、好みのOSやパッケージを導入する場合におすすめ
- 実行自体は無料
つまり、self-hosted runnersは実行環境のリソースは自身で管理する必要がありますが、特定のライブラリやツールが必要な場合は、要件に合わせた実行環境を柔軟に構築することができる点が大きなメリットと言えるでしょう。
実現・解決したいこと
さて、前置きが長くなりましたが本題に入っていきます。
前述の通り社内管理のGitHub Enterprise Serverを使用しているため、self-hosted runners以外に選択肢はありませんでした。
ひとまずActionsを始める取っ掛かりとしては、社内で共用のself-hosted runnersと連携するという手段もありましたが、 以下4つを実現したいこともあり、プロダクト専用でself-hosted runnersを構築することにしました。
- アプリケーションのbuild負荷に耐えられる実行環境にしたい
- 他システムで導入しているライブラリやツールの影響を受けないプライベートな実行環境にしたい
- 必要に応じてライブラリやツールを自由に増やせる実行環境にしたい
- ワークフローを実行していない時のランニングコストは極力抑えたい
self-hosted runnersの構築について
今回構築したself-hosted runnersの全体構成図です。
構成のポイントは以下です。
- ECS on EC2を使用する
- ホストのEC2にはECS最適AMIを使用する
- ECS ClusterのCapacity ProviderにAuto Scaling Groupを使用して、オートスケールを可能にする
以下4ステップでself-hosted runnersの構築とGitHubへの連携を進めていきます。
- GitHubアクセストークンの発行
- インフラ環境の構築
- runner用コンテナイメージの作成
- Organization / リポジトリへのrunner登録
GitHubアクセストークンの発行
GitHub上にrunnerを登録するためのアクセストークンを発行します。
アカウント(右上)の「Settings」>「Developer settings」>「Personal access token」>「Generate new token」で新規アクセストークン発行の画面に遷移します。
scopeは repo、 workflow、 admin: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_TOKEN
、ORGANIZATION
、ENV
の値を定義します ※この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.sh
とrun.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
オプションを渡すことにより、prod
とstg
の環境を区別するためのラベルを設定しています(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しましょう!