# 09 Docker 应⽤的 CICD
# 1. CI/CD 实现⽅式
# 1.1 传统环境的 CI/CD
CI:开发⼈员 -> 提交代码 ->Gitlab 仓库 ->Jenkins/CI 抓取代码 -> 漏洞扫描 -> 编译 --> 推送 nexus 仓库 --> 部署⾄测试环境;
CD:jenkins 拉取 Nexus 仓库代码 --> 部署⽣产环境;

# 1.2 Docker 实现 CI/CD
CI:开发⼈员 -> 提交代码 ->gitlab 仓库 ->Jenkins/CI 抓取代码 -> 漏洞扫描 -> 编译 -> 构建镜像 -> 推送 Harbor-> 部署应⽤⾄ Docker 测试环境;
CD:Jenkins/CD-> 获取 Harbor 仓库对应项⽬镜像 -> 部署应⽤⾄ Docker ⽣产环境;

# 2. 部署服务组件
# 2.1 服务地址规划
| ⻆⾊名称 | 系统 | IP 地址 | 部署⽅式 |
|---|---|---|---|
| gitlab | Centos 7.6 | 192.168.40.110 | 容器部署 |
| jenkins | Centos 7.6 | 192.168.40.120 | 容器部署 |
| nexus | Centos 7.6 | 192.168.40.121 | 容器部署 |
| sonarqube | Centos 7.6 | 192.168.40.130 | 容器部署 |
| harbor | Centos 7.6 | 192.168.40.134 | |
| docker-test | Centos 7.6 | 192.168.40.181 | 8888 |
| docker-prod | Centos 7.6 | 192.168.40.182 | 80 |
1 、所有节点部署 docker
[root@harbor ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 | |
[root@harbor ~]# curl -o /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo | |
[root@harbor ~]# yum list docker-ce --showduplicates |sort -r | |
[root@harbor ~]# yum install docker-ce docker-compose -y |
2、配置 Docker 加速
[root@harbor ~]# sudo mkdir -p /etc/docker | |
[root@harbor ~]# sudo tee /etc/docker/daemon.json <<-'EOF' | |
{ | |
"registry-mirrors": [ | |
"https://docker.credclouds.com", | |
"https://k8s.credclouds.com", | |
"https://quay.credclouds.com", | |
"https://gcr.credclouds.com", | |
"https://k8s-gcr.credclouds.com", | |
"https://ghcr.credclouds.com", | |
"https://do.nark.eu.org", | |
"https://docker.m.daocloud.io", | |
"https://docker.nju.edu.cn", | |
"https://docker.mirrors.sjtug.sjtu.edu.cn", | |
"https://docker.1panel.live", | |
"https://docker.rainbond.cc" | |
], | |
"exec-opts": ["native.cgroupdriver=systemd"] | |
} | |
EOF | |
[root@harbor ~]# systemctl enable docker --now |
3、安装 Harbor
[root@harbor ~]# cd /soft/ | |
[root@harbor ~]# wget https://github.com/goharbor/harbor/releases/download/v2.6.1/harbor-offline-installer-v2.6.1.tgz | |
[root@harbor soft]# tar xf harbor-offline-installer-v2.6.1.tgz | |
[root@harbor soft]# cd harbor | |
[root@harbor harbor]# vim harbor.yml | |
hostname: harbor.hmallleasing.com | |
... | |
#https: | |
# # https port for harbor, default is 443 | |
# port: 443 | |
# # The path of cert and key files for nginx | |
# certificate: /your/certificate/path | |
# private_key: /your/private/key/path | |
... | |
harbor_admin_password: Harbor12345 | |
[root@harbor harbor]# ./install.sh |
4、推送镜像至 Harbor
[root@harbor harbor]# docker tag beae173ccac6 harbor.hmallleasing.com/ops/busybox.v1 | |
[root@harbor harbor]# docker push harbor.hmallleasing.com/ops/busybox.v1 | |
[root@harbor harbor]# docker login harbor.hmallleasing.com | |
[root@harbor harbor]# docker push harbor.hmallleasing.com/ops/busybox.v1 |
5、Harbor 停止与启动
#停用 Harbor | |
[root@harbor harbor]# pwd | |
/soft/harbor | |
[root@harbor harbor]# docker-compose stop | |
#启动 Harbor | |
[root@harbor harbor]# docker-compose up -d | |
[root@harbor harbor]# docker-compose start |
# 2.2 部署 Gitlab
1、部署 gitlab
docker run -d --name gitlab \ | |
-p 80:80 -p 9022:22 \ | |
--restart always \ | |
--privileged=true \ | |
--hostname "gitlab.hmallleasing.com" \ | |
--add-host jenkins.hmallleasing.com:192.168.40.120 \ | |
-v /data/gitlab/etc:/etc/gitlab \ | |
-v /data/gitlab/log:/var/log/gitlab \ | |
-v /data/gitlab/opt:/var/opt/gitlab \ | |
registry.cn-hangzhou.aliyuncs.com/old_xu/gitlab-ce:16.10.0-ce.0 |
2、获取 gitlab 的密码
[root@gitlab ~]# cat /data/gitlab/etc/initial_root_password | |
Password: b//+rFJv06YO83ANK1MRLvFj9ygC1dvqq2Lr4DjNj6Y= |
3、准备项⽬代码
[root@gitlab ~]# wget http://file.oldxu.net/jenkins/springboot-devops-demo-jar-java17.tar.gz | |
[root@gitlab ~]# tar xf springboot-devops-demo-jar-java17.tar.gz |
4、为项⽬源代码注⼊ Dockerfile ⽂件
[root@gitlab springboot-devops-demo-jar-java17]# cat Dockerfile | |
FROM openjdk:17-jdk-alpine | |
COPY ./target/*.jar /oldxu-jar.jar | |
EXPOSE 8080 | |
ENTRYPOINT ["sh","-c","java -jar /oldxu-jar.jar --server.port=8080"] |
5、提交代码⾄ gitlab 服务器
git config --global user.name "Xu Yong" | |
git config --global user.email "373370405@qq.com" | |
git init | |
git add . | |
git commit -m "first" | |
git remote add origin http://gitlab.hmallleasing.com/root/springboot-devops-demo-jar.git | |
git push origin master |
6、检查 gitlab 仓库的代码

# 2.3 部署 Jenkins
因为 Jenkins 需要调⽤ Docker 构建镜像,但默认的 Jenkins 没有内置 docker 命令,也⽆法访问宿主机的 Docker,因此我们需要对 Jenkins 进⾏如下配置:
- 1、挂在宿主机 docker 命令⾄ jenkins 容器内;
- 2、挂载宿主机的 docker.sock ⽂件,确保 jenkins 容器能通过宿主机的 docker 进⾏镜像的构建;
- 3、设置 jenkins 的时区,确保获取的时间是准确的;
- 4、由于 gitlab、harbor 等服务都需要通过域名进⾏访问,因此可以通过 --add-host 明确指定对应的解析;
- 5、jenkins 的数据⽬录需要挂载到宿主机的某个⽬录存储;
1、部署 Jenkins
docker run -d --name jenkins \ | |
--hostname "jenkins.hmallleasing.com" \ | |
--restart=always \ | |
-p 8080:8080 \ | |
-p 50000:50000 \ | |
-u root \ | |
--privileged=true \ | |
-e TZ=Asia/Shanghai \ | |
-v /etc/localtime:/etc/localtime:ro \ | |
-v jenkins_home:/var/jenkins_home \ | |
-v /var/run/docker.sock:/var/run/docker.sock \ | |
-v /usr/bin/docker:/usr/bin/docker \ | |
--add-host gitlab.hmallleasing.com:192.168.40.110 \ | |
--add-host nexus.hmallleasing.com:192.168.40.121 \ | |
--add-host sonar.hmallleasing.com:192.168.40.130 \ | |
--add-host harbor.hmallleasing.com:192.168.40.134 \ | |
jenkins/jenkins:2.528.2-lts-jdk17 | |
# nerdctl | |
nerdctl run -d --name jenkins \ | |
--hostname "jenkins.oldxu.net" \ | |
--restart=always \ | |
-p 8080:8080 \ | |
-p 50000:50000 \ | |
-u root \ | |
--privileged=true \ | |
-e TZ=Asia/Shanghai \ | |
-v /etc/localtime:/etc/localtime:ro \ | |
-v jenkins_home:/var/jenkins_home \ | |
-v /usr/local/bin/nerdctl:/usr/local/bin/nerdctl \ | |
-v /run/containerd/containerd.sock:/run/containerd/containerd.sock \ | |
-v /usr/local/bin/buildctl:/usr/local/bin/buildctl \ | |
-v /run/buildkit/buildkitd.sock:/run/buildkit/buildkitd.sock \ | |
--add-host gitlab.hmallleasing.com:192.168.40.110 \ | |
--add-host nexus.hmallleasing.com:192.168.40.121 \ | |
--add-host sonar.hmallleasing.com:192.168.40.130 \ | |
--add-host harbor.hmallleasing.com:192.168.40.34 \ | |
jenkins/jenkins:2.528.2-lts-jdk17 |
2、获取 Jenkins 的初始密码
[root@jenkins ~]# cat /var/lib/docker/volumes/jenkins_home/_data/secrets/initialAdminPassword | |
90da771dfbdb4b0db4125137fef409e8 |
3、安装 jenkins 插件
- 1、安装 docker、Docker Pipeline 插件,⽤于调⽤ docker 容器;
- 2、安装 pipeline、Pipeline Stage View、Blue Ocean,⽤于执⾏流⽔线语法
- 3、安装 git、gitlab 插件
- 4、安装 Active Choices 插件
- 5、安装 Localization: Chinese 中⽂插件
# 3. 获取代码
# 3.1 创建凭据
点击系统管理 ->Manage Credentials-> 全局凭据,创建⽤户访问 gitlab 的凭据,填写⽤户名、密码、ID 和描述

# 3.2 编写 Stage
创建流水线项目 devops_demo_docker-CI
pipeline { | |
agent any | |
//将workspace工作目录赋予给WORK_SPACES变量,后续stage能正常找到工作目录 | |
environment { | |
Git_Id = "gitlab-root-token" | |
Git_Url = "http://gitlab.hmallleasing.com/root/springboot-devops-demo-jar.git" | |
WORK_SPACES = "${WORKSPACE}" | |
Harbor_Url = "harbor.hmallleasing.com" | |
Pro = "app" //Harbor镜像存储的目录 | |
ImageName = "${Harbor_Url}/${Pro}/springboot" //镜像的完整名称 | |
} | |
stages { | |
stage('获取代码'){ | |
steps { | |
git branch: 'master', credentialsId: "${Git_Id }", url: "${Git_Url}" | |
sh 'pwd && ls -l' | |
} | |
} | |
} | |
} |
# 3.3 检查结果
代码被获取到 /var/jenkins_home/workspace ⼯作路径下

# 4. 编译代码
由于 Jenkins 是通过 Docker 运⾏的,因此 Jenkins 容器内并不包含 Maven 相关的命令。如果需要在 Jenkins 中编译代码,可以选择如下两种⽅法:
1、在宿主机上安装 Maven,并将 Maven 安装⽬录挂载到 Jenkins 容器内。这样,Jenkins 容器可以访问并使⽤宿主机上的 Maven 命令。
2、让 jenkins 在编译时运⾏⼀个 Maven 的容器作为构建环境。这样,每次运⾏构建任务时,Jenkins 会⾃动启动⼀个 Maven 容器来执⾏项⽬编译。
# 4.1 maven 环境
1、下载 maven 镜像
[root@docker-node1 ~]# docker pull maven:3.8.5-openjdk-17-slim |
2、准备 maven 配置⽂件,可以在配置⽂件中注⼊阿⾥云加速地址,或是 Nexus 制品库地址(避免私有依赖的 jar 包⽆法获取)
[root@docker-node1 ~]# wget -O /etc/maven_settings.xml https://linux.oldxu.net/settings_docker.xml | |
# 配置 nexus 仓库认证 | |
<servers> | |
<server> | |
<id>maven-central</id> | |
<username>admin</username> | |
<password>talent</password> | |
</server> | |
<server> | |
<id>nexus-snapshots</id> | |
<username>admin</username> | |
<password>talent</password> | |
</server> | |
<server> | |
<id>nexus-releases</id> | |
<username>admin</username> | |
<password>talent</password> | |
</server> | |
</servers> | |
# 配置 nexus 仓库地址 | |
<mirrors> | |
<mirror> | |
<id>maven-central</id> | |
<mirrorOf>*</mirrorOf> | |
<url>http://nexus.hmallleasing.com/repository/maven-central/</url> | |
</mirror> | |
<mirror> | |
<id>nexus-snapshots</id> | |
<mirrorOf>*</mirrorOf> | |
<url>http://nexus.hmallleasing.com/repository/maven-snapshots/</url> | |
</mirror> | |
<mirror> | |
<id>nexus-releases</id> | |
<mirrorOf>*</mirrorOf> | |
<url>http://nexus.hmallleasing.com/repository/maven-releases/</url> | |
</mirror> | |
</mirrors> |
# 4.2 编写 Stage
pipeline { | |
agent any | |
//将workspace工作目录赋予给WORK_SPACES变量,后续stage能正常找到工作目录 | |
environment { | |
Git_Id = "gitlab-root-token" | |
Git_Url = "http://gitlab.hmallleasing.com/root/springboot-devops-demo-jar.git" | |
WORK_SPACES = "${WORKSPACE}" | |
Harbor_Url = "harbor.hmallleasing.com" | |
Pro = "app" //Harbor镜像存储的目录 | |
ImageName = "${Harbor_Url}/${Pro}/springboot" //镜像的完整名称 | |
} | |
stages { | |
stage('获取代码'){ | |
steps { | |
git branch: 'master', credentialsId: "${Git_Id }", url: "${Git_Url}" | |
sh 'pwd && ls -l' | |
} | |
} | |
stage('编译代码') { | |
agent { | |
docker { | |
image 'maven:3.8.5-openjdk-17-slim' | |
args '-v $HOME/.m2:/root/.m2 -v /etc/maven_settings.xml:/usr/share/maven/conf/settings.xml' | |
//当链接的镜像是私有仓库时,我们需要传递私有仓库的地址和认证信息 | |
//registryUrl "https://${Url}" | |
//registryCredentialsId 'harbor-auth' | |
} | |
} | |
steps { | |
sh 'cd ${WORK_SPACES} && mvn package -Dmaven.test.skip=true' | |
sh 'cd ${WORK_SPACES} && ls -l && ls -l target/' | |
} | |
} | |
} | |
} |
# 4.3 检查结果

# 5. 构建镜像
镜像构建通过镜像名称 + 镜像 Tag 组成,所以我们可以先定义⼀个阶段完成镜像 Tag 的⽣成;
# 5.1 定义镜像 Tag
1、创建新的 Stage 来定义镜像 Tag 相关内容
pipeline { | |
agent any | |
//将workspace工作目录赋予给WORK_SPACES变量,后续stage能正常找到工作目录 | |
environment { | |
Git_Id = "gitlab-root-token" | |
Git_Url = "http://gitlab.hmallleasing.com/root/springboot-devops-demo-jar.git" | |
WORK_SPACES = "${WORKSPACE}" | |
Harbor_Url = "harbor.hmallleasing.com" | |
Pro = "app" //Harbor镜像存储的目录 | |
ImageName = "${Harbor_Url}/${Pro}/springboot" //镜像的完整名称 | |
} | |
stages { | |
stage('获取代码'){ | |
steps { | |
git branch: 'master', credentialsId: "${Git_Id }", url: "${Git_Url}" | |
sh 'pwd && ls -l' | |
} | |
} | |
stage('编译代码') { | |
agent { | |
docker { | |
image 'maven:3.8.5-openjdk-17-slim' | |
args '-v $HOME/.m2:/root/.m2 -v /etc/maven_settings.xml:/usr/share/maven/conf/settings.xml' | |
//当链接的镜像是私有仓库时,我们需要传递私有仓库的地址和认证信息 | |
//registryUrl "https://${Url}" | |
//registryCredentialsId 'harbor-auth' | |
} | |
} | |
steps { | |
sh 'cd ${WORK_SPACES} && mvn package -Dmaven.test.skip=true' | |
sh 'cd ${WORK_SPACES} && ls -l && ls -l target/' | |
} | |
} | |
stage('生成成镜像Tag'){ | |
steps { | |
script { | |
//镜像本次的CommitID | |
env.COMMITID = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim() | |
//镜像构建的时间 | |
env.BuildTime = sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim() | |
//镜像Tag | |
env.ImageTag = COMMITID + "_" + BuildTime | |
} | |
sh 'echo ${ImageTag}' | |
} | |
} | |
} | |
} |
2、检查镜像 Tag 标签格式 commit + 年⽉⽇ + 时分秒

# 5.2 编写 Stage
pipeline { | |
agent any | |
//将workspace工作目录赋予给WORK_SPACES变量,后续stage能正常找到工作目录 | |
environment { | |
Git_Id = "gitlab-root-token" | |
Git_Url = "http://gitlab.hmallleasing.com/root/springboot-devops-demo-jar.git" | |
WORK_SPACES = "${WORKSPACE}" | |
Harbor_Url = "harbor.hmallleasing.com" | |
Pro = "app" //Harbor镜像存储的目录 | |
ImageName = "${Harbor_Url}/${Pro}/springboot" //镜像的完整名称 | |
} | |
stages { | |
stage('获取代码'){ | |
steps { | |
git branch: 'master', credentialsId: "${Git_Id }", url: "${Git_Url}" | |
sh 'pwd && ls -l' | |
} | |
} | |
stage('编译代码') { | |
agent { | |
docker { | |
image 'maven:3.8.5-openjdk-17-slim' | |
args '-v $HOME/.m2:/root/.m2 -v /etc/maven_settings.xml:/usr/share/maven/conf/settings.xml' | |
//当链接的镜像是私有仓库时,我们需要传递私有仓库的地址和认证信息 | |
//registryUrl "https://${Url}" | |
//registryCredentialsId 'harbor-auth' | |
} | |
} | |
steps { | |
sh 'cd ${WORK_SPACES} && mvn package -Dmaven.test.skip=true' | |
sh 'cd ${WORK_SPACES} && ls -l && ls -l target/' | |
} | |
} | |
stage('生成成镜像Tag'){ | |
steps { | |
script { | |
//镜像本次的CommitID | |
env.COMMITID = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim() | |
//镜像构建的时间 | |
env.BuildTime = sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim() | |
//镜像Tag | |
env.ImageTag = COMMITID + "_" + BuildTime | |
} | |
sh 'echo ${ImageTag}' | |
} | |
} | |
stage('制作镜像'){ | |
steps { | |
sh 'cd ${WORK_SPACES} && docker build -t ${ImageName}:${ImageTag} .' | |
} | |
} | |
} | |
} |
# 5.3 检查结果
[root@jenkins ~]# docker images|grep harbor.hmallleasing.com | |
harbor.hmallleasing.com/app/springboot aeacd46_20251130_165729 aa41b44e5aaf 7 minutes ago 345MB |
# 6. 推送镜像⾄仓库
# 6.1 创建凭据
由于推送镜像⾄ Harbor 私有仓库,需要身份认证,为此我们可以创建⼀个凭据,存储 Harbor 对应的⽤户名以及密码,⽽后在 Pipeline 中进⾏使⽤。
点击系统管理 ->Manage Credentials-> 全局凭据

# 6.2 编写 Stage
pipeline { | |
agent any | |
//将workspace工作目录赋予给WORK_SPACES变量,后续stage能正常找到工作目录 | |
environment { | |
Git_Id = "gitlab-root-token" | |
Git_Url = "http://gitlab.hmallleasing.com/root/springboot-devops-demo-jar.git" | |
WORK_SPACES = "${WORKSPACE}" | |
Harbor_Url = "harbor.hmallleasing.com" | |
Pro = "app" //Harbor镜像存储的目录 | |
ImageName = "${Harbor_Url}/${Pro}/springboot" //镜像的完整名称 | |
HARBOR_ID = "harbor-auth" | |
} | |
stages { | |
stage('获取代码'){ | |
steps { | |
git branch: 'master', credentialsId: "${Git_Id }", url: "${Git_Url}" | |
sh 'pwd && ls -l' | |
} | |
} | |
stage('编译代码') { | |
agent { | |
docker { | |
image 'maven:3.8.5-openjdk-17-slim' | |
args '-v $HOME/.m2:/root/.m2 -v /etc/maven_settings.xml:/usr/share/maven/conf/settings.xml' | |
//当链接的镜像是私有仓库时,我们需要传递私有仓库的地址和认证信息 | |
//registryUrl "https://${Url}" | |
//registryCredentialsId 'harbor-auth' | |
} | |
} | |
steps { | |
sh 'cd ${WORK_SPACES} && mvn package -Dmaven.test.skip=true' | |
sh 'cd ${WORK_SPACES} && ls -l && ls -l target/' | |
} | |
} | |
stage('生成成镜像Tag'){ | |
steps { | |
script { | |
//镜像本次的CommitID | |
env.COMMITID = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim() | |
//镜像构建的时间 | |
env.BuildTime = sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim() | |
//镜像Tag | |
env.ImageTag = COMMITID + "_" + BuildTime | |
} | |
sh 'echo ${ImageTag}' | |
} | |
} | |
stage('制作镜像'){ | |
steps { | |
sh 'cd ${WORK_SPACES} && docker build -t ${ImageName}:${ImageTag} .' | |
} | |
} | |
stage('推送镜像至Harbor'){ | |
steps { | |
withCredentials([usernamePassword(credentialsId: "${HARBOR_ID}", passwordVariable: 'HARBOR_PASSWORD', usernameVariable: 'HARBOR_USER')]) { | |
//登陆harbor | |
sh 'echo "${HARBOR_PASSWORD}" | docker login ${Harbor_Url} -u "${HARBOR_USER}" --password-stdin' | |
sh 'docker push ${ImageName}:${ImageTag}' | |
} | |
} | |
} | |
} | |
} |
# 6.3 检查结果

# 7. 交付应⽤⾄ Docker
由于 Jenkins 容器内封装了 Docker 命令,并且挂载了宿主机的 socket ⽂件,我们可以直接在 Jenkins 任务中使⽤容器内的 Docker 命令来构建和运⾏容器。
# 7.1 编写 Stage
1、编写 pipeline 流水线
pipeline { | |
agent any | |
//将workspace工作目录赋予给WORK_SPACES变量,后续stage能正常找到工作目录 | |
environment { | |
Git_Id = "gitlab-root-token" | |
Git_Url = "http://gitlab.hmallleasing.com/root/springboot-devops-demo-jar.git" | |
WORK_SPACES = "${WORKSPACE}" | |
Harbor_Url = "harbor.hmallleasing.com" | |
Pro = "app" //Harbor镜像存储的目录 | |
ImageName = "${Harbor_Url}/${Pro}/springboot" //镜像的完整名称 | |
HARBOR_ID = "harbor-auth" | |
} | |
stages { | |
stage('获取代码'){ | |
steps { | |
git branch: 'master', credentialsId: "${Git_Id }", url: "${Git_Url}" | |
sh 'pwd && ls -l' | |
} | |
} | |
stage('编译代码') { | |
agent { | |
docker { | |
image 'maven:3.8.5-openjdk-17-slim' | |
args '-v $HOME/.m2:/root/.m2 -v /etc/maven_settings.xml:/usr/share/maven/conf/settings.xml' | |
//当链接的镜像是私有仓库时,我们需要传递私有仓库的地址和认证信息 | |
//registryUrl "https://${Url}" | |
//registryCredentialsId 'harbor-auth' | |
} | |
} | |
steps { | |
sh 'cd ${WORK_SPACES} && mvn package -Dmaven.test.skip=true' | |
sh 'cd ${WORK_SPACES} && ls -l && ls -l target/' | |
} | |
} | |
stage('生成成镜像Tag'){ | |
steps { | |
script { | |
//镜像本次的CommitID | |
env.COMMITID = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim() | |
//镜像构建的时间 | |
env.BuildTime = sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim() | |
//镜像Tag | |
env.ImageTag = COMMITID + "_" + BuildTime | |
} | |
sh 'echo ${ImageTag}' | |
} | |
} | |
stage('制作镜像'){ | |
steps { | |
sh 'cd ${WORK_SPACES} && docker build -t ${ImageName}:${ImageTag} .' | |
} | |
} | |
stage('推送镜像至Harbor'){ | |
steps { | |
withCredentials([usernamePassword(credentialsId: "${HARBOR_ID}", passwordVariable: 'HARBOR_PASSWORD', usernameVariable: 'HARBOR_USER')]) { | |
//登陆harbor | |
sh 'echo "${HARBOR_PASSWORD}" | docker login ${Harbor_Url} -u "${HARBOR_USER}" --password-stdin' | |
sh 'docker push ${ImageName}:${ImageTag}' | |
} | |
} | |
} | |
stage('交付镜像测试测试环境') { | |
steps { | |
sh "export DOCKER_HOST=tcp://192.168.40.181:2375 && \ | |
docker rm -f spring_test && \ | |
docker run -d --name spring_test -p8888:8080 ${ImageName}:${ImageTag}" | |
} | |
} | |
} | |
} |
2、在测试服务器上,开启 Docker 的远程访问功能;
[root@docker_test ~]# cat /lib/systemd/system/docker.service | |
... | |
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 | |
... |
3、使⽤方法
export DOCKER_HOST=tcp://10.0.0.182:2375 | |
docker run .... |
# 7.2 检查结果
1、检查容器的运⾏结果
[root@docker_test ~]# docker ps | |
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES | |
f1333491e731 harbor.hmallleasing.com/app/springboot:aeacd46_20251130_182807 "sh -c 'java -jar /o…" About a minute ago Up About a minute 0.0.0.0:8888->8080/tcp, :::8888->8080/tcp spring_test |
2、访问测试

# 8. 实现⾃动化 CI
⾃动化 CI,就是通过 webhook 来实现,所谓 webhook 就是当开发⼀提交代码,则⾃定对项⽬进⾏构建操作;
# 8.1 配置 Jenkins
1、点击 jenkins 中对应的项⽬,找到构建触发器 -->Build when a change ispushed to GitLab;

2、找到⾼级,然后找到 Secret token,点击 Generate ⽣成 token

# 8.2 配置 Gitlab
1、配置 gitlab , 菜单 -> 管理员 -> 设置 -> ⽹络 -> 出站请求 -> 允许 webhooks 集成对本地⽹络的请求 (勾选)

2、找到对应要实现⾃动化发布的项⽬, 点击设置 -->webhook--> 添加新的 webhook
- URL--> 通知 jenkins 的哪个项⽬地址
- 令牌 --> jenkins 针对项⽬⽣成的 token 令牌
- 触发来源 --> 推送事件

# 8.3 验证结果

# 9. 实现 CD 阶段
CI 与 CD 两个流⽔线
- CI:拉取代码 -> 漏洞检测 -> 代码编译 -> 镜像制作 -> 推送私有仓库 -> 交付测试环境
- CD:获取 Harbor 仓库对应项⽬镜像的 tags-> 部署⾄⽣产环境
# 9.1 CD 实现思路
- 1、获取 Harbor 对应项⽬的 tag;
- 2、编写 Stage 拼接完整的镜像名称;
- 3、调⽤ docker 命令在远程⽣产服务器上运⾏对应的容器实例;
注意:获取镜像 Tag 可以使⽤ 级联变量 ⽅式实现,因为镜像可能存储在不同的 Harbor 或不同的项⽬路径中,写死后期修改麻烦;
- 1、使⽤ Active Choices Parameter 定义 Harbor 仓库地址(变量名:Harbor_Url);
- 2、使⽤ Active Choices Parameter 定义 Harbor 项⽬名称(变量名:Harbor_Pro);
- 3、使⽤ Active Choices Parameter 定义 Harbor 镜像名称(变量名:Image_Name);
- 4、使⽤ Active Choices Reactive Parameter 引⽤并参考此前变量,最终获取镜像 Tag(变量名:Image_tags)
需要安装: Active Choices 插件才可以实现;
# 9.2 命令获取镜像 Tag
1、创建流水线项目 devops_demo_docker-CD
[root@jenkins ~]# curl -s -u admin:talent -H 'Content-Type: application/json' -X GET https://harbor.hmallleasing.com/v2/app/springboot/tags/list| sed -r 's#(\{.*\[)(.*)(.*\]\})#\2#g' | xargs -d "," -n1|xargs -n1 | |
aeacd46_20251130_180212 | |
aeacd46_20251130_180702 | |
aeacd46_20251130_181934 | |
aeacd46_20251130_182658 | |
aeacd46_20251130_182807 |
# 9.3 创建级联变量
1、添加⼀个 Active Choices Parameter 的参数化构建,创建 Harbor_Url 变量,变量值 return ["harbor.hmallleasing.com","harbor-dev..hmallleasing.com","harbor-prod..hmallleasing.com"] ,然后点击 Approve script

2、添加⼀个 Active Choices Parameter 的参数化构建,创建 Harbor_Pro 变量,变量值 return ["app","ops","base","library"] ,然后点击 Approve script

3、添加⼀个 Active Choices Parameter 的参数化构建,创建 Image_Name 变量,变量值 return ["springboot","nginx","tomcat"] ,然后点击 Approve script

4、添加⼀个 Active Choices Reactive Parameter 的参数化构建
变量名为:Image_tags
变量值:此前获取 tags 的脚本
除此外,它还需要级联之前的变量 Harbor_Url,Harbor_Pro,Image_Name
def get_tag = [ "bash","-c","curl -s -u admin:talent -H 'Content-Type: application/json' -X GET https://${Harbor_Url}/v2/${Harbor_Pro}/${Image_Name}/tags/list | sed -r 's#(\\{.*\\[)(.*)(.*\\]\\})#\\2#g'| xargs -d ',' -n1|xargs -n1 | sort -t '_' -k2 -k3 -nr|head -n5"] | |
return get_tag.execute().text.tokenize("\n") |


5、验证结果(根据选择的不同,Image_Tags 也会列出不同的结果)

# 9.4 编写 Stage
1、编写 stage
pipeline { | |
agent any | |
//将传参的内容设定为变量 | |
environment { | |
Full_Images="${Harbor_Url}/${Harbor_Pro}/${Image_Name}:${Image_tags}" | |
} | |
stages { | |
stage('获取完整镜像名称') { | |
steps { | |
sh 'echo 镜像名称: ${Full_Images}' | |
} | |
} | |
stage('交付应用至Docker') { | |
steps { | |
//这个地址可以通过传参的方式设定 | |
sh "export DOCKER_HOST=tcp://192.168.40.182:2375 && \ | |
docker rm -f springboot_prod && \ | |
docker run -d -p 80:8080 --name springboot_prod ${Full_Images}" | |
} | |
} | |
} | |
} |
2、在测试服务器上,开启 Docker 的远程访问功能;
[root@docker_prod ~]# cat /lib/systemd/system/docker.service | |
... | |
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 | |
... |
3、使⽤方法
[root@docker_prod ~]# systemctl daemon-reload | |
[root@docker_prod ~]# systemctl restart docker | |
export DOCKER_HOST=tcp://10.0.0.182:2375 | |
docker run .... |
4、部署后检查结果
[root@docker_prod ~]# cat /etc/hosts | |
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 | |
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 | |
192.168.40.134 harbor.hmallleasing.com |

# 10. 完整 Pipeline
# 10.1 Pipeline-CI
pipeline { | |
agent any | |
//将workspace工作目录赋予给WORK_SPACES变量,后续stage能正常找到工作目录 | |
environment { | |
Git_Id = "gitlab-root-token" | |
Git_Url = "http://gitlab.hmallleasing.com/root/springboot-devops-demo-jar.git" | |
WORK_SPACES = "${WORKSPACE}" | |
Harbor_Url = "harbor.hmallleasing.com" | |
Pro = "app" //Harbor镜像存储的目录 | |
ImageName = "${Harbor_Url}/${Pro}/springboot" //镜像的完整名称 | |
HARBOR_ID = "harbor-auth" | |
} | |
stages { | |
stage('获取代码'){ | |
steps { | |
git branch: 'master', credentialsId: "${Git_Id }", url: "${Git_Url}" | |
sh 'pwd && ls -l' | |
} | |
} | |
stage('编译代码') { | |
agent { | |
docker { | |
image 'maven:3.8.5-openjdk-17-slim' | |
args '-v $HOME/.m2:/root/.m2 -v /etc/maven_settings.xml:/usr/share/maven/conf/settings.xml' | |
//当链接的镜像是私有仓库时,我们需要传递私有仓库的地址和认证信息 | |
//registryUrl "https://${Url}" | |
//registryCredentialsId 'harbor-auth' | |
} | |
} | |
steps { | |
sh 'cd ${WORK_SPACES} && mvn package -Dmaven.test.skip=true' | |
sh 'cd ${WORK_SPACES} && ls -l && ls -l target/' | |
} | |
} | |
stage('生成成镜像Tag'){ | |
steps { | |
script { | |
//镜像本次的CommitID | |
env.COMMITID = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim() | |
//镜像构建的时间 | |
env.BuildTime = sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim() | |
//镜像Tag | |
env.ImageTag = COMMITID + "_" + BuildTime | |
} | |
sh 'echo ${ImageTag}' | |
} | |
} | |
stage('制作镜像'){ | |
steps { | |
sh 'cd ${WORK_SPACES} && docker build -t ${ImageName}:${ImageTag} .' | |
} | |
} | |
stage('推送镜像至Harbor'){ | |
steps { | |
withCredentials([usernamePassword(credentialsId: "${HARBOR_ID}", passwordVariable: 'HARBOR_PASSWORD', usernameVariable: 'HARBOR_USER')]) { | |
//登陆harbor | |
sh 'echo "${HARBOR_PASSWORD}" | docker login ${Harbor_Url} -u "${HARBOR_USER}" --password-stdin' | |
sh 'docker push ${ImageName}:${ImageTag}' | |
} | |
} | |
} | |
stage('交付镜像测试测试环境') { | |
steps { | |
sh "export DOCKER_HOST=tcp://192.168.40.181:2375 && \ | |
docker rm -f spring_test && \ | |
docker run -d --name spring_test -p8888:8080 ${ImageName}:${ImageTag}" | |
} | |
} | |
} | |
} |
# 10.2 Pipeline-CD
pipeline { | |
agent any | |
//将传参的内容设定为变量 | |
environment { | |
Full_Images="${Harbor_Url}/${Harbor_Pro}/${Image_Name}:${Image_tags}" | |
} | |
stages { | |
stage('获取完整镜像名称') { | |
steps { | |
sh 'echo 镜像名称: ${Full_Images}' | |
} | |
} | |
stage('交付应用至Docker') { | |
steps { | |
//这个地址可以通过传参的方式设定 | |
sh "export DOCKER_HOST=tcp://192.168.40.182:2375 && \ | |
docker rm -f springboot_prod && \ | |
docker run -d -p 80:8080 --name springboot_prod ${Full_Images}" | |
} | |
} | |
} | |
} |
