使用Jenkins自动化更新项目到K8S集群的方式
在前面的文章中,已经将know-system项目通过流水线自动化的打包成了Docker镜像,接下来,我们需要将这个镜像自动化的发布到K8S集群,完成项目的上线。
使用Jenkins自动化更新项目到K8S集群的方式
-
1.将资源yaml文件也上传到代码仓库,项目打完镜像后,可以通过替换deployment资源我们指定image的字符串,把最新版本的镜 像替换到deployment资源中,最后执行
kubectl apply -f ./
完成更新。 -
2.执行kubectl 命令更新deployment资源的镜像。
接下来会分别演示两种更新方式的pipeline流水线脚本的编写。
由于我们构建任务都是通过agent去运行的,agent部署在k8s node节点,继承了docker、kubectl命令,因此不必担心kubectl命令不能用。
一、针对项目有YAML编排文件的情况下编写的Pipeline脚本
1.实现思路
1.首先将know-system在k8s中进行部署,实现可以访问的状态。
2.将部署know-system的yaml文件复制到代码目录中,并将deployment资源中容器image对应的镜像改成一个字符串,这样pipeline更新时可以通过更换这个字符串,把最新的镜像版本替换到deployment资源中完成更新,最后将代码及部署文件推送到gitlab。
3.优化pipeline脚本,增加k8s部署步骤。
4.更新代码,使用流水线更新项目到k8s。
2.将know-system项目在K8S集群中部署
1)准备项目yaml文件
1.准备deployment资源
[root@k8s-master1 know-system]# cat nginx-depoly.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: know-system
namespace: know-system
spec:
replicas: 3
selector:
matchLabels:
app: know-system
template:
metadata:
labels:
app: know-system
spec:
containers:
- name: nginx
image: harbor.jiangxl.com/project/nginx-project:v1-code
ports:
- containerPort: 80
volumeMounts:
- name: nginx-data
mountPath: /data/code
- name: nginx-config
mountPath: /data/nginx/conf/conf.d/
volumes:
- name: nginx-config
configMap:
name: nginx-configmap
- name : nginx-data
persistentVolumeClaim:
claimName: pvc-know
readOnly: false
2.准备configmap资源
[root@k8s-master1 know-system]# cat nginx-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configmap
namespace: know-system
data:
know.jiangxl.com.conf: |
server {
listen 80;
server_name know.jiangxl.com;
location / {
root /data/code/know_system;
index index.html;
}
}
3.准备svc资源
[root@k8s-master1 know-system]# cat nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: know-system
spec:
selector:
app: know-system
type: NodePort
ports:
- port: 80
targetPort: 80
2)创建所有资源
[root@k8s-master1 know-system]# kubectl apply -f ./
configmap/nginx-configmap unchanged
deployment.apps/know-system configured
service/nginx-service configured
3)查看项目首页
3.将项目的YAML编排文件上传到Gitlab中
1.将部署文件复制到代码目录
[root@k8s-master1 know_system]# mkdir deploy
[root@k8s-master1 know_system]# cp /root/k8s1.19/know-system/* deploy/
2.修改deployment资源中的image
#将image对应的镜像改成一个字符串,pipeline更新时可以通过更换这个字符串把最新的镜像替换到deployment资源中
[root@k8s-master1 know_system]# vim deploy/nginx-depoly.yaml
image: {{updateimage}}
2.提交至gitlab
[root@k8s-master1 know_system]# git add .
[root@k8s-master1 know_system]# git commit -m "deploy"
[root@k8s-master1 know_system]# git push origin master
4.编写Pipeline流水线脚本将项目更新到K8S
pipeline {
agent { label 'Jenkins-slave1-107' } //让该pipeline始终运行在Jenkins-slave1-107 Jenkins agent节点上,因为这个节点所在的服务器可以运行k8s集群的docker、kubelet命令
environment { //environment主要用于定义环境变量,可以把一些常用到的值做成环境变量
IMAGE_REPO="harbor.jiangxl.com/project"
}
parameters { //定义参数化构建流程
gitParameter(name: 'VERSION',defaultValue: 'master',type: 'BRANCH',description: '选择要更新的分支') //定义一个gitparamters参数化构建过程,用于选择更新的代码
string(name: 'project',defaultValue: 'know-system',description: '项目名称',trim: true) //定义一个空白字符串,声明项目名称
}
stages { //定义pipeline执行阶段
stage('运维确认信息') { //阶段1,使用一个交互式,让运行确认更新信息,如果有误可直接退出更新,避免更新错误
steps {
input message: """
jobname: ${project}
branch: ${VERSION}""", ok: "更新" //交互式输出一个更新的项目和分支号
}
}
stage('拉取项目代码') { //阶段2,用于拉取git上对应的项目代码
steps {
checkout([$class: 'GitSCM', branches: [[name: '$VERSION']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-root', url: 'http://192.168.16.106:30080/root/know_system.git']]])
}
}
stage('构建项目镜像') { //阶段3.用于将项目代码更新到docker初始镜像中,主要步骤就是生产一个dockerfile,将代码复制到镜像中,最后根据Dockerfile构建出镜像
steps {
sh """
pwd
echo "
FROM harbor.jiangxl.com/project/nginx-project:v1-code
RUN mkdir /data/code/know_system
COPY ./* /data/code/know_system/
EXPOSE 80
" >Dockerfile
""" //编写一个Dockerfile,定义初始镜像,并将更新的代码复制到容器的指定路径
sh 'docker build -t ${IMAGE_REPO}/${project}:master-v${BUILD_ID} .' //最终镜像的名称就是harbor.jiangxl.com/project/know-system:master-v1
}
}
stage('推送镜像到harbor仓库') { //阶段4,将构建好的镜像推送至harbor仓库中,便于k8s拉取更新程序
steps {
sh 'docker push ${IMAGE_REPO}/${project}:master-v${BUILD_ID}' //推送镜像到harbor仓库
}
}
stage('将项目更新到k8s') { //阶段5,主要是更新k8s中项目使用的容器,将最新构建的镜像替换到项目pod中,然后更新pod
steps { //使用kubectl命令更新项目
sh "sed -i 's#{{updateimage}}#${IMAGE_REPO}/${project}:master-v${BUILD_ID}#g' deploy/*" //将deployment资源中我们写死的镜像版本字符串,替换成刚刚推送至harbor仓库的镜像版本
sh 'kubectl apply -f deploy/' //当镜像版本替换后,更新资源的yaml文件即可完成项目更新
}
}
}
post {
success { //构建成功了发送一个构成成功的消息到钉钉
echo "构建成功,发送消息到钉钉"
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text","text": {"content":"????????构建成功????????\n 关键字:jenkins\n 项目 名称: ${JOB_BASE_NAME}\n 更新的分支号: ${VERSION}\n 本次构建的镜像版本:${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n 构建地址:${RUN_DISPLAY_URL} "}}'
"""
}
failure { //构建失败了发送一个构成成功的消息到钉钉
echo "构建失败,发送消息到钉钉"
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text","text": {"content":"????❌构建失败❌????\n 关键字:jenkins\n 项目 名称: ${JOB_BASE_NAME}\n 更新的分支号: ${VERSION}\n 本次构建的镜像版本:${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n 构建地址:${RUN_DISPLAY_URL} "}}'
"""
}
always { //无论成功还是失败都执行此步骤
echo "构建流程结束"
}
}
}
5.将Pipeline脚本粘贴到流水线任务中
6.构建master分支完成项目上线
1)选择更新信息
2)运维确认信息
3)pipeline任务更新成功
4)在blue ocean查看此次更新的镜像版本
5)在rancher上观察项目是否更新成最新的镜像版本
更新流程顺利完成!
二、针对K8S集群中的项目没有编排文件的Pipeline编写
1.实现思路
1.基于a中的pipeline脚本,多增加几个参数化构建string类型的构建流程,声明项目所在的namespace、项目使用的资源控制器类型、项目使用的容器名称。
2.通过kubectl set image方式更新资源镜像,其中需要指定项目所在的namespace、资源控制器类型、容器名称,由于这些值将来可能会发生变化,因此就需要通过参数化构建形成以变量方式来调度。
2.编写Pipeline流水线脚本
pipeline {
agent { label 'Jenkins-slave1-107' } //让该pipeline始终运行在Jenkins-slave1-107 Jenkins agent节点上,因为这个节点所在的服务器可以运行k8s集群的docker、kubelet命令
environment { //environment主要用于定义环境变量,可以把一些常用到的值做成环境变量
IMAGE_REPO="harbor.jiangxl.com/project"
}
parameters { //定义参数化构建流程
gitParameter(name: 'VERSION',defaultValue: 'master',type: 'BRANCH',description: '选择要更新的分支') //定义一个gitparamters参数化构建过程,用于选择更新的代码
string(name: 'project_namespace',defaultValue: 'know-system',description: '项目所在的命名空间',trim: true) //声明项目所在的命名空间
string(name: 'project_kind',defaultValue: 'deployment',description: '项目资源所使用的pod控制器',trim: true) //声明项目资源使用的pod控制器类型
string(name: 'container_name',defaultValue: 'nginx',description: '项目所使用的pod容器名称',trim: true) //声明项目使用pod的容器名称
string(name: 'project',defaultValue: 'know-system',description: '项目名称',trim: true) //声明项目名称
}
stages { //定义pipeline执行阶段
stage('运维确认信息') { //阶段1,使用一个交互式,让运行确认更新信息,如果有误可直接退出更新,避免更新错误
steps {
input message: """
jobname: ${project}
branch: ${VERSION}""", ok: "更新" //交互式输出一个更新的项目和分支号
}
}
stage('拉取项目代码') { //阶段2,用于拉取git上对应的项目代码
steps {
checkout([$class: 'GitSCM', branches: [[name: '$VERSION']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-root', url: 'http://192.168.16.106:30080/root/know_system.git']]])
}
}
stage('构建项目镜像') { //阶段3.用于将项目代码更新到docker初始镜像中,主要步骤就是生产一个dockerfile,将代码复制到镜像中,最后根据Dockerfile构建出镜像
steps {
sh """
pwd
echo "
FROM harbor.jiangxl.com/project/nginx-project:v1-code
RUN mkdir /data/code/know_system
COPY ./* /data/code/know_system/
EXPOSE 80
" >Dockerfile
""" //编写一个Dockerfile,定义初始镜像,并将更新的代码复制到容器的指定路径
sh 'docker build -t ${IMAGE_REPO}/${project}:master-v${BUILD_ID} .' //最终镜像的名称就是harbor.jiangxl.com/project/know-system:master-v1
}
}
stage('推送镜像到harbor仓库') { //阶段4,将构建好的镜像推送至harbor仓库中,便于k8s拉取更新程序
steps {
sh 'docker push ${IMAGE_REPO}/${project}:master-v${BUILD_ID}' //推送镜像到harbor仓库
}
}
stage('将项目更新到k8s') { //阶段5,主要是更新k8s中项目使用的容器,将最新构建的镜像替换到项目pod中,然后更新pod
steps { //由于项目是通过rancher创建,没有任何yaml文件,因此通过使用kubectl命令更新项目
sh 'kubectl -n ${project_namespace} set image ${project_kind} ${project} ${container_name}=${IMAGE_REPO}/${project}:master-v${BUILD_ID} --record' //通过kubectl命令升级控制器所使用的镜像版本,kubectl -n 命名空间 set image 控制器类型 控制器名称 容器名称=新的镜像版本
}
}
}
post {
success { //构建成功了发送一个构成成功的消息到钉钉
echo "构建成功,发送消息到钉钉"
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text","text": {"content":"????????构建成功????????\n 关键字:jenkins\n 项目 名称: ${JOB_BASE_NAME}\n 更新的分支号: ${VERSION}\n 本次构建的镜像版本:${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n 构建地址:${RUN_DISPLAY_URL} "}}'
"""
}
failure { //构建失败了发送一个构成成功的消息到钉钉
echo "构建失败,发送消息到钉钉"
sh """
curl 'https://oapi.dingtalk.com/robot/send?access_token=6719ac958daf4f31114cb0c1289837c9aca45d111d8653b04c3d6ae164f25146' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text","text": {"content":"????❌构建失败❌????\n 关键字:jenkins\n 项目 名称: ${JOB_BASE_NAME}\n 更新的分支号: ${VERSION}\n 本次构建的镜像版本:${IMAGE_REPO}/${project}:master-v${BUILD_ID}\n 构建地址:${RUN_DISPLAY_URL} "}}'
"""
}
always { //无论成功还是失败都执行此步骤
echo "构建流程结束"
}
}
}
3.将Pipeline脚本复制到Jenkins中
粘贴进去之后,首先先运行一下任务,让pipeline中定义的参数化构建生效。
4.构建master分支完成项目更新
1)填写好项目信息开始构建
2)运维确认信息
3)项目更新成功钉钉消息也已经发送
此次更新的镜像版本号是53
4)查看rancher上项目是否成功更新到53
项目更新成功