TECHSTEP

ITインフラ関連の記事を公開してます。

GitLab RunnerとしてLinuxサーバーを登録する

今回は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専用のRunner
  • Group Runner: Group内の全てのporjectが利用できるRunner
  • Instance (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) を許可すれば利用可能です。

docs.gitlab.com

検証

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を実行したことを確認できます。