Loading...

文章背景图

(二) Runner 部署详解:Shell - Docker - Kubernetes 三种执行器全指南

2026-08-10
0
-
- 分钟

一、先理解架构:Runner 到底是怎么工作的?

在上一篇中,我们把 Runner 比作"工人",但它到底是如何和 GitLab 协作的?先看一张架构图:

┌─────────────────────────────────────────────────────┐
│                    GitLab 服务器                      │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐        │
│  │ Pipeline │   │  Job 队列 │   │  结果存储 │        │
│  └──────────┘   └─────┬────┘   └──────────┘        │
└───────────────────────┼─────────────────────────────┘
                        │ ① 轮询新任务
                        │ ② 分配 Job
                        │ ③ 回传结果
┌───────────────────────┼─────────────────────────────┐
│                Runner 机器(你的服务器 / K8s 集群)   │
│  ┌────────────────────▼───────────────────────────┐ │
│  │              GitLab Runner 进程                 │ │
│  │  ┌─────────────────────────────────────────┐   │ │
│  │  │           Executor(执行器)               │   │ │
│  │  │  Shell │ Docker │ Kubernetes │ ...       │   │ │
│  │  └─────────────────────────────────────────┘   │ │
│  └────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘

关键理解:

  1. Runner 和 GitLab 是分离的:Runner 是独立安装的进程,通过 HTTPS 或 HTTP 与 GitLab 服务器通信

  2. Runner 主动拉取(Pull)而非被动接收:Runner 持续轮询 GitLab 看有没有新任务,而不是 GitLab 推送过来

  3. Executor 决定"在什么环境里执行":同一个 Runner 进程,可以通过不同的 Executor 在宿主机 Shell、Docker 容器或 K8s Pod 中执行任务

Runner 的三种范围

类型

可见范围

适用场景

Shared Runner(共享)

整个 GitLab 实例所有项目

SaaS 平台 / 公司级统一 Runner 池

Group Runner(组级)

某个 Group 下的所有项目

部门级共享、Monorepo 多仓库

Project Runner(项目级)

仅限单个项目

项目专属需求、安全隔离


二、三种执行器(Executor)对比

特性

Shell

Docker

Kubernetes

隔离性

无隔离,共享宿主机

容器级隔离

Pod 级隔离

环境一致性

依赖宿主机环境

镜像保证一致

镜像保证一致

资源控制

无限制

⚠️ 可限制 CPU/内存

原生资源管控

弹性伸缩

固定

固定

自动扩缩

部署复杂度

🟢 极简

🟡 中等

🔴 较高

适用场景

开发测试、简单脚本

大多数项目

大规模团队、微服务

Docker in Docker

N/A

支持

支持

选型建议

  • 个人项目或小团队 → Docker Executor(平衡了隔离性和简单性)

  • 物理机 / 虚拟机已有环境 → Shell Executor(最简单)

  • 已有 K8s 集群、需要弹性伸缩 → Kubernetes Executor


三、通用前置:获取注册令牌(Registration Token)

不管你用哪种执行器,注册 Runner 时都需要一个 Token。获取方式因 Runner 范围而异:

方式一:GitLab Web UI(推荐)

  • Shared Runner:Admin Area → CI/CD → Runners → New instance runner

  • Group Runner:Group → Settings → CI/CD → Runners → New group runner

  • Project Runner:Project → Settings → CI/CD → Runners → New project runner

GitLab 16+ 版本后推荐创建 Runner 时勾选 "Run untagged jobs",这样即使你的 Job 没有指定 tags,该 Runner 也会接收任务。

方式二:注册完成后运行交互式注册命令

新版本 GitLab 会在创建 Runner 时直接展示注册命令,复制粘贴即可。旧版本则需要手动记下 Token 后执行 gitlab-runner register。


四、Shell Executor:最直白的开始

4.1 安装 GitLab Runner

Linux(Debian/Ubuntu):

# 添加官方仓库
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

# 安装
sudo apt-get install gitlab-runner

Linux(RHEL/CentOS):

curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash
sudo yum install gitlab-runner

macOS:

brew install gitlab-runner

4.2 注册 Runner(交互式)

sudo gitlab-runner register

交互式问答环节:

Enter the GitLab instance URL:
https://gitlab.example.com     # ← 你的 GitLab 地址

Enter the registration token:
glrt-xxxxxxxxxxxxxxxx           # ← 前面获取的 Token

Enter a description for the runner:
my-shell-runner                 # ← 起个描述名称

Enter tags for the runner (comma-separated):
shell,linux                     # ← 打标签,后续 Job 用 tags 选择

Enter optional maintenance note:
用于构建和部署的后端任务

Enter an executor:
shell                           # ← 选择 shell

4.3 非交互式注册(一行命令)

sudo gitlab-runner register --non-interactive \
  --url "https://gitlab.example.com" \
  --registration-token "glrt-xxxxxxxxxxxxxxxx" \
  --name "my-shell-runner" \
  --tag-list "shell,linux" \
  --executor "shell"

4.4 验证 Runner 状态

# 查看已注册的 Runner
sudo gitlab-runner list

# 输出示例
Runtime platform    arch=amd64 os=linux pid=1234 revision=abc123
Listing configured runners
my-shell-runner     Executor=shell Token=xxxx URL=https://gitlab.example.com

回到 GitLab Web UI → Settings → CI/CD → Runners,你应该能看到刚注册的 Runner 显示为绿色圆点(在线状态)。

4.5 测试你的 Runner

在项目中创建如下 .gitlab-ci.yml:

shell-test:
  tags:
    - shell      # ← 匹配前面设置的 tag
  script:
    - whoami
    - pwd
    - echo "宿主机内核版本:$(uname -r)"

提交后,如果 Pipeline 成功运行并输出了宿主机信息,说明 Shell Executor 配置成功。

4.6 Shell Executor 的坑与注意事项

  1. 环境依赖:Shell Executor 直接用宿主机的 Shell,所以你的依赖(Node.js、Java、Python 等)必须提前在宿主机上装好

  2. 安全性:Job 脚本拥有 gitlab-runner 用户的权限,小心权限泄露

  3. 残留文件:Job 执行完后,工作目录会保留,需要定期清理。可以在 /etc/gitlab-runner/config.toml 中设置清理策略

  4. 并发控制:默认 concurrent = 1,即同时只能跑一个 Job


五、Docker Executor:生产环境的首选

5.1 安装 GitLab Runner(Docker 方式)

最推荐的方式是用 Docker 运行 Runner 本身:

docker pull gitlab/gitlab-runner:latest

docker run -d \
  --name gitlab-runner \
  --restart always \
  -v /srv/gitlab-runner/config:/etc/gitlab-runner \
  -v /var/run/docker.sock:/var/run/docker.sock \
  gitlab/gitlab-runner:latest

💡 关键:-v /var/run/docker.sock:/var/run/docker.sock 将宿主机的 Docker 套接字挂进容器,这样 Runner 才能"操控"宿主机 Docker 来启动 Job 容器。这就是所谓的 Docker-out-of-Docker (DooD) 模式。

5.2 注册 Runner

docker exec -it gitlab-runner gitlab-runner register \
  --non-interactive \
  --url "https://gitlab.example.com" \
  --registration-token "glrt-xxxxxxxxxxxxxxxx" \
  --name "my-docker-runner" \
  --tag-list "docker,linux" \
  --executor "docker" \
  --docker-image "alpine:latest" \
  --docker-volumes "/var/run/docker.sock:/var/run/docker.sock"

关键参数说明:

  • --executor "docker":指定使用 Docker 执行器

  • --docker-image "alpine:latest":默认镜像——当 Job 中没有显式指定 image 时使用

  • --docker-volumes:挂载 Docker Socket,使 Job 容器内也能操作 Docker(Docker in Docker 的基础)

5.3 Docker Executor 的工作流程

当你提交代码后,Docker Executor 的执行过程是这样的:

① Runner 收到任务
② 拉取 job 中 image 指定的镜像(如 node:20)
③ 启动一个全新的容器
④ 在容器内克隆你的代码
⑤ 执行 before_script → script → after_script
⑥ 上传 artifacts 和日志
⑦ 销毁容器(默认行为)

每次 Job 都是在全新的容器中运行,这保证了环境的一致性和隔离性。

5.4 Docker in Docker (DinD):在容器里构建 Docker 镜像

如果你的 CI 需要构建 Docker 镜像(常见于部署阶段),需要配置 DinD:

build-docker-image:
  image: docker:latest
  stage: build
  services:
    - docker:dind              # ← 启动一个 Docker daemon 作为服务
  variables:
    DOCKER_TLS_CERTDIR: ""     # ← 关闭 TLS(简化配置)
  script:
    - docker build -t myapp:$CI_COMMIT_SHORT_SHA .
    - docker push registry.example.com/myapp:$CI_COMMIT_SHORT_SHA

⚠️ 使用 DinD 时,Runner 注册时必须挂载了 /var/run/docker.sock 或在配置中启用了 privileged = true。

5.5 config.toml 关键配置

Runner 注册后,配置存储在 /etc/gitlab-runner/config.toml(或你挂载的卷中)。几个值得关注的参数:

concurrent = 4                            # 全局最大并发 Job 数

[[runners]]
  name = "my-docker-runner"
  url = "https://gitlab.example.com"
  token = "glrt-xxxxxxxx"
  executor = "docker"
  limit = 2                               # 此 Runner 最大并发数
  [runners.docker]
    image = "alpine:latest"
    privileged = false                    # 谨慎开启!
    volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
    shm_size = 256000000                  # /dev/shm 大小(256MB),Node.js 项目可能需要
    pull_policy = "if-not-present"        # 镜像拉取策略

六、Kubernetes Executor:面向云原生的弹性方案

6.1 为什么需要 K8s Executor?

当你的团队扩张到几十甚至上百个开发者,每天触发数百次 Pipeline 时,Docker Executor 的固定资源模型就不够了。K8s Executor 的核心优势:

  • 弹性伸缩:每个 Job 启动一个独立 Pod,执行完自动销毁,资源回收

  • 原生资源管理:通过 Pod 的 requests/limits 精确控制 CPU 和内存

  • 集群调度:利用 K8s 调度器自动选择最优节点

6.2 使用 Helm 安装(推荐)

# 添加 GitLab Helm 仓库
helm repo add gitlab https://charts.gitlab.io
helm repo update

# 安装 Runner
helm install gitlab-runner gitlab/gitlab-runner \
  --namespace gitlab-runner \
  --create-namespace \
  --set gitlabUrl=https://gitlab.example.com \
  --set runnerRegistrationToken="glrt-xxxxxxxxxxxxxxxx" \
  --set rbac.create=true \
  --set runners.tags="k8s,linux"

6.3 自定义 values.yaml

更推荐的方式是创建一个 values.yaml 文件来控制所有参数:

# values.yaml
gitlabUrl: "https://gitlab.example.com"
runnerRegistrationToken: "glrt-xxxxxxxxxxxxxxxx"

# 并发控制
concurrent: 10

# Runner 配置
runners:
  tags: "k8s,linux"
  privileged: false
  config: |
    [[runners]]
      [runners.kubernetes]
        namespace = "gitlab-runner"
        image = "alpine:latest"

        # 资源限制
        [runners.kubernetes.pod_spec]
          [[runners.kubernetes.pod_spec.containers]]
            name = "build"
            resources.requests.cpu = "500m"
            resources.requests.memory = "512Mi"
            resources.limits.cpu = "2"
            resources.limits.memory = "2Gi"

        # 持久化缓存(可选,使用 PVC)
        [[runners.kubernetes.volumes.pvc]]
          name = "runner-cache"
          mount_path = "/cache"

安装:

helm install gitlab-runner gitlab/gitlab-runner \
  --namespace gitlab-runner \
  --create-namespace \
  -f values.yaml

6.4 K8s Executor 的工作流程

① GitLab 分配 Job 给 K8s Runner
② Runner 创建以下资源:
   - 一个 ConfigMap(注入构建脚本)
   - 一个 Pod(包含 build + helper + service 容器)
   - build 容器运行你的 script
   - helper 容器负责克隆代码、上传 artifacts
   - service 容器运行你声明的附加服务(如数据库)
③ Job 完成后自动清理 Pod

6.5 使用 K8s Executor 的 Job 配置

k8s-job:
  tags:
    - k8s                    # ← 匹配 K8s Runner
  image: node:20
  script:
    - npm install
    - npm test
  # K8s Executor 特有:自定义 Pod 资源
  variables:
    KUBERNETES_CPU_REQUEST: "500m"
    KUBERNETES_CPU_LIMIT: "2"
    KUBERNETES_MEMORY_REQUEST: "512Mi"
    KUBERNETES_MEMORY_LIMIT: "2Gi"

七、Runner 管理与运维

7.1 常用运维命令

# 查看所有 Runner
sudo gitlab-runner list

# 验证 Runner 配置
sudo gitlab-runner verify

# 取消注册某个 Runner
sudo gitlab-runner unregister --name "my-runner"

# 重启 Runner 服务
sudo gitlab-runner restart

# 查看 Runner 日志
sudo journalctl -u gitlab-runner -f

7.2 Runner Tags:精确调度

Tags 是 Runner 选择机制的核心。一套成熟的 Tag 策略建议分层级:

层级

Tag 示例

含义

执行器类型

docker, k8s

环境隔离级别

操作系统

linux, macos, windows

平台

专用能力

gpu, large-memory

特殊硬件

项目/团队

frontend, backend

业务归属

Job 中指定 Tags:

heavy-build:
  tags:
    - docker
    - large-memory
    - linux
  script:
    - make build

⚠️ Job 指定的 tags 必须全部匹配,Runner 才会接收。上面这个 Job 只会被同时拥有 docker、large-memory 和 linux 三个 Tag 的 Runner 执行。

7.3 并发控制

# /etc/gitlab-runner/config.toml
concurrent = 8       # 全局最大并发

[[runners]]
  limit = 4          # 此 Runner 最大并发

7.4 监控 Runner 健康

GitLab Web UI → Admin Area → Runners 可以看到:

  • 每个 Runner 的在线状态(上次心跳时间)

  • 当前正在执行的任务数

  • Runner 版本信息

也可以用 API 查询:

curl --header "PRIVATE-TOKEN: <your-token>" \
  "https://gitlab.example.com/api/v4/runners"

八、小结与下篇预告

三种方案对比速查

方案

安装命令

注册要点

适用场景

Shell

apt install gitlab-runner

--executor shell

简单脚本、已有环境

Docker

docker run gitlab/gitlab-runner

--executor docker --docker-image alpine

大多数项目

K8s

helm install gitlab/gitlab-runner

--set runnerRegistrationToken=...

大规模、弹性需求

下篇预告

有了 Runner 这双"手脚",接下来就要学习如何写出一份高质量的"施工图纸"第三篇《核心关键字详解:stages / jobs / variables / cache / artifacts》将深入讲解流水线配置中最常用、最重要的五个关键字类别,让你从"能跑"升级到"跑得好"。


参考资料:

原创

(二) Runner 部署详解:Shell - Docker - Kubernetes 三种执行器全指南

本文链接: (二) Runner 部署详解:Shell - Docker - Kubernetes 三种执行器全指南

本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

文章目录