AWS EC2에서 GitLab Runner 자동 확장
Offering: GitLab.com, Self-managed
GitLab Runner의 가장 큰 장점 중 하나는 빌드가 즉시 처리될 수 있도록 VM을 자동으로 생성하고 제거하는 능력입니다.
훌륭한 기능이며, 제대로 사용된다면 24/7 동안 러너를 사용하지 않을 때 비용 효율적이고 확장 가능한 솔루션을 원할 때 매우 유용합니다.
소개
이 튜토리얼에서는 AWS에서 GitLab Runner를 제대로 구성하는 방법을 살펴보겠습니다.
AWS의 인스턴스는 필요에 따라 새로운 Docker 인스턴스를 생성하는 러너 관리자 역할을 합니다.
이 인스턴스에 있는 러너는 자동으로 생성되며, 이 가이드에서 다룬 매개변수를 사용하고 생성 후에는 수동 구성할 필요가 없습니다.
또한, Amazon의 EC2 Spot 인스턴스를 활용하여 GitLab Runner 인스턴스의 비용을 크게 줄이면서도
상당히 강력한 자동 확장 머신을 사용할 수 있습니다.
필수 조건
대부분의 구성 작업이 이루어질 Amazon Web Services(AWS)에 대한 기본적인 이해가 필요합니다.
Docker 머신의
amazonec2
드라이버 문서를 간단히 읽어보시기 바랍니다.
이 문서에서는 나중에 설정할 매개변수에 대해 익숙해질 수 있습니다.
GitLab Runner는 네트워크를 통해 GitLab 인스턴스와 통신해야 하며,
AWS 보안 그룹 구성이나 DNS 구성을 설정할 때 고려해야 할 사항입니다.
예를 들어, EC2 리소스를 공용 트래픽과 분리된 다른 VPC에 배치하여
네트워크 보안을 더 강화할 수 있습니다.
귀하의 환경은 다를 수 있으므로 상황에 가장 적합한 방법을 고려하십시오.
AWS 보안 그룹
Docker Machine은 포트 2376
및 SSH 22
에 대한 규칙을 포함하는
기본 보안 그룹을 사용하려고 시도합니다.
이는 Docker 데몬과 통신하는 데 필요합니다. Docker에 의존하는 대신, 필요한 규칙으로 보안 그룹을 생성하고
다음에서 보게 될 GitLab Runner 옵션에서 그것을 제공할 수 있습니다.
이렇게 하면 네트워킹 환경에 따라 미리 원하는 대로 사용자 정의할 수 있습니다.
포트 2376
및 22
가
러너 관리자 인스턴스에서 접근할 수 있는지 확인해야 합니다.
AWS 자격 증명
확장(EC2) 및 캐시 업데이트(S3)에 대한 권한이 있는 사용자에 연결된
AWS Access Key가 필요합니다.
기본적으로 정책을 가진 새 사용자를 생성하십시오.
EC2(AmazonEC2FullAccess) 및 S3에 대한 정책을 생성합니다.
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 러너 등록하기
GitLab 러너를 구성하기 전에 먼저 등록해야 합니다. 그렇게 해야 GitLab 인스턴스와 연결됩니다:
이제 가장 중요한 부분인 GitLab 러너 구성을 진행할 수 있습니다.
러너 구성하기
러너가 등록되었으므로, 이제 구성 파일을 편집하고 AWS 머신 드라이버에 필요한 옵션을 추가해야 합니다.
먼저 세부 사항을 나누어 보겠습니다.
전역 섹션
전역 섹션에서는 모든 러너에서 동시에 실행 가능한 작업의 한계를 정의할 수 있습니다 (concurrent
). 이는 GitLab 러너가 수용할 사용자 수, 빌드 소요 시간 등에 따라 크게 달라집니다. 처음에는 10
과 같이 낮은 값으로 시작하고 이후 필요에 따라 값을 증가시키거나 감소시킬 수 있습니다.
check_interval
옵션은 러너가 GitLab에서 새로운 작업을 확인하는 빈도를 초 단위로 정의합니다.
예제:
concurrent = 10
check_interval = 0
기타 옵션도 사용 가능합니다.
runners
섹션
[[runners]]
섹션에서 가장 중요한 부분은 executor
로, 이는 docker+machine
으로 설정되어야 합니다. 이러한 설정의 대부분은 러너를 처음 등록할 때 처리됩니다.
limit
는 이 러너가 생성할 최대 머신 수(실행 중 및 유휴)를 설정합니다. 더 많은 정보는
limit
, concurrent
및 IdleCount
간의 관계를 확인하세요.
예제:
[[runners]]
name = "gitlab-aws-autoscaler"
url = "<GitLab 인스턴스의 URL>"
token = "<러너의 토큰>"
executor = "docker+machine"
limit = 20
[[runners]]
아래의 기타 옵션도 사용 가능합니다.
runners.docker
섹션
[runners.docker]
섹션에서는 자식 러너가 사용할 기본 Docker 이미지를 정의할 수 있습니다.
.gitlab-ci.yml
에 정의되어 있지 않은 경우에 해당됩니다.
privileged = true
를 사용하면 모든 러너가 Docker in Docker를 실행할 수 있습니다. 이는 GitLab CI/CD를 통해 자체 Docker 이미지를 빌드할 계획이라면 유용합니다.
다음으로, disable_cache = true
를 사용하여 Docker 실행기의 내부 캐시 메커니즘을 비활성화합니다.
이는 다음 섹션에서 설명할 분산 캐시 모드를 사용할 예정이기 때문입니다.
예제:
[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 = "<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는 자식 러너의 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입니다. 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 콘솔에서 인스턴스를 식별하는 데 유용한 추가 태그 키-값 쌍입니다. “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 |
스팟 인스턴스 입찰 가격(미국 달러). --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 |
러너 머신 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가 인터넷 게이트웨이(IGW)와 올바른 라우팅으로 올바르게 구성되어 있는 경우 괜찮지만, 더 복잡한 구성이라면 고려해야 할 사항입니다. VPC 연결성에 대한 Docker 문서를 참조하세요.
[runners.machine]
아래의 기타 옵션도 사용할 수 있습니다.
모든 것을 하나로 모으기
/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 Access Key ID>"
SecretKey = "<당신의 AWS Secret Access Key>"
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 인스턴스로 비용 절감하기
Amazon EC2 Spot 인스턴스는 여유 있는 Amazon EC2 컴퓨팅 용량에 입찰할 수 있게 해줍니다. Spot 인스턴스는 종종 온디맨드 가격에 비해 할인된 가격으로 제공되기 때문에 애플리케이션 실행 비용을 크게 절감할 수 있으며, 동일한 예산으로 애플리케이션의 컴퓨팅 용량과 처리량을 증가시킬 수 있으며, 새로운 유형의 클라우드 컴퓨팅 애플리케이션을 가능하게 합니다.
위에서 선택한 runners.machine
옵션 외에도,
/etc/gitlab-runner/config.toml
의 MachineOptions
섹션 아래에 다음을 추가하세요:
MachineOptions = [
"amazonec2-request-spot-instance=true",
"amazonec2-spot-price=",
]
빈 amazonec2-spot-price
로 설정된 이 구성에서, AWS는
해당 인스턴스 클래스의 기본 온디맨드 가격으로 Spot 인스턴스의 입찰 가격을 설정합니다.
amazonec2-spot-price
를 완전히 생략하면, Docker Machine은 최대 가격을
기본값인 시간당 $0.50으로 설정합니다.
Spot 인스턴스 요청을 추가로 사용자 정의할 수도 있습니다:
MachineOptions = [
"amazonec2-request-spot-instance=true",
"amazonec2-spot-price=0.03",
"amazonec2-block-duration-minutes=60"
]
이 구성으로 Docker Machine은 시간당 최대 Spot 요청 가격이 $0.03이고 Spot 인스턴스 기간이
60분으로 제한된 Spot 인스턴스를 사용하여 생성됩니다.
위에서 언급한 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/
스팟 인스턴스의 주의사항
스팟 인스턴스는 사용하지 않는 리소스를 활용하고 인프라 비용을 최소화하는 좋은 방법이지만, 그로 인한 영향에 대해 인식해야 합니다.
스팟 인스턴스에서 CI 작업을 실행하면 스팟 인스턴스 가격 모델 때문에 실패율이 증가할 수 있습니다. 지정한 최대 스팟 가격이 현재 스팟 가격을 초과하면 요청한 용량을 받을 수 없습니다. 스팟 가격은 매시간 수정됩니다. 수정된 스팟 인스턴스 가격 이하의 최대 가격을 가진 기존 스팟 인스턴스는 2분 이내에 종료되며, 스팟 호스트에서 실행 중인 모든 작업이 실패합니다.
결과적으로, 자동 확장 러너는 새로운 머신을 생성할 수 없게 되고, 계속해서 새로운 인스턴스를 요청하게 됩니다. 이로 인해 60개의 요청이 발생하고 나서 AWS는 더 이상 요청을 수락하지 않습니다. 그런 다음 스팟 가격이 수용 가능한 수준이 되면, 호출량 제한 초과로 인해 잠시 동안 접근이 차단됩니다.
이 경우에는 러너 관리 머신에서 다음 명령어를 사용하여 Docker 머신의 상태를 확인할 수 있습니다:
docker-machine ls -q --filter state=Error --format "{{.NAME}}"
GitLab 포크는 AWS EC2 플릿과 스팟 인스턴스와의 사용을 지원하지 않습니다. 대안으로는 연속 커널 통합 프로젝트의 하위 포크를 사용할 수 있습니다.
결론
이 가이드에서는 AWS에서 자동 확장 모드로 GitLab Runner를 설치하고 구성하는 방법을 배웠습니다.
GitLab Runner의 자동 확장 기능을 사용하면 시간과 비용을 모두 절약할 수 있습니다. AWS에서 제공하는 스팟 인스턴스를 사용하면 더 많은 절약이 가능하지만, 그로 인한 영향에 대해 인식해야 합니다. 입찰가가 충분히 높다면 문제는 없을 것입니다.
다음의 사용 사례를 참고하실 수 있습니다. 이 튜토리얼에 (상당한) 영향을 미쳤습니다: