本次实践主要介绍Docker与Kubernerts动态创建agent
一.前言
Jenkins的分布式架构,分为server节点和agent节点。 server节点也是可以运行构建任务的,但我们一般使其来调度任务分配给agent去做。agent在一定程度上也会减轻server节点的压力,并且可以基于容器环境随着任务的构建来动态创建agent节点,有任务时agent就会被创建出来,执行完空闲时销毁不占用资源。
二.Jenkins-agent实现方式
方式目前主要有三种: VM,Docker,Kubernets
1.VM方式简单来说就是我们传统添加agent客户机的方式,添加一个静态节点。 (本次不做介绍)
2.Docker方式是找一台有Docker环境的机器开放端口,jenkins去链接docker地址,之后的agent都是以容器的方式创建出来(这台docker主机上)
3.Kubernets方式与docker类似,通过连接apiserver的api 来实现k8s集群内动态创建agent pod ;
此方式有两种情况:
a. jenkins安装在k8s集群内(直接写svc地址能访问到即可)
b. jenkins安装在k8s集群外(需要配置创建一个连接k8s集群的凭据来连接)
三.Docker动态创建Jenkins-Agent
我们上面说了这种方式需Jenkins调用Docker的接口完成的,所以需要开启Docker远程访问将Docker的API暴露出去。
1.暴露Docker的api
vim /lib/systemd/system/docker.service
(-H tcp://0.0.0.0:2375)为新增内容
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375
重启docker服务
2.Jenkins安装Docker插件(略)
3.Jenkins配置Cloud
点击管理-管理节点
a.节点设置
参数解读:
Connection Timeout
连接超时时间
Read Timeout
读操作超时时间
Enabled
功能是否开启
Error Duration
错误的持续时间 默认5分钟
Container Cap
容器数量 (默认值100;负值或零代表无限制)
b.pod模板设置
Connect method
连接方式;默认的Attach Docker container
其他设置均默认,可根据需求修改;保存退出。
4. 测试流水线
新增一个流水线项目(docker-slave为配置模板中的标签)
pipeline {
agent {
label 'docker-slave'
}
stages {
stage('Hello') {
steps {
echo 'Hello World'
sh 'pwd'
sh 'sleep 20'
echo 'Finish'
}
}
}
}
在docker主机中创建了一个agent,执行完并销毁。
至此docker动态创建agent完成
—————————————————————————————————————————————
四. Kubernets动态创建Agent
我这里的jenkins为k8s集群外搭建的,连接k8s集群需要创建一个凭据。(证书)
1. Jenkins安装Kubernets插件(略)
2. 创建k8s服务证书
Kubernetes服务证书key是用来与Kubernetes API server建立连接的,生成方法是,从Kubernetes API server的/root/.kube/config文件中,获取/root/.kube/config中certificate-authority-data的内容,并转化成base64编码的文件
2.1- 安装yaml解析工具yq
wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/download/v4.15.1/yq_linux_amd64
chmod +x /usr/local/bin/yq
2.2-服务端证书
yq e '.clusters[0].cluster.certificate-authority-data' .kube/config | base64 -d > ca.crt
2.3-客户端证书
yq e '.users[0].user.client-certificate-data' .kube/config | base64 -d > client.crt
2.4-key:
yq e '.users[0].user.client-key-data' .kube/config | base64 -d > client.key
2.5-生成Clinet P12认证文件:
openssl pkcs12 -export -out cert.pfx -inkey client.key -in client.crt -certfile ca.crt
Enter Export Password:
Verifying - Enter Export Password:
这里必须要输入密码。并且记住,这个后面jenkins配置凭据的时候要用到~
3. 创建凭据
创建一个jenkins用于连接k8s集群api的凭据
进入 Jenkins 的系统管理,点击Manage Credentials; 点击Stores scoped to Jenkins列表下全局中的添加凭据
4. 创建cloud
在系统管理的节点管理点击 Add a new cloud,添加k8s集群
4.1 设置pod模板
容器运行的命令及命令参数均为默认,只有容器名和镜像是我自定义的
注意:(容器名不要叫jnlp,不然会出现一直重启的情况或者不执行任务也一直不退出的情况)
5.创建流水线任务进行测试
介绍2种方式创建pod模板的方式:
1.以上过程中直接在界面中配置保存pod模板信息,在流水线中指定配置的label来运行。
2.直接将pod模板写在pipeline里来直接创建引用。
5.1 方式1的形式,写一个demo流水线测试
注意:以上在界面中配置的pod模板中label为jenkins-agent
这里来指定他
pipeline {
agent {
label 'jenkins-agent'
}
options {
skipDefaultCheckout()
}
stages {
stage('Hello') {
steps {
script{
sh 'whoami'
sh 'sleep 15'
}
}
}
}
}
结果:
可以看到是2/2,两个容器,因为其中有一个是agent默认启动的jnlp的容器用来agent和master链接的容器,所以上面咱们自己定义的容器名字的时候不能叫jnlp,不然就覆盖了默认的配置,只会启动一个咱们自己的jnlp,缺少链接容器,没人干活了就。会一直不停重启。
5.2 方式2的形式,写一个demo流水线测试
这次尝试pod模板创建不在界面上进行了,来pipleine里来直接创建。
pipeline {
agent {
kubernetes{
label "javapod"
cloud "kubernetes"
yaml '''
---
kind: Pod
apiVersion: v1
metadata:
labels:
k8s-app: k8s-slave-agent
name: jenkinsagent
namespace: nacos
spec:
containers:
name: jenkinsagent
image: jenkins/inbound-agent:4.10-3-jdk8
imagePullPolicy: IfNotPresent
'''
}
}
options {
skipDefaultCheckout()
}
stages {
stage('Hello') {
steps {
script{
sh 'sleep 15'
}
}
}
}
}
至此Jenkins基于Kubernets动态创建agent环境已经基本完成。 上面一些基本配置没有配置存储,只是跑了一个demo,后续也将更新最佳实践。
遇到的问题:
Q1: k8s动态创建agent,配置完运行demo流水线进行测试时报错:
INFO: Connecting to [http://192.168.1.28:50000](http://192.168.1.28:50000/)
Feb 10, 2023 1:36:30 AM hudson.remoting.jnlp.Main$CuiListener error
SEVERE: null
java.nio.channels.UnresolvedAddressException
at sun.nio.ch.Net.checkAddress(Net.java:104)
at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:621)
at java.nio.channels.SocketChannel.open(SocketChannel.java:189)
at org.jenkinsci.remoting.engine.JnlpAgentEndpoint.open(JnlpAgentEndpoint.java:206)
at hudson.remoting.Engine.connectTcp(Engine.java:880)
at hudson.remoting.Engine.innerRun(Engine.java:757)
at hudson.remoting.Engine.run(Engine.java:540)
nacos/javapod-2hl99-6klw2 Pod just failed (Reason: null, Message: null) </pre>
原因:可以看到是链接master的50000端口时报错了。分析:
1.远程50000端口无法访问,如果docker或者k8s为jenkins-master检查端口是否暴露出来了。没问题
2.防火墙原因或者安全组检查,远程telnet ip 50000。没问题
3.Jenkins Cloud上配置jenkins地址的时候一个是8080端口,地址http://jenkins_url:8080没错,另一个应该为50000端口,地址jenkins_url:50000(应该为tcp协议去访问,如果是http协议会有这个问题)并且这个50000端口需要控制端也要开启,*系统管理 -> 全局安全设置 ** ->代理-固定端口50000
解决:将http://jenkins_url:50000改成jenkins_url:50000 (jenkins_url替换为你的jenkins-master地址)
Q2: 最终测试流水线的时候,agent容器可以被正常创建出来,但是没有执行我的任务,并且一直自动重启;如果尝试用sleep等类似语句hold住容器 那么它是可以一直保持不退出 ,但是任务也不执行。
原因: Jenkins默认会启动一个用于agent和master链接的一个容器,叫jnlp。那么在Jenkins Cloud 上配置容器部分的时候,那个容器名也写成了jnlp
,这样就会冲突,导致最终创建的时候只创建一个jnlp这个容器,没有"干活"的容器了,所以会发生这个情况。
解决: 自定义容器名的话 ,避开jnlp
这个名字即可