目录
一、实验
1.Jenkins使用GitLab共享库实现基于SaltStack的CD流水线部署前后端应用
2.优化共享库代码
二、问题
1.Jenkins手动构建后端项目流水线报错
(1)GitLab共享库更新代码
① 更新共享库目录结构
② 修改制品类Artifacts.grovvy
package org.devops
//上传制品
def PushRawArtifacts(repoName,targetDir, filePath, pkgName,type ){
withCredentials([usernamePassword(credentialsId: '318df1ad-083b-4158-ac88-2f584446563e', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) {
sh """
curl -X POST "http://192.168.204.13:8081/service/rest/v1/components?repository=${repoName}" \
-H "accept: application/json" \
-H "Content-Type: multipart/form-data" \
-F "raw.directory=${targetDir}" \
-F "raw.asset1=@${filePath}/${pkgName};type=${type}" \
-F "raw.asset1.filename=${pkgName}" \
-u "${USER}":"${TOKEN}"
"""
}
}
//下载制品
def PullArtifacts(version,projectName,repoName,type){
withCredentials([usernamePassword(credentialsId: '318df1ad-083b-4158-ac88-2f584446563e', passwordVariable: 'TOKEN', usernameVariable: 'USER')]) {
repoUrl = "http://192.168.204.13:8081/repository"
pkgPath = "${repoUrl}/${repoName}/${projectName}/${version}/${projectName}-${version}.${type}"
sh "wget --http-user=${user} --http-passwd=${TOKEN} ${pkgPath} -q"
}
}
③ 修改文件类Gitlab.groovy
package org.devops
// 封装HTTP
def HttpReq(reqType, reqUrl,reqBody ){
def gitServer = "http://192.168.204.8:82/api/v4"
withCredentials([string(credentialsId: '02dce3ff-4e46-4de2-b079-5dd6093d4f64', variable: 'GITLABTOKEN')]) {
response = httpRequest acceptType: 'APPLICATION_JSON_UTF8',
consoleLogResponseBody: true,
contentType: 'APPLICATION_JSON_UTF8',
customHeaders: [[maskValue: false, name: 'PRIVATE-TOKEN', value: "${GITLABTOKEN}"]],
httpMode: "${reqType}",
url: "${gitServer}/${reqUrl}",
wrapAsMultipart: false,
requestBody: "${reqBody}"
}
return response
}
//获取文件内容
def GetRepoFile(projectId,filePath, branchName ){
//GET /projects/:id/repository/files/:file_path/raw
apiUrl = "/projects/${projectId}/repository/files/${filePath}/raw?ref=${branchName}"
response = HttpReq('GET', apiUrl, "")
return response.content
}
//更新文件内容
def UpdateRepoFile(projectId,filePath,fileContent, branchName){
apiUrl = "projects/${projectId}/repository/files/${filePath}"
reqBody = """{"branch": "${branchName}","encoding":"base64", "content": "${fileContent}", "commit_message": "update a new file"}"""
response = HttpReq('PUT',apiUrl,reqBody)
println(response)
}
//创建文件
def CreateRepoFile(projectId,filePath,fileContent, branchName){
apiUrl = "projects/${projectId}/repository/files/${filePath}"
reqBody = """{"branch": "${branchName}","encoding":"base64", "content": "${fileContent}", "commit_message": "update a new file"}"""
response = HttpReq('POST',apiUrl,reqBody)
println(response)
}
④ CI流水线更名: ci.jenkinsfile
⑤新增CD流水线: cd.jenkinsfile
@Library("mylib@master") _
import org.devops.*
def artifacts = new Artifacts()
def gitlabutil = new Gitlab()
pipeline {
agent { label "build" }
options {
skipDefaultCheckout true
}
stages{
stage("PullArtifacts"){
steps{
script{
repoName = "${JOB_NAME}".split("/")[0]
env.projectName ="${JOB_NAME}".split("/")[-1].split("_")[0]
if ("${env.projectType}" == "maven"){
type="jar"
}
if ("${env.projectType}" == "npm"){
type="tar.gz"
}
artifacts.PullArtifacts("${env.releaseVersion}","${env.projectName}",repoName,type)
env.pkgName="${env.projectName}-${env.releaseVersion}.${type}"
}
}
}
stage("DeployHost"){
steps{
script{
print("DeployHost")
if ("${env.deployTool}" == "saltstack"){
targetHosts = "${env.saltHosts}"
println(targetHosts)
localDeployDir = "/srv/salt/${env.projectName}"
sh """
[ -d ${localDeployDir} ] || mkdir -p ${localDeployDir}
mv ${env.pkgName} ${localDeployDir}
# 清理发布目录
salt -L "${targetHosts}" cmd.run "rm -fr ${targetDir}/${env.projectName}/* && mkdir -p ${targetDir}/${env.projectName} || echo file is exists"
# 发布应用
salt -L "${targetHosts}" cp.get_file salt://${env.projectName}/${env.pkgName} ${targetDir}/${env.projectName}
"""
if ("${env.projectType}" == "npm") {
sh """
# 解压
salt -L "${targetHosts}" cmd.run "cd ${targetDir}/${env.projectName} ;tar zxf ${env.pkgName}"
"""
}
}
}
}
}
stage("ServiceCtrl"){
steps{
script{
print("ServiceCtrl")
localDeployDir = "/srv/salt/${env.projectName}"
if ("${env.projectType}" == "maven") {
// 文件内容写到本地
response = gitlabutil.GetRepoFile(21, "service.sh", "master")
writeFile file: 'service.sh', text: "${response}"
sh "ls -a "
sh """
mv service.sh ${localDeployDir}
# 发布启动脚本
salt -L "${targetHosts}" cp.get_file salt://${env.projectName}/service.sh ${targetDir}/${env.projectName}
# 启动服务
salt -L "${targetHosts}" cmd.run "cd ${targetDir}/${env.projectName} ;source /etc/profile && sh service.sh ${env.projectName} ${env.releaseVersion} ${env.port} start"
# 检查服务
sleep 5
salt -L "${targetHosts}" cmd.run "cd ${targetDir}/${env.projectName} ;source /etc/profile && sh service.sh ${env.projectName} ${env.releaseVersion} ${env.port} check"
"""
}
}
}
}
stage("HealthCheck"){
steps{
script{
print("HealthCheck")
}
}
}
}
}
⑥ 更新提交到master
(2) Jenkins修改后端流水线
① 流水线设置SCM
② 手动构建CD流水线
(3)Jenkins修改前端流水线
① 流水线设置SCM
② 手动构建CD流水线
③ 成功
④ 再次手动构建CD流水线
⑤ 成功
⑥ 命令观察
# for i in `seq 1000`; do sleep 1 ; curl http://127.0.0.1:8099; echo -e "\n\n\n";done
(1)共享库新建部署类 Deploy.groovy
(2)修改Deploy.groovy
package org.devops
//SaltStack
def SaltCP(){
targetHosts = "${env.saltHosts}"
localDeployDir = "/srv/salt/${env.projectName}"
sh """
[ -d ${localDeployDir} ] || mkdir -p ${localDeployDir}
mv ${env.pkgName} ${localDeployDir}
# 清理发布目录
salt -L "${targetHosts}" cmd.run "rm -fr ${targetDir}/${env.projectName}/* && mkdir -p ${targetDir}/${env.projectName} || echo file is exists"
# 发布应用
salt -L "${targetHosts}" cp.get_file salt://${env.projectName}/${env.pkgName} ${targetDir}/${env.projectName}
"""
if ("${env.projectType}" == "npm") {
sh """
# 解压
salt -L "${targetHosts}" cmd.run "cd ${targetDir}/${env.projectName} ;tar zxf ${env.pkgName}"
"""
}
}
//启动服务
def ServiceCtrl(){
localDeployDir = "/srv/salt/${env.projectName}"
if ("${env.projectType}" == "maven") {
// 文件内容写到本地
gitlab = new Gitlab()
response = gitlab.GetRepoFile(21, "service.sh", "master")
writeFile file: 'service.sh', text: "${response}"
sh "ls -a "
sh """
mv service.sh ${localDeployDir}
# 发布启动脚本
salt -L "${targetHosts}" cp.get_file salt://${env.projectName}/service.sh ${targetDir}/${env.projectName}
# 启动服务
salt -L "${targetHosts}" cmd.run "cd ${targetDir}/${env.projectName} ;source /etc/profile && sh service.sh ${env.projectName} ${env.releaseVersion} ${env.port} start"
# 检查服务
sleep 5
salt -L "${targetHosts}" cmd.run "cd ${targetDir}/${env.projectName} ;source /etc/profile && sh service.sh ${env.projectName} ${env.releaseVersion} ${env.port} check"
"""
}
}
(3)精简代码的 cd.jenkinsfile
@Library("mylib@master") _
import org.devops.*
def artifacts = new Artifacts()
def gitlabutil = new Gitlab()
def deployer = new Deploy()
pipeline {
agent { label "build" }
options {
skipDefaultCheckout true
}
stages{
stage("PullArtifacts"){
steps{
script{
repoName = "${JOB_NAME}".split("/")[0]
env.projectName ="${JOB_NAME}".split("/")[-1].split("_")[0]
if ("${env.projectType}" == "maven"){
type="jar"
}
if ("${env.projectType}" == "npm"){
type="tar.gz"
}
artifacts.PullArtifacts("${env.releaseVersion}","${env.projectName}",repoName,type)
env.pkgName="${env.projectName}-${env.releaseVersion}.${type}"
}
}
}
stage("DeployHost"){
steps{
script{
print("DeployHost")
if ("${env.deployTool}" == "saltstack"){
deployer.SaltCP()
}
}
}
}
stage("ServiceCtrl"){
steps{
script{
print("ServiceCtrl")
deployer.ServiceCtrl()
}
}
}
}
}
(4)Jenkins手动构建后端项目流水线
(1)报错
No signature of method: static org.devops.Gitlab.GetRepoFile()
(2)原因分析
GitLab共享库调用其他类未初始化函数
(3)解决方法
初始化函数。
修改前:
response = Gitlab.GetRepoFile(21, "service.sh", "master")
修改后:
gitlab = new Gitlab()
response = gitlab.GetRepoFile(21, "service.sh", "master")
成功: