1. 项目概述:为什么要在Kubernetes上部署Jenkins?
如果你是一名运维工程师、DevOps实践者,或者正在构建云原生CI/CD流水线,那么“在Kubernetes上部署Jenkins”这个话题你一定不陌生。传统的单体Jenkins部署方式,虽然简单直接,但在面对微服务架构、多环境并行构建、资源弹性伸缩等现代开发需求时,常常显得力不从心。资源浪费、单点故障、环境不一致、维护成本高,这些都是我们踩过的坑。
ssbostan/jenkins-stack-kubernetes这个项目,正是为了解决这些问题而生的一个“开箱即用”的解决方案。它不是一个简单的YAML文件集合,而是一个经过精心设计的、声明式的Jenkins on Kubernetes部署栈。简单来说,它帮你把Jenkins主从架构、动态构建代理(Agent)、持久化存储、网络配置、安全认证等一系列复杂组件,打包成一个用Helm Chart驱动的、可复现的部署方案。你不再需要手动编写几十个Kubernetes资源清单,也不再需要为Jenkins Master的高可用、构建Pod的调度策略而头疼。
这个项目的核心价值在于“标准化”和“自动化”。它基于社区最佳实践,预设了合理的配置,让你能够快速在任何一个Kubernetes集群(无论是本地Minikube、云厂商的托管集群,还是自建集群)上,拉起一个生产就绪级别的Jenkins环境。对于初学者,它是极佳的学习模板;对于团队,它是统一CI/CD基础设施的基石;对于追求效率的工程师,它节省了大量重复劳动和排错时间。接下来,我将带你深入拆解这个项目的设计思路、核心组件以及如何一步步将它落地,并分享我在实际部署和运维中积累的经验与教训。
2. 架构与核心组件深度解析
2.1 整体设计思路:声明式与GitOps的融合
jenkins-stack-kubernetes项目最鲜明的特点是其声明式架构。它不鼓励你通过Jenkins的Web界面进行“点点点”的配置,而是将所有配置“代码化”。Jenkins自身的配置(JCasC - Jenkins Configuration as Code)、流水线定义(Jenkinsfile)、甚至插件列表,都通过ConfigMap、Secrets或直接从Git仓库拉取。这种做法的好处是巨大的:版本可控、易于回滚、支持自动化部署、环境一致性得到保障。这本质上是在实践GitOps理念,将你的CI/CD平台本身也纳入了CI/CD的管控范围。
项目的部署核心是一个Helm Chart。Helm作为Kubernetes的包管理器,使得部署、升级、配置管理变得极其简单。Chart的values.yaml文件就是整个Jenkins栈的“总控制台”,你通过修改这个文件中的参数,就能定制化几乎所有的方面,比如资源限制、存储类选择、Ingress配置、插件安装等。
2.2 核心组件拆解
一个完整的Jenkins on Kubernetes栈通常包含以下核心组件,该项目对每个部分都做了封装:
Jenkins Controller (Master):这是Jenkins的大脑。项目通常会将其部署为一个
StatefulSet或Deployment,并配置Service和Ingress提供访问。关键点在于数据持久化,Jenkins Home目录(包含作业配置、构建历史、插件)必须挂载到持久卷(PV)上,通常使用PersistentVolumeClaim。Jenkins Agent (基于Kubernetes的动态构建代理):这是项目的精髓。传统静态Agent需要提前部署并维护,资源利用率低。该项目集成了
kubernetes-plugin,使得Jenkins能够按需在Kubernetes集群中动态创建Pod作为构建代理。每个构建任务都在一个全新的、隔离的Pod中运行,任务结束Pod即销毁。这实现了极致的资源弹性和环境清洁。- Pod模板定义:在JCasC或Pipeline中,你可以定义不同的Pod模板。例如,一个模板包含Maven和JDK用于Java项目构建,另一个模板包含Node.js和npm用于前端构建。项目通常会在
values.yaml中预置一些常用模板。
- Pod模板定义:在JCasC或Pipeline中,你可以定义不同的Pod模板。例如,一个模板包含Maven和JDK用于Java项目构建,另一个模板包含Node.js和npm用于前端构建。项目通常会在
持久化存储:如前所述,Jenkins Controller的数据必须持久化。项目会定义
StorageClass、PersistentVolumeClaim。你需要根据你的Kubernetes集群环境(如使用云盘、NFS、Ceph等)来配置合适的存储类。网络与访问:通过
Service(ClusterIP类型)暴露Jenkins Controller,再通过Ingress配置域名和TLS证书,实现安全的HTTPS访问。项目Helm Chart通常支持配置Ingress注解、主机名、TLS秘密等。配置即代码 (JCasC):这是现代Jenkins的核心。一个
jenkins.yaml配置文件(通常以ConfigMap形式挂载)定义了Jenkins的系统配置、安全域、插件、云配置(即Kubernetes集群连接信息)等。项目会提供一个基础的JCasC配置,你需要根据自己集群的API Server地址、证书等信息进行修改。插件管理:项目可能会通过一个
plugins.txt文件或直接在JCasC中声明所需插件列表。在启动时,Jenkins会(或通过Init Container)自动安装这些插件,确保环境一致性。RBAC与安全:在Kubernetes中,Jenkins Controller需要一定的权限来创建、删除Pod(用于Agent)。项目会定义相应的
ServiceAccount、ClusterRole和ClusterRoleBinding,遵循最小权限原则。这是一个需要高度关注的安全配置点。
2.3 项目优势与选型考量
选择ssbostan/jenkins-stack-kubernetes这类方案,相比手动搭建,优势明显:
- 快速启动:一条
helm install命令即可获得完整环境。 - 最佳实践内嵌:避免了自行设计架构可能带来的陷阱。
- 易于维护升级:通过Helm进行版本管理和配置变更。
- 社区支持:基于开源项目,有问题可以查阅Issue和代码。
然而,在选型前也需要考量:
- 复杂度:对Kubernetes和Helm有一定要求。
- 定制化:虽然灵活,但深度定制可能需要修改Chart本身。
- 依赖管理:需要确保Chart中定义的镜像、插件版本与你的需求兼容。
注意:部署前,请务必仔细阅读项目的README和
values.yaml中的注释。不同的项目版本可能对应不同的Kubernetes或Jenkins版本,存在兼容性问题。
3. 实操部署:从零到一的完整过程
假设我们已经在本地或云上拥有一个可用的Kubernetes集群(版本1.20+),并且已安装kubectl和helm(3.0+)客户端。下面以部署ssbostan/jenkins-stack-kubernetes为例,展开详细步骤。
3.1 前期准备与环境检查
首先,克隆项目仓库并查看结构。
git clone https://github.com/ssbostan/jenkins-stack-kubernetes.git cd jenkins-stack-kubernetes ls -la你通常会看到类似以下的目录结构:
├── charts/ # Helm Chart目录 ├── templates/ # Helm模板文件 ├── values.yaml # 核心配置文件 ├── README.md └── ... (可能包含examples, tests等)关键文件是values.yaml。在安装前,我们必须根据自身环境定制它。使用helm命令检查Chart依赖和可用性。
helm dependency update ./charts/jenkins-stack # 如果存在依赖 helm lint ./charts/jenkins-stack # 检查Chart语法3.2 定制化配置 values.yaml
不要直接使用默认的values.yaml进行生产部署。创建一个副本进行修改,例如my-values.yaml。以下是一些必须修改或检查的关键配置项:
1. 镜像与版本控制:
controller: image: jenkins/jenkins tag: lts-jdk11 # 明确指定一个稳定的LTS版本,如 2.414.2-lts-jdk11 resources: requests: memory: "1Gi" cpu: "500m" limits: memory: "2Gi" cpu: "1000m"- 为什么:使用固定标签而非
latest,保证环境可复现。根据团队规模设置合理的资源限制,防止Jenkins Controller OOM。
2. 持久化存储配置:
persistence: enabled: true storageClass: "standard" # 修改为你的集群中可用的StorageClass名称 size: 20Gi accessMode: ReadWriteOnce- 为什么:
storageClass必须匹配你的Kubernetes集群。在云环境中可能是gp2(AWS)、standard(GKE) 或managed-csi(Azure)。使用kubectl get storageclass查看。
3. Jenkins配置即代码 (JCasC):
controller: JCasC: enabled: true configScripts: welcome-message: | jenkins: systemMessage: "Jenkins configured automatically by Jenkins Configuration as Code" kubernetes-cloud: | jenkins: clouds: - kubernetes: name: "kubernetes" serverUrl: "https://kubernetes.default.svc.cluster.local" namespace: "jenkins" # 建议指定命名空间 credentialsId: "jenkins-kubernetes-auth" jenkinsUrl: "http://jenkins.jenkins.svc.cluster.local:8080" containerCap: 10 # 最大并发构建Pod数 templates: # Pod模板示例 - name: "maven" label: "maven" containers: - name: "jdk" image: "maven:3.8.6-eclipse-temurin-11" command: "sleep" args: "infinity" resourceRequestCpu: "200m" resourceLimitCpu: "500m" resourceRequestMemory: "256Mi" resourceLimitMemory: "1Gi"- 为什么:
serverUrl通常指向集群内API Server。jenkinsUrl是Jenkins Controller在集群内被访问的地址,用于Agent回调。containerCap控制资源消耗,避免创建过多Pod挤爆集群。Pod模板定义了构建环境。
4. 网络与访问入口:
controller: ingress: enabled: true hostName: jenkins.your-company.com annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: "letsencrypt-prod" # 如果使用cert-manager自动签发证书 tls: - secretName: jenkins-tls hosts: - jenkins.your-company.com- 为什么:
annotations根据你集群的Ingress Controller(Nginx, Traefik, ALB等)而定。如果启用TLS,需要提前准备证书Secret或配置自动签发。
5. RBAC权限配置:
controller: serviceAccount: create: true name: jenkins annotations: {} rbac: create: true # ClusterRole规则通常已由Chart定义,确保其有创建Pod、挂载PVC等权限- 为什么:这是安全关键。确保创建的ServiceAccount拥有足够的权限管理构建Pod,但不应拥有过高权限(如删除节点、查看所有Secret)。
3.3 执行部署与验证
配置好my-values.yaml后,开始部署。强烈建议为Jenkins创建独立的命名空间。
kubectl create namespace jenkins helm install jenkins ./charts/jenkins-stack -n jenkins -f my-values.yaml部署命令解释:
jenkins:是Helm Release的名称。./charts/jenkins-stack:是Chart的路径。-n jenkins:指定部署到jenkins命名空间。-f my-values.yaml:使用我们的定制化配置。
部署完成后,监控Pod状态:
kubectl get pods -n jenkins -w等待所有Pod(特别是Jenkins Controller)进入Running状态。然后获取访问地址:
# 如果使用了Ingress,等待Ingress地址就绪 kubectl get ingress -n jenkins # 如果没有Ingress,可以通过端口转发临时访问 kubectl port-forward svc/jenkins 8080:8080 -n jenkins浏览器访问http://localhost:8080或你的Ingress域名。初始管理员密码可以通过以下命令获取:
kubectl exec -n jenkins deployment/jenkins -- cat /run/secrets/chart-admin-password # 或者,如果Chart使用了不同的Secret命名 kubectl get secret -n jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode登录后,你应该能看到JCasC配置已生效,Kubernetes云配置也已就绪。可以尝试创建一个简单的Pipeline任务,选择kubernetes标签,验证动态Agent是否能成功创建并执行任务。
4. 高级配置与生产级优化
基础部署完成后,要用于生产环境,还需要进行一系列优化。
4.1 高可用性 (HA) 设计
默认部署可能是单副本,存在单点故障。为了实现高可用:
- Controller多副本:在
values.yaml中,将controller.replicaCount设置为大于1(如2)。但注意,Jenkins本身并非完全无状态,多副本需要共享存储和会话。controller: replicaCount: 2 - 共享存储:确保使用的
storageClass支持ReadWriteMany访问模式(如NFS、CephFS),这样多个Pod才能同时挂载同一个Jenkins Home卷。 - 会话亲和性:在Ingress或Service层面配置会话亲和性(Session Affinity),确保用户会话在同一个Controller Pod上保持,避免状态丢失。但这与负载均衡有些冲突,需权衡。
实操心得:对于大多数团队,保证数据持久化并配合快速的Pod重启策略(在
values.yaml中配置controller.livenessProbe和readinessProbe),往往比追求复杂的多副本HA更简单有效。Kubernetes的控制器能确保Pod挂掉后快速在新节点上重建。
4.2 构建性能与资源优化
动态Agent的性能是关键。
- Pod模板优化:
- 镜像选择:使用体积小、包含必要工具的官方镜像(如
eclipse-temurinJDK镜像比openjdk更小)。可以考虑构建自己的基础镜像,预装常用工具。 - 资源请求与限制:在Pod模板中精确设置
resourceRequestCpu/Memory和resourceLimitCpu/Memory。请求值影响调度,限制值防止构建任务失控。建议根据项目构建的平均资源消耗来设定。
containers: - name: "jdk" image: "eclipse-temurin:11-jdk-focal" resourceRequestCpu: "500m" resourceRequestMemory: "1Gi" resourceLimitCpu: "2000m" resourceLimitMemory: "4Gi" - 镜像选择:使用体积小、包含必要工具的官方镜像(如
- 节点亲和性与污点容忍:如果集群中有专门用于CI/CD的节点(可能带有
taint),可以在Pod模板中配置nodeSelector、affinity或tolerations,将构建任务调度到特定节点,避免影响业务应用。 - 构建缓存持久化:Maven、Gradle、npm等工具下载的依赖包可以缓存在一个独立的PVC中,并在Pod模板中挂载,能极大加速后续构建。
你需要提前创建这个PVC,并确保其存储类支持volumes: - name: maven-cache persistentVolumeClaim: claimName: maven-repo-pvc containers: - name: maven volumeMounts: - mountPath: /root/.m2/repository name: maven-cacheReadWriteMany或为每个Pod创建独立副本。
4.3 安全加固
安全无小事。
- 最小权限原则:定期审查Chart生成的
ClusterRole,确保只授予Jenkins ServiceAccount必需的权限(如pods:create,delete,list,secrets:get用于拉取镜像等)。 - 网络策略:使用
NetworkPolicy限制Jenkins命名空间内Pod的网络流量,例如只允许Controller与Kubernetes API Server通信,构建Pod只允许访问外部仓库(如Maven Central, npm Registry)和内部制品库。 - 镜像安全:使用私有镜像仓库,并在Pod模板中配置
imagePullSecrets。定期扫描基础镜像中的漏洞。 - Jenkins自身安全:
- 强制使用HTTPS。
- 启用
CSRF Protection。 - 使用强密码策略或集成LDAP/OAuth等SSO。
- 定期更新Jenkins和插件版本,修复安全漏洞。
5. 运维、监控与故障排查实录
部署上线只是开始,日常运维和问题排查才是重头戏。
5.1 日常运维操作
- 升级:使用Helm进行升级是推荐方式。先检查新版本Chart的变更日志和
values.yaml差异。helm repo update helm upgrade jenkins jenkins/jenkins-stack -n jenkins -f my-values.yaml - 回滚:如果升级出现问题,可以快速回滚到上一个版本。
helm history jenkins -n jenkins helm rollback jenkins <REVISION_NUMBER> -n jenkins - 备份与恢复:Jenkins的核心资产是
JENKINS_HOME目录。定期对绑定的PVC进行快照(如果云存储支持)或使用工具(如kubectl cp结合归档命令)进行备份。恢复时,将备份数据还原到PVC,然后重启Jenkins Pod。
5.2 监控与告警
你需要知道Jenkins是否健康,资源是否充足。
- Kubernetes原生监控:通过
kubectl top pod -n jenkins查看Pod资源使用情况。配置Prometheus采集Jenkins命名空间的指标。 - Jenkins Metrics插件:安装
metrics-plugin和prometheus-plugin,暴露JVM和构建队列等指标给Prometheus。 - Grafana仪表盘:导入或制作Jenkins监控看板,关注关键指标:
jenkins_builds_total:构建总数。jenkins_queue_length:构建队列长度(如果持续很高,说明资源不足)。jenkins_executor_free:空闲执行器数量。- JVM内存使用率、GC情况。
- 日志集中收集:使用Fluentd、Fluent Bit或Filebeat将Jenkins Controller和构建Pod的日志收集到Elasticsearch等中心化日志系统,便于排查问题。
5.3 常见问题与排查技巧
以下是我在实际运维中遇到的一些典型问题及解决思路:
问题1:构建Pod一直处于Pending状态。
- 排查思路:
kubectl describe pod <pod-name> -n jenkins:查看事件,最常见原因是资源不足(Insufficient cpu/memory)或找不到合适的节点(node(s) didn't match Pod's node affinity/selector)。- 检查集群节点资源:
kubectl describe nodes。 - 检查Pod模板中的资源请求是否设置过高。
- 检查节点是否有污点(Taint),而Pod没有配置对应的容忍(Toleration)。
问题2:构建Pod启动成功,但无法连接到Jenkins Controller(Agent离线)。
- 排查思路:
- 检查构建Pod的日志:
kubectl logs <pod-name> -n jenkins。常见错误是连接jenkinsUrl失败。 - 确认
values.yaml中JCasC配置的jenkinsUrl是否正确。在集群内部,通常是http://<service-name>.<namespace>.svc.cluster.local:8080。确保Service名称和端口正确。 - 检查网络策略(NetworkPolicy)是否阻断了从构建Pod到Controller Service的流量。
- 检查构建Pod的日志:
问题3:Pipeline中拉取私有Git仓库或私有镜像仓库失败。
- 排查思路:
- 确认在Pipeline中是否正确使用了带有凭证(Credentials)的语法。
- 确认凭证是否已在Jenkins中正确配置(通过JCasC或手动)。
- 对于私有镜像仓库,确认构建Pod的
serviceAccount(默认是default)是否有权限拉取镜像,或者是否在Pod模板中正确配置了imagePullSecrets。 - 一个关键技巧:可以在Pod模板中挂载宿主的Docker配置或
.kube/config文件(需谨慎处理权限),但更安全的方式是使用Kubernetes的Secret对象创建docker-registry类型的Secret,并在Pod模板中引用。
问题4:JCasC配置不生效或报错。
- 排查思路:
- 登录Jenkins,进入“Manage Jenkins” -> “Configuration as Code”页面,查看配置状态和错误信息。这是最直接的排错入口。
- 检查挂载的ConfigMap内容是否正确:
kubectl get configmap -n jenkins <configmap-name> -o yaml。 - 确保
values.yaml中JCasC的配置格式正确,YAML缩进无误。复杂的配置可以先用在线YAML校验器检查。 - Jenkins重启后,查看Controller Pod的日志,JCasC插件会在启动时加载配置并打印日志。
问题5:磁盘空间不足。
- 排查思路:
- Jenkins Home目录(存储构建历史、工件)会不断增长。定期清理旧的构建记录:在Jenkins系统设置中配置“丢弃旧的构建”。
- 构建Pod的日志也可能占用空间。确保Docker和Kubelet配置了日志轮转。
- 监控PVC的使用量,设置告警,接近阈值时及时扩容或清理。
最后,保持学习。Jenkins和Kubernetes生态都在快速发展,关注官方博客、插件更新和社区讨论,能帮助你提前规避许多潜在问题。将你的values.yaml和JCasC配置文件纳入Git版本控制,任何变更都通过Pull Request进行,这是保障这套复杂系统稳定运行的基石。