基于Jenkins和Kubernetes流水线实现应用的自动发版
本文我们将基于Jenkins和Kubernetes流水线过程实现自动化构建Java应用,即把流水线的过程转换为pipeline语法,实现应用的自动发版。
一、 创建Java测试用例
本书为读者准备了一个简单的Java测试用例,用于读者的学习,可以从 https://github.com/andanyoung/springboot-hello.git 找到该项目(也可以使用公司的Java项目)。
接下来将该项目导入自己的GitLab中。首先找到之前创建的Kubernetes组,然后单击New project,如图1所示。
图1 创建测试项目
选择Import project,如图2所示。
图2 导入项目
单击Repo by URL
图3 导入Java测试项目
在Git repository URL中输入示例地址,然后单击Create project,如图4所示。
图4 创建Project
导入后,结果如图5所示。
图5 查看导入的项目
二、定义Jenkinsfile
Jenkinsfile定义流水线的步骤包括拉取代码、执行构建、生成镜像、更新Kubernetes资源等。本书将Jenkinsfile放置于项目源代码一并管理,也可以单独放置于一个Git仓库进行管理。
接下来在GitLab的源代码中添加Jenkinsfile。首先单击代码首页的“+”,然后单击New file,如图6所示。
图6 添加文件
在窗口中添加如下内容(完整内容见本书代码):
pipeline {...parameters {gitParameter(branch: '', branchFilter: 'origin/(.*)', defaultValue: '', description: 'Branch for build and deploy', name: 'BRANCH', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH')}}
这个Jenkinsfile比较长,接下来我们分别解析一下。
三、 Jenkinsfile详解
首先是顶层的agent,定义Kubernetes的Pod作为Jenkins的Slave:
agent {# 定义使用Kubernetes作为agentkubernetes {选择的云为之前配置的名字cloud 'kubernetes-study'slaveConnectTimeout 1200#将workspace改成hostPath,因为该Slave会固定节点创建,如果有存储可用,可以改成PVC的模式workspaceVolume hostPathWorkspaceVolume(hostPath: "/opt/workspace", readOnly: false)yaml '''apiVersion: v1kind: Podspec:containers:# jnlp容器,和Jenkins主节点通信- args: ['$(JENKINS_SECRET)', '$(JENKINS_NAME)']image: 'registry.cn-beijing.aliyuncs.com/citools/jnlp:alpine'name: jnlpimagePullPolicy: IfNotPresentvolumeMounts: - mountPath: "/etc/localtime" name: "localtime" readOnly: false # build容器,包含执行构建的命令,比如Java的需要mvn构建,就可以用一个maven的镜像 - command: - "cat"env: - name: "LANGUAGE" value: "en_US:en" - name: "LC_ALL" value: "en_US.UTF-8" - name: "LANG" value: "en_US.UTF-8"# 使用Maven镜像,包含mvn工具。NodeJS可以用node的镜像image: "registry.cn-beijing.aliyuncs.com/citools/maven:3.5.3"imagePullPolicy: "IfNotPresent"# 容器的名字,流水线的stage可以直接使用该名字name: "build"tty: truevolumeMounts: - mountPath: "/etc/localtime" name: "localtime" # Pod单独创建了一个缓存的volume,将其挂载到了maven插件的缓存目录,默认是/root/.m2 - mountPath: "/root/.m2/" name: "cachedir" readOnly: false# 发版容器,因为最终是发版至Kubernetes的,所以需要有一个kubectl命令- command: - "cat"env: - name: "LANGUAGE" value: "en_US:en" - name: "LC_ALL" value: "en_US.UTF-8" - name: "LANG" value: "en_US.UTF-8"# 镜像的版本可以替换为其他的版本,也可以不替换,因为只执行set命令,所以版本是兼容的image: "registry.cn-beijing.aliyuncs.com/citools/kubectl:self-1.17"imagePullPolicy: "IfNotPresent"name: "kubectl"tty: truevolumeMounts: - mountPath: "/etc/localtime" name: "localtime" readOnly: false# 用于生成镜像的容器,需要包含docker命令- command: - "cat"env: - name: "LANGUAGE" value: "en_US:en" - name: "LC_ALL" value: "en_US.UTF-8" - name: "LANG" value: "en_US.UTF-8"image: "registry.cn-beijing.aliyuncs.com/citools/docker:20.10.9-git"imagePullPolicy: "IfNotPresent"name: "docker"tty: truevolumeMounts: - mountPath: "/etc/localtime" name: "localtime" readOnly: false # 由于容器没有启动docker服务,因此将宿主机的docker直接挂载至容器即可 - mountPath: "/var/run/docker.sock" name: "dockersock" readOnly: falserestartPolicy: "Never"# 固定节点部署nodeSelector:build: "true"securityContext: {}volumes:# Docker socket volume- hostPath: path: "/var/run/docker.sock"name: "dockersock"- hostPath: path: "/usr/share/zoneinfo/Asia/Shanghai"name: "localtime"# 缓存目录- name: "cachedir"hostPath: path: "/opt/m2"'''}
之后看一下Jenkinsfile最后的环境变量和parameters的配置:
# 定义一些全局的环境变量environment {COMMIT_ID = ""HARBOR_ADDRESS = "10.0.0.204" # Harbor地址REGISTRY_DIR = "kubernetes" # Harbor的项目目录IMAGE_NAME = "spring-boot-project" # 镜像的名称NAMESPACE = "kubernetes" # 该应用在Kubernetes中的命名空间TAG = "" # 镜像的Tag,在此用BUILD_TAG+COMMIT_ID组成}parameters {# 之前讲过一些choice、input类型的参数,本次使用的是GitParameter插件# 该字段会在Jenkins页面生成一个选择分支的选项gitParameter(branch: '', branchFilter: 'origin/(.*)', defaultValue: '', description: 'Branch for build and deploy', name: 'BRANCH', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH')}
接下来是拉取代码的stage,这个stage是一个并行的stage,因为考虑了该流水线是手动触发还是自动触发:
stage('Pulling Code') {parallel { stage('Pulling Code by Jenkins') { when { expression { # 若env.gitlabBranch为空,则该流水线为手动触发,执行该stage;若不为空,则会执行同级的另一个stage env.gitlabBranch == null } } steps { # 这里使用git插件拉取代码,BRANCH变量取自前面介绍的parameters配置 # git@xxxxxx:root/spring-boot-project.git代码地址 # credentialsId: 'gitlab-key',之前创建的拉取代码的key git(changelog: true, poll: true, url: 'git@xxxxxx:root/ spring-boot-project.git', branch: "${BRANCH}", credentialsId: 'gitlab-key') script { # 定义一些变量用于生成镜像的Tag # 获取最近一次提交的Commit ID COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim() # 赋值给TAG变量,后面的docker build可以取到该TAG的值 TAG = BUILD_TAG + '-' + COMMIT_ID println "Current branch is ${BRANCH}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}" } } } stage('Pulling Code by trigger') { when { expression { # 如果env.gitlabBranch不为空,说明该流水线是通过webhook触发的,则此时执行该stage,上述的stage不再执行。此时BRANCH变量为空 env.gitlabBranch != null } } steps { # 以下配置和前面一致,只是此时branch: env.gitlabBranch取的值为env.gitlabBranch git(url: 'git@xxxxxxxxxxx:root/spring-boot-project.git', branch: env.gitlabBranch, changelog: true, poll: true, credentialsId: 'gitlab-key') script { COMMIT_ID = sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim() TAG = BUILD_TAG + '-' + COMMIT_ID println "Current branch is ${env.gitlabBranch}, Commit ID is ${COMMIT_ID}, Image TAG is ${TAG}" } } }}}
代码拉下来后,就可以执行构建命令,由于本次实验是Java示例,因此需要使用mvn命令进行构建:
stage('Building') {steps { # 使用Pod模板里面的build容器进行构建 container(name: 'build') { sh """ # 编译命令,需要根据自己项目的实际情况进行修改,可能会不一致 mvn clean install -DskipTests # 构建完成后,一般情况下会在target目录下生成jar包 ls target/* """ }}}
生成编译产物后,需要根据该产物生成对应的镜像,此时可以使用Pod模板的docker容器:
stage('Docker build for creating image') {# 首先取出HARBOR的账号和密码environment { HARBOR_USER = credentials('HARBOR_ACCOUNT')}steps { # 指定使用docker容器 container(name: 'docker') { sh """ # 执行build命令,Dockerfile会在下一小节创建,也是放在代码仓库,和Jenkinsfile同级 docker build -t ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} . # 登录Harbor,HARBOR_USER_USR和HARBOR_USER_PSW由上述environment生成 docker login -u ${HARBOR_USER_USR} -p ${HARBOR_USER_PSW} ${HARBOR_ADDRESS} # 将镜像推送至镜像仓库 docker push ${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} """ }}}最后一步就是将该镜像发版至Kubernetes集群中,此时使用的是包含kubectl命令的容器:stage('Deploying to k8s') {# 获取连接Kubernetes集群证书 environment { MY_KUBECONFIG = credentials('study-k8s-kubeconfig')}steps { # 指定使用kubectl容器 container(name: 'kubectl'){ sh """ # 直接set更改Deployment的镜像即可 /usr/local/bin/kubectl --kubeconfig $MY_KUBECONFIG set image deploy -l app=${IMAGE_NAME} ${IMAGE_NAME}=${HARBOR_ADDRESS}/${REGISTRY_DIR}/${IMAGE_NAME}:${TAG} -n $NAMESPACE """ }}}}
注意
本例发版的命令为/usr/local/bin/kubectl --kubeconfig MYKUBECONFIGsetimagedeploy−lapp=MY_KUBECONFIG set image deploy -l app=MYKUBECONFIGsetimagedeploy−lapp={IMAGE_NAME} IMAGENAME={IMAGE_NAME}=IMAGENAME={HARBOR_ADDRESS}/REGISTRYDIR/{REGISTRY_DIR} /REGISTRYDIR/{IMAGE_NAME}基于Jenkins和Kubernetes流水线实现应用的自动发版相关推荐
- 基于 Jenkins 和 Kubernetes 的持续集成测试实践了解一下!
作者 | 刘春明,责编 | Carol 出品 | CSDN 云计算(ID:CSDNcloud) 封图 | CSDN下载于视觉中国 目前公司为了降低机器使用成本,对所有的AWS虚拟机进行了盘点,发现利用 ...
- 【有容云案例系列】基于Jenkins和Kubernetes的CI工作流
嘉宾介绍 黄文俊 有容云资深系统架构师 主要负责容器云平台产品架构及设计. 8年工作经验, 有着企业级存储, 云计算解决方案相关理解. 关注于微服务设计思考, 开发流程优化, docker及kuber ...
- git连接jenkins_基于 Jenkins 和 Kubernetes 的持续集成测试实践了解一下!
作者 | 刘春明 责编 | Carol 出品 | CSDN 云计算(ID:CSDNcloud) 封图| CSDN下载于视觉中国 目前公司为了降低机器使用成本,对所有的AWS虚拟机进行了盘点,发现利用率 ...
- 你公司的虚拟机还闲着?基于 Jenkins 和 Kubernetes 的持续集成测试实践了解一下!...
作者 | 刘春明 责编 | Carol 出品 | CSDN 云计算(ID:CSDNcloud) 封图| CSDN下载于视觉中国 目前公司为了降低机器使用成本,对所有的AWS虚拟机进行了盘点,发现利用率 ...
- 基于Jenkins的DevOps流水线实践教程
讲师介绍 课程寄语 我认为Jenkins是对我这些年运维经验的总结,起初我们运维同学都是编写脚本完成一些自动化的操作.而有了Jenkins我们可以将我们的运维经验与Jenkins设计理念融合完成自动化 ...
- 基于Jenkins的DevOps流水线实践教程|2020全新制作|端到端研发效能提升
讲师介绍 课程寄语 我认为Jenkins是对我这些年运维经验的总结,起初我们运维同学都是编写脚本完成一些自动化的操作.而有了Jenkins我们可以将我们的运维经验与Jenkins设计理念融合完成自动化 ...
- 基于Jenkins的DevOps流水线实践教程|2020全新制作|端到到研发效能提升
讲师介绍 课程寄语 我认为Jenkins是对我这些年运维经验的总结,起初我们运维同学都是编写脚本完成一些自动化的操作.而有了Jenkins我们可以将我们的运维经验与Jenkins设计理念融合完成自动化 ...
- Jenkins 流水线 获取git 分支列表_基于Jenkins的DevOps流水线实践课程
讲师介绍 课程寄语 我认为Jenkins是对我这些年运维经验的总结,起初我们运维同学都是编写脚本完成一些自动化的操作.而有了Jenkins我们可以将我们的运维经验与Jenkins设计理念融合完成自动化 ...
- Jenkins 流水线 获取git 分支列表_基于Jenkins的DevOps流水线实践
讲师介绍 课程寄语 我认为Jenkins是对我这些年运维经验的总结,起初我们运维同学都是编写脚本完成一些自动化的操作.而有了Jenkins我们可以将我们的运维经验与Jenkins设计理念融合完成自动化 ...
最新文章
- PNAS: 儿童生长发育迟缓 = 长期饥饿?
- Uber发布了Ludwig,一款不使用代码的人工智能开发工具
- 2.登录linun 输入密码登录不进去 进入单用户模式 修改 然后reboot
- 慕课网 javascript深入浅出编程练习
- tomcat运行报错Failed to start component [StandardEngine[Catalina].StandardHost[localhost].
- 如何使 highchart图表标题文字可选择复制
- mysql switch binlog_如何使用 Golang 处理 MySQL 的 binlog
- ERP failure: Error when opening an RFC connection
- nginx php iconv,Nginx +PHP部署一
- tiny4412u-boot烧写及根文件系统制作(不进入终端问题)
- P5707 【深基2.例12】上学迟到(python3实现)
- local lua 多个_Lua 级别 CPU 火焰图介绍
- Objective-C基础3:内存管理续
- 2021级C语言大作业 - 涂鸦跳跃
- ❤️《AOP》(Spring必备技能)
- 聊聊、Integer 封装特性
- 在myeclipse上设置 SVN过滤上传的文件类型
- OpenPose学习笔记
- js获取当前日期yyyymmdd
- 如何解决 Win10 卡顿的问题
热门文章
- Python鼠标点击图片,获取点击点的像素坐标/像素值
- 使用Python统计历年来各种英语高考题中单词的出现频数
- Win10 22H2更新时间 Win10 22H2怎么更新
- python自动录音程序
- 安卓APP测试要怎么测,测试流程和重点有哪些?我来告诉你
- PySide6 Widgets基本小部件类--QWidget
- 【Qbot】1.ChatGPT简介与Q群机器人部署教程
- 电脑怎么用c语言写丘比特,C语言丘比特#includebr/#includebr/ 爱问知识人
- github上实用、常用的插件和库
- 清华计算机系出了哪些牛人,清华大学16位学霸PK 简历吓坏网友