learn-tech/专栏/Jenkins持续交付和持续部署/14.搞定不同环境下的Jenkins与Kubernetes集群连接配置.md
2024-10-16 06:37:41 +08:00

410 lines
17 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

因收到Google相关通知网站将会择期关闭。相关通知内容
14.搞定不同环境下的Jenkins与Kubernetes集群连接配置
在前面的章节中简单的介绍了使用Jenkins与Docker集成的一些基本语法以及实现持续交付和持续部署的配置。在Jenkins中除了可以与docker集成外还可以与容器编排工具kubernetes集成。
Jenkins使用kubernetes插件主要用于完成两方面的工作一是用于在kubernetes集群内动态生成一个pod作为Jenkins 的slave节点提供流水线执行的工作环境二是用于将应用代码持续部署到kubernetes集群中。
基于上面提到的这两方面的用途在剩下的章节会详细介绍Jenkins与kubernetes的集成配置与使用方法。
同docker pipeline一样在Jenkins里集成kubernetes也是依赖于插件的所以在介绍如何配置与使用jenkins集成kubernetes之前需要先安装插件
Kubernetes plugin
Kubernetes CLI
Kubernetes Continous Deploy
上面列出的插件第一个用于在kubernetes集群中动态生成jenkins slave节点后两个插件用于通过不同的方式持续部署代码到kubernetes集群。无论哪种插件使用前都要先保证jenkins能够连接到kubernetes集群所以本章节就从不同环境下的jenkins连接kubernetes集群的配置说起。
配置Jenkins连接Kubernetes
使用docker pipeline做持续交付的时候默认直接使用的宿主机的docker进程。而Jenkins与kubernetes的集成主要是通过调用Kubernetes的API去kubernetes集群中进行工作的。大多数公司在安装kubernetes集群配置apiserver服务时使用了证书所以在配置jenkins连接kubernetes集群时需要根据kubernetes的配置文件生成一系列证书以及key并将证书上传到Jenkins用来对apiserver进行认证。
下面针对部署在kubernetes集群环境下的Jenkins和非kubernetes集群环境下的jenkins连接kubernetes集群的配置进行详细介绍。
部署在非kubernetes集群内Jenkins连接kubernetes配置
安装好插件以后进入Jenkins首页点击菜单”Manage Jenkins(系统管理)-> Configure System(系统设置)” 在跳转到的界面中,到最底部,点击” Add a new cloud新建一个云> kubernetes“。
如下所示:
其中:
名称这里用于填写要添加的这个云cloud的名称默认为”kubernetes”如果不想用这个可以自定义。在编写pipeline的时候会用到。
kubernetes 地址用于填写kubernetes集群的地址做了多master集群高可用的环境直接写vip地址加端口只有单个master的环境直接写master加端口地址即可。
Kubernetes 服务证书 key用于填写与kubernetes集群认证的证书内容。
Kubernetes 命名空间用于填写调用kubernetes时生成的pod工作的namespace。
Credentials凭据用于连接kubernetes的凭证。
Jenkins 地址Jenkins的连接地址。
了解了基本配置的参数说明下面主要说一下”Kubernetes 服务证书 key“和Credentials凭据配置。
kubernetes集群安装的时候生成了一系列证书以及key并且在配置kubernetes中kubectl客户端命令权限的时候根据这些证书以及key生成了一个kubeconfig文件用于kubectl与集群通信这个文件默认为/root/.kube/config文件对集群有最高操作权限如果给了cluster-admin权限
Jenkins需要根据这个文件生成的证书与集群通信所以我们在生产环境配置Jenkins连接kubernetes集群的时候需要注意一下kubeconfig文件绑定的用户的权限最好从新生成一个低权限的kubeconfig文件而不要用kubectl命令使用的文件。
我这里为了测试方便就先使用kubectl命令使用的kubeconfig文件至于如何生成低权限的kubeconfig文件这里不做介绍有兴趣的可以私聊我。
配置证书key
首先看一下config文件。
[root@k8s_master1 ~]# cat /root/.kube/config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR2akNDQXFhZ0F3SUJBZ0lVT0g4cDd6QXZaR3p4cGxUVy9xe......
WRnVRNm9IcjZ0Yk0wa1NJVkhvN2JNQjRWOGZoUWk4WjlLS243ZTFsQWdaVWhyWGMzTzRqVS9xVHRWRQpSRXc9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
server: https://192.168.176.156:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: admin
name: kubernetes
current-context: kubernetes
kind: Config
preferences: {}
users:
- name: admin
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQzVENDQXNXZ0F3SUJBZ0lVQmI1ZTJFaUk1WndSY1JVeFVyZ......
Qk9DTzRBcEVzWXNOa084UVF2RTlwVEhpNlE0LzhLV0NtU0wyNgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBeDdjNkpRTFdQaC90REtjUDQrcDV5aCtWdWRCUmFacFJ2THM2MU1POGFZWFRCT09pCkJyZzFQb0laRzZEbXNBNnUyUStOVnlGOWg5RTQ3VVpFNjI5ND...... K3dGdUF2S29vRm9lRFZCS3I3NjdiTFA3ZTBibkVqS1ExRmNHVFFFQVU9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
获取文件中certificate-authority-data的内容并转化成base64 encoded文件
echo LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR2akNDQXFhZ0F3SUJBZ0lVT0g4cDd6QXZaR3p4cGxUVy9xejRWRmxLQllRd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1pURUxNQWtHQTFVRUJoTUNRMDR4RURBT0JnTlZCQWdUQjBKbG......
WRnVRNm9IcjZ0Yk0wa1NJVkhvN2JNQjRWOGZoUWk4WjlLS243ZTFsQWdaVWhyWGMzTzRqVS9xVHRWRQpSRXc9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K |base64 -d > ca.crt
将ca.crt的内容粘贴到kubernetes server certificate key(Kubernetes 服务证书 key)框里,如下图所示:
配置凭据
获取/root/.kube/config文件中client-certificate-data和client-key-data的内容并转化成base64 encoded文件
echo LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQzVENDQXNXZ0F3SUJBZ0lVQmI1ZTJFaUk1WndSY1JVeFVyZ......
Qk9DTzRBcEVzWXNOa084UVF2RTlwVEhpNlE0LzhLV0NtU0wyNgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== |base64 -d >client.crt
//生成key
echo LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb2dJQkFBS0NBUUVBeDdjNkpRTFdQaC90REtjUDQrc......
K3dGdUF2S29vRm9lRFZCS3I3NjdiTFA3ZTBibkVqS1ExRmNHVFFFQVU9Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== | base64 -d >client.key
生成Client P12认证文件cert.pfx并下载至本地
openssl pkcs12 -export -out cert.pfx -inkey client.key -in client.crt -certfile ca.crt
Enter Export Password:            //密码自定义jenkins导入证书的时候需要用到
Verifying - Enter Export Password:
在jenkins凭据菜单添加凭据
如上图所指示凭据类型为”Certiticate“password为生成证书时的设置的密码。
添加完成后如下图所示,点击连接测试
连接成功如下所示:
到此部署在非kubernetes集群内的Jenkins连接kubernetes配置就完成了。
部署在kubernetes集群内jenkins连接kubernetes配置
在前面介绍jenkins安装配置章节没有介绍如何在kubernetes集群中部署所以本小节的开头就先介绍一下如何在kubernetes集群中部署jenkins。
kubernetes系统中使用资源对象来描述某个系统的期望状态以及对象的基本信息。对于部署某个应用或者服务使用最多的资源对象就是deployment所以这里使用deployment来描述jenkins的配置并部署。
在kubernetes集群部署jenkins
首先需要创建一个服务账户ServiceAccount用来绑定对某一个命名空间的一系列kubernetes资源对象的操作权限。
如下jenkins-rbac.yaml文件
---
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
然后创建deployment资源对象文件来描述jenkins的一些基本配置信息比如开放的端口启动参数使用的镜像等。
如下jenkins-deployment.yaml文件
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: jenkins
labels:
app-name: jenkins
namespace: kube-system
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app-name: jenkins
spec:
serviceAccount: "jenkins"
containers:
- name: jenkins
image: docker.io/jenkins:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: web
protocol: TCP
- containerPort: 50000
name: agent
protocol: TCP
volumeMounts:
- name: jenkins-home
mountPath: /var/jenkins_home
env:
- name: JAVA_OPTS
value: "-Duser.timezone=Asia/Shanghai -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85"
volumes:
- name: jenkins-home
persistentVolumeClaim:
claimName: jenkins-public-pvc
在资源对象的定义中使用了pv和pvc做持久化volume所以还需要创建这两种资源对象定义的文件。
$ cat jenkins-pv.yaml
kind: PersistentVolume
apiVersion: v1
metadata:
labels:
name: jenkins-public-pv
name: jenkins-public-pv
namespace: kube-system
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /data/nfs/jenkins-data
server: 192.168.177.43
$ cat jenkins-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: jenkins-public-pvc
namespace: kube-system
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 100Gi
selector:
matchLabels:
name: jenkins-public-pv
使用nfs作为共享存储创建pvc使用pv在实际工作中一般使用storageclass替代pv作为动态存储。当然如果为了简单你也可以用挂载nfs目录的方式或者指定节点通过hostpath将工作目录挂在到宿主机方法比较多根据个人实际情况选择合适的存储即可。
部署service资源对象相当于给运行jenkins服务的pod加了一个代理。
如下jenkins-service.yaml
kind: Service
apiVersion: v1
metadata:
labels:
app-name: jenkins
name: jenkins
namespace: kube-system
spec:
ports:
- port: 8080
targetPort: 8080
name: web
- port: 50000
targetPort: 50000
name: agent
selector:
app-name: jenkins
部署ingress服务直接跳过service接管service代理的pod。
如下jenkins-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: jenkins
namespace: kube-system
spec:
rules:
- host: k8s-jenkins.com
http:
paths:
- path: /
backend:
serviceName: jenkins
servicePort: 8080
创建好ingress后需要添加部署ingress controllernode节点的ip和ingress中定义的host到本地hosts文件做解析。如果没有部署ingress服务可以直接编辑上一步骤中创建service时的类型为nodePort这样就可以通过访问nodeIP:nodePort的方式访问jenkins了。
部署完成后如下所示:
$ kubectl get pods,ingress,svc,deploy -n kube-system |grep jenkins
pod/jenkins-78f658b5d6-25qgl 1/1 Running 0 163d
ingress.extensions/jenkins k8s-jenkins.com 80 10m
service/jenkins ClusterIP 10.254.179.172 <none> 8080/TCP,50000/TCP 198d
deployment.extensions/jenkins 1/1 1 1 198d
部署好后的其他配置与在前面章节安装配置jenkins的方法一样。有关在kubernetes集群中安装jenkins服务的方法就介绍到这里。
配置jenkins连接kubernetes
部署在kubernetes集群内的jenkins配置连接kubernetes相对较简单同样在系统配置页进行配置不用生成上面的一系列证书kubernetes的地址直接写kubernetes的FQDN即可。
如下所示:-
说明
Name 处默认为 kubernetes也可以修改为其他名称这里不做重复介绍。
Kubernetes URL 处可以填写 https://kubernetes.default 为Kubernetes Service 对应的 DNS 记录通过该DNS记录可以解析成该 Service 的 Cluster IP。注意这里也可以填写 https://kubernetes.default.svc.cluster.local 完整 DNS 记录,因为它要符合 service_name.namespace_name.svc.cluster_domain的命名方式。也可以直接填写外部 Kubernetes 的地址 https://ClusterIP:Ports (不推荐)。
Jenkins URL 处应该填写Jenkins的service地址和端口。比如我的http://jenkins.kube-system.svc.cluster.local:8080 也可以写成http://jenkins.kube-system:8080 表示jenkins的service名称和所在的namespace名称同kubernetes url设置类似也是使用Jenkins Service 对应的 DNS 记录以及端口。如果暴露服务的方式为nodeport也可以用http://NodeIP:NodePort本示例没配置的方式根据自己实际情况修改即可。
Credentials :同属于一个集群环境,对于集群认证的过程就不需要了,认证凭证也就不用填写了。
Jenkins虽然能连接kubernetes了但是通过kubernetes还不能生成动态的slave代理因为slave agentjnlp-agent在启动的时候会通过50000默认端口与jenkins master进行通信。Jenkins这个端口默认是关闭的所以还需要开启这个端口。
Manage Jenkins(系统管理)->Configure global Security全局安全配置-> Agents(代理)
说明:
这里指定的端口是jnlp-agent连接jenkins-master使用的端口。
如果Jenkins-master只是在Docker容器(没有使用容器编排系统)中启动的一定要记得将这个端口暴露到外部不然jenkins-master会不知道slave是否已经启动会反复去创建pod直到到超过重试次数。
该端口的默认值是50000如果要修改为其他端口需要修改在创建jenkins”云”时对应的Jenkins Tunnel(通道)参数的配置如果使用50000端口这里可以不用填写如果换成别的端口这里需要单独设定最好是jenkins_url:port的形式。
如果不开启代理端口Jenkins通过kubernetes动态生成slave节点的时候jenkins后台会报如下错误并且pod会不断的生成和删除。
到这里jenkins与kubernetes的集成就成功了。
默认情况下agent代理连Jenkins的接超时时间为100秒。在特殊情况下如果想设置一个不同的值可以将system属性设置org.csanchez.jenkins.plugins.kubernetes.PodTemplate.connectionTimeout为一个不同的值。但是100s的话其实够用了如果超过100s还没生成代理pod就需要根据jenkins日志去排查问题了。如果jenkins连接kubernetes配置成功了大多数情况下的错误一般就是配置podtemplate是什么后面章节会介绍到出现了问题。
示例
上面配置好了如何连接kubernetes下面用一个示例测试配置是否成功。
将下面示例放到pipeline脚本中。
def label = "mypod-${UUID.randomUUID().toString()}"
podTemplate(label: label, cloud: 'kubernetes') {
node(label) {
stage('Run shell') {
sh 'hostname'
sh 'echo hello world.'
}
}
}
说明:
PodTemplate中的label参数用于给Pod指定一个唯一的名称。
PodTemplate中cloud参数的值必须是在系统配置添加的云的名称。
node中直接使用”label”便可以引用上面定义的label变量表示在该pod名称中执行命令如果不指定的话默认还是在Jenkins服务所在主机上执行流水线脚本。
执行结果如下:
根据上面的执行结果可以看到Jenkins通过kubernetes调用的资源对象pod的yaml定义使用的镜像默认为jenkins/jnlp-slave:3.35-5-alpine镜像名称以及一些pod的环境变量等信息。
除了可以在pipeline类型的job中使用kubernetes插件外也可以在其他类型的job中使用但是此时需要在jenkins的系统配置中配置PodTemplate此处先不介绍在后面的实践章节会进行说明。
无论哪种类型的job在job执行的过程中都可以通过kubectl命令在kubernetes集群中查看pod运行的一些详细信息而关于该pod的资源定义又是怎么配置的是否可以自定义呢下节会通过学习kubernetes的基本语法来解答这个问题。