Jenkins CD 流水线设计 Gitops CI制品信息保存为CD准备

本文介绍了一种CI/CD流水线设计方法,详细解释了如何通过Jenkins实现自动化构建、测试及部署流程,并利用GitOps理念将部署描述文件存放在Git中,实现了版本管理和自动化触发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面这个阶段实在理解不了,可以将这个阶段去掉,如果公司不想这么用的话,大规模场景下使用也可以发现这种好处。

CI/CD流水线设计


 总体目标:

我是一个用户,点开Jenkins之后输入版本分支,然后点流水线构建,第一个阶段下载代码,第二个阶段构建,生成了我们的包,第三个阶段进行代码扫描,第四个阶段是上传制品,此时这个制品到制品库里面去了,那么就到CD阶段了,也就是包在制品库了,可以进行去部署了。

传到制品库了,要将这个包下载下来,可以复制这个url的地址,现在就需要创建发布流水线,因为CI和CD都是不同的流水线,

这里包的版本号有几种格式

  1. 版本号1.1.1+commitid:拿到分支最后一次提交的ID,然后加上版本号,然后拼凑出最后的版本(这样是看不到历史版本的信息的)
  2. CI上传制品,将制品的下载地址信息存起来,存储到git上面,在上传制品这种生成这个文件,这个文件里面存储了包的一些配置信息,CD流水线在拿的时候就拿这个信息(所以有两种方式,一种是存储信息,一种是不存储信息,不存储就拼接url直接下载下来就可以了,直接输入版本号就行)

提交了ReleaseFile之后想自动触发,存放到git上面去了,这次做了一个变更,git识别到了,这是一个push动作,那么会自动触发CD流水线去部署。如果做自动化可以这样去搞,不做自动化可以将这个步骤去掉。

我们将CI和CD分成两条流水线作业。

  • CI作业: 用户输入版本分支后下载代码,进行构建扫描最终将制品上传到制品仓库, 生成版本文件。(在上传制品之后,还得加一个阶段,生成一个文件,这个ReleaseFile文件里面存储的就是包的一些配置信息,CD流水线拿到这个文件就可以了)
  • CD作业: 用户输入发布版本和选择要发布的主机IP后,下载制品,将制品和服务启动脚本cp到目标机器的发布目录, 远程执行启动脚本启动服务并进行健康检查。

(1)CI  生成版本文件

在流水线最后一个步骤加上生成版本文件

  1. 获取gitlab上面的模板文件到本地(Gitlab下载文件的接口
  2. 生成文件里面内容,将配置信息写入本地的一个文件当中(新版本文件,yaml文件的更改)
  3. 将这个文件传到gitlab(修改的是新版本文件)(gitlab上传文件的接口

k8s里面的yaml文件都需要我们去更新,一般都是通过sed去修改yaml文件里面的内容,我们可以修改版本文件,这样就可以看到变更记录了。变更了啥信息都可以在git上面看得到。

最终效果如下:这个环境库里面存放着所有的发布的信息 

 发布信息的模板按照下面的去写

CD  获取版本文件(这样就可以看到变更的历史记录了)

1 从Gitlab下载版本文件

2 发布的时候只读取本地的版本文件

实践


 先创建一个空项目,用来存储版本信息

新建一个模板文件叫release,根据实际业务想存储什么信息可以自己去定义。

buname:  业务名称
appname: 应用名称
version: 制品版本
artifact: 制品下载链接

现在要修改这个文件的内容,就是要先下载下来,然后上传。

现在创建token 

 这个token拿到了 

 

 现在找到gitlab的api

我这里的实现是用HttpRequest插件来实现的,没有使用curl

[root@localhost ~]# curl --header "PRIVATE-TOKEN:SCPnzayH7YivMxaR1Yy-" "http://192.168.11.129/api/v4/projects/9/repository/files/release.yaml/raw?ref=master" -o test.yml
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    64  100    64    0     0   1369      0 --:--:-- --:--:-- --:--:--  1391

[root@localhost ~]# curl --header "PRIVATE-TOKEN:SCPnzayH7YivMxaR1Yy-" "http://192.168.11.129/api/v4/projects/9/repository/files/release.yaml/raw?ref=master"
buname: _NULL_
appname: _NULL_
version: _NULL_
artifact: _NULL_

curl --location --request GET 'http://192.168.11.129/api/v4/projects/9/repository/files/release.yaml/raw?ref=master' \
--header 'Authorization: Bearer SCPnzayH7YivMxaR1Yy-'


Repository files API | GitLabicon-default.png?t=N7T8https://docs.gitlab.com/ee/api/repository_files.html

现在要去下载这个文件,需要project ID和分支名称和文件名称。

pipeline {
    agent any

    stages {
        stage('Hello') {
            steps {
                    script {
                    //获取版本库文件内容 devops02-env/release.yaml
                    response = GetRepoFile(17,"release.yaml", "main")
                    println(response)
                    
                }
            }
        }
    }
}


// 封装HTTP
def HttpReq(reqType, reqUrl,reqBody ){
            def gitServer = "http://139.198.166.235:81/api/v4"
            withCredentials([string(credentialsId: 'ecbcd399-da69-4802-8760-87a1c1ff58a1', 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

}

结果如下: 

Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on build-01 in /data/cicd/jenkinsagent/workspace/nexus/release-file
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Hello)
[Pipeline] script
[Pipeline] {
[Pipeline] withCredentials
Masking supported pattern matches of $GITLABTOKEN
[Pipeline] {
[Pipeline] httpRequest
Warning: A secret was passed to "httpRequest" using Groovy String interpolation, which is insecure.
		 Affected argument(s) used the following variable(s): [GITLABTOKEN]
		 See https://jenkins.io/redirect/groovy-string-interpolation for details.
HttpMethod: GET
URL: http://139.198.166.235:81/api/v4//projects/17/repository/files/release.yaml/raw?ref=main
Content-Type: application/json; charset=UTF-8
Accept: application/json
PRIVATE-TOKEN: ****
Sending request to url: http://139.198.166.235:81/api/v4//projects/17/repository/files/release.yaml/raw?ref=main
Response Code: HTTP/1.1 200 OK
Response: 
buname: _NULL_
appname: _NULL_
version: _NULL_
artifact: _NULL_

Success: Status code 200 is in the accepted range: 100:399
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] echo
buname: _NULL_
appname: _NULL_
version: _NULL_
artifact: _NULL_

[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

 因为获取文件内容返回的是yaml格式的内容,以前返回的是json,现在用的yaml

//这里的分支版本可以通过branchName再做一个split就可以拿到,比如branchName:relaese-1.1.1
//可以在上传制品的时候返回artifactUrl信息
env.buName = "acmp"
env.appName = "myapp"
env.releaseVersion = "1.1.1"
env.artifactUrl = "http://139.198.166.235:8082/repository/devops-repo/acmp/acmp-myapp-service/1.1.1/acmp-myapp-service-1.1.1.jar"



pipeline {
    agent any


    stages {
        stage('Hello') {
            steps {
                    script {
                    //获取版本库文件内容 devops02-env/release.yaml
                    response = GetRepoFile(17,"release.yaml", "main")
                    //println(response)
                    yamlData = readYaml text: """${response}"""
                    yamlData.version   = "${env.releaseVersion}"
                    yamlData.artifact  = "${env.artifactUrl}"
                    yamlData.buname    = "${env.buName}"
                    yamlData.appname   = "${env.appName}"
                    println(yamlData.toString())
                    
                }
            }
        }
    }
}


def HttpReq(reqType, reqUrl,reqBody ){
            def gitServer = "http://139.198.166.235:81/api/v4"
            withCredentials([string(credentialsId: 'ecbcd399-da69-4802-8760-87a1c1ff58a1', 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

}
Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node
Running on build-01 in /data/cicd/jenkinsagent/workspace/nexus/release-file
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Hello)
[Pipeline] script
[Pipeline] {
[Pipeline] withCredentials
Masking supported pattern matches of $GITLABTOKEN
[Pipeline] {
[Pipeline] httpRequest
Warning: A secret was passed to "httpRequest" using Groovy String interpolation, which is insecure.
		 Affected argument(s) used the following variable(s): [GITLABTOKEN]
		 See https://jenkins.io/redirect/groovy-string-interpolation for details.
HttpMethod: GET
URL: http://139.198.166.235:81/api/v4//projects/17/repository/files/release.yaml/raw?ref=main
Content-Type: application/json; charset=UTF-8
Accept: application/json
PRIVATE-TOKEN: ****
Sending request to url: http://139.198.166.235:81/api/v4//projects/17/repository/files/release.yaml/raw?ref=main
Response Code: HTTP/1.1 200 OK
Response: 
buname: _NULL_
appname: _NULL_
version: _NULL_
artifact: _NULL_

Success: Status code 200 is in the accepted range: 100:399
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] readYaml
[Pipeline] echo
[buname:acmp, appname:myapp, version:1.1.1, artifact:http://139.198.166.235:8082/repository/devops-repo/acmp/acmp-myapp-service/1.1.1/acmp-myapp-service-1.1.1.jar]
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

现在就可以去替换文件里面内容,然后上传

env.buName = "acmp"
env.appName = "myapp"
env.releaseVersion = "1.1.1"
env.artifactUrl = "http://139.198.166.235:8082/repository/devops-repo/acmp/acmp-myapp-service/1.1.1/acmp-myapp-service-1.1.1.jar"
env.branchName = "release-1.1.1"


pipeline {
    agent any


    stages {
        stage('Hello') {
            steps {
                    script {
                    //下载版本库文件 devops02-env/release.yaml
                    response = GetRepoFile(17,"release.yaml", "main")
                    //println(response)
                    yamlData = readYaml text: """${response}"""
                    yamlData.version   = "${env.releaseVersion}"
                    yamlData.artifact  = "${env.artifactUrl}"
                    yamlData.buname    = "${env.buName}"
                    yamlData.appname   = "${env.appName}"
                    println(yamlData.toString())

                    sh "ls && rm -fr test.yaml"
                    writeYaml charset: 'UTF-8', data: yamlData, file: 'test.yaml'
                    newYaml = sh returnStdout: true, script: 'cat test.yaml'
                    
                    println(newYaml)
                    //更新gitlab文件内容,转化为base64,在调用api上传的时候都是base64编码
                    base64Content = newYaml.bytes.encodeBase64().toString()

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


def HttpReq(reqType, reqUrl,reqBody ){
            def gitServer = "http://139.198.166.235:81/api/v4"
            withCredentials([string(credentialsId: 'ecbcd399-da69-4802-8760-87a1c1ff58a1', 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)

}
[root@localhost ~]# curl --request POST --header 'PRIVATE-TOKEN: SCPnzayH7YivMxaR1Yy-'      --headebranch": "master", "author_email": "author@example.com", "author_name": "Firstname Lastname",
               "content": "buname: _NULL_ \nappname: _NULL_\nversion: _NULL_\nartifact: _NULL_", "commit_message": "create a new file"}'      "http://192.168.11.129/api/v4/projects/9/repository/files/release-1.6.yaml"
{"file_path":"release-1.6.yaml","branch":"master"}[root@localhost ~]# 



curl --request POST --header 'PRIVATE-TOKEN: <your_access_token>' \
     --header "Content-Type: application/json" \
     --data '{"branch": "master", "author_email": "author@example.com", "author_name": "Firstname Lastname",
               "content": "some content", "commit_message": "create a new file"}' \
     "https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fproject%2Erb"

${env.appName}%2f${env.branchName}.yaml

上面意思是放在17号仓库, 仓库下面文件夹名字为${env.appName},在该文件夹下面有生成一个文件{env.branchName}.yaml。这里使用的是%2f,本来是目录/文件这种格式,但是编码这里转换为了%2f,所以转化为编码要不然会失败。

(17,"${env.appName}%2f${env.branchName}.yaml",base64Content, "main")

仓库id+文件夹+文件+文件里面内容+分支名称

最后结果如下,可以看到符合预期,在版本信息管理库devops-env下面生成了对应项目的目录,并且目录下面包含制品的信息

 

到时候CD的时候就可以拿下该文件进行发布了,拿下该文件,通过脚本对这个文件处理一下,拿到制品下载地址就可以下载下来了。 

上面就是调用gitlab api去实现这个过程。

Gitops其实就是为环境单独创建了一个git仓库,无非就是在原有的CI的基础上面,加了一个步骤生成了一个文件把项目的以及代码的信息全部都放在这个文件里面了(后期拿到这个文件能够获取里面的参数去部署),然后在这里面做了一个变更,此时自动触发到我们的环境里面,好处是每次的变更都可以看到。

在k8s里面,全部都是yaml文件,我们一般改的就是镜像,如果是helm的话,修改的是values.yaml文件,总之就是更新里面的内容,更新了之后去发布。 

 如果接受不了上面的步骤,那么就不要版本文件了,直接拿制品自己拼接就行了。

总结:所谓的gitops就是把部署描述文件,存放到git系统里面,ci的时候自动更新,cd可以通过仓库自动触发。

完整的代码如下


package org.devops


// 封装HTTP
def HttpReq(reqType, reqUrl,reqBody ){
    def gitServer = "http://139.198.166.235:81/api/v4"
    withCredentials([string(credentialsId: 'ecbcd399-da69-4802-8760-87a1c1ff58a1', 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)

}


script {
                    //下载版本库文件 devops02-env/release.yaml
                    response = GetRepoFile(17,"release.yaml", "main")
                    //println(response)
                    yamlData = readYaml text: """${response}"""
                    yamlData.version   = "${env.releaseVersion}"
                    yamlData.artifact  = "${env.artifactUrl}"
                    yamlData.buname    = "${env.buName}"
                    yamlData.appname   = "${env.appName}"
                    println(yamlData.toString())

                    sh "ls && rm -fr test.yaml"
                    writeYaml charset: 'UTF-8', data: yamlData, file: 'test.yaml'
                    newYaml = sh returnStdout: true, script: 'cat test.yaml'
                    
                    println(newYaml)
                    //更新gitlab文件内容,转化为base64,在调用api上传的时候都是base64编码
                    base64Content = newYaml.bytes.encodeBase64().toString()

                    // 会有并行问题,同时更新报错
                    try {
                        UpdateRepoFile(17,"${env.appName}%2f${env.branchName}.yaml",base64Content, "main")
                    } catch(e){
                        CreateRepoFile(17,"${env.appName}%2f${env.branchName}.yaml",base64Content, "main")
                    }
                    
                }
<think>好的,我现在需要帮助用户了解如何在Jenkins中配置CI/CD流程。首先,我要回顾一下用户的问题和相关引用内容,确保回答准确。 用户提到了几个引用,比如引用[5]说明Jenkins是用于持续集成的工具,引用[2]提到Jenkins X用于Kubernetes集成,还有引用[3]关于工具链的选择。这些信息可能和配置流程相关。 首先,配置JenkinsCI/CD流程通常包括安装插件、创建任务、设置源码管理、构建触发器和部署步骤。根据引用[1],用户可能需要进入Manage Jenkins配置全局工具,比如JDK、Git等。然后,引用[4]中的SonarQube扫描示例可能涉及构建步骤中的脚本执行。 用户可能需要分步骤的指导,比如如何创建流水线项目,编写Jenkinsfile,以及集成Docker和Kubernetes。引用[2]提到的Jenkins X和Helm可能属于最佳实践部分,适合在优化或高级配置中提及。 另外,需要确保回答结构清晰,按照安装、配置、创建任务、编写流水线脚本、触发构建和部署的顺序进行。同时,引用相关的地方要正确标注,比如配置全局工具引用[1],集成Kubernetes引用[2],CI/CD工具链引用[3],SonarQube扫描引用[4]。 可能还需要考虑用户的实际环境,比如是否使用Docker,是否在Kubernetes集群中部署,是否需要代码质量检查工具。因此,在步骤中加入这些可选部分,并引用相应的内容。 最后,生成相关问题时要覆盖用户可能的后续疑问,比如权限管理、分布式构建、与其他工具的集成等,确保问题相关且有价值。</think>### 如何在 Jenkins 中配置 CI/CD 管道 #### 1. **环境准备与工具安装** - **安装 Jenkins** 从[Jenkins官网](https://www.jenkins.io/)下载适合操作系统的安装包,完成基础配置。确保已安装 Java 运行时环境(JRE/JDK)。 - **配置全局工具** 在 Jenkins 主界面点击 `Manage Jenkins` → `Global Tool Configuration`,设置 JDK、Git、Maven/Gradle 等工具的路径或选择自动安装[^1]。 ```bash # 示例:配置 Git 路径 /usr/bin/git ``` #### 2. **创建流水线项目** - **新建任务** 点击 `新建Item` → 输入任务名称 → 选择 `流水线`(Pipeline)→ 点击 `确定`。 - **配置源码管理** 在 `Pipeline` 选项卡中,选择源码仓库类型(如 Git),填写仓库 URL 和凭证。例如: ```bash https://github.com/your-project.git ``` #### 3. **编写 Jenkinsfile** 在项目根目录创建 `Jenkinsfile`,定义流水线阶段: ```groovy pipeline { agent any stages { stage('Checkout') { steps { git 'https://github.com/your-project.git' } } stage('Build') { steps { sh 'mvn clean package' // 或 gradle build } } stage('Test') { steps { sh 'mvn test' } } stage('Deploy') { steps { sh 'kubectl apply -f deployment.yaml' // 示例:Kubernetes 部署 } } } } ``` #### 4. **集成代码质量检查(可选)** 在 `Build` 阶段后添加代码扫描步骤,例如 SonarQube: ```groovy stage('Code Analysis') { steps { withSonarQubeEnv('SonarQube-Server') { sh 'mvn sonar:sonar' } } } ``` 参考 SonarQube 配置步骤[^4]。 #### 5. **设置触发器与自动化** - **Webhook 触发** 在 Jenkins 任务设置中,勾选 `GitHub hook trigger for GITScm polling`,并在 GitHub 仓库的 Webhooks 中添加 Jenkins 服务器的 URL(如 `http://<jenkins-ip>/github-webhook/`)。 - **定时构建** 使用 Cron 表达式(如 `H/15 * * * *` 表示每 15 分钟构建一次)。 #### 6. **部署到 Kubernetes(高级实践)** 若需云原生部署,可结合 Jenkins X 或 Helm: ```groovy stage('Helm Deploy') { steps { sh 'helm upgrade --install my-app ./charts' } } ``` Jenkins X 提供了预置的 Kubernetes 集成流水线,支持 GitOps 流程[^2]。 --- ### 最佳实践 1. **使用声明式流水线** 优先使用 `Jenkinsfile` 而非自由风格项目,便于版本控制和复用。 2. **容器化构建环境** 在流水线中通过 `agent { docker 'maven:3.8.4' }` 指定容器,确保环境一致性。 3. **密钥管理** 使用 Jenkins 的 `Credentials Binding` 插件安全存储数据库密码、API Token 等敏感信息。 4. **并行化阶段** 对独立任务(如单元测试与静态分析)启用并行执行: ```groovy stage('Parallel Tasks') { parallel { stage('Test') { steps { sh 'mvn test' } } stage('Lint') { steps { sh 'npm run lint' } } } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值