使用 coding.net 完成 Springcloud 项目 CI/CD 持续集成部署

本文最后更新于:2021年4月27日 下午

使用 Coding.net 完成项目 CI/CD 持续集成部署

coding.net 是一款提供一站式开发协作工具,帮助研发团队快速落地敏捷开发与 DevOps 开发方式,实现研发效能升级。

  • 实践敏捷开发
    打开即用的 Scrum 敏捷开发工作流,适用于团队项目管理与协作。

  • 构建 DevOps 工作方式
    一站式 DevOps 工具,适用于研发团队快速搭建 DevOps ,实现可持续发布。

  • 代码开发协同
    Git/SVN 代码仓库服务,免费、超大高可用仓库,适用于研发团队协作开发。

  • 测试管理协作
    在线组织和管理测试用例及测试计划,将测试团队工作搬到云上。

一、项目准备

准备一个用于 CI/CD 的 Springcloud 项目

项目结构

  • api-common: 项目通用依赖、配置与工具类模块
  • api-gateway: springcloud-gateway 路由模块
  • api-auth: spring-security 鉴权模块
  • api-web: WEB-API 业务模块

并在需要打包的模块根目录中添加 Dockerfile

Dockerfile

例如 gateway 模块:

1
2
3
4
5
6
7
8
FROM magese-docker.pkg.coding.net/api.magese.com/docker/openjdk:8

EXPOSE 8000

COPY /api-gateway/target/api-gateway.jar api-gateway.jar

ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-Dfile.encoding=UTF-8", "-jar", "api-gateway.jar"]

二、创建项目

coding.net 选择创建 Devops 项目
创建项目

三、新建制品库

在刚刚创建好的项目中新建 Docker 制品库
新建制品库

四、新建构建计划

在之前创建的项目中新建持续构建计划

1. 选择新建构建计划

选择 Java + Spring + Docker 模板
新建构建计划

2. 代码仓库

根据代码储存的仓库选择对应的仓库
选择代码仓库

3. 编辑构建

取消单元测试,编译构建暂不做改动
编译构建

4. Docker镜像

构建 Docker 镜像暂不做修改,Docker 制品库选择之前创建好的制品库
Docker镜像

5. 部署到远端服务

启用部署到远端服务器,填入对应的字段
部署到远端服务

最后确认创建即可

五、修改环境变量

在刚刚新建好的构建计划选择设置
设置

选择变量与缓存
设置

全部变量配置如下:

变量名默认值说明
DOCKER_BUILD_CONTEXT.Docker 构建上下文环境
DOCKER_IMAGE_VERSION${GIT_LOCAL_BRANCH:-branch}Docker 镜像版本-${GIT_COMMIT}
DOCKER_REPO_NAMEdocker当前项目下的 Docker 制品仓库名
DOCKER_USERNAMEdocker-**Docker制品库用户名
DOCKER_PASSWORD****Docker制品库密码
GATEWAY_IMAGE_NAMEapi-gateway模块gateway镜像名称
WEB_IMAGE_NAMEapi-web模块web镜像名称
AUTH_IMAGE_NAMEapi-auth模块auth镜像名称
REMOTE_HOST120.*.**.33远程服务地址
REMOTE_SSH_PORT22远程服务端口
REMOTE_USER_NAMErootSSH 用户名
REMOTE_CRED****SSH 登录凭据
DOCKER_COMPOSE_PATH~/docker-compose.ymldocker-compose 配置路径

Docker 制品库的用户名密码可在制品仓库获取
制品仓库

六、修改 Jenkins 流水线文件 (重点)

选择流程配置-文本编辑器
文本编辑器

1. 拉取代码

这一步无需做修改

1
2
3
4
5
6
7
8
9
10
stage('从仓库中拉取代码') {
steps {
checkout([$class: 'GitSCM',
branches: [[name: GIT_BUILD_REF]],
userRemoteConfigs: [[
url: GIT_REPO_URL,
credentialsId: CREDENTIALS_ID
]]])
}
}

2. 编译打包

项目使用的 Maven 编译,所以将这一步修改为 Maven 命令,并跳过测试与文档构建

1
2
3
4
5
stage('编译打包') {
steps {
sh 'mvn clean package -Dmaven.javadoc.skip=true -Dmaven.test.skip=true'
}
}

3. 登录 Docker 制品库

将原有的 stage('构建镜像并推送到 CODING Docker 制品库') 整个删掉,修改为

1
2
3
4
5
stage('登录 Docker 制品库') {
steps {
sh "docker login -u ${DOCKER_USERNAME} -p ${DOCKER_PASSWORD} ${CODING_DOCKER_REG_HOST}"
}
}

4. 构建 & 推送

因为构建的项目是 Springcloud ,有多个子模块,所以需要多次打包推送

命令说明:
docker build: 构建 Docker 镜像,-t 指定镜像名称,-f 指定 Dockerfile 的路径, DOCKER_BUILD_CONTEXT 指定构建镜像时的上下文环境。
docker images: 查看镜像列表。
docker tag: 给本地镜像打标签。
docker push: 推送本地镜像到远程仓库中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
stage('构建推送 api-gateway 模块') {
steps {
sh """
docker build -t ${GATEWAY_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} -f /root/workspace/${GATEWAY_IMAGE_NAME}/Dockerfile ${DOCKER_BUILD_CONTEXT}
docker images ${GATEWAY_IMAGE_NAME}
docker tag ${GATEWAY_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} magese-docker.pkg.coding.net/api.magese.com/docker/${GATEWAY_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
docker push magese-docker.pkg.coding.net/api.magese.com/docker/${GATEWAY_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
"""
}
}

stage('构建推送 api-web 模块') {
steps {
sh """
docker build -t ${WEB_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} -f /root/workspace/${WEB_IMAGE_NAME}/Dockerfile ${DOCKER_BUILD_CONTEXT}
docker images ${WEB_IMAGE_NAME}
docker tag ${WEB_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} magese-docker.pkg.coding.net/api.magese.com/docker/${WEB_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
docker push magese-docker.pkg.coding.net/api.magese.com/docker/${WEB_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
"""
}
}

stage('构建推送 api-auth 模块') {
steps {
sh """
docker build -t ${AUTH_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} -f /root/workspace/${AUTH_IMAGE_NAME}/Dockerfile ${DOCKER_BUILD_CONTEXT}
docker images ${AUTH_IMAGE_NAME}
docker tag ${AUTH_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} magese-docker.pkg.coding.net/api.magese.com/docker/${AUTH_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
docker push magese-docker.pkg.coding.net/api.magese.com/docker/${AUTH_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
"""
}
}

5. 部署

修改stage("部署到远端服务"),使用 docker-compose 进行部署

命令说明:
docker-compose down: 停止并删除配置文件中指定的镜像容器,-f 指定 docker-compose.yml 配置文件路径,--rmi all 删除配置文件中指定的镜像列表。
docker-compose up: 启动配置文件中指定的镜像容器,-f 指定 docker-compose.yml 配置文件路径,-d 表示后台运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
stage('部署') {
steps {
script {
def remoteConfig = [:]
remoteConfig.name = "my-remote-server"
remoteConfig.host = "${REMOTE_HOST}"
remoteConfig.port = "${REMOTE_SSH_PORT}".toInteger()
remoteConfig.allowAnyHosts = true

withCredentials([
sshUserPrivateKey(
credentialsId: "${REMOTE_CRED}",
keyFileVariable: "privateKeyFilePath"
)
]) {
// SSH 登陆用户名
remoteConfig.user = "${REMOTE_USER_NAME}"
// SSH 私钥文件地址
remoteConfig.identityFile = privateKeyFilePath

sshCommand(
remote: remoteConfig,
command: "docker-compose -f ${DOCKER_COMPOSE_PATH} down --rmi all",
sudo: true,
)

sshCommand(
remote: remoteConfig,
command: "docker-compose -f ${DOCKER_COMPOSE_PATH} up -d",
sudo: true,
)

echo "Deploy success! Go to http://api.magese.com/doc.html for a preview."
}
}
}
}

完整配置文件

点击显示完整配置代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
pipeline {
agent any
stages {
stage('从仓库中拉取代码') {
steps {
checkout([$class: 'GitSCM',
branches: [[name: GIT_BUILD_REF]],
userRemoteConfigs: [[
url: GIT_REPO_URL,
credentialsId: CREDENTIALS_ID
]]])
}
}

stage('编译打包') {
steps {
sh 'mvn clean package -Dmaven.javadoc.skip=true -Dmaven.test.skip=true'
}
}

stage('登录 Docker 制品库') {
steps {
sh "docker login -u ${DOCKER_USERNAME} -p ${DOCKER_PASSWORD} ${CODING_DOCKER_REG_HOST}"
}
}

stage('构建推送 api-gateway 模块') {
steps {
sh """
docker build -t ${GATEWAY_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} -f /root/workspace/${GATEWAY_IMAGE_NAME}/Dockerfile ${DOCKER_BUILD_CONTEXT}
docker images ${GATEWAY_IMAGE_NAME}
docker tag ${GATEWAY_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} magese-docker.pkg.coding.net/api.magese.com/docker/${GATEWAY_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
docker push magese-docker.pkg.coding.net/api.magese.com/docker/${GATEWAY_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
"""
}
}

stage('构建推送 api-web 模块') {
steps {
sh """
docker build -t ${WEB_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} -f /root/workspace/${WEB_IMAGE_NAME}/Dockerfile ${DOCKER_BUILD_CONTEXT}
docker images ${WEB_IMAGE_NAME}
docker tag ${WEB_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} magese-docker.pkg.coding.net/api.magese.com/docker/${WEB_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
docker push magese-docker.pkg.coding.net/api.magese.com/docker/${WEB_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
"""
}
}

stage('构建推送 api-auth 模块') {
steps {
sh """
docker build -t ${AUTH_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} -f /root/workspace/${AUTH_IMAGE_NAME}/Dockerfile ${DOCKER_BUILD_CONTEXT}
docker images ${AUTH_IMAGE_NAME}
docker tag ${AUTH_IMAGE_NAME}:${DOCKER_IMAGE_VERSION} magese-docker.pkg.coding.net/api.magese.com/docker/${AUTH_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
docker push magese-docker.pkg.coding.net/api.magese.com/docker/${AUTH_IMAGE_NAME}:${DOCKER_IMAGE_VERSION}
"""
}
}

stage('部署') {
steps {
script {
def remoteConfig = [:]
remoteConfig.name = "my-remote-server"
remoteConfig.host = "${REMOTE_HOST}"
remoteConfig.port = "${REMOTE_SSH_PORT}".toInteger()
remoteConfig.allowAnyHosts = true

withCredentials([
sshUserPrivateKey(
credentialsId: "${REMOTE_CRED}",
keyFileVariable: "privateKeyFilePath"
)
]) {
// SSH 登陆用户名
remoteConfig.user = "${REMOTE_USER_NAME}"
// SSH 私钥文件地址
remoteConfig.identityFile = privateKeyFilePath

sshCommand(
remote: remoteConfig,
command: "docker-compose -f ${DOCKER_COMPOSE_PATH} down --rmi all",
sudo: true,
)

sshCommand(
remote: remoteConfig,
command: "docker-compose -f ${DOCKER_COMPOSE_PATH} up -d",
sudo: true,
)

echo "Deploy success! Go to http://api.magese.com/doc.html for a preview."
}
}
}
}
}
environment {
CODING_DOCKER_REG_HOST = "${CCI_CURRENT_TEAM}-docker.pkg.${CCI_CURRENT_DOMAIN}"
CODING_DOCKER_IMAGE_NAME = "${PROJECT_NAME.toLowerCase()}/${DOCKER_REPO_NAME}/${DOCKER_IMAGE_NAME}"
}
}

七、修改触发规则

修改触发规则,当代码提交或合并到 master 分支时自动进行构建、部署

触发规则
^refs/((heads/master)|(tags/.*))

八、服务器配置

1. Docker 环境

服务器需要有 docker 相关的环境,docker 安装可参考:

CentOS Docker 安装

2. Docker Compose 环境

因部署使用的是 docker-compose.yml 配置文件形式,所以需要安装 Docker Compose 环境:

1
curl -L "https://github.com/docker/compose/releases/download/1.29.1/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose

如需安装其它版本,查看Github发行版本页:

Github 最新发行版本

修改权限:

1
chmod +x /usr/local/bin/docker-compose

创建软链:

1
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

测试是否安装成功:

1
2
docker-compose --version
docker-compose version 1.29.1, build c34c88b2

3. 添加 docker-compose.yml 配置文件

配置文件说明:

配置名说明
services服务列表,可配置多个
container_name容器名称
image使用的 docker 镜像
env_file环境变量配置文件
environment环境变量
ports端口映射
volumes目录挂载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
version: '3.5'
services:
api-gateway:
container_name: api-gateway
image: magese-docker.pkg.coding.net/api.magese.com/docker/api-gateway:master
env_file:
- ./master.env
environment:
- JAVA_TOOL_OPTIONS=-Xms256m -Xmx256m -Xmn128m
ports:
- "8000:8000"
volumes:
- /usr/local/magese/magese-api/logs:/usr/local/magese/magese-api/logs
- /etc/timezone:/etc/timezone
- /etc/localtime:/etc/localtime

api-web:
container_name: api-web
image: magese-docker.pkg.coding.net/api.magese.com/docker/api-web:master
env_file:
- ./master.env
environment:
- JAVA_TOOL_OPTIONS=-Xms512m -Xmx512m -Xmn256m
ports:
- "8001:8001"
volumes:
- /usr/local/magese/magese-api/logs:/usr/local/magese/magese-api/logs
- /etc/timezone:/etc/timezone
- /etc/localtime:/etc/localtime

api-auth:
container_name: api-auth
image: magese-docker.pkg.coding.net/api.magese.com/docker/api-auth:master
env_file:
- ./master.env
environment:
- JAVA_TOOL_OPTIONS=-Xms256m -Xmx256m -Xmn128m
ports:
- "8002:8002"
volumes:
- /usr/local/magese/magese-api/logs:/usr/local/magese/magese-api/logs
- /etc/timezone:/etc/timezone
- /etc/localtime:/etc/localtime

环境配置文件

1
2
3
4
5
6
spring.profiles.active=master
NACOS_CONFIG_ADDR=http://nacos.magese.com
NACOS_SERVER_ADDR=http://nacos.magese.com:80
NACOS_SERVER_NAMESPACE=master
NACOS_SERVER_DUBBO_ADDR=nacos://nacos.magese.com:80
NACOS_SERVER_DUBBO_NAMESPACE=master-dubbo

九、测试构建

推送代码触发构建,在 coding 中查看构建过程:
构建过程

全部绿了就表示成功啦!

登录服务器使用 docker -ps 可以看到容器正在运行:
容器列表


使用 coding.net 完成 Springcloud 项目 CI/CD 持续集成部署
https://www.magese.com/2021/04/26/使用-Coding.net-完成-Springcloud-项目-CI-CD-持续集成部署/
作者
Magese
发布于
2021年4月26日
更新于
2021年4月27日
许可协议