Terraform Moduleを用いたAWSにおけるGitLab Runnerの運用
GitLabにはCI/CDの機能が統合されています.GitLab CI/CDではGitLab本体とは別のGitLab Runnerと呼ばれるノードでビルドを実行します.GitLab RunnerはJenkinsでいうJenkins Agentと同様に,普通のPCで実行したり,クラウドでDockerコンテナとして実行したりできます.ドキュメントによるとGitLab Runnerの実行方法は以下が用意されています.
- Shell.
- Docker.
- Docker Machine and Docker Machine SSH (autoscaling).
- Parallels.
- VirtualBox.
- SSH.
- Kubernetes.
Jenkins Agentと同様にGitLab Runnerは手軽にインスタンスを構築できる反面,スケールアウトやアップデートなどを考えておかないと運用が泥沼化しがちです.
本項では,GitHubで公開されているTerraform Moduleを利用してAWSでGitLab Runnerを運用する方法を紹介します.このモジュールを利用すると以下のメリットがあります.
ただし,GitLabが公式にサポートしているモジュールではないので,今後も継続的にメンテナンスされていくかは分かりません.OSSなので積極的にcontributeしていきましょう.
terraform-aws-gitlab-runner
https://github.com/npalm/terraform-aws-gitlab-runner はGitLab Runnerに必要なリソースをプロビジョニングしてくれるモジュールです.具体的には以下のリソースが作成されます.
- Auto Scaling Group(GitLab Runnerの実行用)
- Launch Configuration(GitLab Runnerの実行用.GitLab Runnerのインストールスクリプトや設定ファイルが含まれる)
- S3 Bucket(ビルドキャッシュ用)
- CloudWatch Logs(EC2インスタンスのログ)
- 上記で必要なSecurity GroupやIAM Roleなど
このモジュールはGitLab Runnerのauto scaling modeを利用しており,ビルドキューに応じてBuild RunnerのEC2インスタンスを作成および削除する仕組みになっています.具体的には,以下の2種類のEC2インスタンスが作成されます.
- GitLab Runner(Build Runnerを作成するためのノード.Auto Scaling Groupがライフサイクルを管理する)
- Build Runner(実際にビルドを実行するノード.GitLab Runnerがライフサイクルを管理する)
GitLab Runnerのauto scaling modeは内部でDocker Machineを利用しており,Docker Machineが新しいBuild Runnerを作成します.
このモジュールはGitLabオフィシャルの Autoscale GitLab CI/CD runners and save 90% on EC2 costs で紹介されている構成をベースにしているとのことですが,このモジュールではAuto Scaling Groupを利用してGitLab Runner自体もスポットインスタンスにすることでさらなる費用削減を実現しています.例えば,us-west-2リージョンで以下のインスタンスタイプを利用した場合,8〜9割引になります.(私の大好きな激安インスタンスタイプです)
- GitLab Runner
t3.micro
$0.0104/h → $0.0031/h (80% OFF) - Build Runner
m3.medium
$0.0670/h → $0.0067/h (90% OFF)
今のところSpot Fleetには対応していないようですが,今後に期待です.(詳しくはIssue#77を参照)
使ってみよう
https://github.com/npalm/terraform-aws-gitlab-runner/tree/develop/examples にサンプルが用意されています.本稿では,パブリックサブネットにGitLab Runnerを配置する例を示します.
AWSリソースの定義
まず,新しいVPCとサブネットを定義します.IPアドレスブロックや名前は適当で構いません.
resource "aws_vpc" "main" { cidr_block = "172.21.0.0/16" } resource "aws_internet_gateway" "public" { vpc_id = "${aws_vpc.main.id}" } resource "aws_route_table" "public" { vpc_id = "${aws_vpc.main.id}" } resource "aws_route_table_association" "public" { route_table_id = "${aws_route_table.public.id}" subnet_id = "${aws_subnet.public.id}" } resource "aws_route" "public_internet_gateway" { route_table_id = "${aws_route_table.public.id}" destination_cidr_block = "0.0.0.0/0" gateway_id = "${aws_internet_gateway.public.id}" } resource "aws_subnet" "public" { vpc_id = "${aws_vpc.main.id}" cidr_block = "172.21.0.0/20" availability_zone = "us-west-2a" }
次に,terraform-aws-gitlab-runnerモジュールを読み込みます.ここでは https://gitlab.com にGitLab Runnerを登録しますが,独自にホスティングしているGitLabに対しても同様の方法で登録できます.
data "local_file" "public_ssh_key" { filename = ".sshkey.pub" } variable "gitlab_runner_registration_token" { type = "string" description = "Registration token for GitLab Runners" } module "gitlab_runner" { source = "npalm/gitlab-runner/aws" version = "3.5.0" aws_region = "us-west-2" environment = "gitlab_runner" ssh_public_key = "${data.local_file.public_ssh_key.content}" vpc_id = "${aws_vpc.main.id}" subnet_ids_gitlab_runner = ["${aws_subnet.public.id}"] subnet_id_runners = "${aws_subnet.public.id}" aws_zone = "a" runners_use_private_address = false # GitLab Runnerインスタンスの設定 instance_type = "t3.micro" runner_instance_spot_price = "0.01" # Build Runnerインスタンスの設定 docker_machine_instance_type = "m3.medium" docker_machine_spot_price_bid = "0.02" runners_name = "aws.m3" runners_gitlab_url = "https://gitlab.com" # GitLab本体にGitLab Runnerを登録する際の設定 # https://docs.gitlab.com/ee/api/runners.html#register-a-new-runner を参照 gitlab_runner_registration_config = { registration_token = "${var.gitlab_runner_registration_token}" description = "GitLab Runner on AWS" tag_list = "aws" # GitLab Runnerのタグ locked_to_project = "true" run_untagged = "false" maximum_timeout = "3600" } }
AWSリソースのプロビジョニングとGitLabへの登録
https://gitlab.com を開き,新しいプロジェクトを作成します.プロジェクトのCI/CD設定を開き,Registration Tokenを取得します.
Terraformを実行します.ここでは環境変数でRegistration Tokenを指定します.
export TF_VAR_gitlab_runner_registration_token=dvc3717mx7RksPZCbe7a terraform init terraform apply
GitLab Runnerの登録に成功すると,以下のようにプロジェクトのCI/CD設定にRunnerが現れます.
ビルドの実行
プロジェクトに .gitlab-ci.yml
を作成します.このとき以下のように tags
にGitLab Runnerのタグ名を指定します.先ほどTerraformの定義で aws
というタグを付けたので,ここでも aws
というタグを指定しています.
image: golang:1.12 stages: - test format: stage: test script: - go test -race ./... tags: - aws
コミットをpushするとビルドが実行されます.AWSコンソールを確認すると,以下のようにBuild Runnerのインスタンスが作成されているはずです.
Build Runnerライフサイクルの変更
デフォルトでは,ビルドが完了してから10分間が経過するとBuild Runnerのインスタンスが削除されます.また,Build Runnerのインスタンス数の上限は設定されていません.
ここでは,ビルドが完了してから1分後にインスタンスが削除されるように変更します.また,インスタンス数の上限も2つに変更します.
module "gitlab_runner" { # 以下を追記 runners_idle_time = 60 runners_limit = 2 }
AWSリソースの変更を反映します.
terraform apply
上記のコマンドを実行するとLaunch Configurationが変更されます.すでにGitLab Runnerが起動している場合は,既存のインスタンスを削除すると新しい設定でインスタンスが起動されます.
プロジェクトを開き,連続してビルドを実行してみましょう.同時実行数が2つに制限されているはずです.
また,1分間が経過するとBuild Runnerのインスタンスが削除されているはずです.
auto scaling modeの仕組みや設定は https://docs.gitlab.com/runner/configuration/autoscale.html で詳しく説明されているので,ぜひ参照してください.
まとめ
https://github.com/npalm/terraform-aws-gitlab-runner を利用すると,AWSでGitLab Runnerを簡単に運用できます.さらに,スポットインスタンスを利用すると大幅な費用削減を実現できます.