はじめに
DTダイナミクスでSREセクションのテックリードをしている霜鳥です。
この記事はCodeBuild-hosted GitHub Actions runner使ってみた①〜紹介編〜の続編です。
今回は実際にCodeBuildをGitHub Actions(以下GHA)のself-hosted runnerとして設定してGHAから利用する方法をTerraformのコードを交えながらご紹介します。
その他、霜鳥が書いた過去の記事はこちら。
実装
詳細は前回記事に載せましたので今回はいきなり本題から行きます。
CodeBuildはGitHubのリポジトリごと、使うイメージごとに作成する必要があるのでモジュール化しておくのがオススメです。
なおこのTerraformプロジェクトでは以下のディレクトリ構成とし、backendやproviderなどは割愛します。
/ ├ main.tf └ modules └ self-hosted_runner ├ variables.tf └ main.tf
前提
OpenID Connect(以下OIDC)やCodeConnectionsの設定は別途完了しているものとします。
OIDCの確認はIAM > IDプロバイダ
の一覧に以下があればOKです。
- プロバイダ:
token.actions.githubusercontent.com
- タイプ:
OpenID Connect
詳細は以下の記事をご参照ください。
GitHub ActionsとAWSの連携におけるOIDC認証の活用 - Qiita
CodeStarConnectionsの確認はデベロッパー用ツール > 接続
の一覧に以下があればOKです
デベロッパー用ツールはCodeCommitやCodeBuild、CodePipelineと同じページにあります。
- プロバイダー:
GitHub
- ステータス:
利用可能
余談ですが記事執筆時点でIDプロバイダは「プロバイダ」で接続は「プロバイダー」と表記揺れが存在するため本記事は準拠しています。
決して執筆者の表記揺れではありません笑
main.tf
まずはmodule呼び出しているmain.tf側の実装です。
このブロックを複数書いていくことで様々なリポジトリ、イメージに対応させていくことになります。
ユースケースによって変更したい箇所を中心に変数化しておきました。
# main.tf module "msim_rs_buildmachine" { source = "./modules/self-hosted_runner" # Variables ## Basic settings ### このマシン名はGitHub側でも使うので外から見て分かりやすい名前が良い build_machine_name = "CodeBuildのマシン名" ### このビルドマシンを使いたいGitHubのリポジトリURL repository_url = "https://github.com/<owner>/<repository>" ## BuildMachine Specs ### 以下3つは正しい組み合わせが存在するので直下のリンク①を参照 ### runner_imageはカスタムイメージのECRリポジトリでも可!! runner_compute_type = "BUILD_GENERAL1_SMALL" runner_type = "LINUX_CONTAINER" runner_image = "aws/codebuild/amazonlinux2-x86_64-standard:5.0" ### runner imageをpullする際にはデフォルトだとCodeBuildの標準ロールが用いられる ### クロスアカウントでECRからpullしたい際などCodeBuildに設定したサービスロールを用いたい場合は以下を設定 image_pull_credentials_type = "SERVICE_ROLE" ## Networks(※VPC内にCodeBuildを立てる場合) vpc_id = <VPC_ID> subnet_ids = <SUBNET_IDS> # List(string)を想定 security_group_ids = <SG_IDS> # List(string)を想定 }
リンク①: ビルド環境のコンピューティングモードおよびタイプ
variables
main.tfのVariablesで設定しているものを宣言しているブロックになるので割愛します。
モジュール本体(modules/self-hosted_runner/main.tf)
本記事のメインディッシュです。
IAM
まずはCodeBuildに設定するIAMロールから。
今回は実際のユースケースを想定して必要最低限の権限に加えて以下の3要件に対応できるように設定しています。
- ログをCloudWatch Logsへ出力すること
- CodeBuildをVPC内に配置すること
- ECRのカスタムイメージを利用できること
# modules/self-hosted_runner/main.tf ################################### ## IAM ## ################################### # ロール本体 resource "aws_iam_role" "runner" { name = var.build_machine_name assume_role_policy = data.aws_iam_policy_document.runner_assume.json } # 信頼関係 data "aws_iam_policy_document" "runner_assume" { statement { effect = "Allow" actions = [ "sts:AssumeRole", ] principals { type = "Service" identifiers = [ "codebuild.amazonaws.com" ] } } } resource "aws_iam_role_policy" "runner_inline" { name = var.build_machine_name role = aws_iam_role.runner.id policy = data.aws_iam_policy_document.runner_inline.json } data "aws_iam_policy_document" "runner_inline" { # GitHubとの接続に必要な権限 statement { effect = "Allow" actions = [ "codeconnections:GetConnectionToken", "codeconnections:GetConnection", "codestar-connections:UseConnection", "codestar-connections:ListConnections" ] resources = [ "*" ] } statement { effect = "Allow" actions = [ "codeBuild:StartBuild", ] resources = [ "arn:aws:codebuild:ap-northeast-1:${data.aws_caller_identity.current.account_id}:project/${var.build_machine_name}" ] } # Option: ログを出力するのに必要な権限 statement { effect = "Allow" actions = [ "logs:CreateLogStream", "logs:PutLogEvents", ] resources = [ aws_cloudwatch_log_group.runner.arn, "${aws_cloudwatch_log_group.runner.arn}:log-stream:*", ] } # Option: VPC内に配置する場合に必要な権限 statement { effect = "Allow" actions = [ "ec2:CreateNetworkInterface", "ec2:DescribeNetworkInterfaces", "ec2:DeleteNetworkInterface", "ec2:DescribeSubnets", "ec2:DescribeSecurityGroups", "ec2:DescribeVpcs" ] resources = ["*"] } # Option: ECRのカスタムイメージを使うのに必要な権限 statement { effect = "Allow" actions = [ "ecr:GetAuthorizationToken", "ecr:GetDownloadUrlForLayer", "ecr:BatchCheckLayerAvailability", "ecr:InitiateLayerUpload", "ecr:UploadLayerPart", "ecr:CompleteLayerUpload", "ecr:PutImage", "ecr:BatchGetImage" ] resources = ["*"] } }
ビルドマシン
buildspec.ymlを含んでいないため非常にシンプルです。
CodeBuildはWebhookで動かされるためwebhookのリソースとCloudWatch Logsのロググループのリソースが含まれています。
# modules/self-hosted_runner/main.tf ################################### ## CodeBuild ## ################################### resource "aws_codebuild_project" "runner" { depends_on = [ aws_iam_role.runner, aws_iam_role_policy.runner_inline ] name = var.build_machine_name service_role = aws_iam_role.runner.arn source { type = "GITHUB" location = var.repository_url } # CodePipelineなどで前後を接続していないのでここはNO_ARTIFACTSになる artifacts { type = "NO_ARTIFACTS" } environment { compute_type = var.runner_compute_type type = var.runner_type image = var.runner_image image_pull_credentials_type = var.image_pull_credentials_type privileged_mode = true # 内部でDockerを動かす必要があるので特権モードが必要 } # VPC内で動かす際の設定 vpc_config { vpc_id = var.vpc_id subnets = var.subnet_ids security_group_ids = var.security_group_ids } # ログを出す際の設定 logs_config { cloudwatch_logs { group_name = aws_cloudwatch_log_group.runner.name } } cache { type = "LOCAL" modes = [ "LOCAL_CUSTOM_CACHE" ] } } resource "aws_codebuild_webhook" "runner" { project_name = aws_codebuild_project.runner.name build_type = "BUILD" filter_group { filter { type = "EVENT" pattern = "WORKFLOW_JOB_QUEUED" } } } ################################### ## log ## ################################### resource "aws_cloudwatch_log_group" "runner" { name = var.build_machine_name retention_in_days = 7 }
設定の確認
terraform apply
でリソース群を作成するとrepository_url
で指定したGitHubのリポジトリの
Settings > Webhooksに以下の画像のようにCodeBuildのマシンが見えるようになります。
出ていない場合はOIDCやConnection、リソースの設定などを見直してみてください。
特にVPC内に作成する際にはインターネットに出られるサブネット/セキュリティグループである必要があります。
CodeBuild-hosted GitHub Actions runner
それでは最後に実際にCodeBuildをSelf-hosted runnerとしてGHAから動かしてみましょう!
使い方は簡単でいつものGHAの定義ファイル内のJobsでruns-on
にて以下のように指定するだけです。
※${{ github.run_id }}-${{ github.run_attempt }}
はそのままでOK。
runs-on: codebuild-<CodeBuildのマシン名>-${{ github.run_id }}-${{ github.run_attempt }}
お試しで以下に.github/workflows/test.yml
というサンプルコードを置いておきます。
# .github/workflows/test.yml name: test on: workflow_dispatch: jobs: build_and_push: runs-on: codebuild-testmachine-${{ github.run_id }}-${{ github.run_attempt }} steps: - name: hello, world! run: echo "hello, world!"
既知の不具合
TerraformでVPC内にCodeBuildを作成した際、以下のようにPROVISIONINGにて
VPC_CLIENT_ERROR: Unexpected EC2 error: error while getting DHCP options for VPC
というエラーの出ることがあります。
設定自体は正しいのに出ることがあり、これのトラブルシュートとしてはかなり黒魔術チックになってしまうのですが、
マネジメントコンソールにて対象のCodeBuildのプロジェクトを編集
を一度開き、何も設定を変更せずにプロジェクトを更新する
を押すことで直ります。
自分で書いていてもわけが分からないのですがAPI経由だと正しく設定できていないのかもしれません。
さいごに
DTダイナミクスのSREチームでは様々な新しいチャレンジを通して#時間戦略
や#顧客時間価値
にコミットしています。
わたしたちミスミ、そしてDTダイナミクスは一緒にmeviyを通して世界の製造業を支える仲間を募集しています!
少しでも興味のある方はぜひカジュアル面談しましょう!