若依项目非常牛,但是对于一些朋友想快速体验,不想一点一点搭建各种环境,这里我就记录下,我将前后分离的若依项目做成docker的思路。可以实现一键部署。文末有相关连接。
制作后端服务是比较麻烦的,其中遇到了很多很多问题,在这里我将我的试错经历一点一点记录下来。
我们最终想要的效果是:用户只需编写一个yml文件就可以实现启动若依的后端服务,我们先考虑下,我们正常要启动若依的后端项目需要做什么?
然后将SpringBoot达成Jar包然后在java -jar ruoyi-admin.jar
启动即可
我们是使用docker-compose
启动整个后端项目,所以我们的整体思路就是将若依项目中的所有配置信息
都写成变量,然后将该jar包制作成docker镜像(命名为ruoyiapp),在docker-compose中配置redis
,mysql
,以及ruoyiapp
,因为ruoyiapp这个服务要依赖redis和mysql,以及使用他们的ip信息,这些在docker-compose中非常简单(depends_on和links),接下来我们就开始改造。
Redis-配置:
Mysql配置:
我们定义了 Mysql和Redis的配置变量,这样我们可以在Docker启动时候指定这些变量,当然你也可以配置更多的变量 ${变量名称}
定义即可,我们先在服务器根目录创建 ruoyi文件夹,我们打成Jar包传到该目录
docker-compose.yml
文件大致内容就是 配置mysql和redis实例,使用当前目录的Dockerfile文件构建ruoyi-app实例,配置SpringBoot项目我们定义的信息。
docker-compose.yml
内容为:
version: "3.8"
services:
# mysql服务
mysql:
image: mysql
volumes:
- ./mysql:/var/lib/mysql
restart: always
container_name: ruoyi-mysql
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=songweiwei
- MYSQL_DATABASE=ry-vue
- MYSQL_USER=ruoyi
- MYSQL_PASSWORD=ruoyi
# redis服务
redis:
image: library/redis:alpine
container_name: ruoyi-redis
ports:
- 6379:6379
# 给redis设置密码
command: redis-server --requirepass songweiwei --appendonly yes
volumes:
- ./redis/data:/data
# 构建若依后端
ruoyiapp:
# 镜像来源 自己构建的
image: ruoyiapp
# build值为 . 表示从当前目录找Dockerfile进行构建
build: .
restart: always
container_name: ruoyi-app
# 对外暴露端口 8080
ports:
- 8080:8080
# 后端项目需要的配置,可修改
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_DATABASE=0
- REDIS_PASSWORD=songweiwei
- MYSQL_HOST=mysql
- MYSQL_PORT=3306
- MYSQL_DATABASE=ry-vue
- MYSQL_USERNAME=ruoyi
- MYSQL_PASSWORD=ruoyi
depends_on:
- redis
- mysql
links:
- redis
- mysql
Dockerfile文件内容:
FROM java:8
# 维护者
MAINTAINER xiuyi
# copy jar包 命名为 aap.jar
COPY *.jar /app.jar
# 暴露端口
EXPOSE 8080
# 启动 jar包 可通过 PARAM 配置启动参数
ENTRYPOINT java ${PARAM} -jar app.jar
我们可以通过 PARAM
这个参数来覆盖SpringBoot中其他配置,比如说 log日志位置等等。。。
我们使用 docker-compose up --build -d
启动就可以了。-d
表示后台启动
我们 docker ps
查看是否都成功启动了,这时候我们发现访问后端接口提示访问不到,所以我们查看docker的ruoyi-app
日志,使用命令 docker logs ruoyi-app -f --tail=200
如下图:
我们发现 ruoyi项目在启动的时候需要将mysql中的字典等数据放入redis,但是mysql现在还没有数据。我们可以使用docker stop ruoyi-app
先将该容器停止掉,手动连接上mysql,将数据导入。使用Navicat或者Datagrip链接我们在上面docker-compose.yml
中配置的mysql。注意:一定要在导入自己配置的数据库中。
再次启动docker start ruoyi-app
容器即可。再次查看日志docker logs ruoyi-app -f --tail=200
如下:
这样就表示后端部署ok
但是现在这样需要我们人工参与,总感觉少点意思,我们想要的是,只编写个docker-compose.yml
文件,就可以实现部署ok了,所以我们继续改造。我们需要考虑个问题就是表结构
我们在哪个步骤操作呢?无非就两个地方,一个是启动项目时候,一个是构建mysql容器时候。下面就围绕这两种情况来实验。
我们想要实现的效果是什么?项目启动后,自动导入表结构,第二次启动的时候不需要导入。这时候我们可以使用flyway轻松实现这个效果。
pom.xml导入依赖
将初始化sql文件导入到一个文件命名为 V1__ry_20210210.sql
配置flyway信息
打包扔到服务器上。
运行docker-compose up --build -d
这时我们发现报错还是找不到ruoyi-vue
中的表,说明flyway
没有执行到,经过排查发现若依项目中有三处使用@PostConstruct
注解,这个在flyway
配置之前执行的,所以依旧没有导入表结构。
我们要做的就是优先加载flyway
的信息,参考博客:优先加载Flyway,注意,该博客中flyway版本过老,我将里面的方法放到下面。其他的配置参考博客就行
@PostConstruct
public void migrate() {
Flyway flyway = Flyway.configure()
.dataSource(dataSource)
.encoding("UTF-8")
.validateOnMigrate(true)
.load();
try {
flyway.migrate();
} catch (FlywayException e) {
logger.error("Flyway配置第一次加载出错", e);
try {
flyway.repair();
logger.info("Flyway配置修复成功");
flyway.migrate();
logger.info("Flyway配置重新加载成功");
} catch (Exception e1) {
logger.error("Flyway配置第二次加载出错", e1);
throw e1;
}
}
}
上传jar包,使用 docker-compose down
停止之前的,然后 docker-compose up --build -d
再次构建
这次确实先加载flyway了,但是导入表结构的时候发现日志:
提示:权限不足,我构建mysql配置的是 账号:ruoyi 密码:ruoyi 数据库:ruoyi-vue ,SpringBoot项目也是配置的相同信息,不知道为什么会提示权限不足,查找资料发现是flyway本身的问题,解决方式是降低版本。
参考博客:flyway提示权限不足
<dependency>
<groupId>org.flywaydbgroupId>
<artifactId>flyway-coreartifactId>
<version>5.2.1version>
dependency>
然后再次打包,再次启动,发现Mysql连接不上,具体原因不详。希望知道的小伙伴能评论区留言。
这个方法就行不通了, 我们换个思路,在初始化mysql容器的时候倒入表结构以及数据,请继续往下看。。。
这种方式就是若依项目不动,自己构建个Mysql镜像并且初始化sql文件
我们就是要自己制作个Mysql镜像,命名为ruoyimysql,然后初始化若依项目里面的sql文件。大体思路就是初始化ruoyimysql容器时候,将表结构以及数据导入进去。
我们在根目录下的 ruoyi文件夹下面创建 docker-mysql 这个文件夹,里面文件如下:
├── Dockerfile
├── init
│ ├── quartz.sql
│ └── ry_20210210.sql
└── utf8mb4.cnf
Dockerfile
是构建ruoyimysql的依据,内容如下:
FROM mysql
COPY utf8mb4.cnf /etc/mysql/conf.d/utf8mb4.cnf
COPY ./init /docker-entrypoint-initdb.d/
init文件中就是要执行的sql文件,注意,sql语句中如果没有创建数据库语句,必须在构建实例时候指定数据库名称
。
utf8mb4.cnf
就是设置数据库字符编码的,否则会乱码的,内容如下:
init_connect='SET NAMES utf8mb4'
character-set-server=utf8mb4
collation-server = utf8mb4_unicode_ci
default-time_zone = '+8:00'
[mysql]
default-character-set=utf8mb4
[client]
default-character-set=utf8mb4
然后我们使用docker build -t ruoyimysql .
build我们的镜像,记得最后有个点,表示从当前目录找Dockerfile,然后单独测试下我们构建的镜像
使用命令启动
docker run -d -p 3306:3306 --name=ruoyimysql -e MYSQL_ROOT_PASSWORD=ruoyi -e MYSQL_DATABASE=ry-vue ruoyimysql
然后连接mysql查看表结构是否存在。如图显示成功。
我们在idea中将flyway相关的东西全部移除掉,这时候我们需要将项目中的初始化操作的逻辑调整下顺序,将这三个@PostConstruct
注解都注释掉,然后在启动类里去掉用这三个service的init方法。
最终启动类代码如下:
package com.ruoyi;
import com.ruoyi.quartz.service.impl.SysJobServiceImpl;
import com.ruoyi.system.service.impl.SysConfigServiceImpl;
import com.ruoyi.system.service.impl.SysDictTypeServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.DependsOn;
/**
* 启动程序
*
* @author ruoyi
*/
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class})
public class RuoYiApplication implements CommandLineRunner {
@Autowired
private SysConfigServiceImpl configService;
@Autowired
private SysJobServiceImpl jobService;
@Autowired
private SysDictTypeServiceImpl dictTypeService;
public static void main(String[] args) {
// System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(RuoYiApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
}
@Override
public void run(String... args) throws Exception {
configService.init();
jobService.init();
dictTypeService.init();
}
}
上传jar包,我们为了一键部署,我们需要将我们的jar包制作成镜像。在Dockerfile目录执行 docker build -t ruoyiapp .
,别忘了最后有个点,
ruoyiapp服务的build: .
需要去掉,因为我们已经构建成docker镜像了。
我们的最终docker-compose.yml
文件如下:(只需要修改mysql和ruoyiapp镜像即可)
version: "3.8"
services:
# mysql服务
mysql:
image: ruoyimysql #镜像写成自己构建的名称
volumes:
- ./mysql:/var/lib/mysql
restart: always
container_name: ruoyi-mysql
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=songweiwei
- MYSQL_DATABASE=ry-vue
- MYSQL_USER=ruoyi
- MYSQL_PASSWORD=ruoyi
# redis服务
redis:
image: library/redis:alpine
container_name: ruoyi-redis
ports:
- 6379:6379
# 给redis设置密码
command: redis-server --requirepass songweiwei --appendonly yes
volumes:
- ./redis/data:/data
# 构建若依后端
ruoyiapp:
# 镜像来源 自己构建的
image: ruoyiapp
restart: always
container_name: ruoyi-app
# 对外暴露端口 8080
ports:
- 8080:8080
# 后端项目需要的配置,可修改
environment:
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_DATABASE=0
- REDIS_PASSWORD=songweiwei
- MYSQL_HOST=mysql
- MYSQL_PORT=3306
- MYSQL_DATABASE=ry-vue
- MYSQL_USERNAME=ruoyi
- MYSQL_PASSWORD=ruoyi
depends_on:
- redis
- mysql
links:
- redis
- mysql
docker-compose up --build -d
,然后我们启动查看日志。
使用 curl localhost:8080
测试,下图表示成功
所以我们最终的docker-compose文件步骤为:
这是我在看过b站上狂神讲的docker后(点我查看),自己实践了一把,里面很多坑, 自己一点一点摸索,希望大家一起学习进步。
其中第二步中的第5小步
那种集成flyway方式初始化数据,那种思路最终没有走下去,也是有些遗憾,希望有大神解决后,评论留言,指导一番,万分感谢。
在这里我把对若依项目修改的信息,放到gitee上,有兴趣的小伙伴可以基于此工程继续深入,gitee地址:集成Flyway
上面gitee项目主要有两个标签,一个是集成好flyway最终docker-compose启动,有问题待解决,第二块是去掉flyway,修改下初始化顺序。