持续集成及持续部署
在本方案中,需要在通过 code push 事件中触发 Jenkins 进行编译打包,通过邮件审批之后,将应用部署到 Kubernetes 集群中。
安装Jenkins插件
除了前文安装 Jenkins 时默认安装的插件外,还需要安装 GitLab Plugin,Kubernetes CLI,Email Extension插件,详情可以参考官方文档。
在Jenkins Dashboard页面单击左侧“Manage Jenkins”,选择“System Configuration > Manage Plugins”,在“Available”页签中筛选安装“GitLab”、“Kubernetes CLI”和“Email Extension Template”插件。
上述安装的插件版本可能随时间变化发生变动。
配置Gitlab Hook
当推送代码之后,Gitlab通过Webhook来通知Jenkins push event,所以首先需要配置Gitlab Hook。
- 登录Jenkins界面单击“New Item”,新建流水线。
- 复制URL,并单击高级选项。
- 单击“Generate”生成Token并记录,其他选项可保持默认,单击保存。
- 登录Gitlab启用webhook功能。
开启本地请求,因为 GitLab 10.6 版本以后为了安全,不允许向本地网络发送 WebHook 请求。
- 登录到 Gitlab-> java-demo项目中,左边列选择 Settings->webhook,在URL和 secret token 分别填入上文在 Jenkins 里记录下的值。
- 在页面最下端,确认添加 webhook,并进行测试。
邮件通知配置
邮件是Jenkins在消息通知、审批环节中比较通用的一种方式,本方案中也是选择邮件作为审批方式。
- 在“Manage Jenkins”,选择“System”。
- 配置邮箱基本信息,填写管理员邮箱地址。
其中password不是邮箱密码,而是邮箱授权码。
凭据配置
为了保证安全性,K8S 集群都必须通过 https 来访问。因此,需要在 Jenkins 上配置访问 K8S 集群的凭证。
- 获取K8S 集群客户端 kubeconfig 配置,可参考通过kubectl连接集群,获取kubectl配置文件。
- 登录Jenkins 页面,进入“Manage Jenkins”,选择“Security > Manage Credentials”,并通过 secret file 的方式创建集群凭证。
- 同理,重复以上步骤创建生产集群访问凭证。
Pipeline脚本编写
Pipeline是一套运行于Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排与可视化。其作为Jenkins2.X 最核心的特性,帮助Jenkins实现从CI到CD与DevOps的转变。因此,Pipeline脚本编写是整个方案实现的关键。
Pipeline脚本大致涉及到以下概念:
- node(节点)
- stage(阶段)
stage块定义了在整个流水线的不同执行阶段(比如 "Build", "Test" 和 "Deploy" 阶段),每个阶段执行一组特定的任务。
- step(步骤)
step是阶段中的单个任务,如运行测试、部署代码等。 告诉Jenkins在特定的时间点要做的事情,例如,执行一段shell命令。(更多的Jenkins Pipeline语法可参考官网:https://www.jenkins.io/zh/doc/book/pipeline/)
- 进入Jenkins的流水线,单击左侧导航栏的“Configuration”。
- 配置pipeline脚本。以下pipeline脚本仅供您参考,您可根据自身业务自定义脚本内容。
示例脚本中的部分参数需要修改:
- git_url:您Gitlab中代码仓库的SSH地址,需要替换为实际取值。
- swr_login:登录命令为获取长期的docker login命令获取的命令。
- swr_region:SWR的区域,填写实际使用的region。
- organization:SWR中的实际组织名称。
- build_name:制作的镜像名称。
- test_credential :添加到Jenkins的测试集群凭证,请填写凭证ID。如果需要部署在另一个集群,需要重新将这个集群的访问凭证添加到Jenkins,具体操作请参考设置集群访问凭证。
- prod_credential :添加到Jenkins的生产集群凭证,请填写凭证ID。如果需要部署在另一个集群,需要重新将这个集群的访问凭证添加到Jenkins,具体操作请参考设置集群访问凭证。
- test_apiserver :测试集群的APIserver地址,可参考通过kubectl连接集群。需保证从Jenkins集群可以正常访问该地址。
- prod_apiserver :生产集群的APIserver地址,可参考通过kubectl连接集群。需保证从Jenkins集群可以正常访问该地址。
- test_email:测试的邮箱地址。
- admin_email:审批人的邮箱地址。
#!groovy //定义代码仓地址 def git_url = 'ssh://git@xxxx:222/ccedemo/java-demo.git' //定义SWR登录指令 def swr_login = 'docker login -u cn-north-4@xxxx -p xxxxxx swr.cn-north-4.myhuaweicloud.com' //定义SWR区域 def swr_region = 'cn-north-4' //定义需要上传的SWR组织名称 def organization = 'testapp' //定义镜像名称 def build_name = 'demo01' //部署测试集群的证书ID def test_credential = 'test_config' //部署生产集群的证书ID def prod_credential = 'prod_config' //测试集群的APIserver地址,需保证从Jenkins集群可以正常访问该地址 def test_apiserver = 'https://xxx:5443' //生产集群的APIserver地址,需保证从Jenkins集群可以正常访问该地址 def prod_apiserver = 'https://xxxx:5443' // 邮箱地址 def test_email="xxxxx@xx.com" def admin_email="xxxx@xx.com" pipeline{ agent any stages{ stage('Git code'){ steps{ echo "1. Git code" git url: git_url script { // git rev-parse --short HEAD命令的返回值,即commit ID,作为镜像的tag build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim() image_url = "swr.${swr_region}.myhuaweicloud.com/${organization}/${build_name}:${build_tag}" } } } stage('Build') { steps{ echo "2. Build Docker Image Stage and Push Image" sh "docker build -t ${image_url} ." sh swr_login sh "docker push ${image_url}" // 替换k8s资源文件中的镜像地址 sh "sed -i 's+demo01:v1+${image_url}+g' ./demo01.yaml" } } stage('Deploy Test Enviroment') { steps{ //配置测试环境证书 withKubeCredentials echo "3. Deploy Test Enviroment" script { try { withKubeConfig([credentialsId: test_credential, serverUrl: test_apiserver]) { sh 'kubectl apply -f ./demo01.yaml' //该YAML文件位于代码仓中,此处仅做示例,请您自行替换 } println "deploy success" // 发送邮件给测试 mail subject: "【请测试】应用已部署到测试环境,请开始测试", body: """测试通过后, <a href="${BUILD_URL}input">单击该链接使用账号登录后确认测试通过</h3>""", charset: 'utf-8', mimeType: 'text/html', to: "$test_email" } catch (e) { RUN_FLAG = false println "deploy failed!" println e } } } } stage('Test'){ // 等待测试确认 input{ message "测试是否通过" submitter "admin" } steps{ script{ println "4. Test Passed" // 发送邮件给管理员 mail subject: "【请审核】发布到生产环境", body: """测试已通过, <a href="${BUILD_URL}input">单击该链接使用账号登录后进行审批</h3>""", charset: 'utf-8', mimeType: 'text/html', to: "$test_email" } } } stage('Approve'){ input{ message "是否发布到生产环境" submitter "admin" } steps{ script{ println "5. Approved and release it to the production environment." } } } stage('Deploy Produce Enviroment'){ steps{ echo "6. Deploy Produce Enviroment" script { try { withKubeConfig([credentialsId: prod_credential, serverUrl: prod_apiserver]) { sh 'kubectl apply -f ./demo01.yaml' //该YAML文件位于代码仓中,此处仅做示例,请您自行替换 } println "deploy success" } catch (e) { println "deploy failed!" println e } } } } }
- 单击保存后,完成整个项目的配置。
持续构建和部署
- 修改本地代码中的内容,进行提交,触发编译。
git add . && git commit -m "add template" && git push
- 切回 Jenkins 页面,可以看到项目已经自动触发编译构建。
- 大约等待几分钟后,收到测试邮件通知。
- 登录测试集群页面,java-demo工作负载已经创建。
- 本示例中认为升级测试通过,单击邮件中的链接,确认测试通过。
- 审核人邮箱中将会收到审批邮件。
- 由审核人决定可以部署生产环境,单击链接进入,并同意。
- 登录生产集群页面,java-demo工作负载已经创建,生产环境发布成功。