K8S结合Jenkins实现持续集成的动态配置详情分享
大家好,我是阿博,是一名全栈工程师,这是公众号的第一篇推文。
开通订阅号的主要目的是跟大家一起分享自己在产品研发过程中曾经遇到的技术难题以及解决办法。
如对内容有其他理解、疑问,或是不同的看法和好的建议,咱们可以私底下多交流、多对接,欢迎指教。
经验分享,希望能对大家有所帮助,后续也会继续努力写出好的文章。
前言:
Kubernetes,简称K8s,相信大家都不会陌生。这是一个开源的,用于管理云平台中多个主机上的容器化的应用。Jenkins,是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续集成。
在程序员日常的开发当中,使用着各种不同的编程语言,流程中少不了开发、测试、打包、发布等等的步骤,这其中的部分环节,是重复且必须的工作。
所以慢慢地引入了持续集成的概念,从而减轻开发人员,运维人员的操作和时间成本,更好地服务好我们的程序猿(嗷嗷嗷 ~ 程序员太苦啦,是时候来点甜啦~)。
接下来让我来给大家分享一下,如何结合K8S和Jenkins可以实现快速地实现以上的一些重复性且必要的工作,让我们的攻城狮更好地专注在开发工作当中!
前置环境条件:1、已经有部署好的K8S集群环境;2、已经在K8S环境中已经部署好Jenkins应用;3、代码仓库(如gitlab、GitHub等)已经通过webhook等方式,和Jenkins能进行通讯;4、jenkins添加好代码仓库对应的流水线作业。
1、登录到Jenkins UI进行模版配置
登录到Jenkins – 左菜单(系统设置) – 节点管理 – Configure Clouds,进行模版的配置
1.1 编辑Kubernetes模版
第一页详细配置如上图,基本都是用默认值即可,有几个地方需要根据实际的集群信息进行填写就可以啦,挺简单的!!
1.2 编辑pod模版
2-1和2-2是pod模版的名称和模版标签
第二页详细配置如上图,按照上图说明即可。俗话说,工欲善其事,必先利其器,至此,jenkins的模版关键配置已经完成啦,接下来就是使用这些模版的时候啦,请继续往下阅读!!
2、可持续集成配置
2.1 Jenkinsfile使用详解
这里的lable是上面的标签设置的值
//模板需要修改的值:label(配置的jenkins的slave标签),cloud:(配置的jenkins的cloud)
//定义变量
def label = "jenkins-slave-js"
//设置pod模版的信息,label是模版标签,cloud是第一步设置的jenkins模版名
//以下操作都是在打包容器里面进行,内容可以高度自定义,贴合不同的需求
podTemplate(label: label , cloud: kubernetes) {
node(label) {
//拉取仓库代码
def myRepo = checkout scm
def gitBranch = myRepo.GIT_BRANCH.replaceAll("origin/","").replaceAll("/","-").replaceAll("\\.","-")
def timestamp = sh(script: "echo `date +%Y%m%d%H%M%S`", returnStdout: true).trim()
def gitCommit = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim()
gitCommit = "${gitCommit}_${timestamp}"
//镜像标签,这里使用git分支名作为镜像的tag
def imageTag = "${gitBranch}"
//镜像仓库基础地址
def dockerRegistryUrl = "http://xxxxx"
//应用服务名称,统一用于以下各个变量名称
def appName = "testAbc"
//模板需要更改的值 开始
//helm工具发布时,使用的名称,这里使用【应用名-分支名】的格式
def helmReleaseName = "${appName}-${gitBranch}"
//部署应用服务的命名空间
def namespace = "${appName}"
//镜像的中间名称,用于平均基础镜像地址
def imageEndpoint = "${appName}/webapi"
//模板需要更改的值 结束
//完整镜像地址(不包含镜像tag)
def image = "${dockerRegistryUrl}/${imageEndpoint}"
//helmChart模版的仓库名称
def chartName = "${appName}"
//helmChart的版本
def chartVersion = "1.0"
//helmChart完整名称
def chartDirName = "${appName}/${appName}"
//K8S的网络模式,一般有Cluster(不对外访问)、NodePort(释放端口对外访问)
def serviceType = "ClusterIP"
//如果serviceType值是NodePort,这里可以设置指定供对外访问的端口号,不指定则随机,范围详见K8S的NodePort范围,默认是30000-32767
def serviceNodePort = ""
//是否使用外部K8S存储,是则设置true,否则设置false
def createPvc = true
//如果设置了使用外部存储,则这里需要填写k8s的PVC资源的名称,以便以发布的应用服务能绑定此外部存储
def pvcName = "${gitBranch}-${appName}-configs-pvc"
//设置外部存储对应应用服务容器里面的路径
def pvcMountPath = "/var/www/${appName}/storage"
//定义不同阶段,可以方便清晰地在jenkins UI上看到每个阶段的耗时
stage(单元测试阶段) {
script{
}
}
stage(项目编译阶段) {
//此处使用container指定第二步配置的容器名称,就可以使用该容器环境的命令进行操作,如下面命令是前端node编译代码
container("node"){
sh "npm build ./main"
sh "npm run serve"
}
}
stage(构建 Docker 镜像阶段) {
container(构建 Docker 镜像) {
withCredentials([[$class: UsernamePasswordMultiBinding,
credentialsId: docker-harbor,
usernameVariable: DOCKER_HUB_USER,
passwordVariable: DOCKER_HUB_PASSWORD]]) {
//此处是引入了docker环境,进行docker的打包,推送到远程仓库等操作
container(docker) {
sh """
docker login ${dockerRegistryUrl} -u ${DOCKER_HUB_USER} -p ${DOCKER_HUB_PASSWORD}
docker build -t ${imageEndpoint}:${imageTag} .
docker tag ${imageEndpoint}:${imageTag} ${dockerRegistryUrl}/${imageEndpoint}:${imageTag}
docker push ${image}:${imageTag}
"""
}
}
}
}
//K8S使用了helm发布工具进行应用服务的发布
stage(Helm 部署阶段) {
withCredentials([[$class: UsernamePasswordMultiBinding,
credentialsId: docker-harbor,
usernameVariable: DOCKER_HUB_USER,
passwordVariable: DOCKER_HUB_PASSWORD]]) {
container(helm) {
// 这里也可以做一些其他的分支判断是否要直接部署
echo "[INFO] 开始 Helm 部署"
echo "1 初始化helm client"
sh "helm init --client-only --stable-repo-url https://mirror.azure.cn/kubernetes/charts/"
//添加打包容器里面的本地helm仓库
sh "helm repo add --username ${DOCKER_HUB_USER} --password ${DOCKER_HUB_PASSWORD} ${chartName} http://${dockerRegistryUrl}/chartrepo/${chartName}"
echo "2 如果更新了chart包则需要更新repo仓库"
sh "helm repo update"
echo "3 更新 ${helmReleaseName} 应用服务"
sh """
helm upgrade --install ${helmReleaseName} ${chartDirName} \
--version ${chartVersion} \
--set namespace=${namespace} \
--set gitCommit=${gitCommit} \
--set gitBranch=${gitBranch} \
--set productionDeployment.image.repository=${image} \
--set canaryDeployment.image.repository=${image} \
--set productionDeployment.image.tag=${imageTag} \
--set canaryDeployment.image.tag=master \
--set createPvc=${createPvc} \
--set pvcName=${pvcName} \
--set pvcMountPath=${pvcMountPath} \
--set service.type=${serviceType} \
--set service.nodePort=${serviceNodePort} \
--namespace=${namespace}
"""
echo "[INFO] Helm 部署应用成功..."
}
}
}
}
至此,我们已经完成配置好jenkins模版和jenkinsfile完整的一套可持续集成系统的工作,我们后续开发时,只需要合并好代码,触发webhook流水线,通知jenkins进行打包、发布、部署的操作即可,实现真正解放我们的双手啦!!哈哈哈~
以上是本期分享的全部内容,不知道大家有没有成功配置?
欢迎各位在评论区留言,大家的支持就是我的动力!
Jenkins master位于k8s集群外,实现jenkins slave的动态构建、k8s+jenkins中使用自定义maven镜像两篇文章实现了K8S+Jenkins+Maven基础环境,通过此环境我们进一步实现SpringBoot项目的CI/CD。
K8S+Jenkins+Maven基础环境目前能够实现:
- Jenkins slave在K8S集群内的动态构建;
- Maven实现编译、打包、构建镜像并push到远程docker仓库;
剩下的工作需在Jenkins流水线中调用kubectl 命令实现SpringBoot项目在K8S中部署了。
要想Jenkins能够调用kubectl命令,需要安装相关插件,下面我们来介绍下。
Kuberntes相关插件
Jenkins中有两个插件可以实现与Kubernetes进行交互。
一、Kubernetes CLI
此插件允许在Jenkins Job中通过kubectl与k8s集群进行交互,主要是通过kubectl执行各种命令。
1.安装Kubernetes CLI插件
2.通过"Snippet Generator"生成指令
通过"withKubeConfig: Configure Kubernetes CLI"来使用插件:
- Credentials:使用前面文章在devops命令空间中的sa--jenkins
- Kubernetes server endpoint:k8s api server;
- Namespace:需要执行命令的命名空间;
3.添加需要执行的命令
withKubeConfig(caCertificate:, clusterName:, contextName:, credentialsId:k8s-jenkins-slave,namespace:
K8S+Jenkins实现SpringBoot项目CI—CD
下一篇主题简介 手把手搭建一套K8s集群,同时了解一下K8s一些基础概念。如何使用Artifactory制品库作为K8s的镜像中心。最后集合CI工具Jenkins集成K8s,实现Jenkins资源的动态分配,并完成一条容器云上CI&CD流水线
课程大纲
K8s遇上Jenkins&制品库