目录
一、实验
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 替换文件
(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 2docker 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.yamlsed -i 's#__APPNAME__#${appName}#g' deployment.yamlsed -i 's#__NAMESPACE__#${namespace}#g' deployment.yamlsed -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}"breakcase "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) 构建前端项目CI流水线
(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替换成defcat 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/323)更改
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}"