持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布

news2024/12/23 15:32:23

目录

一、实验

1.环境

2.GitLab 更新deployment文件

3.GitLab更新共享库前端项目CI与CD流水线

4.K8S查看前端项目版本

5.Jenkins 构建前端项目

6.Jenkins 再次构建前端项目

二、问题

1. Jenkins 构建CI 流水线报错

2. Jenkins 构建CI 流水线弹出脚本报错

3. Jenkins 构建CD 流水线报错

4.URL中特殊字符实现哪些功能

5.sed如何实现替换特殊字符


一、实验

1.环境

(1)主机

表1 主机

主机架构版本IP备注
master1K8S master节点1.20.6192.168.204.180

jenkins slave

(从节点)

node1K8S node节点1.20.6192.168.204.181
node2K8S node节点1.20.6192.168.204.182
jenkins

 jenkins主节点      

2.414.2192.168.204.15:8080

 gitlab runner

(从节点)

harbor私有仓库1.2.2192.168.204.15
gitlab

gitlab 主节点       

12.10.14192.168.204.8:82

jenkins slave

(从节点)

sonarqube9.6192.168.204.8:9000

2.GitLab 更新deployment文件

(1)项目新建目录,用于存放上传的deployment 替换文件

(2)准备更新模板文件deployment.yaml

 __APPNAME__(应用名称)对应Jenkins作业名称

 __NAMESPACE__ (名称空间)  对应业务名称

 __INAGENAME__(镜像名称) 

(3)更新完成

(4)项目目录如下:

3.GitLab更新共享库前端项目CI与CD流水线

(1)查看项目架构

(2)更新K8S CI流水线 (k8sci.jenkinsfile)

@Library("mylib@master") _
import org.devops.*


def checkout = new Checkout()
def build = new Build()
def unittest = new UnitTest()
def sonar = new Sonar()
def gitlabutil = new Gitlab()


pipeline {
    agent { label "build"}

    options {
        skipDefaultCheckout true
    }
    stages{
        stage("Checkout"){
            steps{
                script {
                    println("GetCode")
                    checkout.GetCode("${env.srcUrl}","${env.branchName}")
                }
            }
        }
        stage("build"){
            steps{
                script{
                    println("Build")
                    build.CodeBuild("${env.buildTool}")
                }
            }

        }

        stage("UnitTest"){
            steps{
                script{
                    println("Test")
                    unittest.CodeTest("${env.buildTool}")
                }
            }

        }
        stage("SonarScan"){
            steps {
                script {
                    groupName = "${JOB_NAME}".split("/")[0]
                    projectName ="${JOB_NAME}".split("/")[-1].split("_")[0]
                    sonar.CodeSonar("${env.buildTool}",projectName,groupName)
                }

            }

        }
        stage("PushImage"){
            steps {
                script {
                    repoName = "${JOB_NAME}".split("/")[0]
                    projectName ="${JOB_NAME}".split("/")[-1].split("_")[0]
                    env.registry = "192.168.204.15"
                    env.imageName = "${env.registry}/${repoName}/${projectName}:${env.branchName}"
                    withCredentials([usernamePassword(credentialsId: '8c662308-4991-4576-9826-74a5417de685', passwordVariable: 'DOCKER_PASSWD', usernameVariable: 'DOCKER_USER')]) {
                        sh """
                            #重写HTML首页
                            echo "${env.imageName}" > dist/index.html 
    
                            #构建镜像
                            docker build -t ${env.imageName} .
                           
                            #登录镜像仓库
                            docker login -u ${DOCKER_USER} -p ${DOCKER_PASSWD} ${env.registry}
                            
                            #上传镜像
                            docker push  ${env.imageName}
    
                            #删除镜像
                            sleep 2
                            docker rmi ${env.imageName}
                        """
                    }


                }

            }

        }

        stage("ReleaseFile"){
            steps{
                script{

                    // 获取模板文件
                    fileData = gitlabutil.GetRepoFile(22,"deployment.yaml", "master")
                    sh "rm -fr deployment.yaml"
                    writeFile file: 'deployment.yaml', text: fileData

                    // 替换模板文件内容
                    namespace = "${JOB_NAME}".split("/")[0]
                    appName ="${JOB_NAME}".split("/")[-1].split("_")[0]
                    sh """
                          sed -i 's#__PORT__#${env.port}#g' deployment.yaml
                          sed -i 's#__APPNAME__#${appName}#g' deployment.yaml
                          sed -i 's#__NAMESPACE__#${namespace}#g' deployment.yaml
                          sed -i 's#__IMAGENAME__#${env.imageName}#g' deployment.yaml
                    """

                    // 上传替换后的版本文件(新建文件或者更新文件)
                    newYaml = sh returnStdout: true, script: 'cat deployment.yaml'
                    println(newYaml)

                    //更新gitlab文件内容
                    base64Content = newYaml.bytes.encodeBase64().toString()

                    // 会有并行问题,同时更新报错
                    try {
                        gitlabutil.UpdateRepoFile(22,"${appName}%2f${env.branchName}.yaml",base64Content, "master")
                    } catch(e){
                        gitlabutil.CreateRepoFile(22,"${appName}%2f${env.branchName}.yaml",base64Content, "master")
                    }
                }
            }
        }
    }

}

(3)更新K8S CD流水线 (k8scd.jenkinsfile)

@Library("mylib@master") _
import org.devops.*



def gitlabbutil = new Gitlab()
env.groupName = "${JOB_NAME}".split("/")[0]
env.projectName ="${JOB_NAME}".split("/")[-1].split("_")[0]


pipeline {
    agent { label "k8s"}

    options {
        skipDefaultCheckout true
    }
    stages{
        stage("GetDeployFile"){
            steps{
                script {

                    env.appName = "${env.projectName}"
                    env.deployFile = "${env.appName}/${env.branchName}.yaml"
                    //println("GetCode")
                    fileData = gitlabbutil.GetRepoFile(22,"${env.appName}%2f${env.branchName}.yaml", "master")
                    //println(fileData)
                    sh "rm -fr ${env.deployFile}"
                    writeFile file: "${env.deployFile}", text: fileData
                    //sh "ls -l; cat deployment.yaml"
                    sh "ls -l "

                }
            }
        }

        stage("DeployAPP"){
            steps{
                script{
                    env.namespace = "${env.groupName}"
                    sh """
                        ## 发布应用
                        kubectl apply -f ${env.deployFile} -n ${env.namespace}
                    """

                    // 获取应用状态
                    5.times{
                        sh "sleep 2; kubectl -n ${env.namespace}  get pod | grep ${env.appName} "
                    }
                }
            }
        }

        stage("RollOut"){
            input {
                message "是否进行回滚"
                ok "提交"
                submitter "david,aa"
                parameters {
                    choice(choices: ['yes','no'], name: 'opts')
                    
                }

            }

            steps{
                script{
                    switch ("${opts}"){
                        case "yes":
                            sh " kubectl rollout undo deployment/${env.appName} -n ${env.namespace}"
                            break

                        case "no":
                            break

                    }
                }
            }
        }

    }
}

4.K8S查看前端项目版本

(1)外部测试访问(当前版本为1.1.7)

# curl http://devops03-devops-ui.devops.com:31291

(2)  另开一个终端用watch命令观察pod变化

# watch -n 1 "kubectl get pod -n devops03"

5.Jenkins 构建前端项目

(1)Jenkins给前端项目CI流水线添加参数添加字符参数port

(2)Jenkins给前端项目CD流水线添加参数添加字符参数branchName

(3) 构建前端项目CI流水线

(4)成功

(5)GitLab查看deployment部署文件已自动上传(RELEASE-1.1.5.yaml)

(6) 构建前端项目CD流水线

(7) 观察pod变化

(8)外部测试访问(当前版本为1.1.5)

# curl http://devops03-devops-ui.devops.com:31291

(9)不进行回滚

(10)完成

6.Jenkins 再次构建前端项目

(1) 构建前端项目CD流水线

(2)成功

(3)GitLab查看deployment部署文件已自动上传(RELEASE-1.1.6.yaml)

(4) 构建前端项目CD流水线

(5) 观察pod变化

(6)外部测试访问(当前版本为1.1.6)

# curl http://devops03-devops-ui.devops.com:31291

(7)不进行回滚

(8)完成

二、问题

1. Jenkins 构建CI 流水线报错

(1)报错

(2)原因分析

函数名错误

(3)解决方法

修改函数名。

修改前:

修改后:

2. Jenkins 构建CI 流水线弹出脚本报错

(1)报错

(2)原因分析

script不允许使用静态方法

(3)解决方法

运行script使用静态方法

根据弹出提示页面,点击进入。

点击Approve

完成

重写构建项目成功

3. Jenkins 构建CD 流水线报错

(1) 报错

(2)原因分析

yaml文件格式错误

(3)解决方法

修改deploymeny模板文件

修改前:

修改后:

成功:

4.URL中特殊字符实现哪些功能

(1)URL特殊字符

​
有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了。
编码的格式为:%加字符的ASCII码,即一个百分号%,后面跟对应字符的ASCII(16进制)码值。例如 空格的编码值是"%20"。
如果不使用转义字符,这些编码就会当URL中定义的特殊字符处理。

​

(2)URL特殊符号及编码 十六进制值

1) + URL 中+号表示空格 %2B
2) 空格 URL中的空格可以用+号或者编码 %20
3) / 分隔目录和子目录 %2F
4) ? 分隔实际的 URL 和参数 %3F
5) % 指定特殊字符 %25
6) # 表示书签 %23
7) & URL 中指定的参数间的分隔符 %26
8) = URL 中指定参数的值 %3D

5.sed如何实现替换特殊字符

(1)普通操作可以使用冒号(:)井号(#)正斜杠(/)来作为分隔符

sed -i 's#abc#def#g'  geng.file  ---将文件geng中的abc替换成def

cat geng.file | sed  's/abc/def/g'   ---打印文件geng,并将其中的abc替换成def

(2)对于变量做替换

sed 若是单引号括起来的,变量上得再额外加个单引号才能引用生效;

       若是双引号括起来的,可直接引用生效。

1)举例
pa='127.0.0.1/32'; field='ip_allow=123'; \
echo $field | sed 's#^ip_allow=.*#ip_allow=${pa}#g' 

结果:ip_allow=${pa}  --变量替换未生效

2)更改
echo $field | sed 's#^ip_allow=.*#ip_allow='${pa}'#g'

结果:ip_allow=127.0.0.1/32

3)更改
echo $field | sed "s#^ip_allow=.*#ip_allow=${pa}#g"

结果:ip_allow=127.0.0.1/32

(3) 特殊字符替换,反斜杠、正斜杠、双引号、$符

单个转义:多加个反斜杠做转义即可:反斜杠(\\)、正斜杠(\/)、双引号(\")

单转多个:参考如下列表

表2 特殊字符转换

实现目标方法能否用单引号还是双引号括起来
单引号双引号为什么
反斜杠(\)替换成两个反斜杠(\\)

sed -i 's#\\#\\\\#g' file

或sed -i 's:\\:\\\\:g' file

×反斜杠用双引号括起来会报错
反斜杠(\)替换成正斜杠(/)sed -i 's#\\#\/#g' file×反斜杠用双引号括起来会报错
双引号(")替换成两个双引号("")

sed -i 's#\"#\"\"#g' file

sed -i "s#\"#\"\"#g" file

单引号(')替换成两个单引号('')sed -i "s#'#''#g" file×不能用单引号括起来,分不清了
($)替换成\$sed -i 's:\$:\\\$:g' file×不能用双引号,否则会认为是$(正则匹配结尾位置)行的结果追加字符呢

(4)curl时用的变量,sed转化

curl -H 'Content-Type: application/json' -X POST -d 参数

(参数中涉及到特殊字符都得转义,而且要多转一层,即$得转成\\$,才能原封不动的供后续使用)
#值替换单引号、反斜杠、双引号 curl的时候用,多一层转义,所以\要用\\

sed -i "s#'#''#g" ${file}      ---单引号要转成两个单引号

sed -i 's#\\#\\\\\\\\#g' ${file}    ---反斜杠

sed -i "s:\":\\\\\":g" ${file}      ---双引号

sed -i 's:\$:\\\\\$:g' ${file}    ---$符

curl引用参数的这种形式有两种写法:

1)直接引用单个参数变量
curl -H 'Content-Type: application/json' -X POST -d '{"type":"0","name":" ' ${pa_name} ' "}'
这种需要对变量额外加上一个单引号,才能引用生效。

2)整个参数变量作为一个整体(推荐)
param="{\"type\":\"0\", \"name\":\"${pa_name}\"}"
curl -H 'Content-Type: application/json' -X POST -d "${param}"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1322644.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

长短期记忆(LSTM)神经网络-多输入分类

目录 一、程序及算法内容介绍: 基本内容: 亮点与优势: 二、实际运行效果: 三、部分程序: 四、完整程序下载: 一、程序及算法内容介绍: 基本内容: 本代码基于Matlab平台编译&am…

Linux-----17、软件包管理

# 软件包管理 # 1、软件包分类 # ㈠ 软件包类型 二进制包源码包 # ① 二进制包 什么是二进制包?有什么特点? 二进制包,指的是已经 1 好了的软件包,只需要直接安装就可以使用。二进制包,不需要编译,直接…

【人工智能革命】:AIGC时代的到来 | 探索AI生成内容的未来

🎥 屿小夏 : 个人主页 🔥个人专栏 : IT杂谈 🌄 莫道桑榆晚,为霞尚满天! 文章目录 📑前言一. AIGC 技术的概述和发展趋势1.1 AIGC 技术的概述1.2 AIGC 技术的发展趋势 二. AIGC 与元宇…

Java-基础部分(二)

一、抽象类 当编写一个类时,我们往往会为该类定义一些方法,这些方法是用来描述该类的行为方式,那么这些方法都有具体的方法体。 分析事物时,发现了共性内容,就出现向上抽取。会有这样一种特殊情况,就是功…

使用 React 实现自定义数据展示日历组件

目录 背景实现日历组件父组件数据 效果最后 背景 项目中需要实现一个日历组件,并且需要展示月,日所对应的数据(因为项目需求问题,就不统计年数据总量)。网上找了一堆,基本都不大符合项目需求,且…

计算机提示由于找不到vcruntime140_1.dll怎么办,那种修复方法推荐

首先,让我们来了解一下vcruntime140_1.dll是什么。其实,vcruntime140_1.dll是Visual C Redistributable Packages的一部分,它是由Microsoft Visual Studio编写的程序运行时库。它包含了许多用于运行Windows应用程序的函数和资源。因此&#x…

VueStu02-创建一个Vue实例

一、核心步骤 1.准备容器 准备一个盒子div。 2.引包 从官网引包,有开发版本和生产版本之分。 3.创建Vue实例 创建一个Vue实例,new Vue()。 4.指定配置项 指定配置项,用于渲染数据 。 el:指定挂载点。知道自己将来要管理的是…

Python实验作业,爬虫,中国院士信息

实验内容: 爬取中国工程院网页上,把每位院士的简介保存为本地文本文件,把每位院士的照片保存为本地图片,文本文件和图片文件都以院士的姓名为主文件名。 实验代码: import os.path import time from urllib.request …

干货教学!!!RHEL8中ansible中常用模块的使用

内容很长各位大老爷耐心观看 本章主要介绍ansible中最常见模块的使用 文件管理模块软件包管理模块服务管理模块磁盘管理模块用户管理模块防火墙管理模块 ansible的基本用法如下 ansible 机器名 -m 模块x -a “模块的参数” 对被管理机器执行不同的操作,只需要调…

git修改远程commit信息

git 修改远程commit信息 如果你已经把本地commit的信息push到远程了,此时需要修改远程中的commit信息 第一步:git log 查看提交的信息,看下提交的commit日志 如下入所示 第二步:然后确定你需要修改的那一次commit,比如&#xf…

LeetCode Hot100 51.N皇后

题目: 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回所有不同的 n 皇后问题 的…

Everything 搜索

正则表达式Regex 首先需要开启 Everything 工具在(字符串)查找时,对正则表达式功能的支持: 需要在【菜单栏】⇒ 【Search】⇒ 勾选【Enable Regex】 查看Everything 支持的语法:

统一大语言模型和知识图谱:如何解决医学大模型-问诊不充分、检查不准确、诊断不完整、治疗方案不全面?

统一大语言模型和知识图谱:如何解决医学大模型问诊不充分、检查不准确、诊断不完整、治疗方案不全面? 医学大模型问题如何使用知识图谱加强和补足专业能力?大模型结构知识图谱增强大模型的方法 医学大模型问题 问诊。偏离主诉和没抓住核心。…

强化学习--DQN

DQN 强化学习 DQN深度网络经验回放目标网络 深度网络 一个神经网络能够将输入向量映射到输出向量,这个映射过程可以用下式表示。 某种意义上来说,神经网络就是一个函数,只不过不同于一般的数值函数,它的输入输出都是向量&#x…

在vue中通过js动态绘制table,并且合并连续相同内容的行,支持点击编辑单元格内容

首先是vue代码 <template><div id"body-container"style"position: absolute"><div class"box-container"><div class"lsb-table-box" ><div class"table-container" id"lsb-table"&…

GO 的 socks5代理 编写

这里学习一下 socks5 代理的编写 网上有很多 学习一下 go 语言实战入门案例之实现Socks5 - 知乎 滑动验证页面 socks5协议原理学习-腾讯云开发者社区-腾讯云 (tencent.com) 首先我们要了解一下socks5的代理方式 socks5 是基于 认证建立连接转发数据 所形成的代理 我们只…

记录一下github深度学习的错误

1.[visdom]无法正常启动服务问题解决 在Anaconda命令窗口中&#xff1a; 使用python -m visdom.server启动visdom服务时&#xff0c;卡在&#xff1a; Checking for scripts. Downloading scripts, this may take a little while 无法下载和启动服务。 ERROR&#xff1a;由…

JS逆向实战——开发者工具检测

说明&#xff1a;仅供学习使用&#xff0c;请勿用于非法用途&#xff0c;若有侵权&#xff0c;请联系博主删除 作者&#xff1a;zhu6201976 一、背景 在JS逆向领域&#xff0c;Chrome开发者工具是核心&#xff0c;抓包、调试、看调用栈等都离不开它。可以说&#xff0c;逆向人…

PFA洗瓶耐温范围广应用化学实验耐强酸

PFA洗瓶&#xff1a;科技让实验更便捷 在实验室里&#xff0c;洗瓶是常用工具之一。而PFA洗瓶则是一种特殊塑料制作的洗瓶&#xff0c;它的外观半透明&#xff0c;方便观察液体。 PFA洗瓶的耐温范围非常广&#xff0c;可以承受-200℃到260℃的温度&#xff0c;这意味着它可以…

vmware离线安装docker-compose

vmware离线安装docker-compose 最近安装docker-compose&#xff0c;发现git取拉取&#xff0c;不是拒绝连接就是报443错误&#xff0c;或者其他错误 最后发现用包直接传上去好用&#xff0c;不用git拉取了 离线安装docker-compose 本文章给的docker-compose离线包&#xff0c;…