AWS Fargate 上弹性伸缩极狐GitLab CI
- Tier: 基础版, 专业版, 旗舰版
- Offering: JihuLab.com, 私有化部署
Fargate 驱动程序由社区支持。极狐GitLab 支持团队会尽力协助排查问题,但不提供保证。
极狐GitLab 针对 AWS Fargate 的自定义执行器 驱动程序会自动在 Amazon Elastic Container Service (ECS) 上启动容器,以执行每一个极狐GitLab CI 作业。
完成本文档中的所有步骤后,执行器即可运行由极狐GitLab 触发的作业。每当极狐GitLab 中有新的提交时,极狐GitLab 实例会通知 runner 有新作业可用。runner 随后会在目标 ECS 集群中,根据你在 AWS ECS 中配置的任务定义启动一个新任务。你可以将 AWS ECS 任务定义配置为使用任意 Docker 镜像。通过这种方式,你可以完全灵活地选择在 AWS Fargate 上执行的构建类型。
本文档展示的示例旨在帮助你初步理解实现方式。该示例不适用于生产环境;在 AWS 上还需额外的安全措施。
例如,你可能需要两个 AWS 安全组:
- 一个用于承载 GitLab Runner 的 EC2 实例,仅允许来自受限外部 IP 范围的 SSH 连接(用于管理访问)。
- 一个应用于 Fargate 任务,仅允许来自 EC2 实例的 SSH 流量。
对于任何非公开的容器镜像仓库,你的 ECS 任务需要 IAM 权限(仅限 AWS ECR)或任务的私有仓库认证(适用于非 ECR 私有仓库)。
你可以使用 CloudFormation 或 Terraform 自动化 AWS 基础设施的配置和部署。
CI/CD 作业使用 ECS 任务中定义的镜像,而不是 .gitlab-ci.yml 文件中 image: 关键字指定的镜像。ECS 不允许你覆盖 ECS 任务所用的镜像。
要规避此限制,你可以:
- 在 ECS 任务定义中使用包含所有项目构建依赖的镜像。
- 创建多个使用不同镜像的 ECS 任务定义,并在 FARGATE_TASK_DEFINITION CI/CD 变量中指定 ARN。
Fargate 对容器主机进行了抽象,限制了对主机属性的配置能力。这会影响需要高磁盘 IO 或网络 IO 的 runner 工作负载,因为这些属性在 Fargate 上几乎无法配置。在将 GitLab Runner 部署到 Fargate 之前,请确保你的 runner 工作负载在 CPU、内存、磁盘 IO 或网络 IO 等高计算特性方面适合 Fargate。
先决条件
在开始之前,你应该具备以下条件:
- 一个具有创建和配置 EC2、ECS 和 ECR 资源权限的 AWS IAM 用户。
- AWS VPC 和子网。
- 一个或多个 AWS 安全组。
步骤 1:为 AWS Fargate 任务准备一个容器镜像
准备一个容器镜像。你可以将此镜像上传到一个镜像仓库中,以便在极狐GitLab 作业运行时创建容器。
- 确保镜像具有构建你的 CI 作业所需的工具。例如,一个 Java 项目需要 Java JDK 和构建工具,如 Maven 或 Gradle。一个 Node.js 项目需要 node 和 npm。
- 确保镜像具有极狐GitLab Runner,它负责处理产物和缓存。请参考 custom executor 文档的 Run 阶段部分以获取更多信息。
- 确保容器镜像可以通过公钥认证接受 SSH 连接。runner 使用此连接将 .gitlab-ci.yml 文件中定义的构建命令发送到 AWS Fargate 上的容器。SSH 密钥由 Fargate 驱动程序自动管理。容器必须能够接受来自 SSH_PUBLIC_KEY 环境变量的密钥。
查看包含极狐GitLab Runner 和 SSH 配置的 Debian 示例。查看 Node.js 示例。
步骤 2:将容器镜像推送到镜像仓库
创建镜像后,将其发布到容器镜像仓库中,以便在 ECS 任务定义中使用。
- 要创建存储库并将镜像推送到 ECR,请遵循 Amazon ECR Repositories文档。
- 要使用 AWS CLI 将镜像推送到 ECR,请遵循 Amazon ECR AWS CLI 文档。
- 要使用 极狐GitLab Container Registry,可以使用 Debian 或 NodeJS 示例。Debian 镜像发布到 registry.gitlab.cn/tmaczukin-test-projects/fargate-driver-debian:latest。NodeJS 示例镜像发布到 registry.gitlab.cn/aws-fargate-driver-demo/docker-nodejs-gitlab-ci-fargate:latest。
步骤 3:为极狐GitLab Runner 创建一个 EC2 实例
现在创建一个 AWS EC2 实例。在下一步中,你将安装极狐GitLab Runner。
- 访问 https://console.aws.amazon.com/ec2/v2/home#LaunchInstanceWizard。
- 对于实例,选择 Ubuntu Server 18.04 LTS AMI。名称可能因你选择的 AWS 区域而异。
- 对于实例类型,选择 t2.micro。选择 下一步:配置实例详细信息。
- 保留 实例数量 的默认值。
- 对于 网络,选择你的 VPC。
- 将 自动分配公有 IP 设置为 启用。
- 在 IAM 角色 下,选择 创建新 IAM 角色。此角色仅用于测试目的,并不安全。
- 选择 创建角色。
- 选择 AWS 服务,并在 常用用例 下,选择 EC2。然后选择 下一步:权限。
- 勾选 AmazonECS_FullAccess 策略的复选框。选择 下一步:标签。
- 选择 下一步:预览。
- 输入 IAM 角色的名称,例如 fargate-test-instance,然后选择 创建角色。
- 返回到你正在创建实例的浏览器标签页。
- 在 创建新 IAM 角色 的左侧,选择刷新按钮。选择 fargate-test-instance 角色。选择 下一步:添加存储。
- 选择 下一步:添加标签。
- 选择 下一步:配置安全组。
- 选择 创建新安全组,将其命名为 fargate-test,并确保定义了 SSH 的规则(类型: SSH, 协议: TCP, 端口范围: 22)。你必须指定入站和出站规则的 IP 范围。
- 选择 预览并启动。
- 选择 启动。
- 可选。选择 创建新密钥对,将其命名为 fargate-runner-manager,并选择 下载密钥对。SSH 的私钥将下载到你的计算机上(请检查浏览器配置的目录)。
- 选择 启动实例。
- 选择 查看实例。
- 等待实例启动。记下 IPv4 公有 IP(IPv4 Public IP) 地址。
步骤 4:在 EC2 实例上安装和配置极狐GitLab Runner
现在在 Ubuntu 实例上安装极狐GitLab Runner。
-
进入你的极狐GitLab 项目的 设置 > CI/CD 并展开 Runner 部分。在 手动设置指定 Runenr 下,记下注册令牌。
-
通过运行 chmod 400 path/to/downloaded/key/file 确保你的密钥文件具有正确的权限。
-
使用以下命令 SSH 进入你创建的 EC2 实例:
shellssh ubuntu@[ip_address] -i path/to/downloaded/key/file
-
当你成功连接后,运行以下命令:
shellsudo mkdir -p /opt/gitlab-runner/{metadata,builds,cache} curl -s "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash sudo apt install gitlab-runner
-
使用你在步骤 1 中记下的极狐GitLab URL 和注册令牌运行此命令。
shellsudo gitlab-runner register --url "https://gitlab.com/" --registration-token TOKEN_HERE --name fargate-test-runner --run-untagged --executor custom -n
-
运行 sudo vim /etc/gitlab-runner/config.toml 并添加以下内容:
toml1concurrent = 1 2check_interval = 0 3 4[session_server] 5 session_timeout = 1800 6 7[[runners]] 8 name = "fargate-test" 9 url = "https://gitlab.com/" 10 token = "__REDACTED__" 11 executor = "custom" 12 builds_dir = "/opt/gitlab-runner/builds" 13 cache_dir = "/opt/gitlab-runner/cache" 14 [runners.custom] 15 volumes = ["/cache", "/path/to-ca-cert-dir/ca.crt:/etc/gitlab-runner/certs/ca.crt:ro"] 16 config_exec = "/opt/gitlab-runner/fargate" 17 config_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "config"] 18 prepare_exec = "/opt/gitlab-runner/fargate" 19 prepare_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "prepare"] 20 run_exec = "/opt/gitlab-runner/fargate" 21 run_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "run"] 22 cleanup_exec = "/opt/gitlab-runner/fargate" 23 cleanup_args = ["--config", "/etc/gitlab-runner/fargate.toml", "custom", "cleanup"]
-
如果你有一个极狐GitLab私有化部署实例,并且使用了私有 CA,请添加这一行:
tomlvolumes = ["/cache", "/path/to-ca-cert-dir/ca.crt:/etc/gitlab-runner/certs/ca.crt:ro"]
config.toml 文件中显示的部分是由注册命令创建的。不要更改它。
toml1concurrent = 1 2check_interval = 0 3 4[session_server] 5 session_timeout = 1800 6 7name = "fargate-test" 8url = "https://gitlab.com/" 9token = "__REDACTED__" 10executor = "custom"
-
运行 sudo vim /etc/gitlab-runner/fargate.toml 并添加以下内容:
toml1LogLevel = "info" 2LogFormat = "text" 3 4[Fargate] 5 Cluster = "test-cluster" 6 Region = "us-east-2" 7 Subnet = "subnet-xxxxxx" 8 SecurityGroup = "sg-xxxxxxxxxxxxx" 9 TaskDefinition = "test-task:1" 10 EnablePublicIP = true 11 12[TaskMetadata] 13 Directory = "/opt/gitlab-runner/metadata" 14 15[SSH] 16 Username = "root" 17 Port = 22
-
注意 Cluster 的值和 TaskDefinition 的名称。此示例显示 test-task,并以 :1 作为修订号。如果未指定修订号,则使用最新的活动修订。
-
选择你的区域。从 runner 管理器实例中获取 Subnet 值。
-
要查找安全组 ID:
- 在 AWS 中,在实例列表中选择你创建的 EC2 实例。显示详细信息。
- 在 Security groups 下,选择你创建的组的名称。
- 复制 Security group ID。
在生产环境中,遵循 AWS 指南设置和使用安全组。
-
如果 EnablePublicIP 设置为 true,则会收集任务容器的公共 IP 以进行 SSH 连接。
-
如果 EnablePublicIP 设置为 false:
- Fargate 驱动程序使用任务容器的私有 IP。要在设置为 false 时建立连接,VPC 安全组必须有一个端口 22 (SSH) 的入站规则,其中源为 VPC CIDR。
- 为了获取外部依赖项,配置的 AWS Fargate 容器必须能够访问公共互联网。要为 AWS Fargate 容器提供公共互联网访问,你可以在 VPC 中使用 NAT 网关。
-
SSH 服务器的端口号是可选的。如果省略,使用默认 SSH 端口 (22)。
-
-
安装 Fargate 驱动程序:
shellsudo curl -Lo /opt/gitlab-runner/fargate "https://gitlab-runner-custom-fargate-downloads.s3.amazonaws.com/latest/fargate-linux-amd64" sudo chmod +x /opt/gitlab-runner/fargate
步骤 5:创建一个 ECS Fargate 集群
Amazon ECS 集群是 ECS 容器实例的分组。
- 访问 https://console.aws.amazon.com/ecs/home#/clusters。
- 选择 创建集群。
- 选择 仅网络 类型。选择 下一步。
- 将其命名为 test-cluster(与 fargate.toml 中的相同)。
- 选择 创建。
- 选择 查看集群。记下 Cluster ARN 值中的区域和账户 ID 部分。
- 选择 更新集群。
- 在 默认容量提供程序策略 旁边,选择 添加另一个提供程序 并选择 FARGATE。选择 更新。
步骤 6:创建一个 ECS 任务定义
在此步骤中,你将创建一个 Fargate 类型的任务定义,并引用你可能用于 CI 构建的容器镜像。
- 访问 https://console.aws.amazon.com/ecs/home#/taskDefinitions。
- 选择 创建新的任务定义。
- 选择 FARGATE 并选择 下一步。
- 将其命名为 test-task。(注意:名称是 fargate.toml 文件中定义的相同值,但没有 :1)。
- 为 任务内存(GB) 和 任务 CPU(vCPU) 选择值。
- 选择 添加容器。然后:
- 将其命名为 ci-coordinator,以便 Fargate 驱动程序可以注入 SSH_PUBLIC_KEY 环境变量。
- 定义镜像(例如 registry.gitlab.com/tmaczukin-test-projects/fargate-driver-debian:latest)。
- 为 22/TCP 定义端口映射。
- 选择 添加。
- 选择 创建。
- 选择 查看任务定义。
一个 Fargate 任务可以启动一个或多个容器。Fargate 驱动程序只会在名称为 ci-coordinator 的容器中注入 SSH_PUBLIC_KEY 环境变量。因此,你必须在所有被 Fargate 驱动程序使用的任务定义中包含一个名为 ci-coordinator 的容器。该容器应当安装有 SSH 服务器以及上述所有极狐GitLab Runner 所需的依赖。
有关设置和使用任务定义的详细说明,请参阅 AWS 官方文档。
关于启动 AWS ECR 镜像所需的 ECS 服务权限,请参阅 Amazon ECS 任务执行 IAM 角色相关说明。
关于 ECS 认证私有镜像仓库(包括托管在极狐GitLab 实例上的仓库),请参阅任务的私有仓库认证相关说明。
此时,runner 管理器和 Fargate 驱动程序已经配置完成,可以开始在 AWS Fargate 上执行作业了。
步骤 7:测试配置
你的配置现在应该可以使用了。
-
在你的极狐GitLab 项目中,创建一个 .gitlab-ci.yml 文件:
yamltest: script: - echo "It works!" - for i in $(seq 1 30); do echo "."; sleep 1; done
-
转到项目的 CI/CD > 流水线。
-
选择 运行流水线。
-
更新分支和任何变量,然后选择 运行流水线。
.gitlab-ci.yml 文件中的 image 和 service 关键字被忽略。runner 只使用在任务定义中指定的值。
清理
如果你想在使用 AWS Fargate 测试 custom executor 后进行清理,请移除以下对象:
配置一个私有的 AWS Fargate 任务
为了确保高水平的安全性,配置一个似有的 AWS Fargate 任务。在此配置中,执行器仅使用内部 AWS IP 地址。它们仅允许来自 AWS 的出站流量,以便 CI/CD 作业在私有 AWS Fargate 实例上运行。
要配置私有 AWS Fargate 任务,请完成以下步骤以配置 AWS 并在私有子网中运行 AWS Fargate 任务:
-
确保现有的公共子网未在 VPC 地址范围内保留所有 IP 地址。检查 VPC 和子网的 cird 地址范围。如果子网 cird 地址范围是 VPC cird 地址范围的子集,则跳过步骤 2 和 4。否则,你的 VPC 没有空闲地址范围,因此你必须删除并重新创建 VPC 和公共子网:
- 删除现有的子网和 VPC。
- 创建一个 VPC,配置与之前删除的 VPC 相同,并更新 cird 地址,例如 10.0.0.0/23。
- 创建一个公有子网,配置与之前删除的子网相同。使用属于 VPC 地址范围的 cird 地址,例如 10.0.0.0/24。
- 创建一个私有子网,配置与公有子网相同。使用不与公有子网重叠的 cird 地址范围,例如 10.0.1.0/24。
- 创建一个 NAT 网关,并将其放置在公有子网中。
- 修改私有子网的路由表,使目标 0.0.0.0/0 指向 NAT 网关。
- 更新 farget.toml 配置:
tomlSubnet = "private-subnet-id" EnablePublicIP = false UsePublicIP = false
-
将以下内联策略添加到与你的 Fargate 任务关联的 IAM 角色中(Fargate 任务关联的 IAM 角色通常名为 ecsTaskExecutionRole,该角色一般已存在)。
json1{ 2 "Statement": [ 3 { 4 "Sid": "VisualEditor0", 5 "Effect": "Allow", 6 "Action": [ 7 "secretsmanager:GetSecretValue", 8 "kms:Decrypt", 9 "ssm:GetParameters" 10 ], 11 "Resource": [ 12 "arn:aws:secretsmanager:*:<account-id>:secret:*", 13 "arn:aws:kms:*:<account-id>:key/*" 14 ] 15 } 16 ] 17}
-
修改安全组的“入站规则”,使其引用自身。在 AWS 配置界面中:
- 将“类型”设置为“ssh”。
- 将“来源”设置为“自定义”。
- 选择当前的安全组。
- 移除原有允许任意主机 SSH 访问的入站规则。
移除原有入站规则后,你将无法通过 SSH 连接到 Amazon Elastic Compute Cloud 实例。
如需了解更多信息,请参阅以下 AWS 文档:
- Amazon ECS 任务执行 IAM 角色
- Amazon ECR 接口 VPC 终端节点(AWS PrivateLink)
- Amazon ECS 接口 VPC 终端节点
- 具有公有和私有子网的 VPC 配置
故障排除
测试配置时出现 No Container Instances were found in your cluster 错误
error="starting new Fargate task: running new task on Fargate: error starting AWS Fargate Task: InvalidParameterException: No Container Instances were found in your cluster."
AWS Fargate 驱动程序要求 ECS 集群配置有一个默认容量提供者策略。
进一步阅读:
- 一个默认的能力提供商策略与每个 Amazon ECS 集群关联。如果没有指定其他容量提供者策略或启动类型,则集群在任务运行或服务创建时使用此策略。
- 如果指定了 capacityProviderStrategy,则必须省略 launchType 参数。如果未指定 capacityProviderStrategy 或 launchType,则使用集群的 defaultCapacityProviderStrategy。
运行作业时出现 Metadata file does not exist 错误
Application execution failed PID=xxxxx error="obtaining information about the running task: trying to access file \"/opt/gitlab-runner/metadata/<runner_token>-xxxxx.json\": file does not exist" cleanup_std=err job=xxxxx project=xx runner=<runner_token>
确保你的 IAM 角色策略配置正确,并能够执行写操作以在 /opt/gitlab-runner/metadata/ 中创建元数据 JSON 文件。要在非生产环境中进行测试,请使用 AmazonECS_FullAccess 策略。根据组织的安全要求审核你的 IAM 角色策略。
运行作业时出现 connection timed out
Application execution failed PID=xxxx error="executing the script on the remote host: executing script on container with IP \"172.x.x.x\": connecting to server: connecting to server \"172.x.x.x:22\" as user \"root\": dial tcp 172.x.x.x:22: connect: connection timed out"
如果 EnablePublicIP 配置为 false,请确保你的 VPC 安全组有一个允许 SSH 连接的入站规则。你的 AWS Fargate 任务容器必须接受来自极狐GitLab Runner EC2 实例的 SSH 流量。
运行作业时出现 connection refused
Application execution failed PID=xxxx error="executing the script on the remote host: executing script on container with IP \"10.x.x.x\": connecting to server: connecting to server \"10.x.x.x:22\" as user \"root\": dial tcp 10.x.x.x:22: connect: connection refused"
确保任务容器已开放端口 22,并根据步骤 6:创建 ECS 任务定义中的说明配置端口映射。如果端口已开放并且容器已配置:
- 检查 Amazon ECS > Clusters > 选择你的任务定义 > Tasks 中是否有任何容器错误。
- 查看状态为 Stopped 的任务,并检查最新失败的任务。如果有容器故障,logs 选项卡会提供更多详细信息。
或者,确保你可以在本地运行 Docker 容器。
运行作业时出现 ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain
如果由于较旧版本的 AWS Fargate 驱动程序而使用了不支持的密钥类型,会出现以下错误。
Application execution failed PID=xxxx error="executing the script on the remote host: executing script on container with IP \"172.x.x.x\": connecting to server: connecting to server \"172.x.x.x:22\" as user \"root\": ssh: handshake failed: ssh: unable to authenticate, attempted methods [none publickey], no supported methods remain"
要解决此问题,请在极狐GitLab Runner EC2 实例上安装最新的 AWS Fargate 驱动程序:
shellsudo curl -Lo /opt/gitlab-runner/fargate "https://gitlab-runner-custom-fargate-downloads.s3.amazonaws.com/latest/fargate-linux-amd64" sudo chmod +x /opt/gitlab-runner/fargate
运行作业时出现 file name too long
以下错误发生在极狐GitLab 18.0 或更高版本上,或在 2025 年 4 月 28 日后在 JihuLab.com 上,因为 job token 格式更改为 JWT token 格式。AWS Fargate custom executor driver 用户必须升级到版本 0.5.1 或更高版本。或者,你可以在不升级 runner 的情况下使用旧的 CI/CD 作业令牌格式,直到极狐GitLab 19.0。