正式なドキュメントは英語版であり、この日本語訳はAI支援翻訳により作成された参考用のものです。日本語訳の一部の内容は人間によるレビューがまだ行われていないため、翻訳のタイミングにより英語版との間に差異が生じることがあります。最新かつ正確な情報については、英語版をご参照ください。

AWS FargateでGitLab CIをオートスケールする

  • プラン: Free、Premium、Ultimate
  • 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated

Fargateドライバーは、コミュニティでサポートされています。GitLabサポートは問題のデバッグを支援しますが、保証は提供しません。

GitLabのcustom executorドライバー(AWS Fargate用)は、Amazon Elastic Container Service (ECS) 上のコンテナを自動的に起動して、各GitLab CIジョブを実行します。

このドキュメントのタスクを完了すると、executorはGitLabから開始されたジョブを実行できます。GitLabでコミットが行われるたびに、GitLabインスタンスは新しいジョブが利用可能になったことをRunnerに通知します。次に、Runnerは、AWS ECSで設定したタスク定義に基づいて、ターゲットECSクラスターで新しいタスクを開始します。任意のDockerイメージを使用するようにAWS ECSタスク定義を設定できます。このアプローチを使用すると、AWS Fargateで実行できるビルドのタイプを完全に柔軟に設定できます。

GitLab Runner Fargateドライバーのアーキテクチャ

このドキュメントでは、実装の最初の理解を深めるための例を示します。本番環境での使用を目的としたものではありません。AWSでは追加のセキュリティが必要です。

たとえば、2つのAWSセキュリティグループが必要になる場合があります:

  • GitLab RunnerをホストするEC2インスタンスで使用され、制限された外部IP範囲(管理アクセス用)からのSSH接続のみを受け入れるもの。
  • Fargateタスクに適用され、EC2インスタンスからのSSHトラフィックのみを許可するもの。

非公開のコンテナレジストリの場合、ECSタスクには、IAM権限(AWS ECRのみ)または非ECRプライベートレジストリのタスクのプライベートレジストリ認証が必要です。

CloudFormationまたはTerraformを使用して、AWSインフラストラクチャのプロビジョニングとセットアップを自動化できます。

CI/CDジョブは、image:ファイルの.gitlab-ci.ymlキーワードの値ではなく、ECSタスクで定義されたイメージを使用します。ECSでは、ECSタスクに使用されるイメージをオーバーライドすることはできません。

この制限を回避するには、次の操作を実行できます:

  • Runnerが使用するすべてのプロジェクトのすべてのビルド依存関係を含むイメージをECSタスク定義に作成して使用します。
  • 異なるイメージを持つ複数のECSタスク定義を作成し、FARGATE_TASK_DEFINITION CI/CD変数でARNを指定します。
  • 公式のAWS EKSブループリントに従って、EKSクラスターの作成を検討してください。

詳細については、GitLab EKS Fargate Runnerを1時間で開始し、コードをゼロにするを参照してください。

Fargateはコンテナホストを抽象化するため、コンテナホストのプロパティの設定可能性が制限されます。これは、ディスクまたはネットワークへの高いIOを必要とするRunnerワークロードに影響します。これらのプロパティは、Fargateでは設定可能性が限られているか、設定できないためです。FargateでGitLab Runnerを使用する前に、CPU、メモリ、ディスクI/O、またはネットワークI/Oに関するコンピューティング特性の高いRunnerワークロードがFargateに適していることを確認してください。

前提条件

始める前に、以下が必要です:

  • EC2、ECS、ECRリソースを作成および構成する権限を持つAWS IAMユーザー。
  • AWS VPCとサブネット。
  • 1つ以上のAWSセキュリティグループ。

ステップ1: AWS Fargateタスクのコンテナイメージを準備する

コンテナイメージを準備します。このイメージをレジストリにアップロードできます。このレジストリは、GitLabジョブの実行時にコンテナを作成するために使用できます。

  1. イメージにCIジョブのビルドに必要なツールがあることを確認します。たとえば、Javaプロジェクトには、Java JDKやMavenやGradleなどのビルドツールが必要です。Node.jsプロジェクトには、nodenpmが必要です。
  2. イメージにアーティファクトとキャッシュを処理するGitLab Runnerがあることを確認します。詳細については、カスタムexecutorドキュメントの実行ステージセクションを参照してください。
  3. コンテナイメージが公開キー認証を介してSSH接続を受け入れることができることを確認します。Runnerは、この接続を使用して、.gitlab-ci.ymlファイルで定義されたビルドコマンドをAWS Fargate上のコンテナに送信します。SSHキーは、Fargateドライバーによって自動的に管理されます。コンテナは、SSH_PUBLIC_KEY環境変数からのキーを受け入れることができる必要があります。

GitLab RunnerとSSH構成を含むDebianの例をご覧ください。Node.jsの例をご覧ください。

ステップ2: コンテナイメージをレジストリにプッシュする

イメージを作成したら、ECSタスク定義で使用するために、イメージをコンテナレジストリに公開します。

  • リポジトリを作成してイメージをECRにプッシュするには、Amazon ECRリポジトリのドキュメントに従ってください。
  • AWS CLIを使用してイメージをECRにプッシュするには、AWS CLIを使用したAmazon ECRの概要ドキュメントに従ってください。
  • 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をインストールします。

  1. https://console.aws.amazon.com/ec2/v2/home#LaunchInstanceWizardにアクセスします。
  2. インスタンスの場合は、Ubuntu Server 18.04 LTS AMIを選択します。名前は、選択したAWSリージョンによって異なる場合があります。
  3. インスタンスタイプの場合は、t2.microを選択します。次へ: インスタンスの詳細を設定
  4. Number of instancesはデフォルトのままにします。
  5. ネットワークはネットワーク、VPCを選択します。
  6. Auto-assign Public IP有効に設定します。
  7. IAM roleで、Create new IAM roleを選択します。このロールはテストのみを目的としており、安全ではありません。
    1. Create roleを選択します。
    2. AWS serviceを選択し、Common use casesで、EC2を選択します。次に、次へ:を選択します: 権限
    3. AmazonECS_FullAccessポリシーのチェックボックスをオンにします。次へ: タグ
    4. 次へ: レビュー
    5. IAMロールの名前(fargate-test-instanceなど)を入力し、ロールを作成するを選択します。
  8. インスタンスを作成しているブラウザータブに戻ります。
  9. Create new IAM roleの左側にある更新ボタンを選択します。fargate-test-instanceロールを選択します。次へ: ストレージを追加
  10. 次へ: タグの追加
  11. 次へ: セキュリティグループを設定
  12. Create a new security groupを選択し、fargate-testという名前を付けて、SSHのルールが定義されていることを確認します(Type: SSH, Protocol: TCP, Port Range: 22)。インバウンドルールとアウトバウンドルールのIP範囲を指定する必要があります。
  13. Review and Launchを選択します。
  14. Launchを選択します。
  15. オプション。オプション。Create a new key pairを選択し、fargate-runner-managerという名前を付けて、Download Key Pairを選択します。SSHのプライベートキーがコンピューターにダウンロードされます(ブラウザーで構成されたディレクトリを確認してください)。
  16. Launch Instancesを選択します。
  17. View Instancesを選択します。
  18. インスタンスが起動するまで待ちます。IPv4 Public IPアドレスを書き留めます。

ステップ4: EC2インスタンスにGitLab Runnerをインストールして構成する

次に、UbuntuインスタンスにGitLab Runnerをインストールします。

  1. GitLabプロジェクトの設定 > CI/CDに移動し、Runnerセクションを展開します。Set up a specific Runner manuallyで、登録トークンを書き留めます。

  2. キーファイルに適切な権限があることを確認するために、chmod 400 path/to/downloaded/key/fileを実行します。

  3. 次のコマンドを使用して、作成したEC2インスタンスにSSHで接続します:

    ssh ubuntu@[ip_address] -i path/to/downloaded/key/file
  4. 正常に接続されたら、次のコマンドを実行します:

    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
  5. 手順1でメモしたGitLab URLと登録トークンを使用して、このコマンドを実行します。

    sudo gitlab-runner register --url "https://gitlab.com/" --registration-token TOKEN_HERE --name fargate-test-runner --run-untagged --executor custom -n
  6. 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"]
  7. プライベートCAを持つGitLab Self-Managedインスタンスがある場合は、次の行を追加します:

           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"
  8. 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
    • Clusterの値とTaskDefinitionの名前を書き留めます。この例では、test-taskがリビジョン番号として:1と表示されています。リビジョン番号が指定されていない場合は、最新のactiveなリビジョンが使用されます。

    • リージョンを選択します。RunnerマネージャーインスタンスからSubnetの値を取得します。

    • セキュリティグループIDを見つける方法:

      1. AWSのインスタンスのリストで、作成したEC2インスタンスを選択します。詳細が表示されます。
      2. Security groupsで、作成したグループの名前を選択します。
      3. Security group IDをコピーします。

      本番環境では、セキュリティグループの設定と使用に関するAWSガイドラインに従ってください。

    • EnablePublicIPがtrueに設定されている場合、タスクコンテナのパブリックIPが収集され、SSH接続が実行されます。

    • EnablePublicIPがfalseに設定されている場合:

      • Fargateドライバーは、タスクコンテナのプライベートIPを使用します。falseに設定されている場合に接続をセットアップするには、VPCセキュリティグループにポート22(SSH)のインバウンドルールが必要です。ソースはVPC CIDRです。
      • 外部依存関係をフェッチするには、プロビジョニングされたAWS Fargateコンテナがパブリックインターネットにアクセスできる必要があります。AWS Fargateコンテナにパブリックインターネットアクセスを提供するには、VPCでNATゲートウェイを使用できます。
    • SSHサーバーのポート番号はオプションです。省略した場合、デフォルトのSSHポート(22)が使用されます。

    • セクション設定の詳細については、Fargateドライバードキュメントを参照してください。

  9. 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コンテナインスタンスのグループです。

  1. https://console.aws.amazon.com/ecs/home#/clustersにアクセスします。
  2. Create Clusterを選択します。
  3. Networking onlyタイプを選択します。次のステップを選択します。
  4. 名前をtest-clusterfargate.tomlと同じ)にします。
  5. Createを選択します。
  6. View clusterを選択します。Cluster ARNの値からリージョンとアカウントIDの部分を書き留めます。
  7. Update Clusterを選択します。
  8. Default capacity provider strategyの横にあるAdd another providerを選択し、FARGATEを選択します。更新を選択します。

ECS Fargateでのクラスターの設定と操作の詳細な手順については、AWSドキュメントを参照してください。

ステップ6: ECSタスク定義を作成する

この手順では、タイプFargateのタスク定義を作成し、CIビルドに使用するコンテナイメージを参照します。

  1. https://console.aws.amazon.com/ecs/home#/taskDefinitionsにアクセスします。
  2. Create new Task Definitionを選択します。
  3. FARGATEを選択し、次のステップを選択します。
  4. 名前をtest-taskにします。(注: 名前はfargate.tomlファイルで定義されているのと同じ値ですが、:1はありません)。
  5. **Task memory (GB)Task CPU (vCPU)**の値を選択します。
  6. Add containerを選択します。次に:
    1. ci-coordinatorという名前を付けて、FargateドライバーがSSH_PUBLIC_KEY環境変数を挿入できるようにします。
    2. イメージを定義します(例:registry.gitlab.com/tmaczukin-test-projects/fargate-driver-debian:latest)。
    3. 22/TCPのポートマッピングを定義します。
    4. 追加を選択します。
  7. Createを選択します。
  8. View task definitionを選択します。

単一のFargateタスクで、1つまたは複数のコンテナを起動できます。Fargateドライバーは、ci-coordinatorという名前のコンテナにのみ、SSH_PUBLIC_KEY環境変数を挿入します。Fargateドライバーで使用されるすべてのタスク定義に、この名前のコンテナが必要です。この名前の付いたコンテナは、上記のように、SSHサーバーとすべてのGitLab Runnerの要件がインストールされているものである必要があります。

タスク定義の設定と操作の詳細な手順については、AWSのドキュメントを参照してください。

AWS ECRからイメージを起動するために必要なECSサービス許可については、Amazon ECSタスク実行IAMロールを参照してください。

GitLabインスタンスでホストされているものを含む、プライベートレジストリへのECS認証については、タスクのプライベートレジストリ認証を参照してください。

この時点で、RunnerマネージャーとFargateドライバーが構成され、AWS AWS Fargateでジョブの実行を開始する準備が完了します。

ステップ7: 設定のテスト

これで設定を使用する準備ができました。

  1. GitLabプロジェクトで、.gitlab-ci.ymlファイルを作成します:

    test:
      script:
        - echo "It works!"
        - for i in $(seq 1 30); do echo "."; sleep 1; done
  2. プロジェクトのCI/CD > パイプラインに移動します。

  3. Run Pipelineを選択します。

  4. ブランチとすべての変数を更新し、Run Pipelineを選択します。

.gitlab-ci.ymlファイル内のimageおよびserviceキーワードは無視されます。Runnerは、タスク定義で指定された値のみを使用します。

クリーンアップ

AWS AWS Fargateでカスタムexecutorをテストした後でクリーンアップを実行する場合は、次のオブジェクトを削除します:

  • 手順3で作成されたEC2インスタンス、キーペア、IAMロール、およびセキュリティグループ。
  • 手順5で作成されたECS AWS Fargateクラスター。
  • 手順6で作成されたECSタスク定義。

プライベートAWS AWS Fargateタスクの設定

高度なセキュリティを確保するには、プライベートAWS AWS Fargateタスクを設定します。この設定では、executorは内部AWS IPアドレスのみを使用します。CI/CDジョブがプライベートAWS AWS Fargateインスタンスで実行されるように、AWSからの送信トラフィックのみを許可します。

プライベートAWS AWS Fargateタスクを設定するには、次の手順を完了して、AWSを設定し、プライベートサブネットでAWS AWS Fargateタスクを実行します:

  1. 既存のパブリックサブネットが、VPCアドレス範囲内のすべてのIPアドレスを予約していないことを確認します。VPCとサブネットのcirdアドレス範囲を調べます。サブネットcirdアドレス範囲がVPC cirdアドレス範囲のサブセットである場合は、手順2と4をスキップします。それ以外の場合、VPCに使用可能なアドレス範囲がないため、VPCとパブリックサブネットを削除して再作成する必要があります:

    1. 既存のサブネットとVPCを削除します。
    2. 削除したVPCと同じ設定でVPCを作成するし、cirdアドレス(例:10.0.0.0/23)を更新します。
    3. 削除したサブネットと同じ設定でパブリックサブネットを作成するcirdアドレス範囲(例:10.0.0.0/24)であるVPCアドレス範囲のサブセットであるアドレスを使用します。
  2. パブリックサブネットと同じ設定でプライベートサブネットを作成するcirdアドレス範囲(例:10.0.1.0/24)であるパブリックサブネット範囲と重複しないアドレス範囲を使用します。

  3. NATゲートウェイを作成するし、パブリックサブネット内に配置します。

  4. 宛先0.0.0.0/0がNATゲートウェイを指すように、プライベートサブネットルーティングテーブルを変更します。

  5. farget.toml設定を更新します:

    Subnet = "private-subnet-id"
    EnablePublicIP = false
    UsePublicIP = false
  6. 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/*"
                ]
            }
        ]
    }
  7. セキュリティグループ自体の参照するように、セキュリティグループの「受信ルール」を変更します。AWS設定ダイアログで、以下を実行します:

    • Typesshに設定します。
    • SourceCustomに設定します。
    • セキュリティグループを選択します。
    • 任意のホストからのSSHアクセスを許可する既存の受信ルールを削除します。

既存の受信ルールを削除すると、SSHを使用してAmazon Elastic Compute Cloudインスタンスに接続できなくなります。

詳細については、次のAWSドキュメントを参照してください:

トラブルシューティング

設定をテストする際のエラー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 AWS Fargateドライバーでは、デフォルトのキャパシティプロバイダー戦略で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 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"

タスクコンテナのポート22が公開されており、手順6の指示に基づいてポートマッピングが設定されていることを確認します: ECSタスク定義を作成します。ポートが公開されていて、コンテナが設定されている場合:

  1. Amazon ECS > Clusters > Choose your task definition > Tasksで、コンテナのエラーがないか確認します。
  2. Stoppedステータスのタスクを表示し、失敗した最新のタスクを確認します。コンテナに失敗がある場合、logsタブには詳細が表示されます。

または、Dockerコンテナをローカルで実行できることを確認します。

エラー: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain

AWS AWS Fargateドライバーの古いバージョンが原因で、サポートされていないキータイプが使用されている場合、次のエラーが発生します。

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\": ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain"

この問題を解決するには、最新のAWS AWS FargateドライバーをGitLab Runner EC2インスタンスにインストールします:

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