- 前提条件
- ステップ 1: AWS Fargate タスク用のコンテナイメージの準備
- ステップ 2: コンテナイメージをレジストリにプッシュします。
- ステップ3:GitLab Runner用のEC2インスタンスの作成
- ステップ4:EC2インスタンスにGitLab Runnerをインストールして設定します。
- ステップ5:ECS Fargateクラスターの作成
- ステップ 6: ECSタスク定義の作成
- ステップ 7: 設定のテスト
- クリーンアップ
- AWS Fargateタスクの非公開設定
- トラブルシューティング
AWS Fargate上でGitLab CIを自動スケーリング
GitLabcustom executordriver forAWS Fargateは、各GitLab CIジョブを実行するためにAmazon Elastic Container Service(ECS) 上のコンテナを自動的に起動します。
このドキュメントのタスクを完了すると、ExecutorはGitLabから開始されたジョブを実行できるようになります。GitLabでコミットが行われるたびに、GitLabインスタンスは新しいジョブが利用可能であることをRunnerに通知します。Runner は、AWS ECS で設定したタスク定義に基づいて、ターゲットの ECS クラスターで新しいタスクを開始します。AWS ECSのタスク定義は任意のDockerイメージを使用するように設定できるので、AWS Fargate上で実行できるビルドの種類に柔軟性があります。
このドキュメントでは、実装の最初の理解を与えるための例を示しています。AWSでは追加のセキュリティが必要です。
例えば、2つのAWSセキュリティグループが必要かもしれません:
- 1つはGitLab RunnerをホストするEC2インスタンスで使用され、制限された外部IPレンジからのSSH接続のみを受け入れます(管理アクセス用)。
- Fargateタスクに適用され、EC2インスタンスからのSSHトラフィックのみを許可するもの。
さらに、非公開コンテナレジストリの場合、ECSタスクはIAM権限(AWS ECRのみ)を必要とするか、ECR以外のプライベートレジストリのタスクにはプライベートレジストリ認証が必要になります。
AWSインフラのプロビジョニングとセットアップを自動化するには、CloudFormationまたはTerraformを使用できます。
.gitlab-ci.yml
ファイル内のimage:
キーワードの値ではなく、ECS タスクで定義されたイメージを使用します。この設定により、Runner Manager のインスタンスが複数になったり、ビルドコンテナが大きくなったりする可能性があります。AWSはこのイシューを認識しており、GitLabは解決を追跡しています。公式のAWS EKS ブループリントに従ってEKS クラスターを作成することを検討してください。前提条件
始める前に
- EC2、ECS、ECRリソースを作成および設定する権限を持つAWS IAMユーザー。
- AWS VPCとサブネット。
- 1つ以上のAWSセキュリティグループ。
ステップ 1: AWS Fargate タスク用のコンテナイメージの準備
コンテナイメージを用意します。このイメージをレジストリにアップロードし、GitLabジョブの実行時にコンテナを作成するために使用します。
- イメージに CI ジョブのビルドに必要なツールが含まれていることを確認しましょう。例えば、Java プロジェクトには
Java JDK
と Maven や Gradle のようなビルドツールが必要です。Node.js プロジェクトにはnode
とnpm
が必要です。 - イメージに GitLab Runner があることを確認してください。GitLab Runner はアーティファクトとキャッシュを処理します。詳細については、カスタムエクゼキューターのドキュメントの実行ステージのセクションを参照してください。
- コンテナイメージが公開キー認証によるSSH接続を受け入れることができることを確認してください。Runner はこの接続を使用して、
.gitlab-ci.yml
ファイルで定義されたビルドコマンドを AWS Fargate 上のコンテナに送信します。SSHキーはFargateドライバによって自動的に管理されます。コンテナはSSH_PUBLIC_KEY
環境変数から鍵を受け入れることができなければなりません。
GitLab Runner と SSH 設定を含むDebian の例をご覧ください。Node.js の例をご覧ください。
ステップ 2: コンテナイメージをレジストリにプッシュします。
イメージを作成したら、ECSタスク定義で使用するコンテナレジストリにイメージを公開します。
- リポジトリを作成してイメージをECRにプッシュするには、Amazon ECR Repositoriesのドキュメントに従ってください。
- AWS CLI を使用して ECR にイメージをプッシュするには、Getting Started with Amazon ECR using the AWS CLIドキュメントに従ってください。
-
GitLab コンテナレジストリを使用するには、DebianまたはNodeJSのサンプルを使用します。Debian イメージは
registry.gitlab.com/tmaczukin-test-projects/fargate-driver-debian:latest
に公開されます。 NodeJS サンプルイメージはregistry.gitlab.com/aws-fargate-driver-demo/docker-nodejs-gitlab-ci-fargate:latest
に公開されます。
ステップ3:GitLab Runner用のEC2インスタンスの作成
AWSのEC2インスタンスを作成します。次のステップでは、GitLab Runnerをインストールします。
- https://console.aws.amazon.com/ec2/v2/home#LaunchInstanceWizard。
- インスタンスはUbuntu Server 18.04 LTS AMIを選択します。選択したAWSリージョンによって名前が異なる場合があります。
- インスタンスタイプはt2.microを選択します。Nextをクリックします:Configure Instance Details] をクリックします。
- Number of instances]はデフォルトのままにします。
- NetworkはVPCを選択します。
- 公開IPの自動割り当て]を[有効]に設定します。
-
IAMロール]で[新しいIAMロールの作成]をクリックします。このロールはテスト目的であり、セキュリティではありません。
- ロールの作成]をクリックします。
- AWSサービスを選択し、[Common use cases]で[EC2]をクリックします。次にNextをクリックします:権限]をクリックします。
- AmazonECS_FullAccessポリシーのチェックボックスを選択します。次へ」をクリックします:タグをクリックします。
- 次へ]をクリックします:レビュアー。
- IAMロールの名前(例:
fargate-test-instance
)を入力し、「Create role(ロールの作成)」をクリックします。
- インスタンスを作成しているブラウザ・タブに戻ります。
-
Create new IAM roleの左にある、refreshボタンをクリックします。
fargate-test-instance
ロールを選択します。Next]をクリックします:Add Storageをクリックします。 - Nextをクリックします:タグの追加。
- 次へ]をクリックします:セキュリティグループを設定します。
-
新しいセキュリティグループの作成]を選択し、名前を「
fargate-test
」とし、SSHのルールが定義されていることを確認します(Type: SSH, Protocol: TCP, Port Range: 22
)。受信および送信ルールのIP範囲を指定する必要があります。 - レビュアーと起動]をクリックします。
- 起動をクリックします。
- オプション。Create a new key pair(新しいキーペアを作成する)」を選択し、名前を「
fargate-runner-manager
」とし、「Download Key Pair(キーペアをダウンロードする)」ボタンをクリックします。SSH用の秘密鍵がコンピュータにダウンロードされます(ブラウザで設定されているディレクトリを確認してください)。 - Launch Instances]をクリックします。
- View Instances]をクリックします。
- インスタンスが立ち上がるのを待ちます。
IPv4 Public IP
アドレスをメモします。
ステップ4:EC2インスタンスにGitLab Runnerをインストールして設定します。
UbuntuインスタンスにGitLab Runnerをインストールします。
- GitLabプロジェクトのSettings > CI/CDに移動し、Runnerセクションを展開します。Set up a specific Runner manuallyの下にある登録トークンに注意してください。
-
chmod 400 path/to/downloaded/key/file
を実行して、鍵ファイルの権限が正しいことを確認します。 -
で作成したEC2インスタンスにSSHでログインします:
ssh ubuntu@[ip_address] -i path/to/downloaded/key/file
-
接続に成功したら、以下のコマンドを実行します:
sudo mkdir -p /opt/gitlab-runner/{metadata,builds,cache} curl -s "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash sudo apt install gitlab-runner
-
手順 1 で指定した GitLab の URL と登録トークンを指定してこのコマンドを実行します。
sudo gitlab-runner register --url "https://gitlab.com/" --registration-token TOKEN_HERE --name fargate-test-runner --run-untagged --executor custom -n
-
sudo vim /etc/gitlab-runner/config.toml
を実行し、以下の内容を追加してください:concurrent = 1 check_interval = 0 [session_server] session_timeout = 1800 [[runners]] name = "fargate-test" url = "https://gitlab.com/" token = "__REDACTED__" executor = "custom" builds_dir = "/opt/gitlab-runner/builds" cache_dir = "/opt/gitlab-runner/cache" [runners.custom] volumes = ["/cache", "/path/to-ca-cert-dir/ca.crt:/etc/gitlab-runner/certs/ca.crt:ro"] config_exec = "/opt/gitlab-runner/fargate" config_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "config"] prepare_exec = "/opt/gitlab-runner/fargate" prepare_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "prepare"] run_exec = "/opt/gitlab-runner/fargate" run_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "run"] cleanup_exec = "/opt/gitlab-runner/fargate" cleanup_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "cleanup"]
-
非公開CAでセルフマネージド・インスタンスを使用している場合は、次の行を追加してください:
volumes = ["/cache", "/path/to-ca-cert-dir/ca.crt:/etc/gitlab-runner/certs/ca.crt:ro"]
証明書の信頼についてはこちらをご覧ください。
以下に示す
config.toml
ファイルのセクションは、登録コマンドによって作成されます。変更しないでください。concurrent = 1 check_interval = 0 [session_server] session_timeout = 1800 name = "fargate-test" url = "https://gitlab.com/" token = "__REDACTED__" executor = "custom"
-
sudo vim /etc/gitlab-runner/fargate.toml
を実行し、以下の内容を追加してください:LogLevel = "info" LogFormat = "text" [Fargate] Cluster = "test-cluster" Region = "us-east-2" Subnet = "subnet-xxxxxx" SecurityGroup = "sg-xxxxxxxxxxxxx" TaskDefinition = "test-task:1" EnablePublicIP = true [TaskMetadata] Directory = "/opt/gitlab-runner/metadata" [SSH] Username = "root" Port = 22
-
TaskDefinition
の名前と同様に、Cluster
の値にも注意してください。 この例では、リビジョン番号として:1
を指定したtest-task
を示しています。リビジョン番号が指定されていない場合、最新のアクティビティリビジョンが使用されます。 - 地域を選択してください。Runner Managerインスタンスから
Subnet
の値を取得します。 -
セキュリティグループIDを検索します:
- AWSのインスタンス一覧で、作成したEC2インスタンスを選択します。詳細が表示されます。
- セキュリティグループ]で、作成したグループ名をクリックします。
- セキュリティグループIDをコピーします。
本番環境では、セキュリティグループの設定と使用に関するAWS のガイドラインに従ってください。
-
EnablePublicIP
を true に設定すると、タスクコンテナの公開 IP を収集して SSH 接続を行います。 -
EnablePublicIP
が false に設定されている場合:- Fargate ドライバはタスクコンテナの非公開 IP を使用します。
false
に設定されている場合に接続を設定するには、VPC のセキュリティグループに Port 22(SSH)のインバウンドルールが必要です。 - 外部の依存関係を取得するには、プロビジョニングされた AWS Fargate コンテナが公開インターネットにアクセスできる必要があります。AWS Fargateコンテナに公開インターネットアクセスを提供するには、VPCでNAT Gatewayを使用できます。
- Fargate ドライバはタスクコンテナの非公開 IP を使用します。
- SSHサーバーのポート番号は省略可能です。省略した場合、デフォルトの SSH ポート(22)が使用されます。
- セクション設定の詳細については、Fargateドライバのドキュメントを参照してください。
-
-
Fargateドライバをインストールします:
sudo curl -Lo /opt/gitlab-runner/fargate "https://gitlab-runner-custom-fargate-downloads.s3.amazonaws.com/latest/fargate-linux-amd64" sudo chmod +x /opt/gitlab-runner/fargate
ステップ5:ECS Fargateクラスターの作成
Amazon ECSクラスタは、ECSコンテナインスタンスのグループです。
-
https://console.aws.amazon.com/ecs/home#/clusters
にアクセスしてください。 - クラスターの作成]をクリックします。
- Networking onlytype]を選択します。次のステップ]をクリックします。
- 名前を
test-cluster
にします(fargate.toml
と同じ)。 - 作成」をクリックします。
-
クラスターの表示]をクリックします。
Cluster ARN
の値から、リージョンとアカウントIDの部分に注意してください。 - クラスターの更新]ボタンをクリックします。
-
Default capacity provider strategy
の横にある [Add another provider] をクリックし、FARGATE
を選択します。更新]をクリックします。
ECS Fargate上のクラスターのセットアップと作業に関する詳細な手順については、AWSのドキュメントを参照してください。
ステップ 6: ECSタスク定義の作成
このステップでは、CIビルドに使用するコンテナイメージを参照して、Fargate
タイプのタスク定義を作成します。
-
https://console.aws.amazon.com/ecs/home#/taskDefinitions
にアクセスしてください。 - 新しいタスク定義の作成」をクリックします。
- FARGATE]を選択し、[次のステップ]をクリックします。
- 名前は
test-task
とします。(注:この名前はfargate.toml
ファイルで定義された値と同じですが、:1
は含まれません)。 - タスク・メモリ((GB))と タスクCPU(vCPU)の値を選択します。
-
コンテナの追加]をクリックします。次に
- Fargateドライバが環境変数
SSH_PUBLIC_KEY
をインジェクトできるように、ci-coordinator
という名前を付けます。 - イメージを定義します(例えば
registry.gitlab.com/tmaczukin-test-projects/fargate-driver-debian:latest
)。 - 22/TCPのポートマッピングを定義します。
- Addをクリックします。
- Fargateドライバが環境変数
- 作成」をクリックします。
- タスク定義の表示]をクリックします。
ci-coordinator
の名前を持つコンテナのみにSSH_PUBLIC_KEY
環境変数を注入します。Fargate ドライバが使用するすべてのタスク定義に、この名前を持つコンテナが必要です。この名前のコンテナは、前述のように SSH サーバーと GitLab Runner のすべての要件がインストールされているものでなければなりません。タスク定義の設定と操作の詳細については、AWS のドキュメントを参照してください。
AWS ECR からイメージを起動するために必要な ECS サービスの権限については、AWS ドキュメントAmazon ECS タスク実行 IAM ロールを参照してください。
GitLab インスタンス上でホストされているものを含む非公開レジストリに対して ECS が認証を行うための情報については、AWS documentationPrivate registry authentication for tasksを参照してください。
この時点で Runner Manager と Fargate Driver は設定され、AWS Fargate 上でジョブの実行を開始する準備が整いました。
ステップ 7: 設定のテスト
これで設定が完了しました。
-
GitLab プロジェクトで、
.gitlab-ci.yml
ファイルを作成します:test: script: - echo "It works!" - for i in $(seq 1 30); do echo "."; sleep 1; done
- プロジェクトのCI/CD > パイプラインに移動します。
- パイプラインの実行をクリックします。
- ブランチと変数を更新し、パイプラインの実行をクリックします。
.gitlab-ci.yml
ファイルのimage
とservice
キーワードは無視されます。Runnerはタスク定義で指定された値のみを使用します。クリーンアップ
AWS Fargateでカスタムエグゼキュータをテストした後にクリーンアップを行いたい場合は、以下のオブジェクトを削除します:
AWS Fargateタスクの非公開設定
高いセキュリティを確保するために、AWS Fargateの非公開タスクを設定します。この設定では、ExecutorはAWS内部のIPアドレスのみを使用し、AWSからのアウトバウンドトラフィックのみを許可するため、CIジョブは非公開のAWS Fargateインスタンス上で実行されます。
プライベートAWS Fargateタスクを設定するには、以下の手順でAWSを設定し、プライベートサブネットでAWS Fargateタスクを実行します:
- 既存の公開サブネットが VPC アドレス範囲のすべての IP アドレスを予約していないことを確認します。VPCとサブネットのCIRDアドレス範囲を検査します。サブネットのCIRDアドレス範囲がVPCのCIRDアドレス範囲のサブセットである場合は、手順2と4をスキップします。そうでない場合は、VPCに空きアドレス範囲がないため、VPCと公開サブネットを削除して再作成する必要があります:
- 既存のサブネットとVPCを削除します。
- 削除したVPCと同じ設定のVPCを作成し、CIRDアドレスを更新します(例:
10.0.0.0/23
)。 - 削除したサブネットと同じ設定で公開サブネットを作成します。VPCのアドレス範囲のサブセットであるCIRDアドレスを使用します(例:
10.0.0.0/24
)。
- 公開サブネットと同じ設定の非公開サブネットを作成します。公開サブネット範囲と重複しないCIRDアドレス範囲を使用します(例:
10.0.1.0/24
)。 - NATゲートウェイを作成し、公開サブネット内に配置します。
- 宛先
0.0.0.0/0
がNATゲートウェイを指すように、非公開サブネットのルーティングテーブルを変更します。 -
farget.toml
設定を更新します:Subnet = "private-subnet-id" EnablePublicIP = false UsePublicIP = false
-
以下のインラインポリシーをfargateタスクに関連するIAMロールに追加します(fargateタスクに関連するIAMロールは通常
ecsTaskExecutionRole
という名前で、すでに存在しているはずです)。{ "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue", "kms:Decrypt", "ssm:GetParameters" ], "Resource": [ "arn:aws:secretsmanager:*:<account-id>:secret:*", "arn:aws:kms:*:<account-id>:key/*" ] } ] }
- セキュリティグループの “inbound rules “を、セキュリティグループ自身を参照するように変更します。AWSの設定ダイアログで:
-
Type
をssh
に設定します。 -
Source
をCustom
に設定します。 - セキュリティグループを選択します。
- 任意のホストからの SSH アクセスを許可する既存の受信ルールを削除します。
-
詳細は以下のAWSドキュメントを参照してください:
- Amazon ECSタスク実行IAMロール
- Amazon ECR インターフェース VPC エンドポイント (AWS PrivateLink)
- Amazon ECSインターフェース VPCエンドポイント
- 公開サブネットと非公開サブネットを持つVPC
トラブルシューティング
No Container Instances were found in your cluster
設定テスト時のエラー
error="starting new Fargate task: running new task on Fargate: error starting AWS Fargate Task: InvalidParameterException: No Container Instances were found in your cluster."
AWS Fargate Driverは、ECSクラスタがデフォルトのキャパシティ・プロバイダ・ストラテジで設定されている必要があります。
さらに読む
- デフォルトのキャパシティ・プロバイダー戦略は、各Amazon ECSクラスターに関連付けられています。他のキャパシティプロバイダー戦略または起動タイプが指定されていない場合、タスクの実行またはサービスの作成時にクラスターはこの戦略を使用します。
-
capacityProviderStrategy
が指定されている場合、launchType
パラメータは省略する必要があります。capacityProviderStrategy
またはlaunchType
が指定されていない場合、クラスターのdefaultCapacityProviderStrategy
が使用されます。
ジョブ実行時のメタデータfile does not exist
エラー
Application execution failed PID=xxxxx error="obtaining information about the running task: trying to access file \"/opt/gitlab-runner/metadata/<runner_token>-xxxxx.json\": file does not exist" cleanup_std=err job=xxxxx project=xx runner=<runner_token>
IAM ロールポリシーが正しく設定され、/opt/gitlab-runner/metadata/
のメタデータ JSON ファイルを作成するための書き込みオペレーションを実行できることを確認してください。非本番環境でテストするには、AmazonECS_FullAccess ポリシーを使用します。組織のセキュリティ要件に従って、IAMロールポリシーをレビューします。
connection timed out
ジョブ実行時
Application execution failed PID=xxxx error="executing the script on the remote host: executing script on container with IP \"172.x.x.x\": connecting to server: connecting to server \"172.x.x.x:22\" as user \"root\": dial tcp 172.x.x.x:22: connect: connection timed out"
EnablePublicIP
が false に設定されている場合は、VPC のセキュリティグループに SSH 接続を許可する受信ルールがあることを確認してください。AWS Fargateタスクコンテナは、GitLab Runner EC2インスタンスからのSSHトラフィックを受け入れることができなければなりません。
connection refused
ジョブ実行時
Application execution failed PID=xxxx error="executing the script on the remote host: executing script on container with IP \"10.x.x.x\": connecting to server: connecting to server \"10.x.x.x:22\" as user \"root\": dial tcp 10.x.x.x:22: connect: connection refused"
ステップ6:ECSタスク定義の作成」の説明に基づいて、タスクコンテナのポート22が公開され、ポートマッピングが設定されていることを確認します。ポートが公開され、コンテナが設定されている場合:
- Amazon ECS > クラスター > タスク定義の選択 > タスクで、コンテナにエラーがないか確認します。
- ステータスが
Stopped
のタスクを表示し、失敗した最新のものを確認します。コンテナに障害が発生した場合、ログタブに詳細が表示されます。
あるいは、Dockerコンテナをローカルで実行できることを確認してください。