Docker 实战:完全容器化部署若依(RuoYi-Vue)项目

若依(RuoYi)是一个流行的 Java 企业级快速开发平台。本项目将指导你如何使用 Dockerfile 和 Docker Compose 将 RuoYi-Vue 版本(分离版)进行完全容器化部署,涵盖后端 Spring Boot 应用、前端 Vue 应用(通过 Nginx 服务)、MySQL 数据库和 Redis 缓存。

目标:

  • 为 RuoYi 后端编写 Dockerfile,实现自动化构建和打包。
  • 为 RuoYi 前端编写 Dockerfile,实现 Vue 项目构建并通过 Nginx 托管。
  • 编写 Docker Compose 文件,统一管理和启动 MySQL、Redis、后端、前端服务。
  • 实现开发、测试或生产环境的快速、一致性部署。

技术栈:

  • Docker & Docker Compose
  • Java (Spring Boot) & Maven
  • Vue.js & Node.js & Npm/Yarn
  • Nginx
  • MySQL
  • Redis

前提条件:

  1. 安装 Docker 和 Docker Compose: 确保你的系统已安装最新稳定版的 Docker Engine 和 Docker Compose。
  2. 下载若依源码: 从 Gitee 克隆或下载 RuoYi-Vue 项目源码。
    git clone https://gitee.com/y_project/RuoYi-Vue.git
    cd RuoYi-Vue
    
  3. 了解项目结构: 熟悉 RuoYi-Vue 的基本目录结构,特别是 ruoyi-admin (后端主模块) 和 ruoyi-ui (前端模块)。

第一步:准备数据库初始化脚本

Docker Compose 可以在 MySQL 容器首次启动时自动执行 *.sql*.sh 脚本。

  1. RuoYi-Vue 源码根目录下创建一个 docker/mysql/init 目录。
  2. 将 RuoYi 源码中的 sql/quartz.sqlsql/ry_2023xxxx.sql (选择最新的 ry_*.sql) 复制到 docker/mysql/init/ 目录下。
mkdir -p docker/mysql/init
cp sql/quartz.sql docker/mysql/init/
# 根据你的源码版本选择最新的 ry_*.sql 文件
cp sql/ry_2023xxxx.sql docker/mysql/init/ry_init.sql # 重命名为 ry_init.sql 或保持原名

第二步:编写后端 Dockerfile (docker/backend/Dockerfile)

这个 Dockerfile 使用多阶段构建,先用 Maven 构建项目,然后将构建好的 Jar 包放入 JRE 运行环境。

  1. RuoYi-Vue 根目录下创建 docker/backend 目录。
  2. docker/backend 目录下创建 Dockerfile 文件:
# docker/backend/Dockerfile

# Stage 1: Build the application using Maven
# 选择一个包含 Maven 和 JDK 的基础镜像 (根据 RuoYi 要求选择 JDK 版本, 如 8 或 11)
FROM maven:3.8-openjdk-11 AS builder

# 设置工作目录为 /app
WORKDIR /app

# 复制 Maven 包装器和项目定义文件 (利用缓存)
# 注意:这里的 pom.xml 和模块路径是相对于 Dockerfile 的位置调整的
# 我们将在 Docker Compose 中设置 build context 为 RuoYi-Vue 根目录
COPY pom.xml .
COPY ruoyi-common ruoyi-common
COPY ruoyi-framework ruoyi-framework
COPY ruoyi-system ruoyi-system
COPY ruoyi-quartz ruoyi-quartz
COPY ruoyi-generator ruoyi-generator
COPY ruoyi-admin ruoyi-admin
# 如果有其他依赖模块,也需要复制

# 下载依赖 (如果 pom.xml 或模块定义未改变,此层会被缓存)
# 如果只需要构建 ruoyi-admin,可以优化此步骤,但完整构建更简单
RUN mvn dependency:go-offline -B

# 复制所有源代码 (如果源代码改变,从这里开始的层会重新构建)
# (上面已经复制了,这一步是为了确保所有文件都在)
# 可以省略,因为上面已经分模块复制了

# 执行 Maven 打包命令,跳过测试
# -pl ruoyi-admin 指定只打包 ruoyi-admin 模块
# -am 同时构建依赖的模块
RUN mvn clean package -pl ruoyi-admin -am -DskipTests

# Stage 2: Create the runtime image
# 使用一个精简的 JRE 镜像
FROM openjdk:11-jre-slim

WORKDIR /app

# 从构建阶段复制构建好的 Jar 包
# Jar 包通常在模块的 target 目录下
COPY --from=builder /app/ruoyi-admin/target/ruoyi-admin.jar ./app.jar

# 暴露后端服务端口 (默认 8080)
EXPOSE 8080

# 设置容器启动时执行的命令
# 使用 exec 格式,允许传递信号
# 通过环境变量传递数据库和 Redis 配置 (将在 docker-compose 中设置)
ENTRYPOINT ["java", \
            "-Djava.security.egd=file:/dev/./urandom", \
            "-jar", \
            "app.jar", \
            "--spring.datasource.url=jdbc:mysql://${RUOYI_MYSQL_HOST:mysql}:${RUOYI_MYSQL_PORT:3306}/${RUOYI_MYSQL_DB:ry-vue}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=Asia/Shanghai", \
            "--spring.datasource.username=${RUOYI_MYSQL_USER:root}", \
            "--spring.datasource.password=${RUOYI_MYSQL_PASS:password}", \
            "--spring.redis.host=${RUOYI_REDIS_HOST:redis}", \
            "--spring.redis.port=${RUOYI_REDIS_PORT:6379}", \
            "--spring.redis.password=${RUOYI_REDIS_PASS:}" \
           ]
# 注意: 上述配置覆盖了 application.yml 中的值。确保环境变量名与 Docker Compose 中一致。
# useSSL=false 在开发或内部网络通常可以接受,生产环境建议根据情况配置 SSL。

第三步:编写前端 Dockerfile (docker/frontend/Dockerfile)

这个 Dockerfile 同样使用多阶段构建,先用 Node.js 构建 Vue 项目,然后将静态文件交给 Nginx 托管。

  1. RuoYi-Vue 根目录下创建 docker/frontend 目录。
  2. docker/frontend 目录下创建 Dockerfile 文件:
# docker/frontend/Dockerfile

# Stage 1: Build the Vue application
# 选择一个 Node.js 镜像 (版本需与 ruoyi-ui 兼容, 查看 package.json 或咨询项目)
FROM node:16 AS builder

WORKDIR /app

# 切换淘宝镜像源加速 (可选)
# RUN npm config set registry https://registry.npmmirror.com

# 复制 package.json 和 lock 文件 (利用缓存)
# 假设 build context 是 RuoYi-Vue 根目录
COPY ruoyi-ui/package.json ruoyi-ui/yarn.lock ./ruoyi-ui/
# 如果使用 npm,复制 package-lock.json

# 进入 UI 目录安装依赖
WORKDIR /app/ruoyi-ui
RUN yarn install
# 如果使用 npm: RUN npm install

# 复制 UI 源代码
WORKDIR /app
COPY ruoyi-ui ./ruoyi-ui

# 进入 UI 目录执行构建
WORKDIR /app/ruoyi-ui
# 查看 ruoyi-ui/package.json 中的 build 命令, 通常是 build:prod
RUN yarn run build:prod
# 如果使用 npm: RUN npm run build:prod

# Stage 2: Serve the built files using Nginx
FROM nginx:1.23-alpine # 使用轻量级 Nginx 镜像

# 移除 Nginx 默认配置
RUN rm /etc/nginx/conf.d/default.conf

# 复制自定义的 Nginx 配置文件 (下一步创建)
COPY docker/frontend/nginx.conf /etc/nginx/conf.d/ruoyi.conf
# 注意: 这个路径是相对于 Dockerfile 的位置,所以 nginx.conf 要放在 docker/frontend/ 下

# 从构建阶段复制构建好的前端静态文件到 Nginx 的 web 根目录
# 构建产物通常在 ruoyi-ui/dist 目录下
COPY --from=builder /app/ruoyi-ui/dist /usr/share/nginx/html

# 暴露 Nginx 端口
EXPOSE 80

# Nginx 默认会以前台模式运行,不需要显式 CMD 或 ENTRYPOINT
  1. docker/frontend 目录下创建 nginx.conf 文件:
# docker/frontend/nginx.conf

server {
    listen       80;
    server_name  localhost; # 或者你的域名

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;
    error_log /var/log/nginx/error.log warn;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        # 解决 Vue Router History 模式下刷新 404 的问题
        try_files $uri $uri/ /index.html;
    }

    # 配置 API 代理,将前端的 /prod-api 请求转发给后端服务
    # /prod-api 这个前缀需要与 ruoyi-ui/.env.production 中的 VUE_APP_BASE_API 一致
    location /prod-api/ {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # 转发到后端服务的地址和端口 (ruoyi-backend 是 docker-compose 中的服务名)
        proxy_pass http://ruoyi-backend:8080/;

        # 可选: 移除 /prod-api 前缀转发给后端
        # rewrite ^/prod-api/(.*)$ /$1 break;
        # RuoYi 后端通常不需要移除前缀,可以直接接收 /prod-api/ 开头的请求
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

第四步:编写 Docker Compose 文件 (docker-compose.yml)

RuoYi-Vue 源码根目录下创建 docker-compose.yml 文件。

# docker-compose.yml
version: '3.8'

services:
  mysql:
    image: mysql:5.7 # 或 8.0, 确保与 RuoYi 兼容
    container_name: ruoyi-mysql
    environment:
      MYSQL_ROOT_PASSWORD: ${RUOYI_MYSQL_ROOT_PASS:-password} # 设置 root 密码 (默认 password)
      MYSQL_DATABASE: ${RUOYI_MYSQL_DB:-ry-vue}            # 创建的数据库名 (默认 ry-vue)
      MYSQL_USER: ${RUOYI_MYSQL_USER:-root}                 # 使用的用户 (这里为了简单用 root,生产环境建议创建独立用户)
      MYSQL_PASSWORD: ${RUOYI_MYSQL_PASS:-password}         # 用户的密码
    ports:
      - "${RUOYI_MYSQL_EXPOSE_PORT:-3306}:3306" # 映射到宿主机端口 (可选)
    volumes:
      - mysql_data:/var/lib/mysql                 # 数据持久化
      - ./docker/mysql/init:/docker-entrypoint-initdb.d # 挂载初始化脚本目录
    networks:
      - ruoyi-net
    restart: unless-stopped
    command: # 设置 MySQL 字符集等
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci

  redis:
    image: redis:6.2 # 选择合适的 Redis 版本
    container_name: ruoyi-redis
    environment:
      # 如果 Redis 需要密码
      # REDIS_PASSWORD: ${RUOYI_REDIS_PASS:-} # 默认无密码
    command: ["redis-server", "--requirepass", "${RUOYI_REDIS_PASS:-}"] # 启动时设置密码 (如果环境变量为空则无密码)
    ports:
      - "${RUOYI_REDIS_EXPOSE_PORT:-6379}:6379" # 映射到宿主机端口 (可选)
    volumes:
      - redis_data:/data # 数据持久化
    networks:
      - ruoyi-net
    restart: unless-stopped

  ruoyi-backend:
    container_name: ruoyi-backend
    build:
      context: . # 构建上下文是当前目录 (RuoYi-Vue 根目录)
      dockerfile: docker/backend/Dockerfile # 指定 Dockerfile 路径
    environment:
      # 这些环境变量会传递给后端 Dockerfile 的 ENTRYPOINT
      RUOYI_MYSQL_HOST: mysql # 使用服务名作为 Host
      RUOYI_MYSQL_PORT: 3306
      RUOYI_MYSQL_DB: ${RUOYI_MYSQL_DB:-ry-vue}
      RUOYI_MYSQL_USER: ${RUOYI_MYSQL_USER:-root}
      RUOYI_MYSQL_PASS: ${RUOYI_MYSQL_PASS:-password}
      RUOYI_REDIS_HOST: redis # 使用服务名作为 Host
      RUOYI_REDIS_PORT: 6379
      RUOYI_REDIS_PASS: ${RUOYI_REDIS_PASS:-}
      # 可以添加其他 Spring Boot 配置覆盖, 如 SERVER_PORT
      # SERVER_PORT: 8080
    ports:
      - "${RUOYI_BACKEND_EXPOSE_PORT:-8080}:8080" # 映射后端端口
    depends_on: # 确保数据库和 Redis 先启动 (但不保证完全可用)
      - mysql
      - redis
    networks:
      - ruoyi-net
    restart: unless-stopped

  ruoyi-frontend:
    container_name: ruoyi-frontend
    build:
      context: . # 构建上下文是当前目录
      dockerfile: docker/frontend/Dockerfile # 指定 Dockerfile 路径
    ports:
      - "${RUOYI_FRONTEND_EXPOSE_PORT:-80}:80" # 映射前端 Nginx 端口到宿主机 80
    depends_on:
      - ruoyi-backend # 依赖后端服务 (确保后端服务名在 Nginx 配置中正确)
    networks:
      - ruoyi-net
    restart: unless-stopped

networks:
  ruoyi-net: # 定义网络
    driver: bridge

volumes: # 定义数据卷
  mysql_data:
  redis_data:

说明:

  • 环境变量: 使用 .env 文件或直接在 docker-compose.ymlenvironment 中设置数据库、Redis 的用户名、密码、数据库名等。后端 Dockerfile 的 ENTRYPOINT 会读取这些环境变量来配置 Spring Boot。
  • 服务名: 在 Docker Compose 网络中,容器可以通过服务名(如 mysql, redis, ruoyi-backend)互相访问。
  • 数据持久化: 使用 Docker 卷 (mysql_data, redis_data) 来持久化数据库和 Redis 的数据,这样即使容器被删除重建,数据也不会丢失。
  • 数据库初始化: MySQL 容器启动时会自动执行 ./docker/mysql/init 目录下的 SQL 文件。
  • 构建上下文: build.context: . 表示 Docker 构建时会将 RuoYi-Vue 根目录作为上下文发送给 Docker 守护进程,这样 Dockerfile 内部的 COPY 指令可以访问项目中的任何文件。
  • 端口映射: 将前端容器的 80 端口映射到宿主机的 80 端口,这样用户可以通过 http://<你的宿主机IP> 访问。其他端口(MySQL, Redis, Backend)可以选择性映射,方便调试或外部访问。
  • .env 文件 (可选): 你可以在 docker-compose.yml 同级目录下创建一个 .env 文件来管理敏感配置,例如:
    # .env file
    RUOYI_MYSQL_ROOT_PASS=your_strong_root_password
    RUOYI_MYSQL_DB=ry-vue
    RUOYI_MYSQL_USER=ry_user
    RUOYI_MYSQL_PASS=your_strong_app_password
    RUOYI_REDIS_PASS=your_redis_password
    
    # Optional: Expose ports differently if needed
    # RUOYI_MYSQL_EXPOSE_PORT=3307
    # RUOYI_REDIS_EXPOSE_PORT=6380
    # RUOYI_BACKEND_EXPOSE_PORT=8081
    # RUOYI_FRONTEND_EXPOSE_PORT=8888
    
    Docker Compose 会自动加载 .env 文件中的变量。

第五步:构建并启动服务

RuoYi-Vue 源码根目录下执行:

# 首次构建并后台启动所有服务
docker-compose up -d --build

# 如果后续代码或 Dockerfile 有更新,需要重新构建
# docker-compose build
# docker-compose up -d

# 查看容器状态
docker-compose ps

# 查看日志 (例如查看后端启动日志)
docker-compose logs -f ruoyi-backend

# 停止并移除容器、网络、卷 (如果需要清理)
# docker-compose down -v

注意:

  • 首次构建可能需要较长时间,因为需要下载基础镜像、Maven 依赖、Node.js 依赖等。
  • MySQL 数据库初始化也需要一些时间,请观察 ruoyi-mysql 容器的日志,等待数据库准备就绪。
  • 后端服务启动需要连接数据库和 Redis,请观察 ruoyi-backend 的日志确保连接成功且 Spring Boot 应用正常启动。

第六步:访问应用

等待所有容器启动并健康运行后(特别是 ruoyi-backendruoyi-frontend),打开浏览器访问:

http://<你的宿主机IP> (或者你在 docker-compose.yml 中为 ruoyi-frontend 指定的其他宿主机端口)

你应该能看到若依的登录界面。使用默认用户名 admin 和密码 admin123 登录。


总结:

通过这套方案,我们成功地将 RuoYi-Vue 项目及其依赖(MySQL, Redis)完全容器化。这带来了以下好处:

  • 环境一致性: 保证了开发、测试、生产环境的一致性。
  • 快速部署: 一条 docker-compose up 命令即可启动整个应用。
  • 易于管理: 将应用拆分为独立的服务容器,便于单独升级、伸缩和监控。
  • 资源隔离: 各服务运行在独立的容器中,互不干扰。

这是一个基础的容器化方案,你可以根据实际需求进一步优化,例如:

  • 使用更安全的非 root 用户运行 Java 和 Nginx 进程。
  • 优化 Dockerfile 构建缓存。
  • 配置更详细的日志收集。
  • 集成 CI/CD 流水线实现自动化构建和部署。
  • 根据生产环境需求调整资源限制(CPU, 内存)。
posted on 2025-04-10 09:27  Leo-Yide  阅读(2825)  评论(0)    收藏  举报