AWS EC2에서 GitLab Runner 자동 스케일링

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-Managed

GitLab Runner의 가장 큰 장점 중 하나는 빌드가 즉시 처리되도록 VM을 자동으로 생성하고 제거할 수 있는 기능입니다. 이 기능은 매우 효율적으로 사용될 수 있으며 러너를 24/7 사용하지 않는 상황에서 비용 효율적이고 확장 가능한 솔루션으로 사용될 수 있습니다.

소개

이 튜토리얼에서는 AWS에서 GitLab Runner를 올바르게 구성하는 방법을 살펴봅니다. AWS의 인스턴스는 요구에 따라 새로운 Docker 인스턴스를 생성하는 러너 관리자로 사용됩니다. 이러한 인스턴스의 러너는 이 가이드에서 다루는 매개변수를 사용하여 자동으로 만들어집니다. 생성 후 매뉴얼 구성이 필요하지 않습니다.

또한, Amazon의 EC2 Spot 인스턴스를 사용하여 GitLab Runner 인스턴스의 비용을 크게 줄일 수 있습니다. 이는 상당히 강력한 자동 확장 머신을 사용하는 동안에도 인스턴스의 비용을 크게 절감할 수 있습니다.

전제 조건

AWS에 대한 친숙함이 요구됩니다. 대부분의 구성은 여기서 이루어지기 때문입니다.

Docker machine amazonec2 driver documentation을 빠르게 읽어서 나중에 이 글에서 설정할 매개변수에 익숙해질 것을 권장합니다.

GitLab Runner는 GitLab 인스턴스와 네트워크에서 통신해야 합니다. 이는 AWS 보안 그룹을 구성하거나 DNS 구성을 설정할 때 고려해야 하는 사항입니다.

예를 들어, EC2 리소스를 공개 트래픽과 분리된 다른 VPC에 유지하여 네트워크 보안을 강화할 수 있습니다. 환경은 개별적일 것이므로 자체 상황에 맞게 최상의 방법을 고려하세요.

AWS 보안 그룹

Docker Machine은 Docker 데몬과의 통신을 위해 포트 2376 및 SSH 22에 대한 규칙이 포함된 기본 보안 그룹을 사용하려고 시도합니다. Docker에 의존하는 대신, 필요한 규칙이 포함된 보안 그룹을 생성하고 이를 GitLab Runner 옵션에 제공할 수 있습니다. 이렇게 하면 네트워킹 환경에 기반하여 미리 원하는대로 사용자 정의할 수 있습니다. Ports 2376 and 22Runner Manager instance에 의해 접근 가능한지 확인해야 합니다.

AWS 자격 증명

작업의 실행을 위해 새로운 EC2 인스턴스를 프로비저닝하는 데 필요한 권한이있는 사용자와 연결된 AWS 액세스 키가 필요합니다. EC2 (AmazonEC2FullAccess) 및 S3 (강조가 필요함)에 대한 정책이 있는 새 사용자를 만듭니다. S3의 최소 권한에 대한 자세한 내용은 runners.cache.s3를 참조하십시오. 보다 안전하게하기 위해 해당 사용자의 콘솔 로그인을 비활성화할 수 있습니다. 보안 자격 증명을 나중에 GitLab Runner configuration 중에 사용할 예정이므로 탭을 열어두거나 보안 자격 증명을 편집기에 복사하여 붙여넣기하십시오.

또한 필요한 AmazonEC2FullAccessAmazonS3FullAccess 정책이있는 EC2 인스턴스 프로필을 생성할 수 있습니다. 이 인스턴스 프로필을 실행기 관리자 EC2 인스턴스에 연결하여 작업의 실행을 위해 새 EC2 인스턴스를 프로비저닝합니다. 러너 머신이 인스턴스 프로필을 사용하는 경우, 러너 관리자의 인스턴스 프로필에 iam:PassRole 작업을 포함하십시오.

예시:

{
    "Statement": [
        {
            "Action": "iam:PassRole",
            "Effect": "Allow",
            "Resource": "arn:aws:iam:::role/instance-profile-of-runner-machine"
        }
    ],
    "Version": "2012-10-17"
}

러너 관리자 인스턴스 준비하기

첫 번째 단계는 새로운 머신을 생성하는 러너 관리자로서 EC2 인스턴스에 GitLab Runner를 설치하는 것입니다. Ubuntu, Debian, CentOS, 또는 RHEL과 같이 Docker와 GitLab Runner가 지원하는 배포판을 선택하세요.

이는 러너 관리자 인스턴스가 작업 자체를 실행하지 않기 때문에 강력한 머신이 아니어도 됩니다. 초기 구성을위한 경우 더 작은 인스턴스에서 시작할 수 있습니다. 이 머신은 항상 켜져 있어야 하므로 기준 비용이 발생하는 전용 호스트입니다.

사전 준비사항 설치:

  1. 서버에 로그인
  2. 공식 GitLab 리포지터리에서 GitLab Runner 설치
  3. Docker 설치
  4. GitLab fork에서 Docker Machine 설치 (Docker는 Docker Machine을 사용하지 않도록 설정되었습니다)

이제 Runner가 설치되었으므로 등록할 차례입니다.

GitLab Runner 등록

먼저 GitLab Runner를 구성하기 전에 등록해야 합니다.

  1. 러너 토큰 획득
  2. 러너 등록
  3. 실행기 유형을 물었을 때 docker+machine을 입력합니다.

이제 가장 중요한 부분으로 이동하여 GitLab Runner를 구성할 수 있습니다.

note
모든 사용자가 자동으로 확장된 러너를 사용할 수 있도록 하려면 공유 러너로 등록하십시오.

러너 설정

러너가 등록되었으므로 구성 파일을 편집하여 AWS 머신 드라이버에 필요한 옵션을 추가해야 합니다.

먼저 조각 단위로 분해하여 살펴봅시다.

전역 섹션

전역 섹션에서 모든 러너를 통틀어 동시에 실행될 수있는 작업 제한 (concurrent)을 정의할 수 있습니다. 이는 GitLab Runner가 수용 할 사용자 수, 빌드에 소요되는 시간 등과 같은 요구 사항에 매우 의존합니다. 10과 같이 낮은 값으로 시작하여 나중에 해당 값을 증가 또는 감소시킬 수 있습니다.

check_interval 옵션은 GitLab을 주기적으로 새로운 작업을 확인해야 할 빈도를 초 단위로 정의합니다.

예시:

concurrent = 10
check_interval = 0

기타 옵션은 여기에서 확인할 수 있습니다.

runners 섹션

[[runners]] 섹션에서 가장 중요한 부분은 executor로, 반드시 docker+machine으로 설정해야 합니다. 처음으로 러너를 등록할 때 대부분의 설정이 처리됩니다.

limit는 이 러너가 생성할 수있는 최대 머신의 숫자 (실행 중 및 비활성 상태)를 설정합니다. 자세한 내용은 이곳을 확인하세요.

예시:

[[runners]]
  name = "gitlab-aws-autoscaler"
  url = "<GitLab 인스턴스의 URL>"
  token = "<러너 토큰>"
  executor = "docker+machine"
  limit = 20

[[runners]] 아래의 기타 옵션은 여기에서 확인할 수 있습니다.

runners.docker 섹션

[runners.docker] 섹션에서는 .gitlab-ci.yml에서 정의되지 않은 경우 자식 러너가 사용할 기본 Docker 이미지를 정의할 수 있습니다. privileged = true를 사용하면 모든 러너가 GitLab CI/CD를 통해 자체 Docker 이미지를 빌드할 수 있습니다.

그 다음, 분산 캐시 모드로 사용할 것이므로 disable_cache = true를 사용하여 Docker executor의 내부 캐시 메커니즘을 비활성화합니다.

예시:

  [runners.docker]
    image = "alpine"
    privileged = true
    disable_cache = true

기타 옵션은 여기에서 확인할 수 있습니다.

runners.cache 섹션

작업을 가속화하기 위해 GitLab Runner는 선택한 디렉터리 및/또는 파일을 저장하고 후속 작업 간에 공유하는 캐시 메커니즘을 제공합니다. 이 설정에는 필수는 아니지만, GitLab Runner가 제공하는 분산 캐시 메커니즘을 사용하는 것이 좋습니다. 새로운 인스턴스가 필요한 경우에는 캐시가 저장된 공통 위치가 필수적입니다.

다음 예에서는 Amazon S3를 사용합니다:

  [runners.cache]
    Type = "s3"
    Shared = true
    [runners.cache.s3]
      ServerAddress = "s3.amazonaws.com"
      AccessKey = "<your AWS Access Key ID>"
      SecretKey = "<your AWS Secret Access Key>"
      BucketName = "<the bucket where your cache should be kept>"
      BucketLocation = "us-east-1"

캐시 메커니즘을 더 자세히 살펴보기 위한 다른 정보는 다음과 같습니다:

runners.machine 섹션

이것이 환경 설정에서 가장 중요한 부분이며, GitLab Runner에게 언제 Docker Machine 인스턴스를 생성하거나 제거할지 알려줍니다.

우리는 나머지 설정에 대해서는 AWS 기계 옵션에 중점을 둘 것이며, 조직의 요구 사항에 따라 자동스케일링 알고리즘 및 해당 기반 기준자동스케일링 주기에 대해 읽어보십시오. 예를 들어 조직에서는 일하는 시간이 아닌 정기적인 시간대(예: 주말)가 있는 경우 유용합니다.

다음은 runners.machine 섹션의 예시입니다:

  [runners.machine]
    IdleCount = 1
    IdleTime = 1800
    MaxBuilds = 10
    MachineDriver = "amazonec2"
    MachineName = "gitlab-docker-machine-%s"
    MachineOptions = [
      "amazonec2-access-key=XXXX",
      "amazonec2-secret-key=XXXX",
      "amazonec2-region=us-central-1",
      "amazonec2-vpc-id=vpc-xxxxx",
      "amazonec2-subnet-id=subnet-xxxxx",
      "amazonec2-zone=x",
      "amazonec2-use-private-address=true",
      "amazonec2-tags=runner-manager-name,gitlab-aws-autoscaler,gitlab,true,gitlab-runner-autoscale,true",
      "amazonec2-security-group=xxxxx",
      "amazonec2-instance-type=m4.2xlarge",
    ]
    [[runners.machine.autoscaling]]
      Periods = ["* * 9-17 * * mon-fri *"]
      IdleCount = 50
      IdleTime = 3600
      Timezone = "UTC"
    [[runners.machine.autoscaling]]
      Periods = ["* * * * * sat,sun *"]
      IdleCount = 5
      IdleTime = 60
      Timezone = "UTC"

Docker Machine 드라이버는 amazonec2로 설정되어 있으며, 머신 이름은 표준 접두사와 %s(필수)로 시작하여 자식 러너의 ID로 교체됩니다: gitlab-docker-machine-%s.

이제 AWS 인프라에 따라 MachineOptions 하위에 설정할 수 있는 많은 옵션이 있습니다. 아래에서 가장 일반적인 옵션을 확인할 수 있습니다.

머신 옵션 설명
amazonec2-access-key=XXXX EC2 인스턴스를 생성할 권한이 있는 사용자의 AWS 액세스 키, AWS 자격 증명 참조
amazonec2-secret-key=XXXX EC2 인스턴스를 생성할 권한이 있는 사용자의 AWS 비밀 액세스 키, AWS 자격 증명 참조
amazonec2-region=eu-central-1 인스턴스를 시작할 때 사용할 리전. 이를 완전히 생략하면 기본 us-east-1이 사용됨
amazonec2-vpc-id=vpc-xxxxx 인스턴스를 시작할 VPC ID(https://gitlab.com/gitlab-org/ci-cd/docker-machine/-/blob/main/docs/drivers/aws.md#vpc-id)
amazonec2-subnet-id=subnet-xxxx AWS VPC 서브넷 ID
amazonec2-zone=x 지정되지 않으면 가용 영역은 a가 됨(가용 영역은 eu-west-1b라면 amazonec2-zone=b로 설정해야 함)
amazonec2-use-private-address=true Docker Machines의 사설 IP 주소를 사용하지만 여전히 공용 IP 주소를 만듭니다. 내부 트래픽을 유지하고 추가 비용을 피하는 데 유용함
amazonec2-tags=runner-manager-name,gitlab-aws-autoscaler,gitlab,true,gitlab-runner-autoscale,true AWS 추가 태그 키-값 쌍으로, AWS 콘솔에서 인스턴스를 식별하는 데 유용하며, 기본적으로 “Name” 태그가 머신 이름으로 설정됨. “runner-manager-name” 함께 [[runners]]에 설정된 러너 이름과 일치시켜 특정 매니저 설정으로 생성된 모든 EC2 인스턴스를 필터링할 수 있음
amazonec2-security-group=xxxx AWS VPC 보안 그룹 이름. 보안 그룹 ID가 아님, AWS 보안 그룹 참조
amazonec2-instance-type=m4.2xlarge 자식 러너가 실행될 인스턴스 유형
amazonec2-ssh-user=xxxx 인스턴스에 SSH 액세스 할 사용자
amazonec2-iam-instance-profile=xxxx_runner_machine_inst_profile_name 러너 머신에 사용할 IAM 인스턴스 프로필
amazonec2-ami=xxxx_runner_machine_ami_id 특정 이미지를 위한 GitLab Runner AMI ID
amazonec2-request-spot-instance=true 온디맨드 가격보다 저렴한 유휴 EC2 용량 사용
amazonec2-spot-price=xxxx_runner_machine_spot_price=x.xx 스pod 인스턴스 입찰 가격 (미국 달러). --amazonec2-request-spot-instance 플래그를 true로 설정해야 함. amazonec2-spot-price를 생략하면 Docker Machine이 최대 가격을 기본값으로 $0.50에 설정함
amazonec2-security-group-readonly=true 보안 그룹을 읽기 전용으로 설정
amazonec2-userdata=xxxx_runner_machine_userdata_path 러너 머신 userdata 경로 지정
amazonec2-root-size=XX 인스턴스의 루트 디스크 크기(GB)

모두 함께 사용하기

다음은 /etc/gitlab-runner/config.toml의 전체 예시입니다.

concurrent = 10
check_interval = 0

[[runners]]
  name = "gitlab-aws-autoscaler"
  url = "<당신의 GitLab 인스턴스 URL>"
  token = "<러너의 토큰>"
  executor = "docker+machine"
  limit = 20
  [runners.docker]
    image = "alpine"
    privileged = true
    disable_cache = true
  [runners.cache]
    Type = "s3"
    Shared = true
    [runners.cache.s3]
      ServerAddress = "s3.amazonaws.com"
      AccessKey = "<당신의 AWS 액세스 키 ID>"
      SecretKey = "<당신의 AWS 시크릿 액세스 키>"
      BucketName = "<캐시를 유지해야 하는 버킷>"
      BucketLocation = "us-east-1"
  [runners.machine]
    IdleCount = 1
    IdleTime = 1800
    MaxBuilds = 100
    MachineDriver = "amazonec2"
    MachineName = "gitlab-docker-machine-%s"
    MachineOptions = [
      "amazonec2-access-key=XXXX",
      "amazonec2-secret-key=XXXX",
      "amazonec2-region=us-central-1",
      "amazonec2-vpc-id=vpc-xxxxx",
      "amazonec2-subnet-id=subnet-xxxxx",
      "amazonec2-use-private-address=true",
      "amazonec2-tags=runner-manager-name,gitlab-aws-autoscaler,gitlab,true,gitlab-runner-autoscale,true",
      "amazonec2-security-group=XXXX",
      "amazonec2-instance-type=m4.2xlarge",
    ]
    [[runners.machine.autoscaling]]
      Periods = ["* * 9-17 * * mon-fri *"]
      IdleCount = 50
      IdleTime = 3600
      Timezone = "UTC"
    [[runners.machine.autoscaling]]
      Periods = ["* * * * * sat,sun *"]
      IdleCount = 5
      IdleTime = 60
      Timezone = "UTC"

Amazon EC2 스pod 인스턴스를 사용하여 비용 절감

Amazon에서 설명한대로:

Amazon EC2 스pod 인스턴스를 사용하면 여분의 Amazon EC2 컴퓨팅 용량에 입찰할 수 있습니다. 스pod 인스턴스는 종종 온디맨드 가격에 비해 할인된 가격으로 제공되므로 응용 프로그램을 실행하는 데 드는 비용을 크게 줄이고, 동일한 예산으로 응용 프로그램의 컴퓨팅 용량 및 처리량을 늘릴 수 있으며 새로운 유형의 클라우드 컴퓨팅 응용 프로그램을 활성화할 수 있습니다.

위에서 선택한 runners.machine 옵션에 추가로, /etc/gitlab-runner/config.tomlMachineOptions 섹션에 다음을 추가하십시오.

    MachineOptions = [
      "amazonec2-request-spot-instance=true",
      "amazonec2-spot-price=",
    ]

amazonec2-spot-price로 이 구성으로 인해 AWS는 스pod 인스턴스에 대한 당신의 입찰 가격을 해당 인스턴스 클래스의 기본 온디맨드 가격으로 설정합니다. amazonec2-spot-price를 완전히 생략하는 경우 Docker Machine은 최대 가격을 기본 값 $0.50/시간으로 설정합니다.

스pod 인스턴스 요청을 더 세부화할 수 있습니다.

    MachineOptions = [
      "amazonec2-request-spot-instance=true",
      "amazonec2-spot-price=0.03",
      "amazonec2-block-duration-minutes=60"
    ]

이 구성에서는 스pod 인스턴스가 최대 $0.03/시간의 스pod 요청 가격으로 생성되며, 스pod 인스턴스의 기간은 60분으로 제한됩니다. 위에서 언급한 0.03 숫자는 예시일 뿐이므로 선택한 지역의 현재 요금을 확인하십시오.

Amazon EC2 스pod 인스턴스에 대해 더 알아보려면 다음 링크를 방문하십시오:

스pod 인스턴스의 주의 사항

스pod 인스턴스는 사용하지 않는 리소스를 사용하고 인프라 비용을 최소화하는 좋은 방법이지만, 결과에 대해 인식해야 합니다.

스pod 인스턴스에서 CI 작업을 실행하면 스pod 인스턴스의 가격 모델 때문에 실패율이 증가할 수 있습니다. 지정한 최대 스pod 가격이 현재의 스pod 가격을 초과하면 요청한 용량을 받을 수 없습니다. 스pod 가격은 시간당 기준으로 변경됩니다. 현재 스pod 인스턴스의 최대 가격이 변경된 스pod 인스턴스 가격보다 낮은 스pod 인스턴스는 2분 이내에 종료되며 스pod 호스트의 모든 작업이 실패합니다.

결과적으로 오토 스케일 러너는 새로운 머신을 만들지 못할 것이고 계속해서 새로운 인스턴스를 요청할 것입니다. 이로 인해 60번의 요청을 할 것이며 그 후로 AWS는 더 이상 요청을 수락하지 않을 것입니다. 이후 스pod 가격이 적절하게 되면 호출량 제한이 초과되어 잠시 체크포인트가 걸리게 됩니다.

이 경우를 만나면, 러너 관리자 머신에서 다음 명령어를 사용하여 Docker Machine의 상태를 확인할 수 있습니다.

docker-machine ls -q --filter state=Error --format "{{.NAME}}"
note
GitLab Runner가 스pod 가격 변경을 우아하게 처리하는 데 문제가 있고, docker-machine이 계속해서 Docker Machine을 제거하려고 시도하는 보고가 있습니다. GitLab은 상위 프로젝트에서 두 경우 모두에 대한 패치를 제공했습니다. 더 많은 정보는 아래 이슈를 참조하십시오. #2771#2772.

GitLab 포크는 AWS EC2 플릿 및 스pod 인스턴스와의 사용을 지원하지 않습니다. 대신, 다음의 downstream fork인 Continuous Kernel Integration Project’s downstream fork를 사용할 수 있습니다.

결론

이 가이드에서 우리는 AWS의 autoscale 모드에서 GitLab Runner를 설치하고 구성하는 방법을 배웠습니다.

GitLab Runner의 autoscale 기능을 사용하면 시간과 비용을 절약할 수 있습니다. AWS가 제공하는 스pod 인스턴스를 사용하면 더 많은 비용을 절약할 수 있지만 결과에 대해 인식해야 합니다. 당신의 입찰이 충분히 높으면 문제가 없어야 합니다.

이 튜토리얼에서 (강력하게) 영향을 받은 다음 사용 사례를 읽을 수 있습니다: