1、概述
本文分享的是基于k8s
环境与jenkins
实现CI/CD
其中的一个配置具体实现
即:不同环境下jenkins与k8s集群连接的问题
为什么会有不同的环境?我总结的原因如下:
a、在实际生产环境中,由于某些历史原因我们或许不能完美的实现所谓的一切皆“云原生”,例如有传统的jenkins
和执行专有任务的slave
节点
b、存在多集群共一个jenkins
服务端的情况,例如k8s
中集群A
用作基础设施集群(包含日志、存储、devops
平台),集群B
、C
、D
用作不同业务线集群
因此,我们可以将不同环境定义为如下两种情况:
-
同集群:指
k8s
集群内部的jenkins
连接本集群 -
跨集群:指外部的
jenkins
连接k8s
集群,或者是jenkins
连接外部的k8s
集群
2、同集群
同集群下,k8s
集群内部的jenkins
连接所在的k8s
集群。这是原生的方式:我们的环境都是全新的,全新的机器、全新安装的集群、全新的jenkins
,总之一切都是新的,没有任何历史问题
由于在k8s
集群内部部署jenkins
时,已经对jenkins
做了以下相关的角色授权绑定
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: kube-system
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: jenkins
namespace: kube-system
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get","list","watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: jenkins
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins
subjects:
- kind: ServiceAccount
name: jenkins
namespace: kube-system
因此只需要在jenkins
中配置相应的连接地址就可以了
在jenkins
中安装好k8s
插件后,打开jenkins
——>系统管理——>系统配置——>新增一个kubernetes
云
配置名称,即这个云的别名
Kubernetes
地址,即在集群内部暴露的k8s service
名称
Kubernetes
命名空间,这个配置就填写jenkins
所属的namespace
Jenkins
地址,填写jenkins svc
的名称
配置完成后点击测试连接成功
后面配置pod template
这里不做介绍,这里配置的pod templete
是默认情况下jenkins slave
的pod
模板,当然也可以在每个流水线中单独指定
配置完成后的动态创建jenkins slave pod
测试在本文后面一并给出
3、跨集群
一个实际场景:jenkins
部署在A
集群或部署在传统VM
的环境下,想通过jenkins
连接B
集群,动态创建pod
用以执行构建任务
3.1 端口有什么
既然是跨集群,那么首先需要考虑的就是网络问题,网络是否可达?需要开通哪些端口的安全组策略?
在这之前,就需要先了解一下jenkins
的运行机制及端口有哪些?
-
http端口:默认
8080
,如果在jenkins
前面做了反向代理并配置了域名,那么可能是常见的80/443
端口,我这里通过域名+https
的方式访问jenkins
-
Agent Port:基于
JNLP
的Jenkins
代理通过TCP
默认端口50000
与Jenkins
进行通信 -
SSH port:
jenkins
作为ssh
服务器,这个一般不会使用,具体使用可参考我之前的文章Jenkins workflowLibs库的使(妙)用
3.2 网络策略打通
由上面知道了有哪些端口之后,因此需要打通的网络策略包括
- B集群节点连接
jenkins
暴露的http port
和Agent port
- A集群节点(即
jenkins server
)连接B
集群kube-apiserver
暴露的端口
除网络策略之外,如果jenkins UI
的地址,例如通过ingress
设置了白名单限制访问,还需要将B
集群的相关源ip
设置为白名单
3.3 证书的生成和配置
3.3.1 kubeconfig文件
由于这里A
集群中的jenkins
并没有对B
集群的操作权限,因此需要配置授权,即发起对B
集群的kube apiserver
的请求,和kubectl
一样利用config
文件用作请求的鉴权,默认在~/.kube/config
下,当然我们也可以单独严格指定权限细节,生成一个jenkins
专用的config
文件,这里就不再延伸了,kubeconfig
文件的组成如下
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxx
server: https://<master-ip>:6443
name: cluster1
contexts:
- context:
cluster: cluster1
user: admin
name: context-cluster1-admin
current-context: context-cluster1-admin
kind: Config
preferences: {}
users:
- name: admin
user:
client-certificate-data: xxx
client-key-data: xxx
其中包含了3
段证书相关的内容,也就是我们常见的证书组成格式:ca.crt
、client.crt
、client.key
3.3.2 生成证书
在jenkins
中能够识别的证书文件为PKCS#12 certificate
,因此需要先将kubeconfig
文件中的证书转换生成PKCS#12
格式的pfx
证书文件
首先,使用yq
命令行工具来解析yaml
并通过base 64
解码生成各个证书文件
服务端证书:
certificate-authority-data
——>base 64
解码——>ca.crt
yq e ‘.clusters[0].cluster.certificate-authority-data‘ .kube/config | base64 -d > ca.crt
客户端证书
client-certificate-data
——>base 64
解码——>client.crt
yq e ‘.users[0].user.client-certificate-data‘ .kube/config | base64 -d > client.crt
client-key-data
——>base 64
解码——>client.key
yq e ‘.users[0].user.client-key-data‘ .kube/config | base64 -d > client.key
然后,通过openssl
进行证书格式的转换,生成Client P12
认证文件cert.pfx
openssl pkcs12 -export -out cert.pfx -inkey client.key -in client.crt -certfile ca.crt
Enter Export Password: # 输入密码加密
Verifying - Enter Export Password:
通过踩坑证明,这里必须输入密码,不然在后面添加jenkins
相关配置后验证会报错
3.3.3 导入证书
生成文件后,打开jenkins
的web
界面
添加全局凭据,凭据的类型选择Certificate
,选择Upload PKCS#12 certificate
上传刚才生成的cert.pfx
证书文件
输入通过openssl
生成证书文件时输入的密码
检查上传的证书文件,此时可以查看到,jenkins
已经成功加载了证书文件并读取了证书文件的相关信息
3.4 配置连接外部的k8s集群
在jenkins
中新增kubernetes
云配置
同样的,打开jenkins
——>系统管理——>系统配置——>新增一个kubernetes
云
配置名称,即这个云的别名,为外部的k8s集群起一个别名
Kubernetes
地址,这里需要填写的是外部集群的kube-apiserver
地址,即https://<master ip>:6443
Kubernetes
服务证书key
,填写上面服务端证书base64
解码后的内容
Kubernetes
命名空间,填写jenkins
所属的namespace
凭据选择上面导入的证书文件作为凭据
Jenkins
地址,填写A
集群现有jenkins UI
域名(访问地址和端口)
配置完成后点击测试连接成功,到这里跨集群的jenkins
连接k8s
就成功了
4、测试验证
4.1 配置pod template
这里以跨集群的环境下进行测试验证A
集群的jenkins
执行构建任务,在B
集群中动态创建slave
的预期结果
在jenkins
系统配置中,除了配置关联外部集群外,这里再配置一下相应的pod template
,以便于在B
集群中创建默认的slave pod
,如图
4.2 *风格构建测试
在*风格中限制项目的运行节点,标签为上面配置的pod template
标签即k8s-test-cluster
,执行shell
命令进行测试,查看控制台输出
4.3 流水线构建测试
编写测试的pipeline
流水线,同样指定标签为上面配置的pod template
标签即k8s-test-cluster
pipeline{
agent{
node {
label ‘k8s-test-cluster-jnlp-slave‘
}
}
stages{
stage(‘Deploy to Kubernetes‘){
steps{
script{
sh """
kubectl version
kubectl get cs
"""
}
}
}
}
}
构建后查看控制台输出
到这里,基于不同基础环境下jenkins
与k8s
连接配置的相关操作就分享完啦
See you ~