AWS Fargateを使ってTerraformを用いてサーバレスGitLabランナーをデプロイする
セキュアでスケーラブルなサーバレスGitLabランナーの完全なセットアップをTerraform IACを通してAWS Fargateで実現します。
(画像: アーキテクチャの概要)
私の組織でGitLabが広く使われるようになるにつれて、セキュリティの高いスケーラブルで効率的なCICDランナー隊を管理する方法が必要です。AWS Fargateのサーバレスセットアップは、そのシンプルなインフラ管理と労力のかからないスケーラビリティで魅力的です。
この投稿では、どんな環境でも容易に再現可能なセットアップのためにTerraformを用いて管理されるAWS Fargate上のサーバレスGitLabランナー隊の設定を共有します。
背景
GitLabには'AWS Fargate上でのGitLab CIのオートスケーリング'についてのガイドがありますが、ランナーマネージャーがEC2上にホストされるため、完全なサーバレスではありません。他の人々はマネージャーとワーカーの両方に対してFargateの完全なECSセットアップを共有しています。例として、Daniel Coutinho de Mirandaの'サーバレスGitLab CI/CD on AWS Fargate'や、Damiano Giorgiの'AWS上でのGitLab連携のためのサーバレス手法'があります。
しかし、これらの例は手動の設定に大きく依存しており、EC2/Fargateタスクで1つのマネージャープロファイルのみをサポートしています。
この投稿で説明されているセットアップの主な動機は以下の通りです:
-
より安全で再現可能かつ設定可能なセットアップのためにTerraformインフラ・アズ・コードを使用する。
-
Fargateインスタンス上で一つのマネージャープロファイルを複数サポートする。
アーキテクチャ概要
主要要素:
-
ECSサービスはAWS Fargate上でマネージャーサービスをホストし、このサービスは複数のランナーマネージャーを登録できます。
-
各ランナーマネージャーは、このECSサービスの下で新しいECSタスクが作成されると、GitLabに自身を登録します。
-
GitLabからジョブがトリガーされると、適切なランナーマネージャーがジョブを割り当てられ、特定のサブネットとセキュリティグループで新しいワーカーECSタスクを実行してジョブを行います。
-
各ワーカータスクは、事前定義された役割とコンテナイメージを持っています。
デプロイメントプロセス
ステップ 1:マネージャー用のコンテナイメージをビルドして公開する
コード:https://github.com/GovTechSG/fargate-gitlab-runner
-
IMAGE_NAME
,IMAGE_TAG
,AWS_ACCOUNT_ID
,AWS_REGION
の環境変数を希望する値に設定します。IMAGE_NAME
は後でECRに公開するためにECRドメイン${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com
で始める必要があります。 -
docker-compose build
を使ってイメージをビルドします。またはdocker build -t ${IMAGE_NAME}:${IMAGE_TAG}
を実行します。 -
ECRにログインします。
aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com
-
docker-compose push
またはdocker push ${IMAGE_NAME}:${IMAGE_TAG}
を使ってECRに公開します。この単一イメージは
MANAGERS_CONFIGS
環境変数からプロファイルを使用して複数のマネージャーを生成します。
docker
の代わりにpodman
を使用する場合は、podman-composeもインストールしてください。
ステップ 2:ワーカータスク用のコンテナイメージをビルドして公開する
サンプルイメージはhttps://github.com/GovTechSG/fargate-gitlab-runner-workerにあります。
-
必要に応じて
Dockerfile
を更新して、新たなツールをインストールします。 -
上記のマネージャーイメージの手順を使用して、イメージをビルドしECRに公開します。
ステップ 3:ECSサービスが必要とする追加のリソースを設定する
次のリソースは手動で設定するか、別のTerraformコードセット(推奨)を使って設定する必要があります:
-
GitLabトークンのシークレット:GitLabからランナー用のトークンを取得し、AWSシークレットマネージャーまたはシステムマネージャーパラメータストアで新しいシークレットを作成します。使用するKMSキーに注意してください。
-
マネージャーやワーカー両方に必要なVPC、サブネット、セキュリティグループ。マネージャーとワーカーのネットワークACLおよびセキュリティグループ間でポート22を介したSSH通信が許可されることに注意してください。
-
ワーカータスクがAWSサービスにアクセスするために必要な適切なポリシーを持つワーカーECSタスクの役割。
Terragruntを使ってECSサービスをデプロイする
ステップ 4:コード:https://github.com/GovTechSG/fargate-gitlab-runner-terraform
-
environments/sample-dev
からenvironments/<env>
にコピーし、<env>
を希望する環境名に置き換えます。 -
environments/<env>/env_inputs.hcl
で環境設定を更新します。 -
マネージャーやワーカーにECSクラスタがまだ無い場合は、
environments/<env>/ecs-cluster-for-managers
やenvironments/<env>/ecs-cluster-for-workers
のサンプルに従って新しいクラスタを作成します。 -
environments/<env>/ecs-fargate-gitlab-runner-service/terragrunt.hcl
の変数値をあなたの環境に合わせて更新します。 -
cd environments/<env>/ecs-fargate-gitlab-runner-service && terragrunt apply
を使用してECSサービスをデプロイします。 -
数分後、ECSサービスのログを見直し、GitLabで新しいランナーが登録されたことを確認します。ランナーの数は
manager_instance_count * length(keys(managers_configs))
の数と等しくなるはずです。 -
あなた自身のジョブやこのようなシンプルなスクリプトで新しいGitLabランナーをテストします:
test:
tags:
- dev
- tool1
script:
- echo "It works!"
- for i in $(seq 1 30); do echo "."; sleep 1; done
フルスクリーンモードを終了する
成功すれば、このような出力が得られます:
(画像: 成功した実行の出力)
簡単なテスト用にTerragruntの代わりにTerraformを使用したい場合は:
terraform_modules/ecs-fargate-gitlab-runner-service
フォルダにenvironments/<env>/ecs-fargate-gitlab-runner-service/terragrunt.hcl
にあるすべての変数値を含むterraform.tfvars
ファイルを作成します。environments/terragrunt.hcl
からversions.tf
とprovider.tf
の内容をterraform_modules/ecs-fargate-gitlab-runner-service
のそれぞれのファイルにコピーします。- 最後に
terraform apply
を実行します。
Terraformによって作成されたリソース
Terraformモジュールによって作成された主要なリソースは以下の通りです:
-
マネージャーコンテナ用のECSサービス
-
必要な環境変数を備えたそのコンテナ定義
-
ワーカーECSタスク定義を用いて新しいECSタスクを実行および停止することを許可するそのIAMロール
-
managers_configsにある各マネージャープロファイルに対して1つずつ、ワーカーECSタスク定義
何が起こったのか?
登録中:
-
TerraformでECSサービスがデプロイされると、マネージャーコンテナイメージをホストするタスクを作成します。
-
このコンテナが起動すると、環境変数を読み込み(特に
MANAGERS_CONFIGS
変数)、それぞれのマネージャーをGitLabにランナーとして登録し、GitLabランナーの完全なconfig.toml
ファイルと個々のランナーのfargate_worker.toml
ファイルを生成します。これにはワーカーのセキュリティ、ネットワーク設定とタスク定義が含まれます。
GitLabのランナー一覧には、MANAGERS_CONFIGS
のキーごとに1つのランナー(manager_instance_count
が1と仮定する)が表示されるはずです。
(画像: GitLab UI内のランナー)
ジョブ実行:
-
そのランナーのタグリストのサブセットに一致するタグを持つジョブがトリガーされると、GitLabはジョブを適切なランナーマネージャーに送ります。
-
ランナーマネージャーは、
MANAGERS_CONFIGS
で渡されたタスク定義を使用して新しいワーカーECSタスクを開始し、プロセスでそのSSH_PUBLIC_KEY
を環境変数として追加します。 -
ワーカーECSタスクは、マネージャーの
SSH_PUBLIC_KEY
がauthorized_keys
に追加された状態でsshd
プロセス付きで開始されます。 -
最後に、マネージャーは
ssh
を介してワーカーECSタスクでジョブを実行し、ジョブの出力とステータスが通常どおりGitLabに共有されます。
トラブルシューティング
以下は発生可能ないくつかの問題です:
クラスタにコンテナインスタンスが見つからないため、Fargateタスクを開始できないというエラー
- ワーカー用のECSクラスタをチェックし、
Default capacity provider strategy
がFARGATE
に設定されていることを確認してください。
マネージャーがECSに接続してタスクを開始できない
- マネージャーがプライベートサブネット内にホストされている場合、VPCエンドポイントをECSおよびECR用に作成し、マネージャーがそれらにアクセスできることを確認してください。
マネージャーがssh
経由でワーカーECSタスクに接続できない
-
ワーカーコンテナイメージにopensshがインストールされていて、
SSH_PUBLIC_KEY
が正しいユーザーの~/.ssh/authorized_keys
に追加されていることを確認してください。 -
マネージャーとワーカーのサブネットとセキュリティグループがポート22での通信を許可していることを確認してください。VPC Reachability Analyzerを使用して確認してください。
-
エラーが
signature algorithm ssh-rsa not in PubkeyAcceptedAlgorithms
の場合は、ワーカーコンテナイメージにRUN echo “PubkeyAcceptedKeyTypes +ssh-rsa” >> /etc/ssh/sshd_config
を追加してssh-rsa
を有効にします。
ワーカーECSタスクがAWSへのアクセス資格情報を持っていない
AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
変数をSSHセッションに共有するために、sshd
実行にこれを追加します:-o "SetEnv=AWS_CONTAINER_CREDENTIALS_RELATIVE_URI=\"$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI\""
既知の制限:
- FargateドライバーはまだECS Execをサポートしていません。詳細はhttps://gitlab.com/gitlab-org/ci-cd/custom-executor-drivers/fargate/-/issues/49を参照してください。
結論
AWS Fargateを使用してGitLabのサーバレスランナーの完全なセットを設定しました。Terraformを使用することで、さまざまな環境に簡単に設定できます。
さらに、さまざまなツールがインストールされたワーカーイメージの配列、コストを最適化するために
こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/aws-builders/deploying-serverless-gitlab-runners-on-aws-fargate-with-terraform-898