一、Nexus制品上传

1.1 使用mvn deploy上传制品

  • 创建仓库maven-release(已创建)
  • 配置maven-release认证
    • settings.xml server
    • 注意server.id == respository.id
  • 使用mvn deploy发布

1.1.1 配置maven-release认证

cd /opt/apache-maven-3.6.3/conf
sudo vim settings.xml

<server>
     <id>maven-releases</id>
     <username>admin</username>
     <password>admin</password>
</server>
<server>
     <id>maven-hosted</id>
     <username>admin</username>
     <password>admin</password>
</server>

1.1.2 使用mvn deploy发布

def pom =readMavenPom file: 'pom.xml'
                    pomVersion = "${pom.version}"
                    pomArtifact = "${pom.artifactId}"
                    pomPackaging = "${pom.packaging}"
                    pomGroupId = "${pom.groupId}"

                    println("${pomGroupId}-${pomArtifact}-${pomVersion}-${pomPackaging}")

                    def mvnHome = tool "m2"
                    sh """
                        cd target/
                        ${mvnHome}/bin/mvn deploy:deploy-file -Dmaven.test.skip=true -Dfile=${jarName} -DgroupId=${pomGroupId} -DartifactId=${pomArtifact} -Dversion=${pomVersion} -Dpackaging=${pomPackaging} -DrepositoryId=maven-releases -Durl=http://192.168.33.1:32000/repository/maven-releases/
                    """

Error: 400 repository version policy: release does not allow version

修改pom.xml里面的version信息

<version>1.1-SNAPSHOT</version> => `<version>1.1</version>

stage('Build') {
            steps {
                script {
                    build.Build(buildType,buildShell)

                    def jarName = sh returnStdout: true, script: "cd target; ls *.jar"
                    jarName = jarName - "\n"

                    def pom =readMavenPom file: 'pom.xml'
                    pomVersion = "${pom.version}"
                    pomArtifact = "${pom.artifactId}"
                    pomPackaging = "${pom.packaging}"
                    pomGroupId = "${pom.groupId}"

                    println("${pomGroupId}-${pomArtifact}-${pomVersion}-${pomPackaging}")

                    def mvnHome = tool "m2"
                    sh """
                        cd target/
                        ${mvnHome}/bin/mvn deploy:deploy-file -Dmaven.test.skip=true -Dfile=${jarName} -DgroupId=${pomGroupId} -DartifactId=${pomArtifact} -Dversion=${pomVersion} -Dpackaging=${pomPackaging} -DrepositoryId=maven-releases -Durl=http://192.168.33.1:32000/repository/maven-releases/
                    """
                } 
            }
        }

1.1.3 Console output

....
+ cd target/
+ /opt/maven/bin/mvn deploy:deploy-file -Dmaven.test.skip=true -Dfile=my-app-1.1.jar -DgroupId=com.mycompany.app -DartifactId=my-app -Dversion=1.1 -Dpackaging=jar -DrepositoryId=maven-releases -Durl=http://192.168.33.1:32000/repository/maven-releases/
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- maven-deploy-plugin:2.7:deploy-file (default-cli) @ standalone-pom ---
Uploading to maven-releases: http://192.168.33.1:32000/repository/maven-releases/com/mycompany/app/my-app/1.1/my-app-1.1.jar
Progress (1): 2.6 kB

Uploaded to maven-releases: http://192.168.33.1:32000/repository/maven-releases/com/mycompany/app/my-app/1.1/my-app-1.1.jar (2.6 kB at 3.4 kB/s)
Uploading to maven-releases: http://192.168.33.1:32000/repository/maven-releases/com/mycompany/app/my-app/1.1/my-app-1.1.pom
Progress (1): 395 B

Uploaded to maven-releases: http://192.168.33.1:32000/repository/maven-releases/com/mycompany/app/my-app/1.1/my-app-1.1.pom (395 B at 914 B/s)
Downloading from maven-releases: http://192.168.33.1:32000/repository/maven-releases/com/mycompany/app/my-app/maven-metadata.xml
Uploading to maven-releases: http://192.168.33.1:32000/repository/maven-releases/com/mycompany/app/my-app/maven-metadata.xml
Progress (1): 299 B

Uploaded to maven-releases: http://192.168.33.1:32000/repository/maven-releases/com/mycompany/app/my-app/maven-metadata.xml (299 B at 466 B/s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.295 s
[INFO] Finished at: 2020-08-04T09:49:11Z
[INFO] ------------------------------------------------------------------------
...

Alt Image Text

Alt Image Text

1.1.4 方法二: 建立新的mixed类型的maven-hosted repository

def mvnHome = tool "m2"
sh """
    cd target/
    ${mvnHome}/bin/mvn deploy:deploy-file -Dmaven.test.skip=true -Dfile=${jarName} -DgroupId=${pomGroupId} -DartifactId=${pomArtifact} -Dversion=${pomVersion} -Dpackaging=${pomPackaging} -DrepositoryId=maven-releases -Durl=http://192.168.33.1:32000/repository/maven-hosted/
 """

Alt Image Text

1.2 使用Jenkins插件上传制品

Alt Image Text

nexusArtifactUploader artifacts: [[artifactId: "${pomArtifact}", 
                                        classifier: '', 
                                        file: "${filePath}", 
                                        type: "${pomPackaging}"]], 
                            credentialsId: 'nexus', 
                            groupId: "${pomGroupId}", 
                            nexusUrl: '192.168.33.1:32000', 
                            nexusVersion: 'nexus3', 
                            protocol: 'http', 
                            repository: "${repoName}", 
                            version: "${pomVersion}"

Console Output

[Pipeline] nexusArtifactUploader
Uploading artifact my-app-1.1-SNAPSHOT.jar started....
GroupId: com.mycompany.app
ArtifactId: com.mycompany.app
Classifier: 
Type: jar
Version: 1.1-SNAPSHOT
File: my-app-1.1-SNAPSHOT.jar
Repository:maven-hosted
Downloading: http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/maven-metadata.xml
100 % completed (767 B / 767 B).
Downloaded: http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/maven-metadata.xml (767 B at 666 B/s)
Uploading: http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.192037-2.jar

1.2.1 Nexus方法置于SharedLibrary

JenkinslibTest/src/org/devops/nexus.groovy

pakcage org.devops

//获取POM中的坐标
def GetGav(){
   //上传制品
    def jarName = sh returnStdout: true, script: "cd target;ls *.jar"
    env.jarName = jarName - "\n"

    def pom = readMavenPom file: 'pom.xml'
    env.pomVersion = "${pom.version}"
    env.pomArtifact = "${pom.artifactId}"
    env.pomPackaging = "${pom.packaging}"
    env.pomGroupId = "${pom.groupId}"

    println("${pomGroupId}-${pomArtifact}-${pomVersion}-${pomPackaging}")

    return ["${pomGroupId}","${pomArtifact}","${pomVersion}","${pomPackaging}"]
}

//Nexus plugin deploy
def NexusUpload(){
    //use nexus plugin
    nexusArtifactUploader artifacts: [[artifactId: "${pomArtifact}", 
                                        classifier: '', 
                                        file: "${filePath}", 
                                        type: "${pomPackaging}"]], 
                            credentialsId: 'nexus', 
                            groupId: "${pomGroupId}", 
                            nexusUrl: '192.168.33.1:32000', 
                            nexusVersion: 'nexus3', 
                            protocol: 'http', 
                            repository: "${repoName}", 
                            version: "${pomVersion}"
}

//mvn deploy
def MavenUpload(){          
    def mvnHome = tool "m2"
    sh  """ 
        cd target/
        ${mvnHome}/bin/mvn deploy:deploy-file -Dmaven.test.skip=true  \
                                -Dfile=${jarName} -DgroupId=${pomGroupId} \
                                -DartifactId=${pomArtifact} -Dversion=${pomVersion}  \
                                -Dpackaging=${pomPackaging} -DrepositoryId=maven-hosted \
                                -Durl=http://192.168.33.1:32000/repository/maven-hosted 
        """
}

def main(uploadType){
    GetGav()
    if ("${uploadType}" == "maven"){
        MavenUpload()
    } else if ("${uploadType}" == "nexus") {
        env.repoName = "maven-hosted"
        env.filePath = "target/${jarName}"
        NexusUpload()
    }
}
  • 三个方法

    • GetGav(): 获取POM中的坐标
    • NexusUpload(): Nexus plugin deploy
    • MavenUpload() mvn deploy
    • 更新pom.xmlversion版本
#!groovy
@Library('jenkinslib@master') _

def build = new org.devops.buildtools()
def sonar = new org.devops.sonarqube()
def nexus = new org.devops.nexus()

pipeline {
    agent { node { label "hostmachine" }}
    parameters {
        string(name: 'srcUrl', defaultValue: 'http://192.168.33.1:30088/root/demo-maven-service.git', description: '') 
        choice(name: 'branchName', choices: 'master\nstage\ndev', description: 'Please chose your branch')
        choice(name: 'buildType', choices: 'mvn', description: 'build tool')
        choice(name: 'buildShell', choices: 'clean package -DskipTest\n--version', description: 'build tool')
    }
    stages{
        stage('Checkout') {
            steps {
                script {
                    checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-admin-user', url: "${srcUrl}"]]])
                } 
            }
        }

        stage('Build') {
            steps {
                script {
                    build.Build(buildType,buildShell)
                    nexus.main("maven")
                    <!--nexus.main("nexus")-->
                } 
            }
        }
    }
 }
  • def nexus = new org.devops.nexus()
  • nexus.main("maven") or nexus.main("nexus")

Console output maven

+ cd target/
+ /opt/maven/bin/mvn deploy:deploy-file -Dmaven.test.skip=true -Dfile=my-app-1.1-RELEASE.jar -DgroupId=com.mycompany.app -DartifactId=my-app -Dversion=1.1-RELEASE -Dpackaging=jar -DrepositoryId=hosted -Durl=http://192.168.33.1:32000/repository/maven-hosted
[INFO] Scanning for projects...
[INFO] 
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] 
[INFO] --- maven-deploy-plugin:2.7:deploy-file (default-cli) @ standalone-pom ---
Uploading to maven-releases: http://192.168.33.1:32000/repository/maven-releases/com/mycompany/app/my-app/1.1-RELEASE/my-app-1.1-RELEASE.jar
Progress (1): 2.6 kB
...

1.3 使用Nexus插件上传制品

  • 安装Nexus插件上传制品 https://plugins.jenkins.io/nexus-artifact-uploader/

  • Name: artifactUrl

  • Nexus Server URL: http://192.168.33.1:32000

  • RepositoryId: maven-hosted
  • GroupId: com.mycompany.app
  • ArtifactId: my-app
  • Packaging: jar

  • http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.192037-2.jar

  • http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar

Alt Image Text

#!groovy
@Library('jenkinslib@master') _

def build = new org.devops.buildtools()
def sonar = new org.devops.sonarqube()
def nexus = new org.devops.nexus()

String artifactUrl = "${env.artifactUrl}"

pipeline {
    agent { node { label "hostmachine" }}
    parameters {
        string(name: 'srcUrl', defaultValue: 'http://192.168.33.1:30088/root/demo-maven-service.git', description: '') 
        choice(name: 'branchName', choices: 'master\nstage\ndev', description: 'Please chose your branch')
        choice(name: 'buildType', choices: 'mvn', description: 'build tool')
        choice(name: 'buildShell', choices: 'clean package -DskipTest\n--version', description: 'build tool')
    }
    stages{
        stage('Checkout') {
            steps {
                script {
                    checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-admin-user', url: "${srcUrl}"]]])
                } 
            }
        }

        stage('Build') {
            steps {
                script {
                    build.Build(buildType,buildShell)

                    // Upload artifact
                    // nexus.main("nexus")

                    // Release artifact
                    sh "wget ${artifactUrl} && ls"

                } 
            }
        }
    }
 }

Alt Image Text

Console output

+ wget http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar
--2020-08-13 19:25:39--  http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar
Connecting to 192.168.33.1:32000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2626 (2.6K) [application/java-archive]
Saving to: ‘my-app-1.1-20200813.190212-1.jar’

     0K ..                                                    100%  286M=0s

2020-08-13 19:25:39 (286 MB/s) - ‘my-app-1.1-20200813.190212-1.jar’ saved [2626/2626]

+ ls
ci.jenkinsfile
jenkins
Jenkinsfile
my-app-1.1-20200813.190212-1.jar
my-app-1.1.jar
pom.xml
README.md
src

1.4 制品晋级

  • 安装Maven Artifact ChoiceList Provider (Nexus)插件
  • 用户选择要晋级的制品
  • 解析生成坐标
  • 上传到发布仓库

1.4.1 nexus.groovy

pakcage org.devops

//获取POM中的坐标
def GetGav(){
   //上传制品
    def jarName = sh returnStdout: true, script: "cd target;ls *.jar"
    env.jarName = jarName - "\n"

    def pom = readMavenPom file: 'pom.xml'
    env.pomVersion = "${pom.version}"
    env.pomArtifact = "${pom.artifactId}"
    env.pomPackaging = "${pom.packaging}"
    env.pomGroupId = "${pom.groupId}"

    println("${pomGroupId}-${pomArtifact}-${pomVersion}-${pomPackaging}")

    return ["${pomGroupId}","${pomArtifact}","${pomVersion}","${pomPackaging}"]
}

//Nexus plugin deploy
def NexusUpload(){
    //use nexus plugin
    nexusArtifactUploader artifacts: [[artifactId: "${pomArtifact}", 
                                        classifier: '', 
                                        file: "${filePath}", 
                                        type: "${pomPackaging}"]], 
                            credentialsId: 'nexus', 
                            groupId: "${pomGroupId}", 
                            nexusUrl: '192.168.33.1:32000', 
                            nexusVersion: 'nexus3', 
                            protocol: 'http', 
                            repository: "${repoName}", 
                            version: "${pomVersion}"
}

//mvn deploy
def MavenUpload(){          
    def mvnHome = tool "m2"
    sh  """ 
        cd target/
        ${mvnHome}/bin/mvn deploy:deploy-file -Dmaven.test.skip=true  \
                                -Dfile=${jarName} -DgroupId=${pomGroupId} \
                                -DartifactId=${pomArtifact} -Dversion=${pomVersion}  \
                                -Dpackaging=${pomPackaging} -DrepositoryId=maven-hosted \
                                -Durl=http://192.168.33.1:32000/repository/maven-hosted 
        """
}

//制品晋级
def ArtifactUpdate(updateType,artifactUrl){

    //晋级策略
    if ("${updateType}" == "snapshot -> release"){
        println("snapshot -> release")

        //下载原始制品
        sh "  rm -fr updates && mkdir updates && cd updates && wget ${artifactUrl} && ls -l "

        //获取artifactID 

        artifactUrl = artifactUrl -  "http://192.168.33.1:32000/repository/maven-hosted/"
        artifactUrl = artifactUrl.split("/").toList()

        println(artifactUrl.size())
        env.jarName = artifactUrl[-1] 
        env.pomVersion = artifactUrl[-2].replace("SNAPSHOT","RELEASE")
        env.pomArtifact = artifactUrl[-3]
        pomPackaging = artifactUrl[-1]
        pomPackaging = pomPackaging.split("\\.").toList()[-1]
        env.pomPackaging = pomPackaging[-1]
        env.pomGroupId = artifactUrl[0..-4].join(".")
        println("${pomGroupId}##${pomArtifact}##${pomVersion}##${pomPackaging}")
        env.newJarName = "${pomArtifact}-${pomVersion}.${pomPackaging}"

        //更改名称
        sh " cd updates && mv ${jarName} ${newJarName} "

        //上传制品
        env.repoName = "maven-releases"
        env.filePath = "updates/${newJarName}"
        NexusUpload()
    }
}

def main(uploadType){
    GetGav()
    if ("${uploadType}" == "maven"){
        MavenUpload()
    } else if ("${uploadType}" == "nexus") {
        env.repoName = "maven-hosted"
        env.filePath = "target/${jarName}"
        NexusUpload()
    }
}
  • def ArtifactUpdate(updateType,artifactUrl){}

1.4.2 Pipeline Script

#!groovy
@Library('jenkinslib@master') _

def nexus = new org.devops.nexus()

String artifactUrl = "${env.artifactUrl}"

pipeline{
    agent { node { label "hostmachine" }}
    parameters {  
        choice(name: 'updateType', choices: 'snapshot -> release\n', description: 'update type')
    }

    stages{
        stage("UpdateArtifact"){
            steps{
                script{
                    println(artifactUrl)

                    updateType = "${env.updateType}"
                    println(updateType)

                    nexus.ArtifactUpdate(updateType,artifactUrl)
                }
            }
        }
    }
}

Alt Image Text

Alt Image Text

Console output

[Pipeline] echo
http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.192037-2.jar
[Pipeline] echo
snapshot -> release
[Pipeline] echo
snapshot -> release
[Pipeline] sh
+ rm -fr updates
+ mkdir updates
+ cd updates
+ wget http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.192037-2.jar
--2020-08-13 20:30:46--  http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.192037-2.jar
Connecting to 192.168.33.1:32000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2626 (2.6K) [application/java-archive]
Saving to: my-app-1.1-20200813.192037-2.jar

     0K ..                                                    100%  277M=0s

2020-08-13 20:30:46 (277 MB/s) - my-app-1.1-20200813.192037-2.jar saved [2626/2626]

+ ls -l
total 4
-rw-rw-r--. 1 vagrant vagrant 2626 Aug 14  2020 my-app-1.1-20200813.192037-2.jar
[Pipeline] echo
11
[Pipeline] echo
http:..192.168.33.1:32000.repository.maven-hosted.com.mycompany.app##my-app##1.1-RELEASE##jar
[Pipeline] sh
+ cd updates
+ mv my-app-1.1-20200813.192037-2.jar my-app-1.1-RELEASE.jar
[Pipeline] nexusArtifactUploader

Alt Image Text

1.5 封装Nexus REST API

1.5.1 Nexus REST API

service/reset/v1/components/${id}

Example

http://192.168.33.1:32000/service/rest/v1/components?repository=maven-hosted
{
  "items" : [ {
    "id" : "bWF2ZW4taG9zdGVkOmM3NzAxNjljMGIyZTNlZDg1MGQ0M2ZlOGUzZTE0ZGY1",
    "repository" : "maven-hosted",
    "format" : "maven2",
    "group" : "com.mycompany.app",
    "name" : "my-app",
    "version" : "1.1-20200813.190212-1",
    "assets" : [ {
      "downloadUrl" : "http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar",
      "path" : "com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar",
      "id" : "bWF2ZW4taG9zdGVkOjM2ZTNkZWM4ZGU1MjhjOWI3MDkyYTJlYTJlYjAxYTlm",
      "repository" : "maven-hosted",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "98b32769384f208997d0e6ce52157864e5af010d",
        "md5" : "933ce8391a4224771a77f19dd21bd66f"
      }
    }, {
      "downloadUrl" : "http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar.md5",
      "path" : "com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar.md5",
      "id" : "bWF2ZW4taG9zdGVkOjM2ZTNkZWM4ZGU1MjhjOWIxOWY2NWRjZjU4MTdlOWEx",
      "repository" : "maven-hosted",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "f949e7f01cda8178bb6c84c57ff9a21534217f36",
        "md5" : "7c1adfe9d1980b88a09e5f384cf2952c"
      }
    }, {
      "downloadUrl" : "http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar.sha1",
      "path" : "com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar.sha1",
      "id" : "bWF2ZW4taG9zdGVkOjM2ZTNkZWM4ZGU1MjhjOWIwZGExY2M2OWIyZDhkNjZl",
      "repository" : "maven-hosted",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "1f6f7277f9f5c966771756cf00db8b9cbeb1623b",
        "md5" : "0d529b4a86c0f6066a015b9e5e484dcc"
      }
    }, {
      "downloadUrl" : "http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.pom",
      "path" : "com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.pom",
      "id" : "bWF2ZW4taG9zdGVkOjM2ZTNkZWM4ZGU1MjhjOWI3Y2M0ZTc0NGMxM2VmMDI5",
      "repository" : "maven-hosted",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "511692613d6474109a227c282b79adb6bb6a282c",
        "md5" : "1d2fd7c19cbd1bd2e4481b3b9b6d5a6c"
      }
    }, {
...

Alt Image Text

Alt Image Text

1.5.2 nexusapi.groovy

package org.devops

//封装HTTP
def HttpReq(reqType,reqUrl,reqBody){
    def sonarServer = "http://192.168.33.1:32000/service/rest"

    result = httpRequest authentication: 'nexus',
            httpMode: reqType, 
            contentType: "APPLICATION_JSON",
            consoleLogResponseBody: true,
            ignoreSslErrors: true, 
            requestBody: reqBody,
            url: "${sonarServer}/${reqUrl}",
            quiet: true

    return result
}

//获取仓库中所有组件

def GetRepoComponents(repoName){
    apiUrl = "/v1/components?repository=${repoName}"
    response = HttpReq("GET",apiUrl,'')

    response = readJSON text: """${response.content}"""
    println(response["items"].size())

    return response["items"]
}

//获取单件组件

def GetComponentsId(repoName,groupId,artifactId,version){
    println("获取单件组件ID")
    result = GetRepoComponents(repoName) 

    for (component in result){

        if (component["group"] == groupId && component["name"] == artifactId && component["version"] == version  ){

            componentId = component["id"]

            return componentId
        }
    }

    println(componentId)
}

//获取组件信息
def GetSingleComponents(repoName,groupId,artifactId,version){
    println("获取单件组件信息")
    componentId = GetComponentsId(repoName,groupId,artifactId,version)
    apiUrl = "/v1/components/${componentId}"
    response = HttpReq("GET",apiUrl,'')

    response = readJSON text: """${response.content}"""
    println(response["assets"]["downloadUrl"])
}
  • 封装HTTP
  • 获取仓库中所有组件
  • 获取单件组件
  • 获取组件信息

1.5.3 获取仓库中所有组件

#!groovy
@Library('jenkinslib@master') _

def nexus = new org.devops.nexus()
def nexusapi = new org.devops.nexusapi()

String artifactUrl = "${env.artifactUrl}"

pipeline{
    agent { node { label "hostmachine" }}

    stages{
        stage("UpdateArtifact"){
            steps{
                script{
                    nexusapi.GetRepoComponents("maven-hosted")
                }
            }
        }
    }
}

Console Output

[Pipeline] stage
[Pipeline] { (GetRepoComponents)
[Pipeline] script
[Pipeline] {
[Pipeline] httpRequest
[Pipeline] readJSON
[Pipeline] echo
5
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

1.5.4 组件信息

#!groovy
@Library('jenkinslib@master') _

def nexus = new org.devops.nexus()
def nexusapi = new org.devops.nexusapi()

pipeline{
    agent { node { label "hostmachine" }}
    parameters {  
         string(name: 'pkgVersion', defaultValue: "1.1-20200813.190212-1", description: '') 
    }

    stages{
        stage("GetSingleComponents"){
            steps{
                script{
                    pkgVersion = "${env.pkgVersion}"
                    nexusapi.GetRepoComponents("maven-hosted")
                    nexusapi.GetSingleComponents("maven-hosted","com.mycompany.app","my-app",pkgVersion)

                }
            }
        }
    }
}

Console Output

[Pipeline] {
[Pipeline] httpRequest
[Pipeline] readJSON
[Pipeline] echo
5
[Pipeline] echo
获取单件组件信息
[Pipeline] echo
获取单件组件ID
[Pipeline] httpRequest
[Pipeline] readJSON
[Pipeline] echo
5
[Pipeline] httpRequest
[Pipeline] readJSON
[Pipeline] echo
[http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar, http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar.md5, http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.jar.sha1, http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.pom, http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.pom.md5, http://192.168.33.1:32000/repository/maven-hosted/com/mycompany/app/my-app/1.1-SNAPSHOT/my-app-1.1-20200813.190212-1.pom.sha1]
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

二、Jenkins & Jfrog Artifactory

2.1 搭建K8S Jfrog Artifactory Factory

$ kubectl create ns devops
namespace/devops created
---
kind: Deployment
apiVersion: apps/v1
metadata:
  labels:
    k8s-app: artifactory
  name: artifactory
  namespace: devops
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s-app: artifactory
  template:
    metadata:
      labels:
        k8s-app: artifactory
      namespace: devops
      name: artifactory
    spec:
      containers:
        - name: artifactory
          image: docker.bintray.io/jfrog/artifactory-oss:latest
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8082
              name: web
              protocol: TCP
          resources:
            limits:
              cpu: 1000m
              memory: 2Gi
            requests:
              cpu: 1000m
              memory: 2Gi
          volumeMounts:
            - name: arthome
              mountPath: /var/opt/jfrog/artifactory
      volumes:
        - name: arthome
          emptyDir: {}
          # hostPath:
          #   path: /data/devops/artifactory
          #   type: Directory
---
apiVersion: v1
kind: Service
metadata:
 name: artifactory
 namespace: devops
 labels:
   k8s-app: artifactory
spec:
 selector:
   k8s-app: artifactory
 type: NodePort
 ports:
 - name: web
   port: 8082
   targetPort: 8082
   nodePort: 30082
kubectl apply -f artifactory.yml 

Login

Artifactory comes with a pre-configured default "admin" account. Username: admin, Password: password.

  • admin
  • admin123

Alt Image Text

2.2 使用Artifactory构建收集数据

安装Artifactory插件: https://plugins.jenkins.io/artifactory/

2.2.1 Jenkins全局配置artifactory

  • Server ID: artifactory
  • URL: http://192.168.33.1:30082/artifactory
  • Username / password

Alt Image Text

2.2.2 artifactory.groovy

package org.devops

//Maven打包构建
def MavenBuild(buildShell){
    def server = Artifactory.newServer url: "http://192.168.33.1:30082/artifactory"
    def rtMaven = Artifactory.newMavenBuild()
    def buildInfo
    server.connection.timeout = 300
    server.credentialsId = 'jfrog' 
    //maven打包
    rtMaven.tool = 'm2' 
    buildInfo = Artifactory.newBuildInfo()

    String newBuildShell = "${buildShell}".toString()
    println(newBuildShell)
    rtMaven.run pom: 'pom.xml', goals: newBuildShell, buildInfo: buildInfo
    //上传build信息
    server.publishBuildInfo buildInfo
}

//上传制品
def PushArtifact(){

    //重命名制品
    def jarName = sh returnStdout: true, script: "cd target;ls *.jar"
    jarName = jarName - "\n"
    def pom = readMavenPom file: 'pom.xml'
    env.pomVersion = "${pom.version}"
    env.serviceName = "${JOB_NAME}".split("_")[0]
    env.buildTag = "${BUILD_ID}"
    def newJarName = "${serviceName}-${pomVersion}-${buildTag}.jar"
    println("${jarName}  ------->>> ${newJarName}")
    sh " mv target/${jarName}  target/${newJarName}"

    //上传制品
    env.businessName = "${env.JOB_NAME}".split("-")[0]
    env.repoName = "${businessName}-${JOB_NAME.split("_")[-1].toLowerCase()}"
    println("本次制品将要上传到${repoName}仓库中!")   
    env.uploadDir = "${repoName}/${businessName}/${serviceName}/${pomVersion}"

    println('上传制品')
    rtUpload (
        serverId: "artifactory",
        spec:
            """{
            "files": [
                {
                "pattern": "target/${newJarName}",
                "target": "${uploadDir}/"
                }
            ]
            }"""
    )
}

def main(buildType,buildShell){
    if(buildType == "mvn"){
        MavenBuild(buildShell)
    }
}

2.2.3 使用artifactorymaven打包构建

#!groovy
@Library('jenkinslib@master') _

def build = new org.devops.buildtools()
def sonar = new org.devops.sonarqube()
def artifactory = new org.devops.artifactory()

pipeline {
    agent { node { label "hostmachine" }}
    parameters {
        string(name: 'srcUrl', defaultValue: 'http://192.168.33.1:30088/root/demo-maven-service.git', description: '') 
        choice(name: 'branchName', choices: 'master\nstage\ndev', description: 'Please chose your branch')
        choice(name: 'buildType', choices: 'mvn', description: 'build tool')
        choice(name: 'buildShell', choices: 'clean package -DskipTest\n--version', description: 'build tool')
    }
    stages{
        stage('Checkout') {
            steps {
                script {
                    checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-admin-user', url: "${srcUrl}"]]])
                } 
            }
        }

        stage('Build') {
            steps {
                script {
                    artifactory.main(buildType,buildShell)
                   // artifactory.PushArtifact()
                } 
            }
        }
    }
 }

Console Output

[Pipeline] artifactoryMavenBuild
Jenkins Artifactory Plugin version: 3.7.3
Artifactory integration is enabled
[chap9_jfrog1] $ /usr/lib/jvm/jre-openjdk/bin/java -classpath /opt/maven/boot/* -Dmaven.home=/opt/maven -Dmaven.conf=/opt/maven/conf -DbuildInfoConfig.propertiesFile=/home/vagrant/workspace/workspace/chap9_jfrog1@tmp/artifactory/buildInfo507882051108967646.properties -Dm3plugin.lib=/home/vagrant/workspace/workspace/chap9_jfrog1@tmp/artifactory/cache/artifactory-plugin/3.7.3 -Dclassworlds.conf=/home/vagrant/workspace/workspace/chap9_jfrog1@tmp/artifactory/classworlds7067099799344911655conf -Dmaven.multiModuleProjectDirectory=/home/vagrant/workspace/workspace/chap9_jfrog1 org.codehaus.plexus.classworlds.launcher.Launcher -f pom.xml clean package -DskipTest
[main] INFO org.apache.maven.cli.event.ExecutionEventLogger - Scanning for projects...
[main] INFO org.jfrog.build.extractor.maven.BuildInfoRecorder - Initializing Artifactory Build-Info Recording
...
Recorder: publish build info set to false, build info will not be published...
[main] INFO org.apache.maven.cli.event.ExecutionEventLogger - ------------------------------------------------------------------------
[main] INFO org.apache.maven.cli.event.ExecutionEventLogger - BUILD SUCCESS
[main] INFO org.apache.maven.cli.event.ExecutionEventLogger - ------------------------------------------------------------------------
[main] INFO org.apache.maven.cli.event.ExecutionEventLogger - Total time:  8.003 s
[main] INFO org.apache.maven.cli.event.ExecutionEventLogger - Finished at: 2020-08-14T01:34:50Z
[main] INFO org.apache.maven.cli.event.ExecutionEventLogger - ------------------------------------------------------------------------
[Pipeline] publishBuildInfo
Deploying build info to: http://192.168.33.1:30082/artifactory/api/build
Deploying build descriptor to: http://192.168.33.1:30082/artifactory/api/build
Build successfully deployed. Browse it in Artifactory under http://192.168.33.1:30082/artifactory/webapp/builds/chap9_jfrog1/4

Alt Image Text

Alt Image Text

2.3 使用rtUpload上传制品

2.3.1 命名规范

仓库命名规范

  • 业务/项目一环境类型例如:demo-dev
  • 制品

命名规范

  • 应用名称一版本号一构建ID.type
  • 例如:demo-myapp-service-1. jar

制品

  • 目录规范 业务/项目
    • 应用名称
      • 版本号
        • 制品

env.serviceName = "${JOB_NAME}".split("_")[0]

Pipeline Name: demo-myapp1-service_DEV

  • repoName: demo-dev
  • businessName: demo
  • serviceName: demo
  • pomVersion: 1.1-SNAPSHOT
  • buildTag: 1

Alt Image Text

2.3.2 artifactory.groovy

//上传制品
def PushArtifact(){

    //重命名制品
    def jarName = sh returnStdout: true, script: "cd target;ls *.jar"
    jarName = jarName - "\n"
    def pom = readMavenPom file: 'pom.xml'
    env.pomVersion = "${pom.version}"
    env.serviceName = "${JOB_NAME}".split("_")[0]
    env.buildTag = "${BUILD_ID}"
    def newJarName = "${serviceName}-${pomVersion}-${buildTag}.jar"
    println("${jarName}  ------->>> ${newJarName}")
    sh " mv target/${jarName}  target/${newJarName}"

    //上传制品
    env.businessName = "${env.JOB_NAME}".split("-")[0]
    env.repoName = "${businessName}-${JOB_NAME.split("_")[-1].toLowerCase()}"
    println("本次制品将要上传到${repoName}仓库中!")   
    env.uploadDir = "${repoName}/${businessName}/${serviceName}/${pomVersion}"

    println('上传制品')
    rtUpload (
        serverId: "artifactory",
        spec:
            """{
            "files": [
                {
                "pattern": "target/${newJarName}",
                "target": "${uploadDir}/"
                }
            ]
            }"""
    )
}

2.3.3 Pipeline Script: demo-myapp1-service_DEV

#!groovy
@Library('jenkinslib@master') _

def build = new org.devops.buildtools()
def sonar = new org.devops.sonarqube()
def artifactory = new org.devops.artifactory()

pipeline {
    agent { node { label "hostmachine" }}
    parameters {
        string(name: 'srcUrl', defaultValue: 'http://192.168.33.1:30088/root/demo-maven-service.git', description: '') 
        choice(name: 'branchName', choices: 'master\nstage\ndev', description: 'Please chose your branch')
        choice(name: 'buildType', choices: 'mvn', description: 'build tool')
        choice(name: 'buildShell', choices: 'clean package -DskipTest\n--version', description: 'build tool')
    }
    stages{
        stage('Checkout') {
            steps {
                script {
                    checkout([$class: 'GitSCM', branches: [[name: "${branchName}"]], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'gitlab-admin-user', url: "${srcUrl}"]]])
                } 
            }
        }

        stage('Build') {
            steps {
                script {
                    artifactory.main(buildType,buildShell)
                    artifactory.PushArtifact()
                } 
            }
        }
    }
 }
  • demo-myapp1-service_DEV

Alt Image Text

Console Output

...
+ cd target
+ ls my-app-1.1-SNAPSHOT.jar
[Pipeline] readMavenPom
[Pipeline] echo
my-app-1.1-SNAPSHOT.jar  ------->>> demo-myapp1-service-1.1-SNAPSHOT-2.jar
[Pipeline] sh
+ mv target/my-app-1.1-SNAPSHOT.jar target/demo-myapp1-service-1.1-SNAPSHOT-2.jar
[Pipeline] echo
本次制品将要上传到demo-dev仓库中!
[Pipeline] echo
上传制品
[Pipeline] rtUpload
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
...

Alt Image Text

三、Jenkins流水线将制品发布到Nexus存储库

3.1 Jenkins流水线将制品发布到Nexus存储库

本指南的目的是创建一个工作流,我们可以在该工作流中通过Maven和CI服务器来构建,存储,管理和监视已编译的制品。

在开始之前,请确保您已经启动并运行了Jenkins。如果您尚未设置Jenkins,请复制以下命令并在启用Docker的主机上运行它。

docker run -d --name jenkins-ci -p 8080:8080 jenkins/jenkins:lts

在本地/远程计算机上配置了Jenkins容器后,请浏览器打开URL。

http:///your-ip-addr:8080

在首页,Jenkins将询问您管理员密码,您可以通过在终端中运行以下提到的命令来找到该密码。

docker exec -i jenkins-ci cat /var/jenkins_home/secrets/initialAdminPassword

b5102c8d9fa245dbb0b8da03f504d3a5

请按照指导的步骤完成配置。安全保存用户名和密码,以备将来使用。

3.2 安装Nexus制品库

Nexus是一个存储库管理器,可让您存储和检索工件。它使您能够将构建的工件托管在私有且安全的存储库中。

您始终可以使用以下命令获取Nexus Docker映像:

$ docker pull sonatype/nexus3

Using default tag: latest
latest: Pulling from sonatype/nexus3
cb3c77f9bdd8: Pull complete 
fd8daf2668d1: Pull complete 
fd1ff82b00e8: Pull complete 
2a05f7b573af: Pull complete 
Digest: sha256:6570855dfbc3eb094fe5cbbacec87aa8b91d16394dab627177e1deeebb5ac8ee
Status: Downloaded newer image for sonatype/nexus3:latest
docker.io/sonatype/nexus3:latest

在默认端口8081上运行 sonatype/nexus。请遵循以下命令:

$ docker run -d --name nexus_repo -p 8081:8081 sonatype/nexus3

在新创建的Docker容器中启动Nexus服务通常需要1-2分钟。如果您希望按照日志查看Nexus是否已启动并准备就绪,请运行以下命令:

$ docker logs nexus_repo -f

在日志中,您会看到一条消息:Started Sonatype Nexus OSS 3.20.1-01这意味着您的Nexus Repository Manager可以使用了。现在转到浏览器并打开

http://your-ip-addr:8081

找到“ 登录” 选项,如下所示:

Alt Image Text

默认用户名是admin,您需要运行以下命令来获取密码:

$ docker exec -i nexus_repo cat /nexus-data/admin.password
502ace93-5450-4f0d-97d2-9b3b3a88d149

就是这样。您的Nexus Repository Manager可以随时使用。下一步是创建一个新的存储库。

3.3 在Nexus中创建存储库

在这一步中,您将在Nexus中创建一个Maven托管存储库,您的Jenkins将在其中上载“构建”工件。

步骤1:按照以下步骤创建托管存储库,并将其命名 maven-nexus-repo,将在本指南中使用。

Alt Image Text

从列表中选择 maven2,如下所示:

Alt Image Text

步骤2:在“ 创建存储库”页面上

  • 输入名称为 maven-nexus-repo
  • 在版本策略中,选择工件的类型。
  • 在“ 托管” 部分 下的“ 部署策略”中,选择“ 允许重新部署”。它将允许您多次部署应用程序。

Alt Image Text

步骤3:要创建新用户,请转到 信息中心>服务器管理员和配置>用户>创建用户。选择 恰好是默认领域的本地用户类型:

Alt Image Text

在“ 创建用户”页面中

1、ID:输入所需的ID;在我们的案例中,它是Jenkins用户。 2、名字:输入所需的名字;就我们而言,就是Jenkins。 3、姓:输入所需的名字;在我们的例子中是用户。 4、电子邮件:输入您的电子邮件地址。 5、状态:从下拉菜单中选择 有效。 6、角色:确保将nx-admin 角色授予 用户。

至此,我们完成了Nexus Repository Manager的设置部分。让我们转到Jenkins在此处设置Nexus。

3.3.1 在Jenkins中安装和配置Nexus插件

在这里,您将为Jenkins中的Nexus安装并配置一些插件。为此,请转到Jenkins,然后转到 信息中心>管理Jenkins>管理插件>可用, 然后搜索并安装 Nexus Artifact Uploader 插件。

在Jenkins中添加Nexus Repository Manager的用户凭据。转到 仪表板>凭证>系统>全局凭证(不受限制),如下所示:

Alt Image Text

接下来,将Maven设置为托管工具。转到 仪表板>管理Jenkins>全局工具配置, 然后找到 Maven。在此部分下,单击“ Maven安装” 按钮并添加 Maven,如下所示:

Alt Image Text

另外,您也可以将Maven二进制文件直接安装到/var/jenkins_home目录中的容器中。

创建一条Jenkins流水线

pipeline {
    agent {
        label "master"
    }
    tools {
        maven "Maven"
    }
    environment {
        NEXUS_VERSION = "nexus3"
        NEXUS_PROTOCOL = "http"
        NEXUS_URL = "you-ip-addr-here:8081"
        NEXUS_REPOSITORY = "maven-nexus-repo"
        NEXUS_CREDENTIAL_ID = "nexus-user-credentials"
    }
    stages {
        stage("Clone code from VCS") {
            steps {
                script {
                    git 'https://github.com/javaee/cargotracker.git';
                }
            }
        }
        stage("Maven Build") {
            steps {
                script {
                    sh "mvn package -DskipTests=true"
                }
            }
        }
        stage("Publish to Nexus Repository Manager") {
            steps {
                script {
                    pom = readMavenPom file: "pom.xml";
                    filesByGlob = findFiles(glob: "target/*.${pom.packaging}");
                    echo "${filesByGlob[0].name} ${filesByGlob[0].path} ${filesByGlob[0].directory} ${filesByGlob[0].length} ${filesByGlob[0].lastModified}"
                    artifactPath = filesByGlob[0].path;
                    artifactExists = fileExists artifactPath;
                    if(artifactExists) {
                        echo "*** File: ${artifactPath}, group: ${pom.groupId}, packaging: ${pom.packaging}, version ${pom.version}";
                        nexusArtifactUploader(
                            nexusVersion: NEXUS_VERSION,
                            protocol: NEXUS_PROTOCOL,
                            nexusUrl: NEXUS_URL,
                            groupId: pom.groupId,
                            version: pom.version,
                            repository: NEXUS_REPOSITORY,
                            credentialsId: NEXUS_CREDENTIAL_ID,
                            artifacts: [
                                [artifactId: pom.artifactId,
                                classifier: '',
                                file: artifactPath,
                                type: pom.packaging],
                                [artifactId: pom.artifactId,
                                classifier: '',
                                file: "pom.xml",
                                type: "pom"]
                            ]
                        );
                    } else {
                        error "*** File: ${artifactPath}, could not be found";
                    }
                }
            }
        }
    }
}

让我们逐一分解上述参数:

  • NEXUS_VERSION:在这里,我们必须提及Nexus的确切版本,可以是nexus2或nexus3。在我们的情况下,它是的最新版本nexus3。
  • NEXUS_PROTOCOL:对于本指南,我们使用了HTTP协议,但是,在正式生产的情况下,您将必须使用HTTPS。
  • NEXUS_URL:添加您的IP地址和端口号,以运行Nexus。确保您添加的Nexus实例详细信息没有提及协议,例如https或http。
  • NEXUS_CREDENTIAL_ID:输入您先前在Jenkins中创建的用户ID,在本例中为 nexus-user-credentials
  • Git项目:在阶段阶段,我们使用了https://github.com/javaee/cargotracker

在完成管道设置的过程中,是时候开始Build我们的项目了。转到JenkinsNexus项目作业页面,然后单击立即构建。由于这是您的第一个构建,因此将需要一些时间。

一旦构建成功,在Jenkins控制台输出中,您将看到类似以下内容

Alt Image Text

而在Nexus Repository Manager中,您会看到类似以下内容:

Alt Image Text

对于任何组织而言,一种系统地分发项目工件的方法都是至关重要的。借助Jenkins Pipeline和Nexus Repository Manager,您可以集中管理制品,从而最终减少了重新生成构建时间以及切换CI工具的工作。

Nexus还可以配置有AWS S3和Google Cloud Storage等云存储服务,从而为您提供了更多的自由度和交付应用程序,而无任何存储麻烦。