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 머신 amazonec2
드라이버 문서를 빠르게 읽어보는 것을 권장합니다. 나중에 이 기사에서 설정할 매개변수에 익숙해질 수 있습니다.
GitLab Runner는 GitLab 인스턴스와 네트워크를 통해 통신해야 하며, 이는 AWS 보안 그룹을 구성하거나 DNS 구성을 설정할 때 고려해야 할 사항입니다.
예를 들어, EC2 리소스를 공개 트래픽에서 분리된 다른 VPC에 유지하여 네트워크 보안을 더 강화할 수 있습니다. 환경은 개별적일 수 있으므로 상황에 가장 적합한 방법을 고려하십시오.
AWS 보안 그룹
Docker 머신은 Docker 데몬과의 통신에 필요한 포트 2376
및 SSH 22
에 대한 규칙이 있는 기본 보안 그룹을 사용하려고 시도할 것입니다. Docker에 의존하는 대신 필요한 규칙을 가진 보안 그룹을 생성하고 이를 GitLab Runner 옵션에 제공할 수 있습니다. 이렇게 하면 네트워킹 환경에 따라 원하는 대로 사전에 사용자 정의할 수 있습니다. 실행 중에 나중에 보안 그룹을 사용하는 대신 사용자 정의할 수 있습니다. 이런 식으로 말이죠.
또한로, 보안 그룹을 사용하는 대신 사용자 정의할 수 있습니다. 이런 식으로 말이죠.
러너 관리자 인스턴스를 준비하세요.
AWS 자격 증명
(EC2) scale 및 캐시 업데이트 (S3를 통해) 권한이있는 사용자와 연결된 AWS 액세스 키가 필요합니다. EC2 (AmazonEC2FullAccess) 및 S3에 대한 정책 (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-policies-for-amazon-ec2.html)을 사용하여 새 사용자를 만듭니다. S3에 대한 필요한 최소 권한에 대한 자세한 정보는 runners.cache.s3
을 참조하십시오. 더 안전하게 하려면 해당 사용자의 콘솔 로그인을 비활성화할 수 있습니다. 보안 자격 증명을 에디터에 복사하여 나중에 GitLab Runner 구성에서 사용하게 될 것이므로 탭을 열어 둡니다.
또한 필요한 AmazonEC2FullAccess
및 AmazonS3FullAccess
정책을 가진 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를 설치하는 것입니다. Docker 및 GitLab Runner가 지원하는 Ubuntu, Debian, CentOS 또는 RHEL과 같은 배포판을 선택하십시오.
이것은 러너 관리자 인스턴스가 작업 자체를 실행하지 않기 때문에 강력한 머신이 아니여도 상관이 없습니다. 초기 구성에는 작은 인스턴스로 시작할 수 있습니다. 이 머신은 항상 켜져 있어야 하므로 전체적인 기본 비용이 들지만 필요할 때만 생성되는 러너와는 다릅니다.
다음은 준비 사항입니다:
- 서버에 로그인
- 공식 GitLab 저장소에서 GitLab Runner 설치
- Docker 설치
- GitLab의 지사에서 Docker Machine 설치 (Docker가 Docker Machine을 폐기했습니다)
러너를 설치했으므로 이제 등록할 차례입니다.
GitLab Runner 등록
GitLab Runner를 구성하기 전에 먼저 등록하여 GitLab 인스턴스에 연결해야 합니다.
이제 가장 중요한 부분인 GitLab Runner 구성으로 이동할 수 있습니다.
참고: 인스턴스의 모든 사용자가 자동으로 스케일링된 러너를 사용할 수 있기를 원한다면 러너를 공유로 등록하십시오.
러너 구성
러너가 등록되었으므로 해당 구성 파일을 편집하여 AWS 머신 드라이버에 필요한 옵션을 추가해야 합니다.
먼저 조각 단위로 살펴봅시다.
전역 섹션
전역 섹션에서 모든 러너 간에 동시에 실행되는 작업의 제한 (concurrent
)을 정의할 수 있습니다. 이는 GitLab Runner가 수용할 사용자 수, 빌드에 걸리는 시간 등과 같이 여러 가지 요소에 크게 의존합니다. 10
과 같은 낮은 값으로 시작하여 이후에 값을 늘리거나 줄일 수 있습니다.
check_interval
옵션은 러너가 새 작업을 확인하는 빈도를 지정합니다(초).
예시:
concurrent = 10
check_interval = 0
다른 옵션들도 사용 가능합니다.
runners
섹션
[[runners]]
섹션에서 가장 중요한 부분은 executor
로, 여기에는 docker+machine
으로 설정해야 합니다. 대부분의 설정은 처음에 runner를 등록할 때 이미 처리됩니다.
limit
은 이 runner가 생성할 수 있는 기계(작동 및 유휴)의 최대 수를 설정합니다. 자세한 정보는 ‘limit
, concurrent
, IdleCount
간의 관계’를 확인하세요.
예시:
[[runners]]
name = "gitlab-aws-autoscaler"
url = "<당신의 GitLab 인스턴스 URL>"
token = "<Runner의 토큰>"
executor = "docker+machine"
limit = 20
다음으로, [[runners]]
하위에 있는 기타 옵션을 확인할 수 있습니다.
runners.docker
섹션
[runners.docker]
섹션에서는 .gitlab-ci.yml
에 정의되지 않은 경우에 자식 runner가 사용할 기본 Docker 이미지를 정의할 수 있습니다. privileged = true
를 사용하여 모든 runner가 GitLab CI/CD를 통해 자체 Docker 이미지를 빌드할 계획이 있다면 Docker in Docker을 실행할 수 있습니다.
다음으로, 우리는 disable_cache = true
를 사용하여 분산된 캐시 모드를 사용할 것이므로 Docker executor의 내부 캐시 메커니즘을 비활성화합니다.
예시:
[runners.docker]
image = "alpine"
privileged = true
disable_cache = true
[runners.docker]
아래에 있는 기타 옵션을 확인할 수 있습니다.
runners.cache
섹션
작업을 가속화하기 위해 GitLab Runner는 선택한 디렉터리 및/또는 파일을 저장하고 후속 작업 사이에 공유하는 캐시 메커니즘을 제공합니다. 이 설정은 이 설정에 대해 필수는 아니지만 GitLab Runner가 제공하는 분산 캐시 메커니즘을 사용하는 것이 좋습니다. 요구 사항에 맞게 새 인스턴스가 필요한 경우, 캐시가 저장되는 공통 장소가 필수적입니다.
다음 예시에서 우리는 Amazon S3를 사용합니다:
[runners.cache]
Type = "s3"
Shared = true
[runners.cache.s3]
ServerAddress = "s3.amazonaws.com"
AccessKey = "<당신의 AWS 액세스 키 ID>"
SecretKey = "<당신의 AWS 비밀 액세스 키>"
BucketName = "<캐시를 저장해야 하는 버킷>"
BucketLocation = "us-east-1"
더 자세한 캐시 메커니즘을 더 알아보려면 아래 페이지들을 확인하세요:
runners.cache
참조runners.cache.s3
참조- GitLab Runner용 캐시 서버를 배포하고 사용하기 - distributed-runners-caching
- 캐시 동작 방식 - cache
runners.machine
섹션
이것은 설정 중 가장 중요한 부분이며, GitLab Runner에게 언제 어떻게 새로운 Docker Machine 인스턴스를 생성하거나 이전 인스턴스를 제거할지 알려줍니다.
우리는 AWS machine 옵션에 중점을 둘 것이며, 다른 설정에 대해서는 다음을 참조하세요: - Autoscaling algorithm and the parameters it’s based on - 당신의 조직의 필요에 따라 다릅니다. - Autoscaling periods - 조직에게 일을 하지 않는 규칙적인 시간 주기가 있는 경우 유용합니다.
다음은 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
(필수)가 따릅니다. 이 %s
는 자식 runner의 ID로 대체됩니다: gitlab-docker-machine-%s
.
이제 당신의 AWS 인프라에 따라서 MachineOptions
아래에 많은 옵션을 설정할 수 있습니다. 아래에서 가장 일반적인 옵션을 확인할 수 있습니다.
기계 옵션 | 설명 |
---|---|
amazonec2-access-key=XXXX
| EC2 인스턴스를 생성할 권한을 가진 사용자의 AWS 액세스 키, AWS credentials를 참조하세요. |
amazonec2-secret-key=XXXX
| EC2 인스턴스를 생성할 권한을 가진 사용자의 AWS 비밀 액세스 키, AWS credentials를 참조하세요. |
amazonec2-region=eu-central-1
| 인스턴스를 시작할 때 사용할 리전입니다. 이것을 완전히 생략할 수 있으며 기본으로 us-east-1 이 사용됩니다.
|
amazonec2-vpc-id=vpc-xxxxx
| 사용할 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]] 에서 설정된 runner 이름과 일치하도록 설정하여 특정 manager 설정으로 생성된 모든 EC2 인스턴스를 필터링할 수 있도록 설정합니다.
|
amazonec2-security-group=xxxx
| AWS VPC 보안 그룹 이름입니다. 보안 그룹 ID가 아닙니다. AWS security groups을 참조하세요. |
amazonec2-instance-type=m4.2xlarge
| 자식 runner가 실행될 인스턴스 유형입니다. |
amazonec2-ssh-user=xxxx
| 인스턴스에 SSH 액세스할 수 있는 사용자입니다. |
amazonec2-iam-instance-profile=xxxx_runner_machine_inst_profile_name
| runner 머신에 사용할 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
| 스팟 인스턴스 입찰가 (미국 달러)입니다. --amazonec2-request-spot-instance flag 을 true 로 설정해야 합니다. amazonec2-spot-price 를 생략하면 Docker Machine에서 $0.50의 기본값으로 최대 가격을 설정합니다.
|
amazonec2-security-group-readonly=true
| 보안 그룹을 읽기 전용으로 설정합니다. |
amazonec2-userdata=xxxx_runner_machine_userdata_path
| runner 머신 userdata 경로를 지정합니다.
|
amazonec2-root-size=XX
| 인스턴스의 루트 디스크 크기(GB)입니다. |
참고:
- MachineOptions
아래에서 AWS Docker Machine 드라이버가 지원하는 것을 추가할 수 있습니다. 당신의 인프라 설정에 따라 다른 옵션을 적용할 수 있으므로 Docker 문서를 권장합니다.
- 자식 인스턴스는 기본적으로 Ubuntu 16.04를 사용하지만 amazonec2-ami
를 설정하여 다른 AMI ID를 선택하여 Docker Machine용 지원되는 기본 운영 체제을 설정할 수 있습니다.
- 만약 인스턴스 옵션 중 amazonec2-private-address-only=true
를 지정하면 EC2 인스턴스에 공용 IP가 할당되지 않습니다. 이는 VPC가 올바르게 구성되어 있고 라우팅이 잘되어 있으면 문제가 없지만 더 복잡한 구성일 때 고려할 사항입니다. Docker 문서에서 VPC 연결에 대해 더 읽어보세요.
[runners.machine]
하위에 있는 기타 옵션을 확인할 수 있습니다.
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 Spot 인스턴스를 통한 비용 절감
아마존의 설명에 따르면:
아마존 EC2 Spot 인스턴스를 사용하면 여분의 아마존 EC2 컴퓨팅 용량에 입찰할 수 있습니다. Spot 인스턴스는 On-Demand 가격보다 종종 할인된 가격으로 제공되므로 응용 프로그램을 실행하는 비용을 크게 줄일 수 있으며 동일한 예산으로 응용 프로그램의 컴퓨팅 용량과 처리량을 증가시키고 새로운 유형의 클라우드 컴퓨팅 응용 프로그램을 활성화할 수 있습니다.
앞서 선택한 runners.machine
옵션에 추가하여 /etc/gitlab-runner/config.toml
에서 MachineOptions
섹션 아래에 다음을 추가합니다:
MachineOptions = [
"amazonec2-request-spot-instance=true",
"amazonec2-spot-price=",
]
이 빈 amazonec2-spot-price
구성에 대해, AWS는 Spot 인스턴스에 대한 최대 입찰 가격을 해당 인스턴스 클래스의 기본 On-Demand 가격으로 설정합니다.
amazonec2-spot-price
를 완전히 생략하는 경우, Docker Machine은 최대 가격을
기본 값 $0.50 per hour로 설정합니다.
Spot 인스턴스 요청을 더 사용자 정의하려면:
MachineOptions = [
"amazonec2-request-spot-instance=true",
"amazonec2-spot-price=0.03",
"amazonec2-block-duration-minutes=60"
]
이 구성으로 인해 Spot 인스턴스가 $0.03 per hour의 최대 Spot 요청 가격으로 생성되며 Spot 인스턴스의 기간이 60분으로 제한됩니다.
위에서 언급된 0.03
숫자는 예시일 뿐이므로 선택한 지역을 기반으로 현재 가격을 확인해야 합니다.
Amazon EC2 Spot 인스턴스에 대해 더 알아보려면 다음 링크를 방문하세요:
- https://aws.amazon.com/ec2/spot/
- https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-requests.html
- https://aws.amazon.com/ec2/spot/getting-started/
Spot 인스턴스의 주의 사항
Spot 인스턴스는 사용되지 않는 리소스를 활용하고 인프라 비용을 최소화하는 좋은 방법이지만, 그러한 영향을 인지해야 합니다.
Spot 인스턴스에서 CI 작업을 실행하면 Spot 인스턴스의 가격 모델로 인해 실패율이 증가할 수 있습니다. 지정한 최대 Spot 가격이 현재 Spot 가격을 초과하면 요청한 용량을 받을 수 없습니다. Spot 가격은 시간당 기준으로 재조정됩니다. 현재 Spot 인스턴스 가격을 초과하는 최대 가격을 지정한 기존의 Spot 인스턴스는 2분 이내에 종료되며 모든 Spot 호스트에서의 작업이 실패합니다.
그 결과, 오토스케일 러너는 새 머신을 생성하지 못할 것이며 계속해서 새 인스턴스를 요청할 것입니다. 이로 인해 최종적으로 60 번의 요청을 할 것이며, 이후 AWS는 더 이상 요청을 받지 않을 것입니다. 그 후에 Spot 가격이 적절하게 되면, 일시적으로 호출 횟수 제한으로 인해 약간 차단됩니다.
이런 경우를 만난다면 러너 관리 기계에서 다음 명령어를 사용하여 Docker Machine의 상태를 확인할 수 있습니다:
docker-machine ls -q --filter state=Error --format "{{.NAME}}"
참고:
GitLab 러너가 Spot 가격 변경을 우아하게 처리하는 것에 관한 몇 가지 문제가 있으며 docker-machine
이 계속 Docker Machine을 제거하려고 하는 보고가 있습니다.
GitLab은 위에서 언급된 두 경우에 대한 패치를 제공했습니다. 더 많은 정보는 이슈
#2771와
#2772를 참조하세요.
GitLab 포크는 AWS EC2 플릿과 Spot 인스턴스와의 사용을 지원하지 않습니다. 대신 아래 링크에서 지속적인 커널 통합 프로젝트의 다운스트림 포크를 사용할 수 있습니다. ```
결론
본 안내서에서는 AWS의 autoscale 모드에서 GitLab Runner를 설치하고 구성하는 방법에 대해 배웠습니다.
GitLab Runner의 autoscale 기능을 사용하면 시간과 비용을 절약할 수 있습니다. AWS가 제공하는 Spot 인스턴스를 사용하면 더 많은 비용을 절약할 수 있지만, 이에 따른 영향을 인식해야 합니다. 충분히 높은 입찰을 하고 있다면 문제가 없어야 합니다.
본 자습서의 영향을 받은 다음 사용 사례를 읽어볼 수 있습니다: - HumanGeo가 Jenkins에서 GitLab으로 전환 - Substrakt Health - Autoscale GitLab CI/CD runners and save 90% on EC2 costs