Jenkins与Kubernetes集成部署流水线
前言:
在云原生技术迅猛发展的今天,快速、可靠地交付软件已成为企业保持核心竞争力的关键。持续集成与持续部署(CI/CD)是这一过程的基石,而容器化与编排技术则为其提供了理想的运行环境。然而,传统的CI/CD工具往往面临资源利用率低、扩展性差和维护成本高等挑战。
Jenkins,作为业界广泛采用的自动化服务器,与Kubernetes,作为容器编排领域的事实标准,二者的结合为解决上述挑战提供了完美的答案。通过将Jenkins构建任务动态调度到Kubernetes集群的临时Pod中执行,我们能够打造一个“无服务器”式的构建农场:它具备极致的弹性,可以轻松应对高并发构建需求;它高度资源高效,任务完成后资源立即释放;并且与底层基础设施完美解耦,实现了真正的云原生CI/CD。
本文将引导您完成这一强大集成的核心步骤,并分享实践中的关键洞察,助力您的团队迈向更高效、更可靠的自动化交付之路。
目录
1. 连接Kubernetes开发集群
1.1 安装kubectl客户端
1.2 配置集群连接文件
1.3 资源清单文件提交
2. Jenkins流水线基础架构
2.1 流水线脚本结构
2.2 代码检出阶段
2.3 Docker镜像构建与推送
2.4 Kubernetes部署阶段
2.5 通知机制
3. Jenkins与Kubernetes插件集成
3.1 Kubernetes插件安装
3.2 云配置设置
3.3 凭据管理
3.4 连接测试与验证
4. 流水线脚本进阶实现
4.1 动态生成资源清单
4.2 静态资源清单实践
4.3 多阶段部署案例(LAMP栈)
5. 常见问题与解决方案
5.1 连接认证失败
5.2 容器启动失败
5.3 Groovy语法错误
5.4 插件版本兼容问题
6. 优化实践与建议
6.1 安全最佳实践
6.2 性能优化方向
6.3 维护性建议
7. 全流程集成示例
7.1 端到端流水线脚本
7.2 关键组件交互图
7.3 验证部署结果
8. 故障排除手册
8.1 诊断流程图
8.2 日志分析要点
9. 附录:核心命令参考
9.1 Kubernetes常用命令
9.2 Jenkins流水线语法
总结
1. 连接Kubernetes开发集群
操作系统 | IP地址 | 主机名 | 角色 |
---|---|---|---|
OpenEuler24.03 | 192.168.72.138 | jenkins | Jenkins服务器/Git仓库 |
OpenEuler24.03 | 192.168.72.166 | k8s-master | master |
OpenEuler24.03 | 192.168.72.167 | k8s-node1 | node1 |
OpenEuler24.03 | 192.168.72.168 | k8s-node2 | node2 |
1.1 安装kubectl客户端
通过在主机上安装kubectl命令实现与Kubernetes集群的连接。首先导入开发环境的软件源,然后安装kubectl客户端工具。
###192.168.72.138主机操作cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo[kubernetes]name=Kubernetesbaseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/enabled=1gpgcheck=1gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/repodata/repomd.xml.keyEOFyum install -y kubectlmkdir .kubecd .kube/###切换192.168.72.166主机操作scp .kube/config 192.168.72.138/root/.kube/
安装完成后切换回jenkins服务器验证命令是否可用:
kubectl get pods
此时命令会报错,因为默认连接本地集群但配置文件缺失。
1.2 配置集群连接文件
将Kubernetes集群的配置文件(如config)拷贝到本地指定目录:
-
源文件位置:集群服务器(例如192.168.72.166)
-
目标目录:
root/.kube/
拷贝后测试连接:
kubectl get nodes
成功显示集群节点信息表明连接建立。
Jenkins 用户环境下配置 kubectl
访问 Kubernetes 集群:
###切换回192.168.72.138主机操作su -s /bin/bash jenkins###cd###pwd/root###kubectl get node###cd .kube/ls当执行上述kubectl命令后会生成一个cache文件###exit###回到root环境cp .kube/config /var/lib/jenkins/.kube###修改config文件属主属组ls -l chown jenkins:jenkins config###回到jenkins环境进行验证bash-5.2$ kubectl get nodeNAME STATUS ROLES AGE VERSIONk8s-master Ready control-plane,master 21d v1.28.15k8s-node1 Ready worker 21d v1.28.15k8s-node2 Ready worker 21d v1.28.15
1.3 资源清单文件提交
连接集群后,可直接提交YAML资源清单文件部署应用:
# 示例资源清单(CPU需求1500毫核)apiVersion: apps/v1kind: Deploymentspec:template:spec:containers:- name: appresources:requests:cpu: "1500m"
提交命令:
kubectl apply -f pod.yaml
部署成功后在集群中创建对应Pod。
2. Jenkins流水线基础架构
2.1 流水线脚本结构
使用Groovy语法编写Jenkinsfile,核心结构包含代理声明和阶段定义:
agent {kubernetes {label 'jenkins-agent'yaml '''apiVersion: v1kind: Podspec:containers:- name: jnlpimage: jenkins/jnlp-agent:alpine'''}}stages {stage('Build') {steps {sh 'mvn clean package'}}}
注意事项:
-
多行文本需用三个双引号
'''
或"""
包裹 -
agent
块定义运行环境连接到代理
2.2 代码检出阶段
通过checkout
插件从Git仓库拉取代码:
stage('Checkout') {steps {checkout([$class: 'GitSCM', branches: [[name: '*/master']],userRemoteConfigs: [[url: 'http://git.example.com/repo.git']]])}}
参数说明:
-
branches
:指定代码分支 -
userRemoteConfigs
:配置Git仓库URL
2.3 Docker镜像构建与推送
构建镜像并推送到仓库的配置:
stage('Build Image') {steps {docker.build("192.168.1.32:5000/myapp:latest")docker.push("192.168.1.32:5000/myapp:latest")}}
关键点:
-
仓库地址需包含IP和端口
-
镜像标签需明确版本标识
2.4 Kubernetes部署阶段
提交资源清单文件到集群:
stage('Deploy') {steps {sh 'kubectl apply -f deployment.yaml'}}
部署流程:
-
根据清单文件中的镜像仓库拉取镜像
-
Kubernetes集群自动创建Pod
2.5 通知机制
构建结果邮件通知配置:
post {success {mail to: 'team@example.com', subject: 'SUCCESS: ${JOB_NAME}',body: '构建成功'}failure {mail to: 'team@example.com', subject: 'FAILED: ${JOB_NAME}',body: '构建失败'}}
3. Jenkins与Kubernetes插件集成
3.1 Kubernetes插件安装
在Jenkins中安装Kubernetes插件步骤:
-
进入插件管理页面
-
搜索安装
Kubernetes
和Kubernetes CLI
插件 -
重启Jenkins生效
3.2 云配置设置
配置Kubernetes集群连接信息:
-
Jenkins系统设置 → 云 → 新增Kubernetes云
-
关键参数配置:
参数项 值示例 说明 名称 k8s-1.28 自定义云名称 Kubernetes地址 https://192.168.166.132:6443 API Server地址 命名空间 default 目标部署命名空间
3.查看K8S证书文件,并使用base64解密
[root@k8s-master ~]# cat /etc/kubernetes/admin.conf | awk -F: '/certificate-authority-data/{print $2}' | tr -d ' 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJZkl1R0tUVmU3TjR3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TkRFeU1ESXdPREUxTkRaYUZ3MHpOREV4TXpBd09ESXdORFphTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUUNaTzF5d3dZQ1pvWjJteUhQN0UzbUcyNTBoK2IyKzlRTTJLMFNSbHkyNk1ibjR1MXB1R1JQcUNiNEYKYW1OamI3WUFHdms4TGNWaWRFTjJxSytqWm1ackxDMWUxRVpQVWpGYmxPdTR1aFBMYmdyUFBSQnl1WXd0SWowagozWkczam5tTVp2YVkzcW0zbndaZjBvUnFrd1A5eFdUbUIvQWVGQm5sY05pOTdCWjBJRkxsQzRQbzZNdk8xbG90CnJMOEU2ZjJrekZQZ1plK0VGdEFuSkF4UXZmTldyT2VEcHI5NzBHd3VxTGpRSFZmOFlMcm44Y3JvQlZjbmE2ZGkKM2lYaklKaTl0WmtXQjM5b1VmMGtWY2FSc1ZuVzlHSTIzanMvMG11bDRFM0FLTEZzeUE5dFZrRmVmY2xCSkVkdQovWHkzbEVnR2ZpV3JydmxhZ1RlZmxhWVVKWWlQQWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJUTGlzVGp6YTZDcjJ5UHBYUUU5WHFsZlAySUZUQVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQmlVejFrYlB5ZQpvOHRoa0lUeXdocFpIc09ibURpN0RkRjNtS0xNblB0bnJ1VnYvVWs4c0Z4eGtVYnpMMWVucEZRbFBUcjh3RGp6CjRDd296dmhxQjFLRERNY2RlenB1Q1ppY0pDbmFpRnVBYnlBTDhFKzJUL0o4UnFOVVk1cDRTbTBpYittbDBYZnEKY3IrMThBM1Y1VjMvTXBjNXc0SWlkYXB2SllHeEhjeUxxa2ZuaXR2N0NYZkxwSUdjNXJqd3JxWVNUUEx3ZDJNZAp3dGd3NnBUQms1V0QyMUhYK1FTSkFrQUp6TzFJTzhISzlSVEJoVWVUWVN3allvbFFic2JmOEpFdWZJT0o0NE4xCnhNbHdtTVA0MUdxdVdGanFVbzhRNy81ZmhpTVVlUE1qclBRMFdDdUtRbU9HbU04K1k3aVN3dTFYcFNnWGdFdG0KRE1kKzdzV0d5MHMvCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K[root@k8s-master ~]# k8s_crt=$(cat /etc/kubernetes/admin.conf | awk -F: '/certificate-authority-data/{print $2}' | tr -d ' ')[root@k8s-master ~]# echo $k8s_crt | base64 -d-----BEGIN CERTIFICATE-----MIIDBTCCAe2gAwIBAgIIfIuGKTVe7N4wDQYJKoZIhvcNAQELBQAwFTETMBEGA1UEAxMKa3ViZXJuZXRlczAeFw0yNDEyMDIwODE1NDZaFw0zNDExMzAwODIwNDZaMBUxEzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZO1ywwYCZoZ2myHP7E3mG250h+b2+9QM2K0SRly26Mbn4u1puGRPqCb4FamNjb7YAGvk8LcVidEN2qK+jZmZrLC1e1EZPUjFblOu4uhPLbgrPPRByuYwtIj0j3ZG3jnmMZvaY3qm3nwZf0oRqkwP9xWTmB/AeFBnlcNi97BZ0IFLlC4Po6MvO1lotrL8E6f2kzFPgZe+EFtAnJAxQvfNWrOeDpr970GwuqLjQHVf8YLrn8croBVcna6di3iXjIJi9tZkWB39oUf0kVcaRsVnW9GI23js/0mul4E3AKLFsyA9tVkFefclBJEdu/Xy3lEgGfiWrrvlagTeflaYUJYiPAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLisTjza6Cr2yPpXQE9XqlfP2IFTAVBgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQBiUz1kbPyeo8thkITywhpZHsObmDi7DdF3mKLMnPtnruVv/Uk8sFxxkUbzL1enpFQlPTr8wDjz4CwozvhqB1KDDMcdezpuCZicJCnaiFuAbyAL8E+2T/J8RqNUY5p4Sm0ib+ml0Xfqcr+18A3V5V3/Mpc5w4IidapvJYGxHcyLqkfnitv7CXfLpIGc5rjwrqYSTPLwd2Mdwtgw6pTBk5WD21HX+QSJAkAJzO1IO8HK9RTBhUeTYSwjYolQbsbf8JEufIOJ44N1xMlwmMP41GquWFjqUo8Q7/5fhiMUePMjrPQ0WCuKQmOGmM8+Y7iSwu1XpSgXgEtmDMd+7sWGy0s/-----END CERTIFICATE-----#####复制以上解密后的证书内容#####3
4.填写证书文件
3.3 凭据管理
配置集群访问凭证:
-
创建Secret文本类型凭据
-
生成token:
[root@k8s-master ~]# kubectl create sa jenkins[root@k8s-master ~]# cat role.txt kind: RoleapiVersion: rbac.authorization.k8s.io/v1metadata:namespace: defaultname: pod-reader-rolerules:- apiGroups: [""]resources: ["*"]verbs: ["get", "list", "watch","create","update","delete"][root@k8s-master ~]# kubectl apply -f role.txt##若要给于jenkins用户对default命名空间下所有资源具有所有权限,可以修改为 ["*"]###添加bindroling绑定[root@k8s-master ~]# cat rolebinding.txt kind: RoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata:namespace: defaultname: pod-reader-role-bindingsubjects:- kind: ServiceAccountname: jenkinsnamespace: defaultroleRef:kind: Rolename: pod-reader-roleapiGroup: rbac.authorization.k8s.io[root@k8s-master ~]# kubectl apply -f rolebinding.txt ###生成token[root@k8s-master ~]# kubectl -n default create token jenkins eyJhbGciOiJSUzI1NiIsImtpZCI6Ik9CNkNkSWdBa0lkODJTV1dUckhPaWpJV3pqbTVWOU9VZWwxNUlEcDFwWEUifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzMzNDcwMzc1LCJpYXQiOjE3MzM0NjY3NzUsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiYjNjNDgyMDAtNjVkMy00MzJjLThhMmQtOWE2MjAzNTNhNWZhIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImplbmtpbnMiLCJ1aWQiOiI1YTIzMmNkMC1mMDdlLTQwYjctYWQzNy00MTAzMjU5YTg5YWUifX0sIm5iZiI6MTczMzQ2Njc3NSwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6amVua2lucyJ9.bNcXCDP_lMWpETzp5SXMBSYCDGAfVeTTB3gNC9swiFWLOBmIv4pFhDEcQqdCsZP0wDZMIoX3ixIo0_N_4TDgthe8iyL5vmfnE32RYYCefVZu7edWzQUv9ARXrmkrRk6BvkFzabJNlv17Y-DoVieMggCVV4epKXGti-dOGJTclKgdut053dzO9_GtlDAdx7ZngWXFetstiVawdcZNlpsa62ZkrV8xNvieflunJ7qKA1pVLY6vibg5QYsjztWadmxmv6P4RbbqP5BfeGC-7QAe12MtLjzjixgimLlociKDcO2YI5plVjYNzS20leW3yxNsKVL02s_rzvIfSgnMWq6ChQ
复制输出的token到Jenkins凭据
3.4 连接测试与验证
在云配置页面执行测试连接:
成功返回集群版本信息(如:v1.28.15
)表明配置正确。
4. 流水线脚本进阶实现
4.1 动态生成资源清单
通过Groovy脚本动态生成Kubernetes资源文件:
stage('Generate YAML') {steps {writeFile file: 'deployment.yaml', text: """apiVersion: apps/v1kind: Deploymentmetadata:name: webappspec:replicas: 3selector:matchLabels:app: web"""}}
文件生成后提交到集群:
kubectl apply -f deployment.yaml
此方法适用于模板化部署但增加复杂度。
4.2 静态资源清单实践
推荐使用预定义的资源清单文件:
-
提前准备好YAML文件(如
mysql-deployment.yaml
) -
存储在Jenkins工作空间固定目录
-
流水线中直接调用:
stage('Deploy DB') {steps {sh 'kubectl apply -f k8s/mysql.yaml'}}
优点:避免脚本错误且易于维护。
4.3 多阶段部署案例(LAMP栈)
完整部署流程示例:
stages {stage('Deploy MySQL') {steps {sh 'kubectl apply -f mysql-pvc.yaml'sh 'kubectl apply -f mysql-deployment.yaml'}}stage('Deploy PHP') {steps {sh 'kubectl apply -f php-deployment.yaml'}} stage('Deploy Nginx') {steps {sh 'kubectl apply -f nginx-service.yaml'}}}
注意点:
-
部署顺序:先数据库后前端服务
-
PVC需提前配置PersistentVolume
5. 常见问题与解决方案
5.1 连接认证失败
现象:执行kubectl命令返回Unauthorized
原因:token过期(默认有效期60分钟) 解决:
-
重新生成token:
kubectl -n default create token jenkins
-
更新Jenkins凭据中的token值
5.2 容器启动失败
现象:Pod状态显示CrashLoopBackOff
诊断步骤:
-
查看Pod日志:
kubectl logs <pod-name>
-
描述Pod事件:
kubectl describe pod <pod-name>
常见原因:
-
镜像拉取超时(国内网络问题)
-
资源限制不足(如MySQL内存溢出)
-
启动参数错误
5.3 Groovy语法错误
典型错误:
// 错误示例:未转义$符sh "echo $PATH" // 正确写法:sh "echo \$PATH"
调试方法:
-
使用Jenkins流水线语法检查器
-
分段测试脚本
-
避免在多行文本中使用特殊符号
5.4 插件版本兼容问题
表现:日志报java.lang.UnsupportedClassVersionError
根本原因:插件要求的Java版本与运行时环境不匹配 解决方案:
-
确认Jenkins服务器Java版本:
java -version
-
在Docker agent中指定兼容镜像:
agent {docker {image 'openjdk:11-jre' }}
6. 优化实践与建议
6.1 安全最佳实践
-
最小权限原则:为ServiceAccount绑定精确RBAC角色
apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:namespace: defaultname: pod-managerrules:- apiGroups: [""]resources: ["pods"]verbs: ["create", "get", "list"]
-
敏感数据存储:使用Kubernetes Secret管理密码
6.2 性能优化方向
-
镜像缓存:在Kubernetes节点预拉取基础镜像
-
资源预留:合理设置Pod资源请求/限制
resources:requests:memory: "256Mi"cpu: "500m"limits:memory: "512Mi"cpu: "1000m"
-
构建并行化:利用parallel阶段加速流程:
stage('Parallel Build') {parallel {stage('Frontend') { ... }stage('Backend') { ... }}}
6.3 维护性建议
-
代码与配置分离:将Kubernetes YAML文件存入Git仓库
-
版本化管理:
-
镜像使用语义化标签(如
v1.2.3
) -
Jenkinsfile纳入版本控制
-
-
文档化模板:创建标准流水线模板目录结构
├── Jenkinsfile├── k8s│ ├── deployment.yaml│ └── service.yaml└── scripts└── deploy.sh
7. 全流程集成示例
7.1 端到端流水线脚本
pipeline {agent {kubernetes {label 'jenkins-k8s-agent'yamlFile 'k8s/pod-template.yaml'}}stages {stage('Checkout') {steps {git url: 'http://192.168.72.166/git/k8s.git', branch: 'master'}}stage('Build Image') {steps {script {docker.build("registry.local:5000/app:${env.BUILD_ID}")docker.push("registry.local:5000/app:${env.BUILD_ID}")}}}stage('Deploy') {steps {sh 'kubectl apply -f k8s/deployment.yaml'}}}post {always {cleanWs()}}}
7.2 关键组件交互图
7.3 验证部署结果
-
检查Pod状态:
kubectl get pods -l app=myapp
-
查看部署日志:
kubectl logs deploy/myapp
-
服务访问测试:
curl http://<service-ip>:<port>
成功标准:返回应用预期响应内容。
8. 故障排除手册
8.1 诊断流程图
8.2 日志分析要点
-
认证错误:
解决方案:更新RBAC或ServiceAccount tokenUnauthorized
或Forbidden
-
镜像拉取失败:
检查点:ErrImagePull
-
镜像仓库认证
-
节点网络连通性
-
镜像地址是否正确
-
-
容器崩溃:
处理步骤:OOMKilled
-
kubectl describe pod <name> | grep -A 10 Eventskubectl top pod <name>增加内存限制
-
9. 附录:核心命令参考
9.1 Kubernetes常用命令
命令 | 功能 | 示例 |
---|---|---|
kubectl apply | 应用资源清单 | kubectl apply -f deploy.yaml |
kubectl get | 查看资源状态 | kubectl get pods |
kubectl describe | 查看详细信息 | kubectl describe pod nginx |
kubectl logs | 查看容器日志 | kubectl logs -f mysql-0 |
kubectl delete | 删除资源 | kubectl delete deployment myapp |
9.2 Jenkins流水线语法
// 条件执行stage('Conditional') {when {expression { params.DEPLOY_ENV == 'prod' }}steps {sh './deploy-prod.sh'}}// 超时控制stage('Build') {steps {timeout(time: 15, unit: 'MINUTES') {sh 'mvn package'}}}// 人工审核stage('Approve') {steps {input message: '确认部署到生产环境?'}}
总结:
Jenkins与Kubernetes的集成,标志着CI/CD实践从静态、固定的模式向动态、弹性的云原生模式的一次重要演进。通过本次实践,我们成功地将构建环境容器化并交由Kubernetes调度管理,不仅解决了传统Slave节点资源浪费和维护繁琐的痛点,更获得了极致的弹性伸缩能力和高度的环境一致性。
实践表明,这种集成的核心优势在于:资源利用最优化(按需创建,用完即焚)、环境标准化(容器镜像确保环境绝对一致)、以及强大的可扩展性(轻松应对突发构建流量)。尽管在初期需要投入精力进行服务账户权限配置和Pipeline脚本改造,但所带来的长期收益是巨大的,它为企业的DevOps流程提供了坚实且面向未来的技术底座。最终,Jenkins on Kubernetes不再是简单的工具叠加,而是构建了一条高效、可靠且能够自我修复的软件交付流水线。