在 AWS EC2 上弹性伸缩极狐GitLab Runner

  1. Tier: 基础版, 专业版, 旗舰版
  2. Offering: JihuLab.com, 极狐GitLab 私有化部署, 极狐GitLab Dedicated

极狐GitLab Runner 的最大优势之一是其能够自动启动和关闭虚拟机,以确保您的构建能立即处理。这是一个很棒的功能,如果使用得当,在不需要 24/7 使用 runners 的情况下,可以提供一种经济高效且可扩展的解决方案。

介绍#

在本教程中,我们将探讨如何在 AWS 中正确配置极狐GitLab Runner。AWS 中的实例将作为 runner 管理器,根据需要生成新的 Docker 实例。这些实例上的 runners 是自动创建的。它们使用本指南中介绍的参数创建,不需要手动配置。

此外,我们将利用 Amazon 的 EC2 Spot 实例,这将大大降低极狐GitLab Runner 实例的成本,同时仍然使用相当强大的自动扩展机器。

先决条件#

需要熟悉 Amazon Web Services (AWS),因为大部分配置将在这里进行。

我们建议快速阅读 Docker machine 的 amazonec2 驱动程序文档,以熟悉我们将在本文后面设置的参数。

您的极狐GitLab Runner 需要通过网络与您的极狐GitLab 实例通信,这是您在配置任何 AWS 安全组或设置 DNS 配置时需要考虑的事情。

例如,您可以将 EC2 资源与公共流量分隔在不同的 VPC 中,以更好地加强网络安全。您的环境可能不同,因此请考虑哪种方法最适合您的情况。

AWS 安全组#

Docker Machine 将尝试使用带有端口 2376 和 SSH 22 规则的默认安全组,这对于与 Docker 守护程序的通信是必需的。您可以创建一个具有所需规则的安全组,并在极狐GitLab Runner 选项中提供该安全组,如下所示。这种方式,您可以提前根据您的网络环境自定义它。您必须确保 Runner 管理器实例 可以访问端口 237622

AWS 凭证#

您需要一个与具有 EC2 扩展权限和通过 S3 更新缓存权限的用户绑定的 AWS 访问密钥。为 EC2 (AmazonEC2FullAccess) 和 S3 创建具有策略的新用户。有关 S3 所需最低权限的更多信息,请参阅 runners.cache.s3。为了更安全,您可以禁用该用户的控制台登录。保持选项卡打开或将安全凭证复制粘贴到编辑器中,因为我们稍后将在 极狐GitLab Runner 配置 中使用它们。

您还可以创建一个具有所需 AmazonEC2FullAccessAmazonS3FullAccess 策略的EC2 实例配置文件。

要为作业执行配置新的 EC2 实例,请将此实例配置文件附加到 runner 管理器 EC2 实例。如果 runner 机器使用实例配置文件,请在 runner 管理器的实例配置文件中包含 iam:PassRole 操作。

示例:

json
1{ 2 "Statement": [ 3 { 4 "Action": "iam:PassRole", 5 "Effect": "Allow", 6 "Resource": "arn:aws:iam:::role/instance-profile-of-runner-machine" 7 } 8 ], 9 "Version": "2012-10-17" 10}

准备 runner 管理器实例#

第一步是在将用作生成新机器的 runner 管理器的 EC2 实例中安装极狐GitLab Runner。选择一个 Docker 和极狐GitLab Runner 都支持的发行版,如 Ubuntu、Debian、CentOS 或 RHEL。

这不必是强大的机器,因为 runner 管理器实例本身不会运行作业。对于您的初始配置,您可以从较小的实例开始。这台机器是一个专用主机,因为我们需要它始终保持运行。因此,它是唯一持续产生基础成本的主机。

安装先决条件:

  1. 登录到您的服务器
  2. 从官方极狐GitLab 仓库安装极狐GitLab Runner
  3. 安装 Docker
  4. 从极狐GitLab 分支安装 Docker Machine (Docker 已弃用 Docker Machine)

现在 Runner 已安装,是时候注册它了。

注册极狐GitLab Runner#

在配置极狐GitLab Runner 之前,您需要先注册它,以便它与您的极狐GitLab 实例连接:

  1. 获取 runner 令牌
  2. 注册 runner
  3. 当询问执行器类型时,输入 docker+machine

现在您可以继续进行最重要的部分,配置极狐GitLab Runner。

如果您希望实例中的每个用户都能使用自动扩展的 runners,请将 runner 注册为共享 runner。

配置 runner#

现在 runner 已注册,您需要编辑其配置文件,并为 AWS 机器驱动程序添加所需的选项。

让我们先将其分解成部分。

全局部分#

在全局部分,您可以定义所有 runners 上可以同时运行的作业数量限制 (concurrent)。这在很大程度上取决于您的需求,例如极狐GitLab Runner 将容纳多少用户,您的构建需要多长时间等。您可以从较低的值,如 10 开始,随着时间推移增加或减少其值。

check_interval 选项定义 runner 应检查极狐GitLab 是否有新作业的频率,以秒为单位。

示例:

toml
concurrent = 10 check_interval = 0

其他选项 也可用。

runners 部分#

[[runners]] 部分,最重要的部分是 executor,它必须设置为 docker+machine。这些设置大部分是在您首次注册 runner 时处理的。

limit 设置该 runner 将生成的最大机器数量(运行和空闲)。有关更多信息,请查看 limitconcurrentIdleCount 之间的关系

示例:

toml
1[[runners]] 2 name = "gitlab-aws-autoscaler" 3 url = "<URL of your GitLab instance>" 4 token = "<Runner's token>" 5 executor = "docker+machine" 6 limit = 20

其他选项[[runners]] 下也可用。

runners.docker 部分#

[runners.docker] 部分,您可以定义子 runners 使用的默认 Docker 镜像,如果未在 .gitlab-ci.yml 中定义。通过使用 privileged = true,所有 runners 都可以运行 Docker in Docker,如果您计划通过极狐GitLab CI/CD 构建自己的 Docker 镜像,这将非常有用。

接下来,我们使用 disable_cache = true 禁用 Docker 执行器的内部缓存机制,因为我们将使用分布式缓存模式,如下节所述。

示例:

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

其他选项[runners.docker] 下也可用。

runners.cache 部分#

为了加快您的作业速度,极狐GitLab Runner 提供了一种缓存机制,选定的目录和/或文件将在后续作业之间保存和共享。虽然不是此设置的必需项,但建议使用极狐GitLab Runner 提供的分布式缓存机制。由于新实例将按需创建,因此有一个存储缓存的公共位置至关重要。

在以下示例中,我们使用 Amazon S3:

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

以下是一些关于缓存机制的更多信息:

runners.machine 部分#

这是配置中最重要的部分,它告诉极狐GitLab Runner 如何以及何时生成新的或移除旧的 Docker Machine 实例。

我们将专注于 AWS 机器选项,其他设置请阅读:

以下是 runners.machine 部分的示例:

toml
1 [runners.machine] 2 IdleCount = 1 3 IdleTime = 1800 4 MaxBuilds = 10 5 MachineDriver = "amazonec2" 6 MachineName = "gitlab-docker-machine-%s" 7 MachineOptions = [ 8 "amazonec2-access-key=XXXX", 9 "amazonec2-secret-key=XXXX", 10 "amazonec2-region=us-central-1", 11 "amazonec2-vpc-id=vpc-xxxxx", 12 "amazonec2-subnet-id=subnet-xxxxx", 13 "amazonec2-zone=x", 14 "amazonec2-use-private-address=true", 15 "amazonec2-tags=runner-manager-name,gitlab-aws-autoscaler,gitlab,true,gitlab-runner-autoscale,true", 16 "amazonec2-security-group=xxxxx", 17 "amazonec2-instance-type=m4.2xlarge", 18 ] 19 [[runners.machine.autoscaling]] 20 Periods = ["* * 9-17 * * mon-fri *"] 21 IdleCount = 50 22 IdleTime = 3600 23 Timezone = "UTC" 24 [[runners.machine.autoscaling]] 25 Periods = ["* * * * * sat,sun *"] 26 IdleCount = 5 27 IdleTime = 60 28 Timezone = "UTC"

Docker Machine 驱动程序设置为 amazonec2,机器名称具有标准前缀,后跟 %s(必需),它被子 runner 的 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。
amazonec2-subnet-id=subnet-xxxxAWS 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,trueAWS 额外的标签键值对,用于在 AWS 控制台中识别实例。默认情况下,“Name” 标签设置为机器名称。我们将“runner-manager-name”设置为与 [[runners]] 中的 runner 名称匹配,以便我们可以筛选出特定管理器设置创建的所有 EC2 实例。
amazonec2-security-group=xxxxAWS VPC 安全组名称,而不是安全组 ID。参见 AWS 安全组
amazonec2-instance-type=m4.2xlarge子 runners 将运行的实例类型。
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.xxSpot 实例竞价价格(以美元为单位)。需要设置 --amazonec2-request-spot-instance flagtrue。如果您省略 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 正确配置了 Internet 网关 (IGW) 并且路由正常,这没有问题,但如果您有更复杂的配置,这是需要考虑的事情。

其他选项[runners.machine] 下也可用。

整体配置#

以下是 /etc/gitlab-runner/config.toml 的完整示例:

toml
1concurrent = 10 2check_interval = 0 3 4[[runners]] 5 name = "gitlab-aws-autoscaler" 6 url = "<URL of your GitLab instance>" 7 token = "<runner's token>" 8 executor = "docker+machine" 9 limit = 20 10 [runners.docker] 11 image = "alpine" 12 privileged = true 13 disable_cache = true 14 [runners.cache] 15 Type = "s3" 16 Shared = true 17 [runners.cache.s3] 18 ServerAddress = "s3.amazonaws.com" 19 AccessKey = "<your AWS Access Key ID>" 20 SecretKey = "<your AWS Secret Access Key>" 21 BucketName = "<the bucket where your cache should be kept>" 22 BucketLocation = "us-east-1" 23 [runners.machine] 24 IdleCount = 1 25 IdleTime = 1800 26 MaxBuilds = 100 27 MachineDriver = "amazonec2" 28 MachineName = "gitlab-docker-machine-%s" 29 MachineOptions = [ 30 "amazonec2-access-key=XXXX", 31 "amazonec2-secret-key=XXXX", 32 "amazonec2-region=us-central-1", 33 "amazonec2-vpc-id=vpc-xxxxx", 34 "amazonec2-subnet-id=subnet-xxxxx", 35 "amazonec2-use-private-address=true", 36 "amazonec2-tags=runner-manager-name,gitlab-aws-autoscaler,gitlab,true,gitlab-runner-autoscale,true", 37 "amazonec2-security-group=XXXX", 38 "amazonec2-instance-type=m4.2xlarge", 39 ] 40 [[runners.machine.autoscaling]] 41 Periods = ["* * 9-17 * * mon-fri *"] 42 IdleCount = 50 43 IdleTime = 3600 44 Timezone = "UTC" 45 [[runners.machine.autoscaling]] 46 Periods = ["* * * * * sat,sun *"] 47 IdleCount = 5 48 IdleTime = 60 49 Timezone = "UTC"

使用 Amazon EC2 Spot 实例降低成本#

正如 Amazon 所描述:

Amazon EC2 Spot 实例允许您竞标未使用的 Amazon EC2 计算容量。由于 Spot 实例通常比按需定价便宜,您可以显著降低运行应用程序的成本,增加应用程序的计算容量和吞吐量,并支持新类型的云计算应用程序。

除了您在 /etc/gitlab-runner/config.toml 中挑选的 runners.machine 选项,在 MachineOptions 部分下,添加以下内容:

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

在此配置中,使用空的 amazonec2-spot-price,AWS 将您的 Spot 实例竞价价格设置为该实例类别的默认按需价格。如果您完全省略 amazonec2-spot-price,Docker Machine 会将最大价格设置为 每小时 $0.50 的默认值。

您可以进一步自定义您的 Spot 实例请求:

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

通过此配置,Docker Machines 使用 Spot 实例创建,最大 Spot 请求价格为每小时 $0.03,Spot 实例的持续时间限制为 60 分钟。上述 0.03 数字只是一个示例,因此请务必检查您选择的区域的当前定价。

Spot 实例的注意事项#

虽然 Spot 实例是一种利用未使用资源并最大限度地降低基础设施成本的好方法,但您必须了解其影响。

在 Spot 实例上运行 CI 作业可能会增加失败率,因为 Spot 实例的定价模型。如果您指定的最大 Spot 价格超过当前 Spot 价格,您将无法获得请求的容量。Spot 定价每小时修订一次。任何现有的 Spot 实例如果最大价格低于修订后的 Spot 实例价格,将在两分钟内被终止,所有在 Spot 主机上的作业将失败。

因此,自动扩展 Runner 将无法创建新机器,同时它将继续请求新实例。这最终将进行 60 次请求,然后 AWS 将不再接受更多请求。一旦 Spot 价格合适,您将因为调用次数限制而被锁定一段时间。

如果您遇到这种情况,您可以在 runner 管理器机器上使用以下命令查看 Docker Machine 的状态:

shell
docker-machine ls -q --filter state=Error --format "{{.NAME}}"
有关使极狐GitLab Runner 优雅处理 Spot 价格变化的问题,已报告 `docker-machine` 尝试持续移除 Docker Machine。极狐GitLab 已为这两种情况在上游项目中提供补丁。

极狐GitLab 分支不支持 AWS EC2 fleets 及其与 Spot 实例的使用。

结论#

在本指南中,我们学习了如何在 AWS 上安装和配置极狐GitLab Runner 的自动扩展模式。

使用极狐GitLab Runner 的自动扩展功能可以为您节省时间和金钱。使用 AWS 提供的 Spot 实例可以为您节省更多,但您必须了解其影响。只要您的出价足够高,就不应该有问题。