一、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] ------------------------------------------------------------------------
...


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

1.2 使用Jenkins插件上传制品¶
- 安装
nexus artifact uploader插件 nexus artifact uploader - 使用片段生成器生成DSL

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 deployMavenUpload()mvn deploy- 更新
pom.xml的version版本
#!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")ornexus.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

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

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


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

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"
}
}, {
...


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

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

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 使用artifactory和maven打包构建¶
#!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


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

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

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
...

三、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
找到“ 登录” 选项,如下所示:

默认用户名是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,将在本指南中使用。

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

步骤2:在“ 创建存储库”页面上
- 输入名称为
maven-nexus-repo - 在版本策略中,选择工件的类型。
- 在“ 托管” 部分 下的“ 部署策略”中,选择“ 允许重新部署”。它将允许您多次部署应用程序。

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

在“ 创建用户”页面中
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的用户凭据。转到 仪表板>凭证>系统>全局凭证(不受限制),如下所示:

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

另外,您也可以将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控制台输出中,您将看到类似以下内容

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

对于任何组织而言,一种系统地分发项目工件的方法都是至关重要的。借助Jenkins Pipeline和Nexus Repository Manager,您可以集中管理制品,从而最终减少了重新生成构建时间以及切换CI工具的工作。
Nexus还可以配置有AWS S3和Google Cloud Storage等云存储服务,从而为您提供了更多的自由度和交付应用程序,而无任何存储麻烦。