0
0
0

GitLab Runner 详解

2026-06-17
2026-09-18
文章摘要
|

GitLab CI/CD 中,GitLab 负责管理代码、创建 Pipeline、调度 Job 和保存执行结果,而真正执行 .gitlab-ci.yml 中命令的是 GitLab Runner。

本文按照实际搭建流程,从 Runner 的工作原理开始,依次介绍 Runner 的创建、安装、注册、Executor、多个 Runner 管理,以及 Java 项目常见的 Build + Deploy 推荐架构。

本文主要以 GitLab Self-Managed + Ubuntu + Java/Maven + Docker 为例。


1、GitLab Runner 是什么

GitLab Runner 是 GitLab CI/CD 的 Job 执行程序。

GitLab 本身主要负责:

  • 保存代码

  • 解析 .gitlab-ci.yml

  • 创建 Pipeline

  • 创建和调度 Job

  • 保存 Artifact

  • 展示执行日志和结果

真正执行下面这些命令的,是 Runner:

script:
  - mvn clean package
  - npm run build
  - docker compose up -d

整体关系可以理解为:

GitLab
   ↓
读取 .gitlab-ci.yml
   ↓
创建 Pipeline
   ↓
创建 Job
   ↓
根据 Runner 作用域 + tags 寻找可用 Runner
   ↓
Runner 获取 Job
   ↓
Runner 使用 Executor 创建执行环境
   ↓
执行 script
   ↓
上传日志 / Artifact / Cache
   ↓
GitLab 展示执行结果

1.1 GitLab Runner 程序和 Runner 实例不是一回事

这是最容易混淆的地方。

Linux 上安装的是一个程序:

gitlab-runner

例如:

gitlab-runner --version

而在 GitLab 页面创建并注册以后,会产生一个具体的 Runner 配置。

可以这样理解:

一台 Linux 服务器
        │
        └── gitlab-runner 程序 / 服务
                │
                ├── build-runner
                ├── deploy-runner
                └── vue-build-runner

所以:

GitLab Runner 程序 ≠ 一个 Runner

一套 gitlab-runner 服务可以管理多个已注册 Runner。

1.2 Runner 的作用域

常见 Runner 有三种作用域:

Runner 类型

可使用范围

Project Runner

仅指定项目使用

Group Runner

指定 Group 及其子项目使用

Instance Runner

整个 GitLab 实例中的项目都可能使用

公司内部项目一般优先使用:

Project Runner

如果多个项目构建环境完全一致,也可以考虑 Group Runner。

1.3 Job 到底怎么找到 Runner

Job 不是通过 stage 找 Runner,而是主要通过:

Runner 作用域
+
Runner 是否在线
+
tags
+
Runner 是否允许执行 untagged job
+
Runner 是否满足 protected 等限制

例如:

job_build:
  stage: build
  tags:
    - build

GitLab 会寻找带有:

build

标签的可用 Runner。

如果 Job 配置多个 tag:

tags:
  - build
  - docker
  - linux

那么 Runner 必须同时拥有:

build
docker
linux

这三个 tag 才能接这个 Job。

tags 是 Runner 选择条件,不是“满足任意一个即可”,而是 Job 中声明的 tag 必须全部匹配。


2、在 GitLab 创建 Runner

以 Project Runner 为例。

进入:

项目
  ↓
Settings
  ↓
CI/CD
  ↓
Runners
  ↓
Create project runner

不同 GitLab 版本页面名称可能略有差异。

2.1 配置 Runner tags

例如创建构建 Runner:

Runner description:
build-runner

Tags:
build

部署 Runner:

Runner description:
deploy-runner

Tags:
deploy

这样 .gitlab-ci.yml 就可以通过:

tags:
  - build

或者:

tags:
  - deploy

决定由哪个 Runner 执行。

2.2 Run untagged jobs

如果 Runner 开启:

Run untagged jobs

那么没有配置 tags 的 Job 也可能被这个 Runner 执行。

例如:

job_test:
  stage: test
  script:
    - echo "test"

如果不希望 Job 被错误 Runner 执行,建议公司的专用 Runner:

关闭 Run untagged jobs
+
明确配置 tags

这样 Runner 的职责会更清晰。

2.3 Runner Token

创建 Runner 后,GitLab 会提供注册命令,例如:

gitlab-runner register \
  --url http://gitlab.example.com \
  --token glrt-xxxx

glrt- 开头的是 Runner authentication token。


3、在 Ubuntu 安装 GitLab Runner

3.1 推荐使用 GitLab 官方软件源

不建议直接在一个全新的 Ubuntu 上执行:

sudo apt install gitlab-runner

原因是 Ubuntu 自带软件源中的版本可能明显落后。

推荐先添加 GitLab 官方软件源。

下载官方仓库脚本:

curl -L \
  "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" \
  -o /tmp/gitlab-runner-script.deb.sh

执行:

sudo bash /tmp/gitlab-runner-script.deb.sh

然后安装:

sudo apt update
sudo apt install -y gitlab-runner

检查版本:

gitlab-runner --version

3.4 使用 systemd 管理 Runner

安装完成后,一般会作为 systemd 服务运行。

查看状态:

sudo systemctl status gitlab-runner

启动:

sudo systemctl start gitlab-runner

停止:

sudo systemctl stop gitlab-runner

重启:

sudo systemctl restart gitlab-runner

设置开机启动:

sudo systemctl enable gitlab-runner

查看最近日志:

sudo journalctl -u gitlab-runner -n 100 --no-pager

持续查看日志:

sudo journalctl -u gitlab-runner -f

4、注册 Runner,以及 GitLab 和 Linux 是如何关联的

创建 Runner 以后,还只是 GitLab 服务端存在这个 Runner 记录。

真正让 Linux 服务器能够执行 Job,需要在安装了 gitlab-runner 的机器上执行注册。

完整流程:

GitLab 项目
   ↓
创建 Project Runner
   ↓
GitLab 生成 Runner authentication token
   ↓
Linux 安装 gitlab-runner
   ↓
执行 gitlab-runner register
   ↓
本地生成 Runner 配置
   ↓
配置写入 config.toml
   ↓
Runner 开始向 GitLab 获取可执行 Job

这里有点绕,简单理解:

  • gitlab可以创建多个runner,每个runner都根据自己的tag来确定是否执行工作流。

  • gitlab上创建的runner可以理解为一个标记, linux上的gitlab-runner是一个软件,(可以把他比作分布式系统的注册中心)gitlab创建的runner可以通过命令注册到gitlab-runner.gitlab-runner管理多个runner。

4.1 注册命令

例如在gitlab创建runner后会获得:

sudo gitlab-runner register \
  --url http://gitlab.example.com \
  --token glrt-xxxx

执行后会进入交互式配置。

示例:

Runtime platform                 arch=amd64 os=linux version=xx.x.x
Running in system-mode.
#询问1 gitlab地址 命令已经包含直接回车即可
Enter the GitLab instance URL:
[http://gitlab.example.com]:

Verifying runner... is valid
#询问2:这个runner的注册名字 (自己可以自定义,默认直接回车,也可以去gitlab的toml文件修改):
Enter a name for the runner:
[DataBase]: build-runner
#询问3:选择这个runner的执行器命令,简单来说执行器执行命令的环境是 linux选 shell 是docker容器环境 此处选docker
Enter an executor: shell, docker, kubernetes, ...

docker
#询问4:我这里选择的是docker 所以我需要选择默认的镜像,如果runner执行的job指定了别的镜像 那么他会以job的为准
Enter the default Docker image:
maven:3.8.8-eclipse-temurin-21

Runner registered successfully.
#配置写入/etc/gitlab-runner/config.toml,你可以修改此文件来配置runner
Configuration was saved in:
"/etc/gitlab-runner/config.toml"

4.2 Runner 名称和 GitLab 页面描述

需要注意:

注册过程中出现的:

Enter a name for the runner

主要是本地 config.toml 中的 Runner 名称。

例如:

[[runners]]
  name = "build-runner"

它和 GitLab 页面上的 Runner description 是两个不同位置的配置。

为了方便维护,推荐两边使用相同或相近的命名。


5、Executor 执行器详解

Executor 决定:

Runner 到底在哪个环境中执行 Job。

常见 Executor:

shell
docker
kubernetes
ssh
custom
...

对于普通 Java / Vue 项目,最常见的是:

Docker Executor
Shell Executor

5.1 一个注册 Runner 使用一种 Executor

一个 [[runners]] 配置只有一个:

executor = "docker"

或者:

executor = "shell"

不能同一个 Runner 同时既是:

Docker Executor
+
Shell Executor

如果项目需要:

Docker 环境构建
+
Shell 操作宿主机部署

推荐注册两个 Runner:

build-runner
executor = docker
tag = build

deploy-runner
executor = shell
tag = deploy

但是:

两个 Runner ≠ 两台服务器

两个 Runner 完全可以在同一台 Linux 服务器上:

DataBase 服务器
│
├── build-runner
│   └── executor = docker
│
└── deploy-runner
    └── executor = shell

5.2 Docker Executor

Docker Executor 会使用 Docker 容器作为 Job 的执行环境,一般build都使用docker执行器,因为build的时候要用到特定的环境 比如vue项目在build时要用到node,java要用到maven和jdk。

例如:

job_build:
  stage: build
  tags:
    - build
  image: maven:3.8.8-eclipse-temurin-8
  script:
    - mvn -B -ntp clean package

大致过程:

GitLab 创建 Job
      ↓
build-runner 获取 Job
      ↓
Docker Executor 准备容器环境
      ↓
准备代码工作目录
      ↓
使用 Maven 镜像执行 script
      ↓
生成构建结果
      ↓
上传 Artifact / Cache
      ↓
Job 结束
      ↓
临时 Job 容器被清理

Docker Executor 的优点

构建服务器宿主机不需要安装每个项目需要的:

JDK 8
JDK 17
JDK 21
Maven
Node.js
pnpm
Python
...

项目直接在 .gitlab-ci.yml 中声明环境:

image: maven:3.8.8-eclipse-temurin-8

另一个项目可以使用:

image: maven:3.9-eclipse-temurin-21

不会因为服务器本机 JDK 或 Maven 版本冲突影响不同项目。

因此:

Build / Test 阶段通常优先推荐 Docker Executor。


5.3 Docker Executor 中 image 的作用

例如:

job_build:
  image: maven:3.8.8-eclipse-temurin-21

这里的:

image:

不是:

docker build

也不是每次重新构建一个 Maven 镜像。

它的意思是:

使用指定 Docker 镜像作为当前 Job 的容器执行环境。

例如:

image: node:22-alpine

表示当前 Job 使用 Node.js 镜像执行。

5.4 image 不等于“本地有镜像就一定不拉取”

这个地方很容易理解错。

Docker Executor 默认的镜像拉取策略通常是:

pull_policy = "always"

也就是说,即使本机已经存在对应镜像,Runner 默认仍会尝试从 Registry 拉取 / 检查镜像。

这和:

重新 docker build 镜像

是两回事。

如果是可信的专用 Runner,希望优先复用本地镜像,可以在/etc/gitlab-runner/config.toml配置:

[runners.docker]
  pull_policy = "if-not-present"

逻辑变成:

本地有镜像
   ↓
直接使用

本地没有
   ↓
docker pull

但共享 Runner 不建议随意使用 if-not-present,尤其是涉及私有镜像时,需要考虑镜像访问权限和安全问题。

5.5 Runner 默认镜像和 YAML image 的区别

注册 Docker Runner 时可能会配置:

[runners.docker]
  image = "node:22-alpine"

它表示:

Runner 默认镜像

如果 Job 中没有:

image:

就使用默认镜像。

如果 .gitlab-ci.yml 中明确指定:

image: maven:3.8.8-eclipse-temurin-8

那么 Job 中的镜像优先。

关系:

.gitlab-ci.yml 中的 image
          ↓ 优先

Runner config.toml 默认 image
          ↓
Job 未指定 image 时使用

因此注册 Runner 时填写:

node:22-alpine

以后 Java Job 完全可以写:

image: maven:3.8.8-eclipse-temurin-21

不冲突。


5.6 Shell Executor

Shell Executor 会直接在 Runner 所在宿主机执行命令。

例如:

job_deploy:
  stage: deploy
  tags:
    - deploy
  script:
    - mkdir -p /opt/test
    - cp dist/admin.jar /opt/test/admin.jar
    - systemctl restart test

这些命令本质上就是在宿主机执行:

mkdir -p /opt/test
cp dist/admin.jar /opt/test/admin.jar
systemctl restart test

所以 Shell Executor 很适合:

部署文件
systemctl
Docker Compose
操作宿主机目录
执行部署脚本

当前 GitLab 官方文档已将 Shell Executor 标记为 maintenance mode:仍会获得关键安全更新,但不再规划新功能。对于需要直接操作宿主机的内部部署场景仍然可以使用,但新项目的构建、测试任务更推荐 Docker 等隔离性更好的 Executor。

但是它的缺点也很明显:

依赖宿主机环境
隔离性弱
不同 Job 可能相互影响
需要自己维护 JDK / Maven / Node / Docker 等工具

例如 Job 中执行:

mvn clean package

宿主机就必须能够执行:

mvn -v

否则会出现:

mvn: command not found

5.7 Shell Runner 的权限问题

Shell Job 通常不是以你当前登录的 root 用户执行,而是由 Runner 服务对应的用户执行,例如:

gitlab-runner

因此你手动执行成功:

cp xxx.jar /opt/test/

不代表 CI 中一定成功。

可以检查:

id gitlab-runner

目录权限:

ls -ld /opt/test

如果部署目录需要 Runner 写入,应正确配置目录属主和权限,例如:

sudo chown -R gitlab-runner:gitlab-runner /opt/test

相比在 Job 中大量使用:

sudo ...

更推荐提前把部署目录、服务权限设计好。

Shell Runner 能直接操作宿主机,风险明显高于 Docker 构建 Runner。部署 Runner 建议限制项目、限制 tag,并结合 protected branch / protected runner 使用。


6、常见阶段如何选择 Executor

不同类型的任务,对执行环境的要求不同。选择 Runner 时,核心是根据任务特点选择合适的 Executor。

例如:

需要固定 JDK / Maven / Node 环境
        ↓
Docker Executor

需要直接操作宿主机目录或服务
        ↓
Shell Executor

6.1 常见选择

阶段

推荐 Executor

原因

Java Maven Build

Docker

JDK/Maven 版本隔离,环境一致

Vue / Node Build

Docker

Node/pnpm/npm 版本容易固定

单元测试

Docker

测试环境可复现

代码扫描

Docker

工具镜像方便管理

Docker 镜像构建

Docker / 专门构建 Runner

需要根据 Docker 构建方案设计

复制 JAR 到服务器

Shell

需要访问宿主机目录

systemctl restart

Shell

需要操作宿主机服务

docker compose up -d

Shell

直接操作部署服务器 Docker

Kubernetes 部署

Kubernetes / Docker / Shell

根据集群访问方式选择

6.2 推荐职责划分

普通 Java 项目推荐:

build
  ↓
Docker Runner

test
  ↓
Docker Runner

deploy
  ↓
Shell Runner

也就是:

构建环境容器化
部署动作宿主机化

这样职责最清晰。


7、多个 Runner 管理

7.1 不需要安装多套 GitLab Runner

一台 Linux 不需要:

安装一个 build 版 gitlab-runner
+
再安装一个 deploy 版 gitlab-runner

只需要安装一次:

gitlab-runner

然后多次注册:

sudo gitlab-runner register ...

每注册一个 Runner,通常会在:

/etc/gitlab-runner/config.toml

增加一个:

[[runners]]

例如:

concurrent = 2

[[runners]]
  name = "deploy-runner"
  url = "http://gitlab.example.com"
  token = "glrt-xxxx"
  executor = "shell"

[[runners]]
  name = "build-runner"
  url = "http://gitlab.example.com"
  token = "glrt-yyyy"
  executor = "docker"

  [runners.docker]
    image = "maven:3.8.8-eclipse-temurin-8"
    volumes = ["/cache"]

结构可以理解为:

gitlab-runner 服务
      │
      └── config.toml
              │
              ├── [[runners]] build-runner
              │      └── docker
              │
              └── [[runners]] deploy-runner
                     └── shell

7.2 不推荐手动复制 [[runners]]

虽然理论上可以直接编辑:

/etc/gitlab-runner/config.toml

但创建新 Runner 时更推荐:

gitlab-runner register

因为注册过程会正确完成:

Runner authentication
+
服务端关联
+
本地配置写入

手动复制 Token 或配置容易造成:

  • Runner 身份混乱

  • Token 重复

  • 配置和 GitLab UI 不一致

  • 后续排查困难

7.3 常用 Runner 管理命令

查看已注册 Runner:

sudo gitlab-runner list

验证 Runner:

sudo gitlab-runner verify

查看版本:

gitlab-runner --version

查看服务:

sudo systemctl status gitlab-runner

取消注册时,应明确指定对应 Runner,不建议直接暴力删除整个 config.toml。

7.4 concurrent 是什么

config.toml 顶层可以看到:

concurrent = 2

表示整个 gitlab-runner 进程最多同时执行多少个 Job。

例如:

concurrent = 2

即使本机注册了:

build-runner
deploy-runner
vue-runner
test-runner

整个 Runner 服务同时最多执行:

2 个 Job

如果:

concurrent = 1

那么多个 Runner 即使都在线,也只能一个 Job 执行完后再执行下一个。

所以:

Runner 数量

和:

最大并发 Job 数量

不是一个概念。

7.5 多个 Runner 可以使用相同 tag 吗

可以。

例如:

runner-01 → tag = build
runner-02 → tag = build
runner-03 → tag = build

Job:

tags:
  - build

那么 GitLab 可以把多个构建 Job 分配给这些可用 Runner。

这种方式适合扩容构建能力。

如果希望指定不同职责:

Java 构建 → java-build
Vue 构建  → vue-build
部署      → deploy

就配置不同 tags。

8、推荐架构

对于普通 Java + Vue + Docker 部署项目,推荐把:

Build

和:

Deploy

分开。

8.1 推荐 Runner

同一台 Linux 服务器

├── build-runner
│   ├── tag = build
│   └── executor = docker
│
└── deploy-runner
    ├── tag = deploy
    └── executor = shell

如果前端构建也很多,可以进一步拆分:

├── java-build-runner
│   ├── tag = java-build
│   └── executor = docker
│
├── vue-build-runner
│   ├── tag = vue-build
│   └── executor = docker
│
└── deploy-runner
    ├── tag = deploy
    └── executor = shell

但是项目规模不大时,没有必要拆得太细。


8.2 Runner 职责建议

项目规模不大时,推荐至少拆成两个 Runner:

build-runner
├── executor = docker
├── tag = build
└── 负责:
    ├── Java / Maven 构建
    ├── Vue / Node 构建
    ├── 单元测试
    └── 代码扫描


deploy-runner
├── executor = shell
├── tag = deploy
└── 负责:
    ├── 操作部署目录
    ├── systemctl
    ├── docker compose
    └── 其他宿主机部署命令

这样做的重点不是把 Runner 数量拆得越多越好,而是:

构建环境
和
宿主机部署权限
分开管理

如果后期构建任务明显增多,再增加新的 Docker Runner 扩展构建能力即可。


8.3 整体架构

                         GitLab
                           │
                  根据 Runner 条件调度 Job
                           │
              ┌────────────┴────────────┐
              │                         │
         build-runner              deploy-runner
              │                         │
       executor = docker         executor = shell
              │                         │
       Maven / JDK 容器            Linux 宿主机
              │                         │
       Java / Vue 构建            部署 / 重启服务

优点:

1. 构建环境干净
2. Maven / JDK / Node 版本容易控制
3. 不需要在宿主机安装多套构建环境
4. 构建 Runner 和部署 Runner 职责分离
5. 部署 Runner 权限可以单独控制
6. 后期可以独立增加构建 Runner 扩容

8.4 不推荐的结构

不太推荐一个 Shell Runner 什么都做:

Shell Runner
   │
   ├── Maven Build
   ├── Vue Build
   ├── Unit Test
   ├── Docker Build
   └── Deploy

因为最后服务器可能需要同时安装:

JDK 8
JDK 21
Maven
Node 18
Node 22
pnpm
Docker
各种扫描工具
...

项目越多,宿主机环境越容易混乱。

更推荐:

编译 / 测试 → Docker Executor
部署         → Shell Executor

8.5 Runner 常见问题排查顺序

Runner 出现 Pending、无法执行、环境异常等问题时,可以按下面顺序排查:

1. Runner 是否在线?
   ↓
   GitLab 页面查看 Runner 状态
   systemctl status gitlab-runner

2. GitLab Runner 服务是否正常?
   ↓
   systemctl status gitlab-runner
   journalctl -u gitlab-runner -n 100 --no-pager

3. Runner 是否已经正确注册?
   ↓
   gitlab-runner list
   gitlab-runner verify

4. config.toml 中 Executor 是否配置正确?
   ↓
   /etc/gitlab-runner/config.toml

5. Docker Executor 是否能正常使用 Docker?
   ↓
   docker version
   docker images
   docker pull <image>



11. concurrent / Runner limit 是否限制了并发?
    ↓
    检查 config.toml


8.6 最后记住这 5 句话

1. GitLab 负责调度,GitLab Runner 负责真正执行 Job。

2. 一套 gitlab-runner 服务可以同时管理多个已注册 Runner。

3. 一个已注册 Runner 配置一种 Executor。

4. 多个 Runner 不代表多台服务器,同一台 Linux 可以注册多个 Runner。

5. 构建任务通常更适合 Docker Executor,需要直接操作宿主机的部署任务可以使用 Shell Executor。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论