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

目录

一、实验

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 备注
master1 K8S master节点 1.20.6 192.168.204.180

jenkins slave

(从节点)

node1 K8S node节点 1.20.6 192.168.204.181  
node2 K8S node节点 1.20.6 192.168.204.182  
jenkins

 jenkins主节点      

2.414.2 192.168.204.15:8080

 gitlab runner

(从节点)

  harbor私有仓库 1.2.2 192.168.204.15  
gitlab

gitlab 主节点       

12.10.14 192.168.204.8:82

jenkins slave

(从节点)

  sonarqube 9.6 192.168.204.8:9000  

 

2.GitLab 更新deployment文件

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

61c1cbe42f2d49a39e69240126b465b4.png持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第1张图片

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

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

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

 __INAGENAME__(镜像名称) 

(3)更新完成

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

(4)项目目录如下:

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

 

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

(1)查看项目架构

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

(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

32d8f31c58604548bdd6cc611ab8295d.png

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

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

d96aae45ce34497591dc6de5697a69c5.png

47a29171ffd848509def7e5d120697d6.png

 

5.Jenkins 构建前端项目

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

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

(2)Jenkins给前端项目CD流水线添加参数添加字符参数branchName持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第6张图片

 

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

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

(4)成功

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

5203e2aeeb5f4120bad2a3deb55945a2.png

 

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

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

(6) 构建前端项目CD流水线持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第10张图片

(7) 观察pod变化

8fdf0d54fe094e7fb1fb2982237a138d.png持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第11张图片持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第12张图片7e827018b4be476fb283aea9b6c353b1.png

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

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

26984850e4ae42cb85ff70b1384dea00.png

(9)不进行回滚

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

(10)完成

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

 

6.Jenkins 再次构建前端项目

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

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

(2)成功

持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第16张图片持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第17张图片

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

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

(4) 构建前端项目CD流水线持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第19张图片

(5) 观察pod变化

持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第20张图片持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第21张图片持续集成交付CICD:K8S 通过模板文件自动化完成前端项目应用发布_第22张图片

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

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

d3f58ce4df0740eca5618712df063206.png

(7)不进行回滚

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

(8)完成

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

 

二、问题

1. Jenkins 构建CI 流水线报错

(1)报错

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

(2)原因分析

函数名错误

(3)解决方法

修改函数名。

修改前:

c992530857914cc4b17c0812f0a39723.png

修改后:

b6b8a6fd3a634c7bbdbd28d7022b1b2e.png

 

 

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

(1)报错

dac675a89db84b22ba0cf1a0429db99a.png

(2)原因分析

script不允许使用静态方法

(3)解决方法

运行script使用静态方法

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

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

点击Approve

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

完成

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

重写构建项目成功

39907b913566440889afda475addf7a6.png

3. Jenkins 构建CD 流水线报错

(1) 报错

f0191d23859141a59087d93bd2538cb7.png

(2)原因分析

yaml文件格式错误

(3)解决方法

修改deploymeny模板文件

修改前:

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

修改后:

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

成功:

be3873f0b9da4f7386c365cc8c36caf2.png

 

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}"

 

 

你可能感兴趣的:(持续集成交付CICD,ci/cd,kubernetes,自动化)