第 5/18 天
引言
昨天的文章完成了 GitLab CE 的 Helm 部署和首个代码仓库的初始化推送。但 GitLab 本身只是代码托管平台,真正执行 CI/CD 作业的是 GitLab Runner——一个独立的执行代理,负责拉取代码、运行构建脚本、推送镜像、部署应用。
今天我们将深入 GitLab Runner 的 K8s Executor 运行模式,通过 Helm 部署 Runner,配置 ServiceAccount 和 RBAC 权限,并完成与 Harbor 镜像仓库的认证对接,为明天的 CI 流水线搭建铺平道路。

一、GitLab Runner 架构与 Executor 选型
1.1 Runner 工作原理
GitLab Runner 是一个轻量级守护进程,通过 GitLab API 长轮询(long-polling)获取待执行的 CI 作业。当 GitLab 触发 Pipeline 时,Runner 接收作业指令,根据配置的 Executor 类型创建执行环境,运行 .gitlab-ci.yml 中定义的 stages。
核心工作流程:GitLab 触发 Pipeline → Runner 轮询获取 Job → Executor 创建执行环境 → 拉取代码 → 执行脚本 → 回传日志和产物 → 销毁执行环境。
1.2 Executor 类型对比
GitLab Runner 支持多种 Executor,生产环境选型至关重要:
| Executor | 隔离方式 | 启动速度 | 资源开销 | 适用场景 |
|---|---|---|---|---|
| Shell | 无隔离(直接在 Runner 主机上执行) | 最快 | 最低 | 单机测试、脚本调试 |
| Docker | Docker 容器隔离 | 快 | 中等 | 标准构建、需要容器环境 |
| Kubernetes | K8s Pod 隔离 | 中等 | 中等 | 生产 CI/CD、弹性扩缩 |
| Docker Machine | 自动创建 VM | 慢 | 高 | 需要完全隔离的构建 |
本系列选择 Kubernetes Executor,原因如下:
- 弹性调度:每个 CI Job 自动创建独立 Pod,执行完毕自动销毁,资源利用率高
- 天然隔离:不同 Job 在不同 Pod 中运行,互不干扰
- 与 K8s 集群无缝集成:Runner 本身以 Helm Chart 部署在 K8s 中,管理 CI Pod 如同管理应用 Pod
- 水平扩展:多 Runner 实例并发处理多个 Job,无需手动扩容
1.3 K8s Executor 架构
K8s Executor 执行一个 CI Job 时的完整流程:
┌─────────────┐ 轮询 Job ┌──────────────────┐
│ GitLab │ ──────────────→ │ GitLab Runner │
│ Server │ │ (Deployment) │
│ │ ←────────────── │ │
└─────────────┘ 回传日志 └────────┬──────────┘
│ 创建 Pod
▼
┌──────────────────────────────┐
│ CI Job Pod │
│ ┌─────────┐ ┌────────────┐ │
│ │ build │ │ svc-acct │ │
│ │ container│ │ (RBAC) │ │
│ └─────────┘ └────────────┘ │
│ PVC: 代码缓存 + 产物持久化 │
└──────────────────────────────┘
每个 CI Job Pod 包含:build 容器(执行脚本)、helper 容器(拉取代码和上传产物)、ServiceAccount(RBAC 权限)、PVC(缓存和产物)。
二、RBAC 权限规划
2.1 为什么 Runner 需要 RBAC
K8s Executor 创建 Pod 执行 CI Job,这需要 K8s API 的操作权限。如果不配置 RBAC,Runner 将因权限不足无法创建 Pod,CI Job 会直接失败。
权限需求分析:
| 操作 | 需要的资源权限 | 说明 |
|---|---|---|
| 创建/删除 Pod | pods, pods/log | 每个 Job 创建和销毁 Pod |
| 创建/删除 PVC | persistentvolumeclaims | Job 缓存和产物持久化 |
| 创建/删除 Secret | secrets | 存储 CI 环境变量 |
| 创建/删除 ConfigMap | configmaps | 存储 Runner 配置 |
| 查看 Service | services | 服务发现和网络访问 |
2.2 最小权限原则
生产环境应遵循最小权限原则,Runner 只授予 CI 命名空间的权限,不使用 cluster-admin:
# gitlab-runner-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: gitlab-runner
namespace: gitlab-runner
—
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: gitlab-runner-role
namespace: gitlab-runner
rules:
# Pod 管理(核心权限)
– apiGroups: [""]
resources: ["pods", "pods/log", "pods/attach"]
verbs: ["get", "list", "watch", "create", "delete", "update", "patch"]
# PVC 管理(缓存和产物)
– apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "create", "delete"]
# Secret 管理(CI 变量)
– apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch", "create", "delete", "update"]
# ConfigMap 管理
– apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "create", "delete"]
# Service 查看(网络访问)
– apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch"]
—
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: gitlab-runner-binding
namespace: gitlab-runner
subjects:
– kind: ServiceAccount
name: gitlab-runner
namespace: gitlab-runner
roleRef:
kind: Role
name: gitlab-runner-role
apiGroup: rbac.authorization.k8s.io
三、Helm 部署 GitLab Runner
3.1 添加 Helm 仓库并创建命名空间
# 添加 GitLab Runner 官方 Helm 仓库
helm repo add gitlab-runner https://charts.gitlab.io
helm repo update
# 创建专用命名空间(与 GitLab 分离,便于权限隔离)
kubectl create namespace gitlab-runner
# 先应用 RBAC 配置
kubectl apply -f gitlab-runner-rbac.yaml -n gitlab-runner
3.2 编写 Helm Values 配置
# gitlab-runner-values.yaml
image:
registry: registry.gitlab.com
image: gitlab-org/gitlab-runner
tag: alpine-v17.8.2
gitlabUrl: https://gitlab.stellardata.top
# Runner 注册 Token(从 GitLab 管理界面获取)
runnerRegistrationToken: "GR13489xx_your_token_here"
rbac:
create: false # 使用上面手动创建的 RBAC
serviceAccountName: gitlab-runner
runners:
config: |
[[runners]]
name = "k8s-executor-runner"
url = "https://gitlab.stellardata.top"
token = "{{ .Values.runnerRegistrationToken }}"
executor = "kubernetes"
[runners.kubernetes]
namespace = "gitlab-runner"
service_account = "gitlab-runner"
# Pod 资源限制
cpu_limit = "2"
memory_limit = "4Gi"
cpu_request = "500m"
memory_request = "1Gi"
# 构建容器配置
image = "alpine:3.19"
privileged = true
# 缓存配置
[runners.kubernetes.pvc]
enabled = true
size = "10Gi"
storage_class = "local-storage"
# Harbor 认证
[runners.kubernetes.node_selector]
"node-role.kubernetes.io/worker" = "true"
tags: "k8s,build,deploy"
runUntagged: false
concurrent: 5 # 并发 Job 数
checkInterval: 30 # 轮询间隔(秒)
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
memory: 512Mi
配置要点说明:
executor = "kubernetes"指定使用 K8s Executorprivileged = true允许特权模式(Docker-in-Docker 构建需要)service_account = "gitlab-runner"绑定前面创建的 ServiceAccountconcurrent = 5限制并发数,避免资源争抢- PVC 缓存配置加速重复构建(依赖包、Docker 层缓存)
3.3 执行 Helm 安装
# 安装 GitLab Runner
helm install gitlab-runner gitlab-runner/gitlab-runner
-n gitlab-runner
-f gitlab-runner-values.yaml
–version 0.69.0
# 监控部署状态
kubectl -n gitlab-runner get pods -w
# 等待 Runner Pod 就绪
kubectl -n gitlab-runner wait –for=condition=Ready pod
-l app=gitlab-runner
–timeout=120s
# 确认 Runner 状态
kubectl -n gitlab-runner get pods
# 预期输出:
# NAME READY STATUS RESTARTS
# gitlab-runner-xxxxx 1/1 Running 0
四、Harbor 镜像仓库认证对接
4.1 创建 Harbor 认证 Secret
CI 构建过程中需要向 Harbor 推送镜像,需要预先创建 Docker Registry Secret:
# 创建 Harbor 认证 Secret
kubectl create secret docker-registry harbor-auth
–docker-server=harbor.stellardata.top
–docker-username=admin
–docker-password='Harbor12345'
–docker-email=devops@stellardata.top
-n gitlab-runner
# 验证 Secret 创建成功
kubectl -n gitlab-runner get secret harbor-auth
# 预期输出:
# NAME TYPE DATA
# harbor-auth kubernetes.io/dockerconfigjson 1
4.2 在 .gitlab-ci.yml 中引用
在 CI 变量中配置 Harbor 凭据,避免硬编码到 .gitlab-ci.yml:
# 在 GitLab 项目中配置 CI/CD Variables:
# Settings → CI/CD → Variables → Add Variable
# Key: HARBOR_URL
# Value: harbor.stellardata.top
# Key: HARBOR_USER
# Value: admin
# Key: HARBOR_PASS
# Value: Harbor12345
# 勾选 Masked(隐藏变量值,不在日志中显示)
五、验证 Runner 可用性
5.1 确认 Runner 已注册
# 查看 Runner 日志确认注册成功
kubectl -n gitlab-runner logs -l app=gitlab-runner | tail -10
# 预期输出:
# Configuration loaded and runner started
# Registering runner… succeeded
# Runner registered successfully
# 通过 GitLab API 查看 Runner 列表
curl -k –header "PRIVATE-TOKEN: <your-token>"
"https://gitlab.stellardata.top/api/v4/runners/all" | python3 -m json.tool | head -20
# 预期输出包含:
# "description": "k8s-executor-runner"
# "status": "online"
# "runner_type": "project_type"
5.2 运行测试 Pipeline
在 GitLab 仓库中创建 .gitlab-ci.yml 触发一个简单的测试 Job:
# .gitlab-ci.yml — Runner 可用性测试
stages:
– test
verify-runner:
stage: test
tags:
– k8s
image: alpine:3.19
script:
– echo "GitLab Runner K8s Executor 验证"
– kubectl version –client
– echo "Runner 节点信息:"
– hostname
– echo "CI 环境变量:"
– env | grep CI_
– echo "✅ Runner 工作正常"
# 提交 .gitlab-ci.yml 触发 Pipeline
cd demo-app
git add .gitlab-ci.yml
git commit -m "ci: 添加 Runner 可用性测试"
git push origin main
# 实时查看 CI Job Pod 状态
kubectl -n gitlab-runner get pods -w
# 预期输出:
# NAME READY STATUS
# runner-xxxxx-project-N-job-N 1/1 Running # CI Job Pod
# → 执行完毕后自动 Terminating → 消失
# 在 GitLab Web 界面查看 Pipeline 执行结果:
# https://gitlab.stellardata.top/devops-chain/demo-app/-/pipelines
5.3 日常巡检命令
# 查看 Runner Pod 运行状态
kubectl -n gitlab-runner get pods -l app=gitlab-runner
# 查看 Runner 最近日志(排查轮询和注册问题)
kubectl -n gitlab-runner logs -l app=gitlab-runner –tail=50
# 查看当前活跃的 CI Job Pod
kubectl -n gitlab-runner get pods | grep runner-
# 查看 Runner 配置(确认 Executor 类型和参数)
kubectl -n gitlab-runner get configmap gitlab-runner -o yaml
# 检查 RBAC 权限是否正常
kubectl auth can-i create pods –as=system:serviceaccount:gitlab-runner:gitlab-runner -n gitlab-runner
# 预期输出:yes
# 查看 Runner 资源使用情况
kubectl -n gitlab-runner top pod -l app=gitlab-runner
六、常见问题
Q: CI Job Pod 一直处于 Pending 状态,怎么排查?
A: 首先查看 Pod 事件:kubectl -n gitlab-runner describe pod <pod-name> | tail -20。常见原因:① 节点资源不足无法调度 → 调整 Pod resource requests 或增加节点;② StorageClass 不支持动态供应导致 PVC Pending → 检查 kubectl get pvc -n gitlab-runner;③ Taint 导致节点不可调度 → 检查 kubectl describe node | grep Taints。
Q: Runner 注册失败,日志报 401 Unauthorized?
A: 检查 runnerRegistrationToken 是否正确。Token 从 GitLab 管理界面获取:Admin Area → CI/CD → Runners → Register Runner。注意 Token 有时效性,过期后需重新生成。另外确认 gitlabUrl 配置正确,且 Runner Pod 能访问到 GitLab Service(网络策略没有阻断)。
Q: CI Job 中 docker push 到 Harbor 报 401?
A: 两种方式解决:① 在 GitLab CI/CD Variables 中配置 HARBOR_USER 和 HARBOR_PASS(推荐,已在上文配置);② 创建 Docker Registry Secret 并在 Pod spec 中引用 imagePullSecrets。检查变量是否勾选了 Masked(Masked 变量的值不会在 CI 日志中显示)和 Protected(仅在 protected 分支生效)。
总结
今天完成了 GitLab Runner 的完整部署和验证,核心成果:
- 选择了 K8s Executor 作为 CI 执行引擎,实现每 Job 独立 Pod 隔离
- 配置了最小权限 RBAC(ServiceAccount + Role + RoleBinding),仅授予 CI 命名空间内的 Pod/PVC/Secret 操作权限
- 通过 Helm Chart 部署 Runner,配置了资源限制、缓存 PVC 和并发控制
- 创建了 Harbor 认证 Secret,为 CI 中推送镜像做好了凭据准备
- 通过测试 Pipeline 验证了 Runner 的端到端可用性
DevOps 全链路已具备:代码托管(GitLab)→ 执行引擎(Runner)→ 镜像仓库(Harbor),三者准备就绪。明天我们将编写 .gitlab-ci.yml 流水线,用 Kaniko 无守护进程方式构建镜像并推送到 Harbor,打通从代码提交到镜像产出的完整 CI 链路。
下期预告
第 6 天:GitLab CI 流水线搭建:.gitlab-ci.yml 与 Kaniko 无守护进程构建
将深入 .gitlab-ci.yml 的完整语法,用 Kaniko 替代 Docker-in-Docker 实现无特权容器镜像构建,并配置多阶段流水线(lint → build → push → scan)。
系列大纲
- 全链路架构总览:从代码提交到灰度发布的完整管道设计
- K8s 集群与网络基础:kubeadm 离线部署与 Cilium 网络插件
- Harbor 私有镜像仓库部署与验证:Helm 安装与镜像推送
- GitLab CE 自托管部署:代码仓库与项目管理平台
- GitLab Runner 配置:K8s Executor 与 RBAC 权限设置(今天)
- GitLab CI 流水线搭建:.gitlab-ci.yml 与 Kaniko 无守护进程构建
- Harbor 镜像版本管理与 Tag 策略配置
- Argo CD 部署与 GitOps 配置仓库创建
- CI 与 CD 联动:从代码提交到部署的全自动闭环
- Prometheus 部署:kube-prometheus-stack 与 ServiceMonitor 指标采集
- Grafana 看板搭建:K8s 标准面板与自定义业务看板
- 告警规则与 Alertmanager:钉钉/邮件通知渠道配置
- Argo Rollouts 安装与基础概念:CRD 与 Rollout 资源定义
- 金丝雀发布实战:setWeight 流量分割与 pause 步骤
- AnalysisTemplate 指标分析与自动回滚机制
- 全链路端到端演示:代码提交→构建→灰度→监控→告警完整流程
- 生产化加固要点:Harbor/GitLab/Argo CD 高可用方案
- 供应链安全闭环:Trivy 扫描 + cosign 签名 + Kyverno 验签

















暂无评论内容