写点什么

(项目实战)如何结合 k8s 和 pipeline 的流水线,并通过 k8s 接口完成镜像升级

用户头像
极客good
关注
发布于: 刚刚

checkout([class: 'RelativeTargetDirectory', relativeTargetDir: 'DEPLOYJAVA']], //DEPLOYJAVA: 把代码存放到此目录中 userRemoteConfigs: [[credentialsId: 'chenf-o', url: '构建脚本的仓库地址']]])}}}}}stage('Set Env') {steps {script {date_time = sh(script: "date +%Y%m%d%H%M", returnStdout: true).trim()git_cm_id = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim()whole_img_addr = "{date_time}_{git_cm_id}"}}}stage('Complie Code') {steps {script {withMaven(maven: 'maven_latest_linux') {sh "mvn -U package -am -amd -P{env_name} -pl {pom_dir}"}}}}stage('Build image') {steps {script {dir("{env.WORKSPACE}/${pom_dir}") {sh """echo 'FROM 基础镜像地址' > Dockerfile //由于我这里进行了镜像的优化,只指定一个基础镜像地址即可,后面会详细的说明"""withCredentials([usernamePassword(credentialsId: 'faabc5e8-9587-4679-8c7e-54713ab5cd51', passwordVariable: 'img_pwd', usernameVariable:


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


'img_user')]) {sh """docker login -u {img_pwd} {img_addr}:{date_time}_{git_cm_id} .docker push {whole_img_addr}"""}}}}}stage('Deploy img to K8S') {steps {script {dir('DEPLOYJAVA/deploy') {//执行构建脚本sh """/usr/local/python3/bin/python3 deploy.py -n {server_name} -s {whole_img_addr} -c {cluster_name}"""}}}// 做了下判断如果上面脚本执行失败,会把上面阶段打的镜像删除掉post {failure {sh "docker rmi -f {whole_img_addr}"}}}stage('Clear somethings') {steps {script {// 删除打的镜像 sh "docker rmi -f ${whole_img_addr}"}}post {success {// 如果上面阶段执行成功,将把当前目录删掉 deleteDir()}}}}}

优化构建镜像

上面的 pipeline 中有一条命令是生成Dockerfile的,在这里做了很多优化,虽然我的Dockerfile就写了一个FROM,但是在这之后又会执行一系列的操作,下面我们对比下没有做优化的Dockerfile 未优化


FROM 基础镜像地址 RUN mkdir xxxxxCOPY *.jar /usr/app/app.jarENTRYPOINT java -jar app.jar


优化后的


FROM 基础镜像地址


优化后的Dockerfile就这一行就完了。。。。。 下面简单介绍下这个ONBUILDONBUILD 可以这样理解,就比如我们这里使用的镜像,是基于 java 语言做的一个镜像,这个镜像有两部分,一个是包含 JDK 的基础镜像 A,另一个是包含 jar 包的镜像 B,关系是先有 A 再有 B,也就是说 B 依赖于 A。假设一个完整的基于 Java 的 CICD 场景,我们需要拉代码,编译,打镜像,推镜像,更新 pod 这一系列的步骤,而在打镜像这个过程中,我们需要把编译后的产物 jar 包 COPY 到基础镜像中,这就造成了,我们还得写一个 Dockerfile,用来 COPY jar 包,就像下面这个样子:


FROM jdk 基础镜像 COPY xxx.jar /usr/bin/app.jarENTRYPOINT java -jar app.jar


这样看起来也还好,基本上三行就解决了,但是能用一行就解决为什么要用三行呢?


FROM jdk 基础镜像 ONBUILD COPY target/*.jar /usr/bin/app.jarCMD ["/start.sh"]


打成一个镜像,比如镜像名是:java-service:jdk1.8,在打镜像的时候,ONBUILD后面的在本地打镜像的过程中不会执行,而是在下次引用时执行的


FROM java-service:jdk1.8


只需要这一行就可以了,并且这样看起来更加简洁,pipeline看起来也很规范,这样的话,我们每一个 java 的服务都可以使用这一行 Dockerfile 了。

使用凭据

有时候使用 docker 进行 push 镜像时需要进行认证,如果我们直接在 pipeline 里写的话不太安全,所以得进行脱敏,这样的话我们就需要用到凭据了,添加凭据也是非常简单,由于我们只是保存我们的用户名和密码,所以用Username with password类型的凭据就可以了,如下所示



比如说:拉取 git 仓库的代码需要用到,然后这里就添加一个凭据,对应与 pipeline 里的下面这段内容:


stage('Pull server code') {steps {script {checkout([{Branch}']],userRemoteConfigs: [[credentialsId: "{git_addr}"]]])}}}


这里的变量${git_auth}就是添加凭据时设置的ID,如果不设置ID会随机生成一个ID


然后docker push时会需要进行认证,也需要添加凭据,添加方式和上面是一样的,不过我们可以用 pipeline 的语法来生成一个,方式如下: 点击Pipeline Syntax



选择withCredentials: Bind credentials to variables



然后和之前添加的凭据进行绑定,这里选择类型为:Username and password (separated)



设置用户名和密码的变量名,然后选择刚才添加好的凭据



点击生成即可,就是上面 pipeline 里的下面这段:


withCredentials([usernamePassword(credentialsId: 'faabc5e8-9587-4679-8c7e-54713ab5cd51', passwordVariable: 'img_pwd', usernameVariable: 'img_user')]) {sh """docker login -u {img_pwd} {img_addr}:{date_time}_{git_cm_id} .docker push ${whole_img_addr}"""}


credentialsId: 这个 ID 就是随机生成的 ID

执行脚本进行更新镜像

这里是使用 python 写了一个小脚本,来调用 kubernetes 的接口做了一个patch的操作完成的。先来看下此脚本的目录结构



核心代码:deploy.py核心文件:config.yaml 存放的是 kubeconfig 文件,用于和 kubernetes 的认证


下面贴一下deploy.py的脚本内容,可以参考下:


import osimport argparsefrom kubernetes import client, config


class deployServer:def init(self, kubeconfig):self.kubeconfig = kubeconfigconfig.kube_config.load_kube_config(config_file=self.kubeconfig)self._AppsV1Api = client.AppsV1Api()self._CoreV1Api = client.CoreV1Api()self._ExtensionsV1beta1Api = client.ExtensionsV1beta1Api()


def deploy_deploy(self, deploy_namespace, deploy_name, deploy_img=None, deploy_which=1):try:old_deploy = self._AppsV1Api.read_namespaced_deployment(name=deploy_name,namespace=deploy_namespace,)old_deploy_container = old_deploy.spec.template.spec.containerspod_num = len(old_deploy_container)if deploy_which == 1:pod_name = old_deploy_container[0].nameold_img = old_deploy_container[0].imageprint("获取上一个版本的信息\n")print("当前 Deployment 有 {} 个 pod, 为: {}\n".format(pod_num, pod_name))print("上一个版本的镜像地址为: {}\n".format(old_img))print("此次构建的镜像地址为: {}\n".format(deploy_img))print("正在替换当前服务的镜像地址....\n")old_deploy_container[deploy_which - 1].image = deploy_imgelse:print("只支持替换一个镜像地址")exit(-1)new_deploy = self._AppsV1Api.patch_namespaced_deployment(name=deploy_name,

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
(项目实战)如何结合k8s和pipeline的流水线,并通过k8s接口完成镜像升级