1. 为什么 Kubernetes 上跑 Jenkins 不是“装个插件就完事”——从一次部署失败说起
我第一次在 Kubernetes 集群里部署 Jenkins,是在一个刚用 KubeKey 搭好的 Ubuntu 22.04 环境上。当时照着网上“Jenkins 安装配置”“Kubernetes 菜鸟教程”这类标题点进去,三步走:helm install jenkins、kubectl port-forward、浏览器打开。结果页面加载到一半卡住,控制台报错 Failed to resolve host name mirrors.tuna.tsinghua.edu.cn ,紧接着 Pipeline v608 plugin failed to load ,整个 UI 进不去。折腾六小时,重装三次,最后发现根本不是网络或插件问题——而是 Jenkins 的 Pod 启动时,容器内 /var/jenkins_home 目录权限被 Kubernetes 的 SecurityContext 默认设为 root-only,而 Jenkins 官方镜像(尤其是高版本)默认以非 root 用户 jenkins (UID 1001)运行,一启动就因无法写入 home 目录直接 crash。
这件事让我彻底意识到: 在 Kubernetes 上跑 Jenkins,本质不是“把 Jenkins 搬上云”,而是重构它的生命周期管理逻辑 。你面对的不再是单机上的 Java 进程,而是一个受 Deployment 控制、由 StatefulSet 管理存储、通过 Service 暴露、依赖 ConfigMap 注入配置、靠 Secret 管理凭证的完整应用拓扑。CI/CD Pipeline 在这里不再是一串 Groovy 脚本,它成了 Kubernetes 原生资源的一部分——Job 对象触发构建,Pod 模板定义执行环境,PersistentVolumeClaim 保障构建缓存不丢失,NetworkPolicy 控制它能访问哪些 Git 或 Harbor 服务。
所以这篇内容,不讲“Jenkins 怎么配置前端项目配置”这种零散操作,也不复述“Jenkins 安装部署”的通用流程。我们聚焦一个真实起点: Create Your First CI/CD Pipeline on Kubernetes With Jenkins 。这意味着你要亲手完成:一个可稳定运行的 Jenkins 主节点(Master)、一套能动态拉起构建 Agent 的 Kubernetes Pod 模板、一个从 GitLab 拉代码 → 编译 Vue 项目 → 构建 Docker 镜像 → 推送至 Harbor → 部署到同一集群的完整流水线。所有步骤都基于生产级实践验证,参数有依据、配置有解释、坑有定位路径。如果你正卡在 jenkins.initreactorrunner$1.ontaskfailed 或 failed loading plugin pipeline 这类错误上,或者刚学完“kubernetes详解”却不知如何让 CI/CD 真正落地,那接下来的内容,就是你缺的那一块拼图。
2. Master 节点不是“装好就行”,而是 Kubernetes 原生应用的起点
2.1 为什么不能直接用 helm chart 默认值?三个致命陷阱
Helm 社区最常用的 jenkinsci/kubernetes-operator 或 stable/jenkins (已归档)chart,表面看一键部署,实则埋了三条暗线:
-
陷阱一:StorageClass 绑定失效
默认 chart 使用persistence.enabled=true+persistence.storageClass="",这会导致 PVC 处于Pending状态。原因很简单:Kubernetes 1.20+ 已弃用defaultStorageClass 的隐式绑定逻辑,且多数生产集群(尤其用 KubeKey 或 RKE2 搭建的)不会自动创建名为default的 StorageClass。我见过太多人kubectl get pvc一直显示Pending,却去查 Jenkins 日志,完全跑偏。正确做法是显式指定集群中真实存在的 StorageClass 名称,比如local-path(Rancher 环境)或openebs-hostpath(OpenEBS 环境)。命令行部署时必须加:helm install jenkins jenkinsci/jenkins \ --set persistence.storageClass="local-path" \ --set persistence.size="10Gi" -
陷阱二:SecurityContext 权限冲突(就是开头那个坑)
Jenkins 官方镜像(jenkins/jenkins:lts-jdk11及更新版)固定以 UID 1001 运行,但 Kubernetes 默认 Pod 的securityContext.runAsUser是 0(root),且fsGroup未设置。结果容器启动时,/var/jenkins_home目录属主是 root,而 Jenkins 进程想以 UID 1001 写入,直接 Permission Denied。解决方案不是降权运行 Jenkins(安全风险),而是让 Kubernetes 自动修正目录权限:securityContext: runAsUser: 1001 runAsGroup: 1001 fsGroup: 1001 # 关键!让 kubelet 自动 chown /var/jenkins_home 所有文件这个
fsGroup字段是 Kubernetes 原生能力,不是 Jenkins 插件,必须写进 Deployment 的 Pod 模板里。 -
陷阱三:Service 类型选错导致外部不可达
很多人用service.type=LoadBalancer,但在私有云或本地 K8s(如 MicroK8s、K3s)中,没有云厂商的 LB 组件,Service 会永远卡在<pending>。更稳妥的方案是service.type=NodePort,并指定一个固定端口(如 30080),再通过kubectl get nodes -o wide查到任一节点 IP,用http://<NODE_IP>:30080访问。如果集群有 Ingress 控制器(如 Nginx Ingress),则应禁用 NodePort,改用 Ingress 资源,这样能支持 HTTPS 和域名路由。
提示:
jenkins.failed to resolve host name mirrors.tuna.tsinghua.edu.cn这类 DNS 错误,90% 源于 Jenkins Pod 的dnsPolicy被设为Default,导致它继承了宿主机的 DNS 配置(可能指向内网 DNS 服务器,而该服务器无法解析公网镜像源)。正确做法是显式设置dnsPolicy: ClusterFirstWithHostNet或直接在 Pod 中注入 DNS:dnsConfig: nameservers: - 114.114.114.114 - 8.8.8.8
2.2 初始化配置必须绕过 Web UI,用 JCasC(Jenkins Configuration as Code)
很多人部署完 Jenkins,第一反应是打开浏览器,点“系统配置”填 Git 凭证、配 Maven、装插件……这是最危险的操作。因为一旦 Jenkins Pod 重启(比如节点故障、升级),所有 Web 界面配置全丢。真正的 Kubernetes 做法是: 所有配置即代码,全部通过 ConfigMap 注入 。
JCasC(Jenkins Configuration as Code)插件是官方推荐方案。但它不能等 Jenkins 启动后再装——得在 Jenkins 镜像启动前就准备好配置。标准做法是:
- 创建
jenkins-config.yaml,定义全局工具、凭据、插件列表; - 将其打包进自定义 Jenkins 镜像,或通过 volumeMount 挂载到
/var/jenkins_home/casc_configs/; - 在 Jenkins 启动参数中指定
-Dcasc.jenkins.config=/var/jenkins_home/casc_configs/jenkins-config.yaml。
一个最小可用的 jenkins-config.yaml 示例(含 GitLab 凭据和 Maven 配置):
jenkins:
systemMessage: "Jenkins on Kubernetes - Managed by JCasC"
numExecutors: 0 # 关键!禁用内置 executor,所有构建交给 Kubernetes Agent
securityRealm:
local:
allowsSignup: false
enableCaptcha: false
authorizationStrategy:
loggedI


496

被折叠的 条评论
为什么被折叠?



