一、制品的管理
1.1 從Pipeline中下載制品
在如上的pipeline流程中,我們是無法從Jenkins的流水線詳情中下載制品的:

但Jenkins本身就支持該種模式,只需要將Jenkinsfile中的流水線定義改為:
pipeline {
agent any
stages {
stage('Build') {
steps {
bat 'mvn -B -DskipTests clean package'
}
}
stage('Archive') {
steps {
archiveArtifacts artifacts: 'target/*.jar',allowEmptyArchive: true,fingerprint: true,onlyIfSuccessful: true
}
}
}
}
再次運行流水線,就可以查看和下載制品了:

該種方式比較原始,需要手動下載和管理制品,不太推薦。
1.2 將制品上傳到私倉
大多數(shù)公司都是有自己的制品私倉的,比如使用Nexus搭建的Maven倉庫,這種方式比較適合研發(fā)中間件項目,直接上傳到私倉供別的依賴項目使用了。
方式一:通過maven
首先項目的pom文件中需要增加如下配置:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>nexus-snapshot</id>
<name>my nexus snapshot</name>
<url>http://10.x.x.x:8081/repository/maven-snapshots</url>
</snapshotRepository>
<repository>
<id>nexus-release</id>
<name>my nexus release</name>
<url>http://10.x.x.x:8081/repository/maven-releases</url>
</repository>
</distributionManagement>
然后在需要使用的maven settings.xml中增加nexus私倉的賬密信息:
<servers>
<server>
<id>nexus-snapshot</id>
<username>admin</username>
<password>password</password>
</server>
<server>
<id>nexus-release</id>
<username>admin</username>
<password>password</password>
</server>
</servers>
我們再修改pipeline的流程如下:
pipeline {
agent any
stages {
stage('Build') {
steps {
bat 'mvn -B -DskipTests clean package'
}
}
stage('Archive') {
steps {
bat 'mvn deploy'
}
}
}
}
提交代碼,運行流水線,Deploy插件會根據(jù)Maven項目中定義的version值決定是使用nexus-snapshot倉庫還是nexus-release倉庫。當version值是以-SNAPSHOT后綴結(jié)尾時,則發(fā)布到nexus-snapshot倉庫。
如下是流水線輸入日志的最后部分:
Uploaded to nexus-snapshot: http://10.x.x.x:8081/repository/maven-snapshots/com/example/java-cicd-test/0.0.2-SNAPSHOT/java-cicd-test-0.0.2-20221012.055840-1.jar (18 MB at 14 MB/s)
Uploading to nexus-snapshot: http://10.x.x.x:8081/repository/maven-snapshots/com/example/java-cicd-test/0.0.2-SNAPSHOT/java-cicd-test-0.0.2-20221012.055840-1.pom
Progress (1): 2.2 kB
Uploaded to nexus-snapshot: http://10.x.x.x:8081/repository/maven-snapshots/com/example/java-cicd-test/0.0.2-SNAPSHOT/java-cicd-test-0.0.2-20221012.055840-1.pom (2.2 kB at 66 kB/s)
Downloading from nexus-snapshot: http://10.x.x.x:8081/repository/maven-snapshots/com/example/java-cicd-test/maven-metadata.xml
Uploading to nexus-snapshot: http://10.3.17.71:8081/repository/maven-snapshots/com/example/java-cicd-test/0.0.2-SNAPSHOT/maven-metadata.xml
Progress (1): 775 B
Uploaded to nexus-snapshot: http://10.x.x.x:8081/repository/maven-snapshots/com/example/java-cicd-test/0.0.2-SNAPSHOT/maven-metadata.xml (775 B at 5.8 kB/s)
Uploading to nexus-snapshot: http://10.x.x.x:8081/repository/maven-snapshots/com/example/java-cicd-test/maven-metadata.xml
Progress (1): 285 B
Uploaded to nexus-snapshot: http://10.x.x.x:8081/repository/maven-snapshots/com/example/java-cicd-test/maven-metadata.xml (285 B at 9.2 kB/s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 14.466 s
[INFO] Finished at: 2022-10-12T13:58:41+08:00
[INFO] ------------------------------------------------------------------------
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
然后搜索nexus上我們的項目名稱,就能搜索到了:

方式二:通過Jenkins插件
首先需要在jenkins的插件市場上安裝Nexus Platform,然后在Jenkins的系統(tǒng)設(shè)置中添加nexus服務(wù)的信息:
!jenkins配置nexus服務(wù)](https://upload-images.jianshu.io/upload_images/5673257-e14728f08afd0ab4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
然后需要我們編寫流水線Archive階段的腳本,這個有點復雜,我們借助Jenkins Pipeline流水線語法工具生成:



- 示例步驟:選擇nexus publisher;
- nexus instance:選擇上一步配置好的nexus服務(wù);
- nexus repository:根據(jù)自己需要選擇release庫或者snapshots庫;
- tag:隨意;
- packages Group:填寫你項目的GroupId;
- packages Artifact:填寫你項目的ArtifactId;
- packages Version:填寫你項目的Version;
- packages packaging:選擇打包方式,我們是jar;
- packages Artifacts File Path:選擇需要上傳的制品內(nèi)容;
其余保持默認不動。然后點擊下面的“生成流水線腳本”按鈕,即可得到該步驟的流水線腳本了,將其放到流水線文件中:
pipeline {
agent any
stages {
stage('Build') {
steps {
bat 'mvn -B -DskipTests clean package'
}
}
stage('Archive') {
steps {
nexusPublisher nexusInstanceId: 'my-nexus', nexusRepositoryId: 'maven-snapshots', packages: [[$class: 'MavenPackage', mavenAssetList: [[classifier: '', extension: '', filePath: './target/*.jar']], mavenCoordinate: [artifactId: 'java-cicd-test', groupId: 'com.example', packaging: 'jar', version: '0.0.3-SNAPSHOT']]]
}
}
}
}
然后提交代碼,觸發(fā)流水線運行,就能看到執(zhí)行成功,同樣查看下日志,并在nexus上搜索下我們的制品,這里同上,就不再贅述了。
總結(jié)下,這兩種方式,第二種的好處就是和nexus的配置,包括密碼都保存在Jenkins的配置中了,Jenkins本身就有權(quán)限控制,比較安全;缺點就是pipeline的配置略顯麻煩,不如maven的方式簡單好用,個人比較推薦使用maven。
1.3 將制品上傳到鏡像倉庫
首先我們自己新建一個鏡像私倉,這個可以參考:Docker Registry的搭建與使用 - 簡書 (jianshu.com)
然后,我們需要在項目根目錄下新增一個Dockerfile:
FROM openjdk:8
EXPOSE 8080
ADD target/java-cicd-test-0.0.3-SNAPSHOT.jar /app/app.jar
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
方式一:在Pipeline中使用docker命令
我們修改pipeline的描述:
pipeline {
agent any
stages {
stage('Build') {
steps {
bat 'mvn -B -DskipTests clean package'
}
}
stage('Archive') {
steps {
bat 'docker build -t java-cicd-test:0.0.3-SNAPSHOT .'
bat 'docker tag java-cicd-test:0.0.3-SNAPSHOT localhost:5000/java-cicd-test:0.0.3-SNAPSHOT'
bat 'docker push localhost:5000/java-cicd-test:0.0.3-SNAPSHOT'
}
}
}
}
提交代碼運行流水線,就能將當前項目打成鏡像并提交到私倉鏡像倉庫了。
C:\Users\zhangxun\.jenkins\workspace\java-cicd-test>docker push localhost:5000/java-cicd-test:0.0.3-SNAPSHOT
The push refers to repository [localhost:5000/java-cicd-test]
cc71e4dd775f: Preparing
bff9fe6e429c: Preparing
7c245b2fe4f1: Preparing
f9e18e59a565: Preparing
26a504e63be4: Preparing
8bf42db0de72: Preparing
31892cc314cb: Preparing
11936051f93b: Preparing
8bf42db0de72: Waiting
31892cc314cb: Waiting
11936051f93b: Waiting
7c245b2fe4f1: Pushed
f9e18e59a565: Pushed
cc71e4dd775f: Pushed
8bf42db0de72: Pushed
31892cc314cb: Pushed
11936051f93b: Pushed
bff9fe6e429c: Pushed
26a504e63be4: Pushed
0.0.3-SNAPSHOT: digest: sha256:06fb42031d422fbfdac62918ccdf375537e145f607a01409198eaf9c7fba4c13 size: 2007
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
真實生產(chǎn)中,我們搭建的鏡像倉庫或者使用的公有云進行倉庫,比如阿里云、騰訊云鏡像倉庫肯定是需要登錄驗證的,只需要加一行命令docker login --username=xxx --password=xxx即可,而且公有云鏡像倉庫還配有webhook,可用于讓Jenkins監(jiān)控到鏡像推送是否成功,從而決定是否繼續(xù)下一個部署操作,這塊內(nèi)容和上面講解sonarqube比較類似,而且需要開通公有云服務(wù),此處就不展開了。
方式二:使用maven的docker插件
由于我們項目使用的是Spring Boot2.7.3,自身就包含了對鏡像制作的支持,因此無需下載和引入其它插件,而且也不需要項目根目錄下的Dockefile。
首先,我們需要設(shè)置本地的Docker Engine,使之對外暴露端口,否則SpringBoot無法和Docker Engine進行交互:

然后,我們pom中增加如下配置:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
<image>
<!--鏡像名稱-->
<name>localhost:5000/${project.name}:${project.version}</name>
<!--生成鏡像后是否推送到鏡像倉庫-->
<publish>true</publish>
</image>
<docker>
<!--docker daemon地址,此處是本機的Docker Desktop暴露的地址-->
<host>http://localhost:2375</host>
<!--不使用TLS訪問-->
<tlsVerify>false</tlsVerify>
<!--Docker推送鏡像倉庫配置-->
<publishRegistry>
<!--推送鏡像倉庫用戶名-->
<username>admin</username>
<!--推送鏡像倉庫密碼-->
<password>admin</password>
<!--推送鏡像倉庫地址-->
<url>http://localhost:5000</url>
</publishRegistry>
</docker>
</configuration>
</plugin>
</plugins>
</build>
然后執(zhí)行構(gòu)建命令mvn spring-boot:build-image或者雙擊IDEA中Maven面板中的SpringBoot:build-image,就可以嘗試鏡像的制作了。此處需要下載一些內(nèi)容,時間較長,對github的訪問也要暢通。如果能順利完成的話,我們修改Pipeline中內(nèi)容:
pipeline {
agent any
stages {
stage('Build') {
steps {
bat 'mvn -B -DskipTests clean package'
}
}
stage('Archive') {
steps {
bat 'mvn spring-boot:build-image'
}
}
}
}
如此就可以通過簡單的配置晚上將項目打包鏡像推送到私倉中了。
總結(jié)下,這兩種方式,個人比較偏向第一種,Dockerfile比較靈活,可以定制自己需要的內(nèi)容,而且docker命令比較直觀簡單,方便修改。第二種方式試了幾次,因為不能從github很流暢地下載內(nèi)容,并沒有真的實驗成功,估計在真實環(huán)境中也會存在這個問題。
二、自動部署
自動部署則是在Jenkinsfile中增加一個stage,通過遠程命令或者接口調(diào)用的方式將制品從私倉中拉取到目標服務(wù)器上進行部署。這塊內(nèi)容如果涉及遠程服務(wù)器或者公有云,甚至是k8s集群會比較復雜,此處為簡單演示起見,就在本機上演示下如何將上一步的鏡像拉取下來進行部署。
修改Jenkinsfile如下:
pipeline {
agent any
stages {
stage('Build') {
steps {
bat 'mvn -B -DskipTests clean package'
}
}
stage('Archive') {
steps {
bat 'docker build -t java-cicd-test:0.0.4-SNAPSHOT .'
bat 'docker tag java-cicd-test:0.0.4-SNAPSHOT localhost:5000/java-cicd-test:0.0.4-SNAPSHOT'
bat 'docker push localhost:5000/java-cicd-test:0.0.4-SNAPSHOT'
}
}
stage('Deploy') {
steps {
bat 'docker pull localhost:5000/java-cicd-test:0.0.4-SNAPSHOT'
bat 'docker run -d -p 8080:8080 --name java-cicd-test localhost:5000/java-cicd-test:0.0.4-SNAPSHOT'
}
}
}
}
然后提交代碼運行流水線,流水線能正常運行成功,且發(fā)現(xiàn)新的0.0.4-SNAPSHOT鏡像已經(jīng)成功上傳私倉鏡像倉庫。然后我們看下本地的Docker Desktop,發(fā)現(xiàn)鏡像也從私倉中拉取下來并成功運行了。



DevOps和CICD是一個永恒的話題,其中的思想、組件、工具都有很多種選擇,沒有說一定要如何如何,各家公司也需要按照自己實際情況制定合適的流水線模式。