前言:
在云原生技术迅猛发展的今天,快速、可靠地交付软件已成为企业保持核心竞争力的关键。持续集成与持续部署(CI/CD)是这一过程的基石,而容器化与编排技术则为其提供了理想的运行环境。然而,传统的CI/CD工具往往面临资源利用率低、扩展性差和维护成本高等挑战。
Jenkins,作为业界广泛采用的自动化服务器,与Kubernetes,作为容器编排领域的事实标准,二者的结合为解决上述挑战提供了完美的答案。通过将Jenkins构建任务动态调度到Kubernetes集群的临时Pod中执行,我们能够打造一个“无服务器”式的构建农场:它具备极致的弹性,可以轻松应对高并发构建需求;它高度资源高效,任务完成后资源立即释放;并且与底层基础设施完美解耦,实现了真正的云原生CI/CD。
本文将引导您完成这一强大集成的核心步骤,并分享实践中的关键洞察,助力您的团队迈向更高效、更可靠的自动化交付之路。
目录
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=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.28/rpm/repodata/repomd.xml.key
EOF
yum install -y kubectl
mkdir .kube
cd .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 node
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 21d v1.28.15
k8s-node1 Ready worker 21d v1.28.15
k8s-node2 Ready worker 21d v1.28.15
1.3 资源清单文件提交
连接集群后,可直接提交YAML资源清单文件部署应用:
# 示例资源清单(CPU需求1500毫核)
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
resources:
requests:
cpu: "1500m"
提交命令:
kubectl apply -f pod.yaml
部署成功后在集群中创建对应Pod。
2. Jenkins流水线基础架构
2.1 流水线脚本结构
使用Groovy语法编写Jenkinsfile,核心结构包含代理声明和阶段定义:
agent {
kubernetes {
label 'jenkins-agent'
yaml '''
apiVersion: v1
kind: Pod
spec:
containers:
- name: jnlp
image: 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-----
MIIDBTCCAe2gAwIBAgIIfIuGKTVe7N4wDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE
AxMKa3ViZXJuZXRlczAeFw0yNDEyMDIwODE1NDZaFw0zNDExMzAwODIwNDZaMBUx
EzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCZO1ywwYCZoZ2myHP7E3mG250h+b2+9QM2K0SRly26Mbn4u1puGRPqCb4F
amNjb7YAGvk8LcVidEN2qK+jZmZrLC1e1EZPUjFblOu4uhPLbgrPPRByuYwtIj0j
3ZG3jnmMZvaY3qm3nwZf0oRqkwP9xWTmB/AeFBnlcNi97BZ0IFLlC4Po6MvO1lot
rL8E6f2kzFPgZe+EFtAnJAxQvfNWrOeDpr970GwuqLjQHVf8YLrn8croBVcna6di
3iXjIJi9tZkWB39oUf0kVcaRsVnW9GI23js/0mul4E3AKLFsyA9tVkFefclBJEdu
/Xy3lEgGfiWrrvlagTeflaYUJYiPAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP
BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTLisTjza6Cr2yPpXQE9XqlfP2IFTAV
BgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQBiUz1kbPye
o8thkITywhpZHsObmDi7DdF3mKLMnPtnruVv/Uk8sFxxkUbzL1enpFQlPTr8wDjz
4CwozvhqB1KDDMcdezpuCZicJCnaiFuAbyAL8E+2T/J8RqNUY5p4Sm0ib+ml0Xfq
cr+18A3V5V3/Mpc5w4IidapvJYGxHcyLqkfnitv7CXfLpIGc5rjwrqYSTPLwd2Md
wtgw6pTBk5WD21HX+QSJAkAJzO1IO8HK9RTBhUeTYSwjYolQbsbf8JEufIOJ44N1
xMlwmMP41GquWFjqUo8Q7/5fhiMUePMjrPQ0WCuKQmOGmM8+Y7iSwu1XpSgXgEtm
DMd+7sWGy0s/
-----END CERTIFICATE-----
#####复制以上解密后的证书内容#####3
4.填写证书文件
3.3 凭据管理
配置集群访问凭证:
创建Secret文本类型凭据
生成token:
[root@k8s-master ~]# kubectl create sa jenkins [root@k8s-master ~]# cat role.txt kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: default name: pod-reader-role rules: - 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: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: namespace: default name: pod-reader-role-binding subjects: - kind: ServiceAccount name: jenkins namespace: default roleRef: kind: Role name: pod-reader-role apiGroup: 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/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 3
selector:
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/v1 kind: Role metadata: namespace: default name: pod-manager rules: - 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 Events kubectl 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不再是简单的工具叠加,而是构建了一条高效、可靠且能够自我修复的软件交付流水线。