今回はAmazon EC2インスタンスをGitLab Runnerとして登録する手順について紹介します。
背景
GitLab RunnerはGitLab CI/CDパイプラインの実行基盤です。GitLab SaaS版を利用する場合、Shared Runnerという共有リソースを利用できますが、セキュリティ等の理由から自前の仮想マシン・コンテナをRunnerとして管理したいケースもあると思います。
GitLab Runnerは以下の3種類があり、Runnerを登録するうえでどの形態が良いか確認する必要があります。今回はGitLab SaaS版に Project Runner
を登録する手順を検証しました。
Project Runner
: 特定のProject専用のRunnerGroup Runner
: Group内の全てのporjectが利用できるRunnerInstance (Shared) Runner
: GitLab Instance内の全てのProjectが利用できるRunner※
※ドキュメントを見ると、GitLab 16.8までは Shared runner
という名称でしたが、GitLab 16.9からは Instance runner
に変わったようです。
また、GitLab RunnerとGitLabの処理の流れは、GitLabドキュメントに記載されています。GitLab RunnerとGitLab間では、GitLab RunnerからGitLab方向の通信のみが発生します。そのため、GitLab Runnerは、GitLabに対するアウトバウンド方向の通信 (ポート: 443) を許可すれば利用可能です。
検証
Runner authentication tokenの取得
GitLab Runnerを登録するため、まずはGitLab側でRunnerの認証に使うトークンを発行します。GitLabの画面から 設定
CI/CD
を選択します。
Runnerの項目を開き、 新規プロジェクトRunner
を選択します。
次のページで、登録するRunnerの情報を入力します。ここでは以下のように設定しました。
- プラットフォーム:
Linux
- Tags:
project-test
- その他: 空欄
上記設定を入力後に ランナーを作成
を選択すると、Runnerを登録するためのコマンドやRunner authentication tokenが表示されます。Runner authentication tokenはここでしか確認できないため、コピーしておきます。
Runnerのページに戻ると、Project Runnerは割り当てられていますが、黒三角のアイコンが表示されています。これはこのRunnerがまだ利用できない状態であることを示します。
AWS Secrets Managerへの登録
Runner authentication tokenはGitLab Runnerを登録する際に利用します。後ほどAWS CloudFormationテンプレートでAmazon EC2を作成する際にトークン情報を使いますが、テンプレートに直接記述するのを避けるため、事前にAWS Secrets managerに登録したものを呼び出す形にしました。
AWS Secrets managerのメニューを開き、シークレットの作成を行います。ここでは GitLabProjectRunnerToken
という名称のシークレットを作成しました。
作成時は その他のシークレットのタイプ
を選択し、プレーンテキストでRunner authentication tokenを記載しました。
Amazon EC2の作成
つづいて、GitLab RunnerをインストールするAmazon EC2インスタンスを用意します。ここではVPC/Security Group/IAM等も含めてリソースを作成しており、SSMでインスタンスにアクセスできるよう設定しています。
gitlab-runner-ec2.yaml
AWSTemplateFormatVersion: '2010-09-09' Description: "EC2 instance for GitLab Runner" Parameters: ImageId: Default: "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> InstanceType: Default: "t3.large" Type: String KeyName: Type: String VPCCidr: Default: "10.0.0.0/16" Type: String PublicSubnetCidr: Default: "10.0.0.0/24" Type: String PublicSubnetAZ: Default: "ap-northeast-1a" Type: String EnvName: Default: "gitlab-runner-test" Type: String Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VPCCidr EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Ref EnvName PublicSubnet: Type: AWS::EC2::Subnet DependsOn: AttachGateway Properties: CidrBlock: !Ref PublicSubnetCidr VpcId: !Ref VPC AvailabilityZone: !Ref PublicSubnetAZ Tags: - Key: Name Value: !Ref EnvName InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Ref EnvName AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway PublicRouteTable: Type: AWS::EC2::RouteTable DependsOn: AttachGateway Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Ref EnvName PublicRoute: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnetRouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet RouteTableId: !Ref PublicRouteTable EIP: Type: AWS::EC2::EIP Properties: Domain: vpc Tags: - Key: Name Value: !Ref EnvName EIPAssociation: Type: AWS::EC2::EIPAssociation Properties: AllocationId: !GetAtt EIP.AllocationId InstanceId: !Ref GitLabInstance EC2SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: EC2SecurityGroup VpcId: !Ref VPC Tags: - Key: Name Value: !Sub ${EnvName}-EC2SecurityGroup SecurityGroupIngress: - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: '0.0.0.0/0' EC2IAMRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${EnvName}-SSM-role AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore - arn:aws:iam::aws:policy/SecretsManagerReadWrite EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: - Ref: EC2IAMRole InstanceProfileName: !Sub ${EnvName}-EC2InstanceProfile GitLabInstance: Type: AWS::EC2::Instance Properties: ImageId: !Ref ImageId KeyName: !Ref KeyName InstanceType: !Ref InstanceType SecurityGroupIds: - !Ref EC2SecurityGroup IamInstanceProfile: !Ref EC2InstanceProfile SubnetId: !Ref PublicSubnet UserData: Fn::Base64: | #!/bin/bash sudo yum update -y sudo amazon-linux-extras install -y docker sudo systemctl start docker sudo systemctl enable docker sudo usermod -a -G docker ec2-user curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash sudo yum install -y gitlab-runner RUNNER_TOKEN=$(aws --region=ap-northeast-1 secretsmanager get-secret-value --secret-id GitLabProjectRunnerToken --query 'SecretString' --output text) sudo gitlab-runner register \ --non-interactive \ --url "https://gitlab.com/" \ --token $RUNNER_TOKEN \ --executor "docker" \ --docker-image alpine:latest \ --description "docker-runner" Tags: - Key: Name Value: !Sub ${EnvName}-EC2
Runnerの登録の確認と動作確認
Amazon EC2が作成されてしばらくすると、GitLabのRunnerページに表示されるProject Runnerは緑丸のアイコンが表示されます。
この状態になると登録したGitLab Runnerは利用可能となるため、テスト用の .gitlab-ci.yml
を作成します。登録したRunnerをGitLab CI/CDから呼び出すには、 tags
に登録時に指定したタグを指定します (今回は project-test
)。ここでは以下のファイルを使用しました。
job: stage: build tags: - project-test script: - echo "Hello, GitLab Runner!"
上記ファイルを作成するとパイプラインが起動します。
実行後のログを見ると、作成したRunnerを使ってJobを実行したことを確認できます。