CICD(持续集成/持续部署)是提升研发效率、保障代码质量的核心实践。本文将基于Docker容器化技术,通过两台物理机/虚拟机搭建完整的CICD流水线,实现若依(RuoYi-Vue)前后端分离项目的自动化构建、测试与部署。全程步骤详细、解析透彻,适合DevOps入门者和企业级项目实践参考。
一、整体架构与环境规划
1.1 核心技术栈
- 容器化:Docker 20.10.18
- 代码管理:GitLab 10.7.5
- 持续集成:Jenkins 2.480
- 数据库:MySQL 8.0.39
- 缓存:Redis 7.4.1
- 项目:RuoYi-Vue(Spring Boot+Vue前后端分离)
- 反向代理:Nginx 1.26.2
1.2 两台主机角色分配
| 主机IP | 配置要求 | 部署服务清单 | 核心作用 |
|---|---|---|---|
| 192.168.10.13 | 2C 8G | Jenkins、MySQL、Redis、Nginx、Spring Boot后端 | 构建节点+应用运行环境 |
| 192.168.10.80 | 1C 4G | GitLab、Docker | 代码仓库+版本控制中心 |
1.3 核心流程说明
- 开发者提交代码到GitLab仓库
- GitLab通过WebHook触发Jenkins构建
- Jenkins拉取代码,执行自动化构建(编译、打包)
- 构建产物生成Docker镜像,推送至本地镜像仓库
- Jenkins部署镜像到目标主机,自动启动服务
- 部署结果实时通知(本文以日志反馈为例)
二、前置条件:两台主机统一安装Docker
所有服务均基于Docker部署,需先在两台主机完成Docker环境初始化,步骤完全一致。
2.1 安装Docker依赖包
bash
# 安装yum工具集和存储依赖
yum install -y yum-utils device-mapper-persistent-data lvm2
2.2 配置阿里云Docker镜像源
默认官方镜像源下载速度较慢,替换为阿里云镜像源提升效率:
bash
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
2.3 安装指定版本Docker并设置开机自启
bash
# 安装Docker-CE 20.10.18(稳定版)
yum install -y docker-ce-20.10.18 docker-ce-cli-20.10.18 containerd.io
# 启动Docker服务
systemctl start docker.service
# 设置开机自动启动
systemctl enable docker.service
2.4 配置华为镜像加速器(关键优化)
进一步提升Docker镜像下载速度,配置华为云加速器:
bash
# 创建Docker配置目录
mkdir -p /etc/docker
# 写入加速器配置
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://0a40cefd360026b40f39c00627fa6f20.mirror.swr.myhuaweicloud.com"]
}
EOF
# 重启Docker使配置生效
systemctl daemon-reload
systemctl restart docker
2.5 验证Docker安装成功
bash
docker --version # 输出Docker版本信息即成功
三、主机192.168.10.80:部署GitLab代码仓库
GitLab用于存储项目源代码、管理分支和触发CICD流水线,是整个流程的代码入口。
3.1 下载GitLab镜像
bash
docker pull beginor/gitlab-ce # 社区版镜像,轻量且满足需求
3.2 创建数据卷挂载目录(核心步骤)
为避免容器删除导致配置、数据和日志丢失,需将GitLab关键目录挂载到宿主机:
bash
# 创建挂载目录
mkdir -p /data/gitlab/etc /data/gitlab/log /data/gitlab/data
# 授予目录最高权限(避免容器访问权限不足)
chmod 777 /data/gitlab/etc /data/gitlab/log /data/gitlab/data
3.3 启动GitLab容器
bash
docker run -itd \
--name=gitlab \
--restart=always \ # 容器异常自动重启
--privileged=true \ # 授予容器特权,避免文件权限问题
-p 8443:443 \ # HTTPS端口映射
-p 80:80 \ # HTTP端口映射
-p 222:22 \ # SSH端口映射(避免与宿主机22端口冲突)
-v /data/gitlab/etc:/etc/gitlab \ # 配置文件挂载
-v /data/gitlab/log:/var/log/gitlab \ # 日志挂载
-v /data/gitlab/data:/var/opt/gitlab \ # 数据挂载
beginor/gitlab-ce
3.4 配置GitLab访问地址与SSH端口
容器启动后,需修改配置文件指定访问地址,否则无法正常访问:
bash
# 1. 修改外部访问地址(GitLab Web界面地址)
sed -i "/external_url 'GENERATED_EXTERNAL_URL'/a external_url\t'http://192.168.10.80' " /data/gitlab/etc/gitlab.rb
# 2. 修改SSH连接主机(与Web地址一致)
sed -i "/gitlab_ssh_host/a gitlab_rails['gitlab_ssh_host']= '192.168.10.80' " /data/gitlab/etc/gitlab.rb
# 3. 修改SSH连接端口(与容器映射的222端口一致)
sed -i "/gitlab_shell_ssh_port/a gitlab_rails['gitlab_shell_ssh_port'] = 222" /data/gitlab/etc/gitlab.rb
# 重启GitLab使配置生效
docker restart gitlab
3.5 初始化GitLab管理员账号
- 访问GitLab Web界面:浏览器输入
http://192.168.10.80(首次启动需等待3-5分钟) - 初始化root密码:首次登录会提示设置密码(本文设置为
1qaz@WSX) - 登录:使用用户名
root+ 新设密码登录
3.6 配置SSH密钥(免密拉取代码)
为了让Jenkins和本地开发机免密拉取GitLab代码,需配置SSH密钥:
bash
# 在GitLab宿主机或开发机生成SSH密钥(以GitLab宿主机为例)
ssh-keygen # 一路回车,无需设置密码
# 查看公钥内容
cat ~/.ssh/id_rsa.pub
将输出的公钥复制到GitLab Web界面:
- 登录GitLab → 右上角头像 → Settings → SSH Keys
- 粘贴公钥,设置标题(如"Jenkins访问密钥"),点击Add Key
3.7 上传若依项目到GitLab
3.7.1 下载若依源码
bash
# 本地开发机(Windows需安装Git Bash,Linux需安装git)
git clone https://gitee.com/y_project/RuoYi-Vue.git
3.7.2 在GitLab创建项目
- 登录GitLab → New Project → 项目名称
ruoyi-server(后端)、ruoyi-ui(前端) - 可见等级选择"私有"(仅团队成员可访问)
- 点击"Create project"
3.7.3 推送代码到GitLab
bash
# 进入若依项目根目录
cd RuoYi-Vue
# 初始化本地Git仓库
git init
# 关联GitLab后端项目远程仓库
git remote add origin ssh://git@192.168.10.80:222/root/ruoyi-server.git
如果已经存在则:
git remote set-url origin ssh://git@192.168.10.80:222/root/ruoyi-server.git
# 添加所有文件到暂存区
git add .
# 提交代码
git commit -m "Initial commit: 若依后端项目初始化"
# 推送到GitLab master分支
git push -u origin master
## 四、主机192.168.10.13:部署Jenkins持续集成工具
Jenkins是CICD流水线的核心,负责拉取代码、构建打包、部署发布等自动化操作。由于若依项目需要JDK、Maven、Node.js环境,需对Jenkins镜像二次打包。
### 4.1 准备Jenkins二次打包资源
#### 4.1.1 创建工作目录
```bash
mkdir -p /data/jenkins
cd /data/jenkins
4.1.2 下载依赖包(JDK、Maven、Node.js)
将以下包上传到 /data/jenkins 目录(可通过wget或本地传输):
- JDK:jdk-8u421-linux-x64.tar.gz(若依后端需JDK8)
- Maven:apache-maven-3.9.9-bin.tar.gz(构建Java项目)
- Node.js:node-v11.0.0-linux-x64.tar.gz(构建Vue前端)
4.1.3 配置Maven settings.xml
3.8.x以上Maven默认不支持HTTP仓库,需自定义配置文件:
bash
tee settings.xml <<-'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
</settings>
EOF
4.2 编写Dockerfile二次打包Jenkins
dockerfile
# 基础镜像:Jenkins 2.480 + JDK21(后续手动配置JDK8)
FROM jenkins/jenkins:2.480-jdk21
# 暴露Jenkins默认端口
EXPOSE 8080
# 复制并自动解压JDK、Maven、Node.js到容器
ADD apache-maven-3.9.9-bin.tar.gz /usr/local
ADD jdk-8u421-linux-x64.tar.gz /usr/local
ADD node-v11.0.0-linux-x64.tar.gz /usr/local
# 覆盖Maven配置文件
ADD settings.xml /usr/local/apache-maven-3.9.9/conf/
# 配置环境变量(时区、Maven、Node.js)
ENV TZ=Asia/Shanghai
ENV M2_HOME=/usr/local/apache-maven-3.9.9
ENV NODE_HOME=/usr/local/node-v11.0.0-linux-x64
ENV PATH=$M2_HOME/bin:$NODE_HOME/bin:$PATH
4.3 构建自定义Jenkins镜像
bash
# 创建Jenkins数据目录并授权
mkdir jenkins_home
chmod +777 jenkins_home
# 构建镜像(镜像名jenkins)
docker build -t jenkins .
# 授予Docker sock权限(Jenkins需调用宿主机Docker命令)
chmod +777 /var/run/docker.sock
4.4 启动Jenkins容器
bash
docker run -d \
--name=jenkins \
-p 8080:8080 \ # Jenkins Web端口
-v /data/jenkins/jenkins_home:/var/jenkins_home \ # 数据挂载
-v /etc/localtime:/etc/localtime \ # 同步宿主机时区
-v /run/docker.sock:/run/docker.sock \ # 挂载Docker sock
-v /usr/bin/docker:/usr/bin/docker \ # 挂载Docker命令
jenkins
4.5 初始化Jenkins
4.5.1 获取初始管理员密码
bash
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
输出类似 a07829a8375a47f7b6e516ca2f0bad1f 的密码,用于首次登录。
4.5.2 登录并安装插件
- 访问Jenkins Web界面:
http://192.168.10.13:8080 - 输入初始密码 → 选择"安装推荐插件"(包含Git、Pipeline等核心插件)
- 安装完成后,创建管理员账号(本文设置用户名
admin,密码123456) - 配置Jenkins URL:默认
http://192.168.10.13:8080,直接保存
4.5.3 配置JDK环境(关键步骤)
Jenkins二次打包时未配置JDK环境变量,需手动配置:
- 进入Jenkins → 系统管理 → 全局工具配置 → JDK
- 点击"新增JDK",取消"自动安装"
- 名称填写
jdk8(后续Jenkinsfile需引用) - JAVA_HOME填写
/usr/local/jdk1.8.0_421(容器内JDK实际路径) - 点击"保存"
4.5.4 安装GitLab插件
为了让Jenkins接收GitLab的WebHook触发,需安装GitLab插件:
- 系统管理 → 插件管理 → 可选插件
- 搜索"GitLab" → 勾选安装 → 重启Jenkins
五、主机192.168.10.13:部署MySQL与Redis
若依项目依赖MySQL数据库和Redis缓存,需在应用主机部署这两个服务。
5.1 部署MySQL 8.0.39
bash
docker run -d \
--name=mysql \
-p 3306:3306 \ # 数据库端口映射
-e MYSQL_ROOT_PASSWORD=123456 \ # root密码
--restart=always \
mysql:8.0.39
5.1.1 创建若依数据库并导入数据
bash
# 进入MySQL容器
docker exec -it mysql bash
# 登录MySQL
mysql -u root -p123456
# 创建数据库(若依默认数据库名ry-vue)
create database ry-vue;
# 使用数据库
use ry-vue;
# 导入若依SQL文件(需先将ry_20250522.sql和quartz.sql上传到容器/opt目录)
source /opt/ry_20250522.sql;
source /opt/quartz.sql;
# 验证导入成功(查看表结构)
show tables;
5.2 部署Redis 7.4.1
bash
docker run -d \
--name=redis \
-p 6379:6379 \ # 缓存端口映射
--restart=always \
redis:7.4.1
5.3 验证服务可用性
bash
# 查看容器运行状态(均为Up状态即正常)
docker ps | grep -E "mysql|redis"
六、Jenkins实现CICD自动化部署(前后端)
6.1 后端部署(ruoyi-server)
6.1.1 修改若依后端配置文件
需修改数据库和Redis连接信息,指向主机192.168.10.13的服务:
-
本地开发机打开
ruoyi-admin/src/main/resources/application-druid.yml -
修改MySQL配置:
yamlspring: datasource: url: jdbc:mysql://192.168.10.13:3306/ry-vue?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: 123456 -
修改Redis配置:
yamlspring: redis: host: 192.168.10.13 port: 6379 password: # 默认为空,若有密码需填写 -
提交配置修改到GitLab:
bashgit add . git commit -m "修改数据库和Redis连接配置" git push origin master
6.1.2 新增后端构建部署文件
在若依项目根目录新增3个文件,用于Jenkins构建和Docker部署:
1. Dockerfile(构建后端镜像)
dockerfile
# 基础镜像:JDK8(若依后端依赖JDK8)
FROM openjdk:8u342
# 配置时区
ENV TZ=Asia/Shanghai
# 复制打包后的jar包到容器
ADD ruoyi-admin/target/ruoyi-admin.jar app.jar
# 容器启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
2. .dockerignore(优化构建速度)
屏蔽不必要的文件,减少镜像体积和构建时间:
.git
ruoyi-admin/src
ruoyi-admin/target/classes
ruoyi-admin/target/generated-sources
ruoyi-common
ruoyi-framework
ruoyi-generator
ruoyi-quartz
ruoyi-system
ruoyi-ui
sql
3. Jenkinsfile(流水线脚本)
定义CICD构建和部署流程:
groovy
pipeline {
agent any // 任意Jenkins节点执行
tools {
jdk 'jdk8' // 引用之前配置的JDK环境
}
environment {
APP_NAME = 'ruoyi-server' // 项目名称
APP_PORT = 9800 // 后端服务端口
}
stages {
// 构建阶段:编译打包
stage('build') {
steps {
script {
sh 'mvn clean package -DskipTests=true' // Maven打包,跳过测试
}
}
}
// 部署阶段:构建镜像并启动容器
stage('deploy') {
steps {
script {
// 停止并删除旧容器和镜像
sh 'docker stop $APP_NAME || true'
sh 'docker rm $APP_NAME || true'
sh 'docker rmi $APP_NAME || true'
// 构建新镜像
sh 'docker build -t $APP_NAME .'
// 启动新容器
sh "docker run -d --name $APP_NAME -p 0.0.0.0:$APP_PORT:$APP_PORT --restart=always $APP_NAME --server.port=$APP_PORT"
}
}
}
}
}
6.1.3 提交构建文件到GitLab
bash
git add .dockerignore Dockerfile Jenkinsfile
git commit -m "新增Jenkins构建和Docker部署文件"
git push origin master
6.1.4 Jenkins创建后端流水线任务
- Jenkins → 新建Item → 任务名称
ruoyi-server→ 选择"流水线" → 确定 - 配置流水线:
- 选择"Pipeline script from SCM"(从GitLab拉取Jenkinsfile)
- SCM选择"Git"
- 仓库URL:
ssh://git@192.168.10.80:222/root/ruoyi-server.git(GitLab项目SSH地址) - Credentials:添加Jenkins的SSH密钥(与GitLab配置的一致)
- 分支:
*/master - 脚本路径:
Jenkinsfile(项目根目录下的Jenkinsfile路径)
- 配置GitLab WebHook触发:
- 勾选"Build when a change is pushed to GitLab"
- 点击"Generate"生成Secret token(后续GitLab配置需用到)
- 保存配置
6.1.5 GitLab配置WebHook
- 登录GitLab → 进入ruoyi-server项目 → Settings → Integrations
- URL填写:
http://192.168.10.13:8080/project/ruoyi-server(Jenkins项目地址) - Secret token填写Jenkins生成的令牌
- 触发器选择"Push events"(代码推送时触发构建)
- 点击"Add webhook" → 测试连接(显示200即成功)
6.2 前端部署(ruoyi-ui)
6.2.1 新增前端构建部署文件
进入 ruoyi-ui 目录,新增4个文件:
1. nginx.conf(前端反向代理配置)
nginx
server {
listen 9801; // 前端访问端口
charset utf-8;
# 前端静态资源访问
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html; // 解决Vue路由刷新404问题
}
# 后端接口代理(转发/prod-api请求到后端服务)
location /prod-api {
rewrite ^/prod-api/(.*)$ /$1 break;
proxy_pass http://192.168.10.13:9800; // 后端服务地址
}
}
2. Dockerfile(构建前端镜像)
dockerfile
# 基础镜像:Nginx 1.26.2
FROM nginx:1.26.2
# 解决中文乱码
ENV LC_ALL=C.UTF-8
# 删除默认Nginx配置
RUN rm -rf /etc/nginx/conf.d/default.conf
# 复制自定义Nginx配置
ADD nginx.conf /etc/nginx/conf.d
# 复制前端打包后的dist目录到Nginx静态资源目录
COPY dist/ /usr/share/nginx/html/
3. .dockerignore(优化构建)
node_modules
src
4. Jenkinsfile(前端流水线脚本)
groovy
pipeline {
agent any
environment {
APP_NAME = 'ruoyi-ui' // 前端项目名称
APP_PORT = 9801 // 前端访问端口
}
stages {
// 构建阶段:安装依赖并打包
stage('build') {
steps {
script {
sh 'npm install' // 安装Node依赖
sh 'npm run build:prod' // 打包生产环境版本
}
}
}
// 部署阶段:构建镜像并启动容器
stage('deploy') {
steps {
script {
sh 'docker stop $APP_NAME || true'
sh 'docker rm $APP_NAME || true'
sh 'docker rmi $APP_NAME || true'
sh 'docker build -t $APP_NAME .'
sh "docker run -d --name $APP_NAME -p 0.0.0.0:$APP_PORT:$APP_PORT --restart=always $APP_NAME"
}
}
}
}
}
6.2.2 提交文件到GitLab并配置Jenkins
- 提交前端构建文件到GitLab(步骤同后端)
- Jenkins新建
ruoyi-ui流水线任务(配置同后端,仓库URL改为前端项目地址) - GitLab配置前端项目WebHook(步骤同后端)
七、测试CICD流水线
7.1 手动触发构建
- 进入Jenkins → 选择
ruoyi-server→ 点击"立即构建" - 查看构建日志:点击构建记录 → Console Output,显示"Finished: SUCCESS"即构建成功
- 同理触发
ruoyi-ui构建
7.2 自动触发构建(验证WebHook)
-
本地开发机修改若依项目代码(如修改前端页面标题)
-
提交并推送代码到GitLab:
bashgit add . git commit -m "测试WebHook自动构建" git push origin master -
观察Jenkins:自动触发对应项目构建,无需手动操作
7.3 访问若依项目
- 前端访问:
http://192.168.10.13:9801(输入用户名admin,密码admin123) - 后端接口:
http://192.168.10.13:9800/prod-api/system/index(返回JSON即正常)
八、常见问题排查
- Jenkins无法拉取GitLab代码 :检查SSH密钥是否配置正确,Jenkins容器内是否生成
known_hosts文件(可通过ssh-keyscan -p 222 192.168.10.80 >> ~/.ssh/known_hosts生成) - Maven打包失败:检查Maven配置文件是否正确,依赖是否能正常下载
- Docker构建镜像失败:检查Dockerfile路径是否正确,.dockerignore文件是否屏蔽必要文件
- 前端访问后端接口404 :检查Nginx配置中的
proxy_pass是否指向正确的后端地址
九、总结
本文基于两台主机搭建了完整的Docker+CICD流水线,实现了若依项目的自动化构建、测试和部署。核心优势在于:
- 容器化部署:所有服务隔离运行,环境一致性强,迁移方便
- 自动化流水线:代码提交后自动触发构建部署,减少人工操作
- 架构清晰:两台主机分工明确,兼顾性能和稳定性