GitLab Runner 三种类型详解:从共享到项目专属的CI/CD执行器部署指南
2026/7/30 13:29:13 网站建设 项目流程

1. 从手动到自动:为什么我们需要 GitLab Runner

如果你用过 GitLab,肯定知道它的 CI/CD 功能很强大,能把代码提交、测试、构建、部署这些繁琐的活儿串起来。但很多刚开始接触的朋友会卡在一个地方:我写的.gitlab-ci.yml流水线脚本,到底是在哪里执行的呢?答案就是GitLab Runner。你可以把它理解成一个“工人”,GitLab 这个“调度中心”把任务(流水线作业)派发给它,它领了任务就去干活。

那么问题来了,这个“工人”住在哪里?用什么姿势干活?这就是标题里说的“三种 Runner”要解决的问题。在 GitLab 的世界里,Runner 主要分三种:共享 Runner群组 Runner项目 Runner。它们的区别,核心在于“管辖范围”和“资源隔离”。用个不太严谨但好懂的比喻:共享 Runner 像公司公用的那几台高配电脑,谁有急活都能用,但可能得排队,环境也杂;群组 Runner 像你们部门自己买的一台服务器,只有部门里的人能用,配置和环境可以按部门需求来;项目 Runner 就更私密了,像是给你这个项目单独配的一台虚拟机,完全独享,想怎么折腾都行。

搞清楚这三种 Runner 的创建和使用,你才能真正掌控 CI/CD 的执行环境,避免“在我机器上好好的,一上流水线就挂”的尴尬。接下来,我们就抛开官方文档那套理论,从实际运维和开发的角度,把这三种 Runner 的创建、配置、使用场景和那些容易踩的坑,给你掰开揉碎了讲清楚。

2. 三种 Runner 的本质区别与选型指南

在动手创建之前,我们必须先彻底理解这三种 Runner 在设计上的根本差异。这决定了你该在什么场景下用哪一种,而不是拍脑袋随便选。

2.1 共享 Runner:公司的“公共服务”

共享 Runner 是注册在 GitLab 实例级别(对于自托管 GitLab)或是在 GitLab.com 上由 GitLab 官方提供的 Runner。它的最大特点是对所有拥有访问权限的项目可见

核心特性与适用场景:

  • 全局可见性:一旦管理员创建并注册了一个共享 Runner,该 GitLab 实例下的所有项目,在流水线设置里都能看到它,并可以选择使用。
  • 资源池化:它非常适合用来跑一些通用的、轻量级的任务,比如代码风格检查(Lint)、依赖安装、单元测试等。这些任务对运行环境要求不高,且执行频繁。
  • 管理成本低:由平台或运维团队统一维护、升级、打补丁,项目开发者无需关心 Runner 本身的状态。
  • 潜在问题:因为是共享的,所以可能面临资源竞争。如果某个项目提交了一个非常耗时的构建任务,它可能会阻塞其他项目的流水线。此外,环境隔离是个挑战。虽然 Docker 执行器可以提供一定的隔离,但宿主机资源(如网络、磁盘I/O)仍然是共享的。

注意:对于安全性要求高的项目(例如需要访问内部数据库、特定密钥),通常不建议使用共享 Runner,因为你无法完全控制其运行环境和其他可能并行的任务。

2.2 群组 Runner:部门的“专有资产”

群组 Runner 注册在某个特定的 GitLab 群组下。这个群组下的所有项目,以及其子群组下的所有项目,都可以使用这个 Runner。

核心特性与适用场景:

  • 范围可控:完美解决了共享 Runner 范围过广的问题。你可以为“前端组”、“后端微服务组”或“移动端组”分别创建各自的群组 Runner。
  • 环境定制:可以为特定群组的工作流定制 Runner 环境。例如,为 Android 开发群组配置一个安装了完整 Android SDK、NDK 和特定版本 Gradle 的 Runner;为数据科学群组配置一个带有 Python 科学计算库和 GPU 支持的 Runner。
  • 资源隔离与成本分摊:资源在群组内共享,避免了公司级别的资源竞争,同时又比给每个项目单独配置 Runner 更经济。运维团队可以将群组 Runner 部署在对应的部门网络或VPC内,方便访问内部资源。
  • 权限管理:群组管理员负责 Runner 的维护,项目开发者只有使用权。这实现了运维和开发的权责分离。

2.3 项目 Runner:项目的“私人订制”

项目 Runner,顾名思义,只属于某一个特定的 GitLab 项目。只有这个项目能使用它。

核心特性与适用场景:

  • 最高隔离度:资源完全独享,不受其他任何项目干扰。这对于构建耗时极长、资源消耗巨大(例如编译大型C++项目、训练机器学习模型)或对执行环境有极端定制化需求的任务至关重要。
  • 极致定制化:你可以为这个 Runner 安装任何项目所需的特殊软件、驱动、证书,而不用担心影响其他项目。
  • 安全边界清晰:Runner 可以部署在项目专属的安全域内,甚至与项目生产环境网络互通,方便进行集成测试或部署,同时最大程度减少暴露面。
  • 管理成本最高:每个项目 Runner 都需要单独维护、监控。如果公司有上百个项目,每个都配一个专属 Runner,运维复杂度会指数级上升。

选型决策流程图(心智模型):

  1. 任务是否需要访问敏感信息(如生产数据库密钥、内部包仓库凭证)?
    • 是 -> 考虑项目 Runner或部署在安全区域的群组 Runner
    • 否 -> 进入下一步。
  2. 任务是否非常耗时(>30分钟)或消耗大量资源(CPU/内存/GPU)?
    • 是 -> 强烈建议使用项目 Runner,避免阻塞他人。
    • 否 -> 进入下一步。
  3. 是否有多个项目需要相似的特殊环境(如特定的编译器版本、运行时)?
    • 是 ->群组 Runner是最佳选择,一次配置,多处使用。
    • 否 -> 进入下一步。
  4. 任务是否通用、轻量且频繁(如 lint, unit test)?
    • 是 ->共享 Runner足矣,管理最省心。

3. 实战:手把手创建与注册三种 Runner

理论懂了,我们直接上实操。这里假设你有一个自托管的 GitLab 实例(版本 >= 14.x),并且你拥有相应级别的管理员或维护者权限。我们将从准备 Runner 主机开始,一步步完成注册。

3.1 第一步:准备 Runner 主机与安装 gitlab-runner

无论哪种 Runner,其本体都是一个叫做gitlab-runner的可执行程序。我们需要先找一台机器(物理机、虚拟机、容器均可)来安装它。

1. 主机选择考量:

  • 操作系统:Linux 是最常见和最佳支持的选择(如 Ubuntu, CentOS, RHEL)。macOS 和 Windows 也可,但通常用于特定平台的项目构建。
  • 资源:根据你预计要运行的流水线作业来配置 CPU、内存和磁盘。例如,前端构建可能需要大内存,C++编译需要多核CPU。
  • 网络:Runner 主机必须能访问你的 GitLab 服务器(用于接收任务和上报结果),并且可能需要访问互联网(下载依赖)或内网(访问私有仓库)。

2. 安装 gitlab-runner(以 Ubuntu 22.04 为例):

# 1. 添加官方仓库 sudo curl -L --output /usr/share/keyrings/gitlab-runner-archive-keyring.gpg https://packages.gitlab.com/runner/gitlab-runner/gpgkey echo "deb [signed-by=/usr/share/keyrings/gitlab-runner-archive-keyring.gpg] https://packages.gitlab.com/runner/gitlab-runner $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/gitlab-runner.list > /dev/null # 2. 更新并安装 sudo apt-get update sudo apt-get install gitlab-runner # 3. 验证安装 gitlab-runner --version

安装完成后,gitlab-runner会作为一个系统服务运行。你可以用sudo systemctl status gitlab-runner查看状态。

3.2 第二步:获取注册令牌

注册 Runner 时,需要一个“密码”来向 GitLab 证明身份,这就是注册令牌。三种 Runner 的令牌获取位置不同。

  • 共享 Runner 令牌: 进入 GitLab 管理区域(Admin Area)。路径:左上角菜单 -> Admin -> Overview -> Runners。在页面右侧,你会看到“Register an instance runner”按钮,下方显示Registration token。这个令牌需要 GitLab 实例的管理员权限才能看到。

  • 群组 Runner 令牌: 进入目标群组的主页。路径:进入该群组 -> 左侧边栏 Settings -> CI/CD。展开Runners部分,你会看到“Register a group runner”区域,其中包含Registration token。需要群组所有者(Owner)或维护者(Maintainer)权限。

  • 项目 Runner 令牌: 进入目标项目的主页。路径:进入该项目 -> 左侧边栏 Settings -> CI/CD。展开Runners部分,在 “Specific runners” 区域找到Registration token。需要项目维护者(Maintainer)及以上权限。

实操心得:务必妥善保管这些令牌,它们相当于给 Runner 发放进入对应范围的“门票”。建议在注册完成后,可以考虑在 GitLab 界面上点击“重置令牌”,使旧的令牌失效,这是一个好的安全实践。

3.3 第三步:执行注册命令

在安装好gitlab-runner的主机上,执行注册命令。这是一个交互式过程,但我们可以用一条命令带全参数来完成。以下示例假设你的 GitLab 地址是https://gitlab.mycompany.com

注册一个共享 Runner:

sudo gitlab-runner register \ --non-interactive \ --url "https://gitlab.mycompany.com/" \ --registration-token "YOUR_SHARED_RUNNER_TOKEN" \ --executor "docker" \ --docker-image "alpine:latest" \ --description "docker-shared-runner-01" \ --tag-list "shared,linux,docker" \ --run-untagged="true"
  • --executor “docker”:指定使用 Docker 执行器,这是最常用、隔离性最好的方式。每个 CI 作业都会在一个全新的容器中运行。
  • --docker-image “alpine:latest”:指定默认的 Docker 镜像。如果项目中的.gitlab-ci.yml没有指定image,则会使用这个。
  • --description:给你的 Runner 一个易于识别的描述。
  • --tag-list:给 Runner 打上标签。标签是用于在流水线中定向选择 Runner 的关键机制。这里我们打了shared, linux, docker
  • --run-untagged=“true”这是共享 Runner 的关键设置。意味着那些没有指定任何标签(tags)的作业,也会被这个 Runner 执行。这确保了所有项目最基本的流水线都能跑起来。

注册一个群组 Runner:

sudo gitlab-runner register \ --non-interactive \ --url "https://gitlab.mycompany.com/" \ --registration-token "YOUR_GROUP_RUNNER_TOKEN" \ --executor "shell" \ --description “group-runner-for-android” \ --tag-list “android, heavy-build” \ --run-untagged=“false”
  • 这里我们使用了--executor “shell”。对于 Android 构建,有时需要直接使用宿主机环境(因为涉及 USB 调试、硬件加速等),Shell 执行器更合适。你需要确保宿主机上已安装好所有 Android 构建工具。
  • --tag-list我们打了android, heavy-build
  • --run-untagged=“false”这是群组和项目 Runner 的典型设置。这意味着只有明确指定了androidheavy-build标签的作业,才会被这个 Runner 执行。这实现了资源的精准调度。

注册一个项目 Runner:

sudo gitlab-runner register \ --non-interactive \ --url "https://gitlab.mycompany.com/" \ --registration-token "YOUR_PROJECT_RUNNER_TOKEN" \ --executor “docker” \ --docker-image “ubuntu:22.04” \ --docker-volumes “/var/run/docker.sock:/var/run/docker.sock” \ --docker-volumes “/cache” \ --description “project-runner-for-data-pipeline” \ --tag-list “data-pipeline, gpu” \ --run-untagged=“false”
  • --docker-volumes:这里我们挂载了两个卷。第一个docker.sock是著名的 “Docker in Docker” 模式,允许 CI 作业在容器内继续运行 Docker 命令(用于构建镜像等)。这是一个需要谨慎评估安全性的操作。第二个/cache是挂载一个缓存卷,用于在不同作业之间缓存依赖(如 pip packages, npm modules),可以显著加速流水线。
  • --tag-list我们打了>android-build: stage: build tags: - android # 这个标签匹配我们之前注册的群组 Runner - heavy-build script: - ./gradlew assembleRelease only: - main

    这个android-build作业只会被那些打了androidheavy-build标签的 Runner 执行,也就是我们之前注册的那个群组 Runner。

    示例 2:使用项目 Runner 进行数据训练

    train-model: stage: train tags: ->lint: stage: test # 不指定 tags,或者指定一个非常通用的标签 tags: - shared script: - npm run lint

    这个作业没有特殊标签要求,或者指定了共享 Runner 也拥有的通用标签shared。因此,它会被配置为run-untagged=true的共享 Runner,或者任何拥有shared标签的 Runner 执行。

    4.2 配置详解与高级用法

    1. Runner 锁定与解锁:在 Runner 的管理页面,你可以看到一个Lock to current projects的选项。这对于项目 Runner是自动且强制的(它只能被锁定的项目使用)。对于群组 Runner,你可以选择锁定它,这样只有当前群组下的项目能使用,即使其他项目知道了它的标签也无法使用,增加了安全性。

    2. 执行器选择与配置:我们之前用了dockershell。还有其他执行器:

    • kubernetes:在 K8s 集群中动态创建 Pod 来运行作业,弹性极佳。
    • ssh:在远程机器上通过 SSH 执行命令。
    • virtualbox,parallels:用于需要完整虚拟机的场景。 选择哪种,取决于你对隔离性、启动速度、环境依赖的要求。Docker 是目前最均衡和流行的选择。

    3. 缓存与制品:为了让流水线更快,需要合理配置cacheartifactscache用于存储作业间的中间文件(如依赖包),artifacts用于传递作业生成的最终文件(如构建好的二进制包)。Runner 的配置(如我们之前挂载的/cache卷)和.gitlab-ci.yml中的定义需要配合使用。

    cache: key: “$CI_COMMIT_REF_SLUG” # 按分支缓存 paths: - node_modules/ - .gradle/wrapper/ build-job: stage: build script: - npm install # 如果缓存命中,这步会极快 - npm run build artifacts: paths: - dist/ # 将构建产物传递给后续的部署作业

    5. 运维、监控与避坑指南

    Runner 创建好并跑起来只是开始,长期的稳定运行更需要运维功夫。

    5.1 日常维护操作

    • 查看 Runner 状态
      sudo gitlab-runner list # 列出本机所有已注册的 Runner sudo gitlab-runner verify # 检查 Runner 与 GitLab 的连接状态 sudo systemctl status gitlab-runner # 查看服务状态
    • 更新 gitlab-runner:定期更新以获得新功能和安全补丁。sudo apt-get update && sudo apt-get install gitlab-runner
    • 查看日志:日志是排错的生命线。sudo journalctl -u gitlab-runner.service -f可以实时跟踪日志。

    5.2 常见问题与排查思路

    问题 1:作业一直处于pending状态。

    • 可能原因 1:没有符合条件的 Runner。检查作业的tags是否与任何在线 Runner 的标签匹配。检查 Runner 是否被禁用(Settings -> CI/CD -> Runners页面查看)。
    • 可能原因 2:Runner 虽然在线,但并发数已满。每个 Runner 有一个concurrent配置(在/etc/gitlab-runner/config.toml中),表示它能同时执行多少个作业。如果所有槽位都被占用,新作业就会排队。
    • 排查命令:在 Runner 主机上,sudo gitlab-runner run以调试模式运行,可以查看详细的作业拉取和执行日志。

    问题 2:作业失败,报错“准备环境失败”或“拉取镜像失败”。

    • 可能原因 1:网络问题。Runner 主机无法访问 Docker Hub 或内部镜像仓库。检查网络连接和 DNS。
    • 可能原因 2:对于 Shell 执行器,可能是宿主机缺少必要的命令或权限。确保gitlab-runner用户(通常是gitlab-runner)有权限执行脚本中所需的命令。
    • 可能原因 3:Docker 执行器权限问题。如果使用docker.sock绑定,确保gitlab-runner用户属于docker用户组。

    问题 3:缓存没有生效,每次都要重新下载依赖。

    • 可能原因 1cache:key配置不合理。如果 key 设置成了“$CI_COMMIT_REF_NAME”(默认),那么不同分支的缓存是隔离的。可以尝试使用key: “global-cache”来全局共享,但要注意不同项目或分支的依赖冲突。
    • 可能原因 2:Runner 配置的缓存目录没有正确挂载或权限不足。检查 Runner 配置文件中[runners.docker][runners.cache]部分的volumescache_dir设置。

    5.3 安全最佳实践

    1. 最小权限原则:为 Runner 配置的服务账户(如gitlab-runner用户)只赋予其执行任务所需的最小权限。避免使用 root 用户。
    2. 谨慎使用 Docker Socket 绑定docker.sock绑定赋予了容器内几乎等同于宿主机的 Docker 控制权。如果必须使用,应确保该 Runner 为受信任的、隔离的项目专用,并且 CI 脚本来源可信。
    3. 使用私有镜像仓库:避免从公共仓库拉取不可信的镜像。配置 Runner 使用内部私有仓库,并设置镜像拉取策略。
    4. 定期轮换注册令牌:如前所述,定期在 GitLab 界面上重置 Runner 的注册令牌。
    5. 隔离网络:将 Runner 部署在独立于核心生产环境的网络区域,通过防火墙策略严格控制其网络访问。

    6. 性能调优与成本控制

    当你的 CI/CD 流水线越来越多,Runner 的性能和成本就成了必须考虑的问题。

    6.1 Runner 并发与资源分配

    在 Runner 的配置文件/etc/gitlab-runner/config.toml中,concurrent参数控制全局并发作业数。[[runners]]部分下的limit参数可以限制单个 Runner 的并发数。

    concurrent = 10 # 这台主机上所有 Runner 最多同时运行 10 个作业 [[runners]] name = “my-docker-runner” limit = 4 # 这个特定的 Runner 最多同时运行 4 个作业 executor = “docker” [runners.docker] ...

    设置时需要平衡宿主机的资源(CPU、内存、磁盘 I/O)。过高的并发会导致所有作业都变慢,甚至因内存不足而失败。一个经验法则是,并发数不要超过宿主机的 CPU 核心数,并预留足够的内存给每个作业和宿主机系统。

    6.2 基于 Kubernetes 的弹性伸缩

    对于云原生环境,使用kubernetes执行器是解决资源弹性问题的最佳方案。你可以配置 GitLab Runner 在 K8s 集群中运行,并利用autoscaler根据待处理的作业队列长度,动态地创建和销毁运行作业的 Pod。这实现了真正的“用多少,起多少”,极大优化了资源利用率和成本。

    配置相对复杂,需要在config.toml中定义[runners.kubernetes]部分,并指定命名空间、服务账户、Pod 模板等。但一旦配置成功,你将获得一个几乎无限弹性、按需付费的 Runner 池。

    6.3 分层 Runner 策略

    一个成熟的做法是采用分层 Runner 策略:

    • 第一层(共享 Runner):使用轻量级、无状态的 Docker 镜像(如alpine),处理海量的代码检查、单元测试等短时任务。可以部署在公有云 Spot 实例上以降低成本。
    • 第二层(群组 Runner):使用定制化镜像,处理中等耗时的构建和集成测试。根据群组负载,采用固定数量的虚拟机或 K8s 节点池。
    • 第三层(项目 Runner):使用高性能专用主机或带特殊硬件(如 GPU)的实例,处理耗时极长的编译、训练或部署任务。按需启动,任务完成后可以关机。

    通过这种分层,你可以确保快速反馈的流水线阶段(如 lint)不被重型任务阻塞,同时又能为特殊任务提供充足的资源。

    7. 从配置管理到自动化部署

    手动在一台台机器上安装和注册 Runner 在规模小时可行,但一旦 Runner 数量增多,就需要配置管理工具。

    7.1 使用 Ansible 批量部署 Runner

    Ansible 是自动化 Runner 部署的利器。你可以编写一个 Playbook,完成从安装软件、配置到注册的全过程。

    # gitlab-runner-deploy.yml - hosts: runner_hosts become: yes vars: gitlab_url: “https://gitlab.mycompany.com” runner_token: “{{ vault_runner_token }}” # 令牌应从加密的 vault 中读取 runner_description: “{{ inventory_hostname }}-docker-runner” runner_tags: “docker, linux” tasks: - name: Add GitLab Runner repository key apt_key: url: https://packages.gitlab.com/runner/gitlab-runner/gpgkey state: present - name: Add GitLab Runner repository apt_repository: repo: “deb https://packages.gitlab.com/runner/gitlab-runner {{ ansible_distribution_release }} main” state: present update_cache: yes - name: Install GitLab Runner apt: name: gitlab-runner state: latest update_cache: yes - name: Register GitLab Runner (non-interactive) command: > gitlab-runner register --non-interactive --url “{{ gitlab_url }}” --registration-token “{{ runner_token }}” --executor “docker” --docker-image “alpine:latest” --description “{{ runner_description }}” --tag-list “{{ runner_tags }}” --run-untagged “false” args: creates: /etc/gitlab-runner/config.toml # 避免重复注册 notify: restart gitlab-runner handlers: - name: restart gitlab-runner systemd: name: gitlab-runner state: restarted daemon_reload: yes

    这样,你只需要维护一个主机清单和令牌变量,就能一键部署几十上百台 Runner。

    7.2 容器化 Runner 与动态注册

    更云原生的做法是将gitlab-runner本身也容器化,并在 Kubernetes 中作为 DaemonSet 或 Deployment 运行。GitLab 官方提供了gitlab/gitlab-runner镜像。结合 K8s 的 Secrets 来管理注册令牌,可以实现 Runner 的动态伸缩和故障自愈。

    这种模式下,Runner 的生命周期完全由 K8s 管理。当 Pod 被调度到新节点上时,它会自动从 Secret 中读取令牌并向 GitLab 注册自己。当 Pod 被销毁时,GitLab 也会自动清理掉离线的 Runner。这实现了最高级别的自动化和弹性。

    无论是选择传统的配置管理还是云原生的容器化方案,目标都是将 Runner 的部署和管理变成一种可重复、可审计、自动化的基础设施即代码流程,从而让你能从繁琐的运维中解放出来,更专注于流水线逻辑和业务代码本身。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询