手把手教你Docker部署若依项目(后端服务)

若依项目非常牛,但是对于一些朋友想快速体验,不想一点一点搭建各种环境,这里我就记录下,我将前后分离的若依项目做成docker的思路。可以实现一键部署。文末有相关连接。

一、开始干活

制作后端服务是比较麻烦的,其中遇到了很多很多问题,在这里我将我的试错经历一点一点记录下来。

我们最终想要的效果是:用户只需编写一个yml文件就可以实现启动若依的后端服务,我们先考虑下,我们正常要启动若依的后端项目需要做什么?

  • 启动Redis服务
  • 启动Mysql服务,并且导入若依项目的初始化表结构
  • 修改若依项目的 redis配置和mysql配置

然后将SpringBoot达成Jar包然后在java -jar ruoyi-admin.jar启动即可


我们是使用docker-compose启动整个后端项目,所以我们的整体思路就是将若依项目中的所有配置信息都写成变量,然后将该jar包制作成docker镜像(命名为ruoyiapp),在docker-compose中配置redismysql,以及ruoyiapp,因为ruoyiapp这个服务要依赖redis和mysql,以及使用他们的ip信息,这些在docker-compose中非常简单(depends_on和links),接下来我们就开始改造。

1. 修改若依项目的配置信息

Redis-配置:

image-20210313213533831

Mysql配置:

Mysql配置

我们定义了 Mysql和Redis的配置变量,这样我们可以在Docker启动时候指定这些变量,当然你也可以配置更多的变量 ${变量名称} 定义即可,我们先在服务器根目录创建 ruoyi文件夹,我们打成Jar包传到该目录

上传jar包

2. 编写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
3. Dockerfile文件

Dockerfile文件内容:

FROM java:8
# 维护者
MAINTAINER xiuyi<kid0510z@163.com>
# copy jar包 命名为 aap.jar
COPY *.jar /app.jar
# 暴露端口
EXPOSE 8080
# 启动 jar包 可通过 PARAM 配置启动参数
ENTRYPOINT java  ${PARAM} -jar app.jar

我们可以通过 PARAM 这个参数来覆盖SpringBoot中其他配置,比如说 log日志位置等等。。。

4. 启动项目

我们使用 docker-compose up --build -d 启动就可以了。-d表示后台启动

image-20210313221710987

我们 docker ps 查看是否都成功启动了,这时候我们发现访问后端接口提示访问不到,所以我们查看docker的ruoyi-app 日志,使用命令 docker logs ruoyi-app -f --tail=200 如下图:

image-20210313222520245

5. 手动导入表结构到mysql

我们发现 ruoyi项目在启动的时候需要将mysql中的字典等数据放入redis,但是mysql现在还没有数据。我们可以使用docker stop ruoyi-app先将该容器停止掉,手动连接上mysql,将数据导入。使用Navicat或者Datagrip链接我们在上面docker-compose.yml中配置的mysql。注意:一定要在导入自己配置的数据库中。

image-20210313225706923

6.再次启动

再次启动docker start ruoyi-app 容器即可。再次查看日志docker logs ruoyi-app -f --tail=200如下:

image-20210313230604910

7. 最终测试

这样就表示后端部署ok

image-20210313231210206

8. 存在问题

但是现在这样需要我们人工参与,总感觉少点意思,我们想要的是,只编写个docker-compose.yml文件,就可以实现部署ok了,所以我们继续改造。我们需要考虑个问题就是表结构我们在哪个步骤操作呢?无非就两个地方,一个是启动项目时候,一个是构建mysql容器时候。下面就围绕这两种情况来实验。

二、导入表结构(项目启动)

我们想要实现的效果是什么?项目启动后,自动导入表结构,第二次启动的时候不需要导入。这时候我们可以使用flyway轻松实现这个效果。

1. 集成flyway
  1. pom.xml导入依赖

  2. 将初始化sql文件导入到一个文件命名为 V1__ry_20210210.sql

  3. 配置flyway信息

  4. 打包扔到服务器上。

2. 第一次测试

运行docker-compose up --build -d

这时我们发现报错还是找不到ruoyi-vue中的表,说明flyway没有执行到,经过排查发现若依项目中有三处使用@PostConstruct注解,这个在flyway 配置之前执行的,所以依旧没有导入表结构。

3. 配置优先执行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;
    }
  }
}

配置flyway执行优先级

4. 第二次测试

上传jar包,使用 docker-compose down停止之前的,然后 docker-compose up --build -d再次构建

这次确实先加载flyway了,但是导入表结构的时候发现日志:

image-20210314014037492

提示:权限不足,我构建mysql配置的是 账号:ruoyi 密码:ruoyi 数据库:ruoyi-vue ,SpringBoot项目也是配置的相同信息,不知道为什么会提示权限不足,查找资料发现是flyway本身的问题,解决方式是降低版本。

参考博客:flyway提示权限不足

<dependency>
  <groupId>org.flywaydb</groupId>
  <artifactId>flyway-core</artifactId>
  <version>5.2.1</version>
</dependency>
5. 依旧连接不上

然后再次打包,再次启动,发现Mysql连接不上,具体原因不详。希望知道的小伙伴能评论区留言。

image-20210314205818922

6. 换个思路

这个方法就行不通了, 我们换个思路,在初始化mysql容器的时候倒入表结构以及数据,请继续往下看。。。

三、导入表结构(初始化MySQl容器)

这种方式就是若依项目不动,自己构建个Mysql镜像并且初始化sql文件

1. 思路

我们就是要自己制作个Mysql镜像,命名为ruoyimysql,然后初始化若依项目里面的sql文件。大体思路就是初始化ruoyimysql容器时候,将表结构以及数据导入进去。

2. 准备工作

我们在根目录下的 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
3. 构建Mysql镜像

然后我们使用docker build -t ruoyimysql . build我们的镜像,记得最后有个点,表示从当前目录找Dockerfile,然后单独测试下我们构建的镜像

4. 单独测试镜像

使用命令启动

docker run -d -p 3306:3306 --name=ruoyimysql -e MYSQL_ROOT_PASSWORD=ruoyi -e MYSQL_DATABASE=ry-vue ruoyimysql

然后连接mysql查看表结构是否存在。如图显示成功。

image-20210314224347313

5. 调整项目

我们在idea中将flyway相关的东西全部移除掉,这时候我们需要将项目中的初始化操作的逻辑调整下顺序,将这三个@PostConstruct注解都注释掉,然后在启动类里去掉用这三个service的init方法。

image-20210314231411396

最终启动类代码如下:

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镜像了。

6. 测试

我们的最终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,然后我们启动查看日志。

image-20210314235743492

使用 curl localhost:8080测试,下图表示成功

image-20210314235847707

四、总结

所以我们最终的docker-compose文件步骤为:

  1. 我们自己构建的mysql镜像:ruoyimysql(已经初始化表结构和数据)
  2. redis镜像
  3. 我们自己制作的ruoyiapp镜像,配置好项目变量

五、最后的话

这是我在看过b站上狂神讲的docker后(点我查看),自己实践了一把,里面很多坑, 自己一点一点摸索,希望大家一起学习进步。

  1. 其中第二步中的第5小步那种集成flyway方式初始化数据,那种思路最终没有走下去,也是有些遗憾,希望有大神解决后,评论留言,指导一番,万分感谢。

  2. 在这里我把对若依项目修改的信息,放到gitee上,有兴趣的小伙伴可以基于此工程继续深入,gitee地址:集成Flyway

  3. 上面gitee项目主要有两个标签,一个是集成好flyway最终docker-compose启动,有问题待解决,第二块是去掉flyway,修改下初始化顺序。

image-20210315000522604

image-20210315000614405

相关链接

Logo

快速构建 Web 应用程序

更多推荐