AWS EC2에서 러너 Docker Machine 오토스케일 설정
Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
GitLab Runner의 가장 큰 장점 중 하나는 빌드가 즉시 처리되도록 VM을 자동으로 시작하고 중지하는 기능입니다. 이 튜토리얼에서는 AWS에서 GitLab Runner를 올바르게 구성하는 방법을 살펴봅니다. 또한 Amazon의 EC2 Spot 인스턴스를 활용하여 꽤 강력한 오토스케일링 머신을 사용하면서도 GitLab Runner 인스턴스 비용을 크게 줄일 수 있습니다.
GitLab Runner의 가장 큰 장점 중 하나는 빌드가 즉시 처리되도록 VM을 자동으로 시작하고 중지하는 기능입니다. 이것은 훌륭한 기능이며, 올바르게 사용하면 러너를 24/7 사용하지 않는 상황에서 비용 효율적이고 확장 가능한 솔루션을 원할 때 매우 유용합니다.
소개#
이 튜토리얼에서는 AWS에서 GitLab Runner를 올바르게 구성하는 방법을 살펴봅니다. AWS의 인스턴스는 요청 시 새 Docker 인스턴스를 생성하는 러너 매니저 역할을 합니다. 이러한 인스턴스의 러너는 자동으로 생성됩니다. 이 가이드에서 설명하는 파라미터를 사용하며 생성 후 수동 구성이 필요하지 않습니다.
또한 Amazon의 EC2 Spot 인스턴스를 활용하여 꽤 강력한 오토스케일링 머신을 사용하면서도 GitLab Runner 인스턴스 비용을 크게 줄일 수 있습니다.
사전 요구 사항#
대부분의 설정이 이루어지는 Amazon Web Services(AWS)에 대한 친숙함이 필요합니다.
이 문서 후반부에서 설정할 파라미터에 익숙해지기 위해 Docker Machine amazonec2 드라이버 문서를 빠르게 읽어보길 권장합니다.
GitLab Runner는 네트워크를 통해 GitLab 인스턴스와 통신해야 하므로, AWS 보안 그룹을 구성하거나 DNS 설정을 구성할 때 이를 고려해야 합니다.
예를 들어 네트워크 보안을 강화하기 위해 EC2 리소스를 다른 VPC의 공용 트래픽과 분리할 수 있습니다. 환경이 다를 수 있으므로 상황에 맞는 방법을 고려하세요.
AWS 보안 그룹#
Docker Machine은 Docker 데몬과의 통신에 필요한 포트 2376 및 SSH 22에 대한 규칙이 있는 기본 보안 그룹을 사용하려고 시도합니다. Docker에 의존하는 대신 필요한 규칙이 있는 보안 그룹을 만들고 아래에서 볼 수 있듯이 GitLab Runner 옵션에 이를 제공할 수 있습니다. 이렇게 하면 네트워킹 환경에 따라 미리 원하는 대로 커스터마이징할 수 있습니다. 러너 매니저 인스턴스에서 포트 2376 및 22에 액세스할 수 있어야 합니다.
AWS 자격 증명#
캐시를 스케일(EC2) 및 업데이트(S3를 통해)할 권한이 있는 사용자에 연결된 AWS 액세스 키가 필요합니다. 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를 설치하는 것입니다. Ubuntu, Debian, CentOS, RHEL과 같이 Docker와 GitLab Runner 모두 지원하는 배포판을 선택하세요.
러너 매니저 인스턴스는 작업 자체를 실행하지 않으므로 강력한 머신일 필요는 없습니다. 초기 구성에서는 더 작은 인스턴스로 시작할 수 있습니다. 이 머신은 항상 실행 중이어야 하므로 전용 호스트입니다. 따라서 지속적인 기본 비용이 있는 유일한 호스트입니다.
사전 요구 사항을 설치하세요:
- 서버에 로그인합니다
- 공식 GitLab 리포지터리에서 GitLab Runner를 설치합니다
- Docker를 설치합니다
- GitLab 포크에서 Docker Machine을 설치합니다(Docker는 Docker Machine을 더 이상 지원하지 않음)
러너가 설치되면 이제 등록할 차례입니다.
GitLab Runner 등록#
GitLab Runner를 구성하기 전에 먼저 등록해야 GitLab 인스턴스와 연결됩니다:
- 러너 토큰을 얻습니다
- 러너를 등록합니다
- 실행기 유형을 묻는 경우
docker+machine을 입력합니다
이제 가장 중요한 부분인 GitLab Runner 구성으로 넘어갈 수 있습니다.
인스턴스의 모든 사용자가 오토스케일링 러너를 사용할 수 있도록 하려면 러너를 공유 러너로 등록하세요.
러너 설정#
러너가 등록되었으면 설정 파일을 편집하고 AWS 머신 드라이버에 필요한 옵션을 추가해야 합니다.
먼저 각 부분으로 나누어 살펴보겠습니다.
글로벌 섹션#
글로벌 섹션에서 모든 러너에 걸쳐 동시에 실행할 수 있는 작업의 제한(concurrent)을 정의할 수 있습니다. 이는 GitLab Runner가 얼마나 많은 사용자를 수용할지, 빌드에 얼마나 걸릴지 등과 같이 필요에 따라 크게 달라집니다. 10과 같이 낮은 값으로 시작하여 향후 값을 늘리거나 줄일 수 있습니다.
check_interval 옵션은 러너가 새 작업에 대해 GitLab을 확인하는 빈도(초 단위)를 정의합니다.
예시:
concurrent = 10
check_interval = 0
다른 옵션도 사용할 수 있습니다.
runners 섹션#
[[runners]] 섹션에서 가장 중요한 부분은 executor이며 docker+machine으로 설정해야 합니다. 이러한 설정의 대부분은 러너를 처음 등록할 때 처리됩니다.
limit은 이 러너가 생성하는 최대 머신 수(실행 중 및 유휴)를 설정합니다. 자세한 내용은 limit, concurrent, IdleCount의 관계를 확인하세요.
예시:
[[runners]]
name = "gitlab-aws-autoscaler"
url = ""
token = "<러너의 토큰>"
executor = "docker+machine"
limit = 20
[[runners]] 아래에 다른 옵션도 사용할 수 있습니다.
runners.docker 섹션#
[runners.docker] 섹션에서 .gitlab-ci.yml에 정의되지 않은 경우 하위 러너가 사용하는 기본 Docker 이미지를 정의할 수 있습니다. privileged = true를 사용하면 모든 러너가 GitLab CI/CD를 통해 자체 Docker 이미지를 빌드할 계획이 있는 경우 유용한 Docker in Docker를 실행할 수 있습니다.
다음으로 다음 섹션에서 설명하는 분산 캐시 모드를 사용하므로 Docker 실행기의 내부 캐시 메커니즘을 비활성화하기 위해 disable_cache = true를 사용합니다.
예시:
[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 = ""
SecretKey = ""
BucketName = "<캐시를 보관할 버킷>"
BucketLocation = "us-west-2"
캐시 메커니즘에 대한 추가 정보:
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=eu-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로 설정되고 머신 이름에는 표준 접두사 뒤에 하위 러너의 ID로 대체되는 %s(필수)가 따릅니다: gitlab-docker-machine-%s.
AWS 인프라에 따라 MachineOptions 아래에 설정할 수 있는 많은 옵션이 있습니다. 아래에서 가장 일반적인 옵션을 볼 수 있습니다.
| 머신 옵션 | 설명 |
|---|---|
amazonec2-access-key=XXXX |
EC2 인스턴스를 생성할 권한이 있는 사용자의 AWS 액세스 키입니다. AWS 자격 증명을 참조하세요. |
amazonec2-secret-key=XXXX |
EC2 인스턴스를 생성할 권한이 있는 사용자의 AWS 시크릿 키입니다. AWS 자격 증명을 참조하세요. |
amazonec2-region=eu-central-2 |
인스턴스를 시작할 리전입니다. 완전히 생략하면 기본값 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 Machine의 비공개 IP 주소를 사용하지만 공개 IP 주소도 생성합니다. 트래픽을 내부로 유지하고 추가 비용을 피하는 데 유용합니다. |
amazonec2-tags=runner-manager-name,gitlab-aws-autoscaler,gitlab,true,gitlab-runner-autoscale,true |
AWS 추가 태그 키-값 쌍으로, AWS 콘솔에서 인스턴스를 식별하는 데 유용합니다. "Name" 태그는 기본적으로 머신 이름으로 설정됩니다. 특정 매니저 설정으로 생성된 모든 EC2 인스턴스를 필터링할 수 있도록 [[runners]]에 설정된 러너 이름과 일치하도록 "runner-manager-name"을 설정합니다. |
amazonec2-security-group=xxxx |
보안 그룹 ID가 아닌 AWS VPC 보안 그룹 이름입니다. 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 |
On-Demand 가격보다 저렴하게 사용 가능한 여분의 EC2 용량을 사용합니다. |
amazonec2-spot-price=xxxx_runner_machine_spot_price=x.xx |
Spot 인스턴스 입찰 가격(미국 달러). --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)입니다. |
참고:
MachineOptions아래에 AWS Docker Machine 드라이버가 지원하는 모든 항목을 추가할 수 있습니다. 인프라 설정에 따라 다른 옵션을 적용해야 할 수 있으므로 Docker 문서를 읽어보시기 바랍니다.amazonec2-ami를 설정하여 다른 AMI ID를 선택하지 않는 한 하위 인스턴스는 기본적으로 Ubuntu 16.04를 사용합니다. 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 = ""
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 = ""
SecretKey = ""
BucketName = "<캐시를 보관할 버킷>"
BucketLocation = "us-west-2"
[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=eu-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의 설명에 따르면:
Amazon EC2 Spot 인스턴스를 사용하면 여분의 Amazon 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는 해당 인스턴스 클래스의 기본 On-Demand 가격으로 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"
]
이 구성을 사용하면 최대 Spot 요청 가격이 시간당 $0.03이고 Spot 인스턴스 기간이 60분으로 제한된 Spot 인스턴스를 사용하여 Docker Machine이 생성됩니다. 위에서 언급한 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 "{}"
GitLab Runner가 Spot 가격 변경을 정상적으로 처리하는 것과 관련된 이슈가 있으며, docker-machine이 Docker Machine을 계속 제거하려는 시도 보고가 있습니다. GitLab은 업스트림 프로젝트에서 두 경우 모두에 대한 패치를 제공했습니다. 자세한 내용은 이슈 2771과 이슈 2772를 참조하세요.
GitLab 포크는 AWS EC2 플릿과 Spot 인스턴스와의 사용을 지원하지 않습니다. 대안으로 Continuous Kernel Integration Project의 다운스트림 포크를 사용할 수 있습니다.
결론#
이 가이드에서는 AWS에서 오토스케일 모드로 GitLab Runner를 설치하고 구성하는 방법을 알아보았습니다.
GitLab Runner의 오토스케일 기능을 사용하면 시간과 비용을 모두 절약할 수 있습니다. AWS가 제공하는 Spot 인스턴스를 사용하면 더 많이 절약할 수 있지만, 그 영향을 인식해야 합니다. 입찰가가 충분히 높은 한 문제가 없어야 합니다.
이 튜토리얼에 많은 영향을 받은 다음 사용 사례를 읽어보세요:
