引言

  • 若依管理系统简介(基于Spring Boot的权限管理系统)
  • Docker在现代化部署中的优势(环境一致性、快速部署、资源隔离

准备工作

  • 环境要求:Docker及Docker Compose已安装

获取若依项目源码(GitHub或Gitee仓库)

git clone https://github.com/yangzongzhuan/RuoYi-Vue.git

后端Docker化

  • 编写Dockerfile:基于OpenJDK镜像构建Spring Boot应用
FROM maven:3.8-jdk-8 AS build
WORKDIR /app
# 注入阿里云镜像加速
RUN mkdir -p /root/.m2 && \
    echo '<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"><mirrors><mirror><id>aliyun</id><name>aliyun</name><url>https://maven.aliyun.com/repository/public</url><mirrorOf>*</mirrorOf></mirror></mirrors></settings>' > /root/.m2/settings.xml

COPY . .
RUN mvn clean package -DskipTests

FROM eclipse-temurin:17-jre-alpine
RUN apk add --update --no-cache ttf-dejavu fontconfig
WORKDIR /app
COPY --from=build /app/ruoyi-admin/target/ruoyi-admin.jar app.jar
ENTRYPOINT ["java", "-Xmx512m", "-jar", "app.jar"]

前端Docker化

  • 构建Vue项目静态资源(npm run build)
# 阶段 1: 编译前端
FROM node:16-alpine AS build-stage
WORKDIR /app
# 设置淘宝镜像源,加速 npm install
RUN npm config set registry https://registry.npmmirror.com
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build:prod

# 阶段 2: 运行前端 (Nginx)
FROM nginx:alpine
COPY --from=build-stage /app/dist /usr/share/nginx/html
# 拷贝我们自定义的 nginx.conf
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80

配置nginx

vim nginx.conf


worker_processes  1;
events { worker_connections  1024; }

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   /usr/share/nginx/html;
            try_files $uri $uri/ /index.html;
            index  index.html index.htm;
        }

        # 核心:转发所有接口请求到后端容器
        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;
            proxy_pass http://ruoyi-server:8080/;
        }
    }
}

编写docker-compose.yml

version: '3'
services:
  ruoyi-db:
    image: mysql:8.0
    container_name: ruoyi-db
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=ry-vue
    volumes:
      - ./docker-data/db:/var/lib/mysql
      - ./sql:/docker-entrypoint-initdb.d # 源码里的sql文件夹
    ports:
      - "3306:3306"

  ruoyi-redis:
    image: redis:latest
    container_name: ruoyi-redis

  ruoyi-server:
    build: .
    container_name: ruoyi-server
    depends_on:
      - ruoyi-db
      - ruoyi-redis
    environment:
      - SPRING_DATASOURCE_DRUID_MASTER_URL=jdbc:mysql://ruoyi-db:3306/ry-vue?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
      - SPRING_REDIS_HOST=ruoyi-redis

  ruoyi-nginx:
    build: ./ruoyi-ui
    container_name: ruoyi-nginx
    volumes:
      - /root/java/RuoYi-Vue/ruoyi-ui/nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "80:80"
    depends_on:
      - ruoyi-server

启动服务

docker-compose up -d ruoyi-db ruoyi-redis
docker-compose up -d --build ruoyi-server
docker-compose up -d --build ruoyi-nginx

访问ip

部署监控

version: '3'
services:
  ruoyi-db:
    image: mysql:8.0
    container_name: ruoyi-db
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=ry-vue
    volumes:
      - ./docker-data/db:/var/lib/mysql
      - ./sql:/docker-entrypoint-initdb.d # 源码里的sql文件夹
    ports:
      - "3306:3306"
    networks:
      - ruoyi-net

  ruoyi-redis:
    image: redis:latest
    container_name: ruoyi-redis
    command: redis-server --appendonly yes
    volumes:
      - ./docker-data/redis:/data
    networks:
      - ruoyi-net

  ruoyi-server:
    build: .
    container_name: ruoyi-server
    depends_on:
      - ruoyi-db
      - ruoyi-redis
    environment:
      - SPRING_DATASOURCE_DRUID_MASTER_URL=jdbc:mysql://ruoyi-db:3306/ry-vue?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
      - SPRING_REDIS_HOST=ruoyi-redis
    networks:
      - ruoyi-net
  ruoyi-nginx:
    build: ./ruoyi-ui
    container_name: ruoyi-nginx
    volumes:
      - /root/java/RuoYi-Vue/ruoyi-ui/nginx.conf:/etc/nginx/nginx.conf:ro
    ports:
      - "80:80"
    networks:
      - ruoyi-net
    depends_on:
      - ruoyi-server
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    # 核心:共享宿主机网络和 PID 以实现“破墙”监控
    network_mode: "host"
    pid: "host"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'

  # 容器性能采集 (cAdvisor)
  cadvisor:
    image: google/cadvisor:latest
    container_name: cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    networks:
      - ruoyi-net
  redis-exporter:
    image: oliver006/redis_exporter:latest
    container_name: redis-exporter
    environment:
      - REDIS_ADDR=redis://ruoyi-redis:6379
    networks:
      - ruoyi-net
  # 1. Nginx 深度监控采集器
  nginx-exporter:
    image: nginx/nginx-prometheus-exporter:latest
    container_name: nginx-exporter
    command:
      - "-nginx.scrape-uri=http://ruoyi-nginx/nginx_status"
    ports:
      - "9113:9113"
    depends_on:
      - ruoyi-nginx
    networks:
      - ruoyi-net

  # 2. MySQL 深度监控采集器
  mysql-exporter:
    image: prom/mysqld-exporter:latest
    container_name: mysql-exporter
    volumes:
      - ./my-exporter.cnf:/.my.cnf:ro  # 确保这里对应日志里报错的路径
    networks:
      - ruoyi-net
    depends_on:
      - ruoyi-db
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - ruoyi-net
    ports:
      - "9090:9090"

  # 可视化仪表盘
  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    networks:
      - ruoyi-net
    depends_on:
      - prometheus
networks:
  ruoyi-net:
    driver: bridge 

查看docker网段

docker network inspect ruoyi-vue_ruoyi-net
"Name": "ruoyi-vue_ruoyi-net",
        "Id": "4a9cee137815fe158841a81a8595fa20bf40c61baee69db672efb40d492ba6a1",
        "Created": "2026-02-02T16:07:59.471440835+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1"
                }
            ]

将这里的Gateway写入Prometheus的node-exporter配置中

创建Prometheus的配置文件

mkdir promethues
vim promethues/promethues.yml
global:
  scrape_interval: 15s # 默认每 15 秒抓取一次数据
  evaluation_interval: 15s

scrape_configs:
  # 监控宿主机性能 (CPU, 内存, 磁盘)
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['172.19.0.1:9100'] # 对应的网关信息

  # 监控每个容器的资源占用 (cAdvisor)
  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

  # 监控 Redis 运行状态
  - job_name: 'redis-exporter'
    static_configs:
      - targets: ['redis-exporter:9121']

  - job_name: 'nginx-exporter'
    static_configs:
      - targets: ['nginx-exporter:9113']

  - job_name: 'mysql-exporter'
    static_configs:
      - targets: ['mysql-exporter:9104']

修改nginx配置

vim ruoyi-ui/nginx.conf
worker_processes  1;
events { worker_connections  1024; }

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        location /nginx_status {
            stub_status on;
            access_log off;
            allow 127.0.0.1;
            # 允许 ruoyi-net 网段访问,或者简单点先允许所有
            allow all;
        }

        location / {
            root   /usr/share/nginx/html;
            try_files $uri $uri/ /index.html;
            index  index.html index.htm;
        }

        # 核心:转发所有接口请求到后端容器
        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;
            proxy_pass http://ruoyi-server:8080/;
        }
    }
}

创建一个mysql配置文件

vim my-exporter.cnf

[client]
user=root
password=password
host=ruoyi-db

然后启动

docker-compose up -d

 

服务正常启动

配置grafana

这里就不多说了,跟我上个文章差不多

这里直接填服务名就行

数据库主从配置

修改主库(ruoyi-db)配置

主库必须开启二进制日志(binlog)并设置唯一的 server-id

在宿主机创建或修改主库配置文件(例如 ./mysql/master.cnf):

[mysqld]
server-id=1
log-bin=mysql-bin
# 允许从库连接的网段,也可以不设置
binlog-do-db=ry-vue

然后在 docker-compose.yml 中将该文件挂载到 ruoyi-db

ruoyi-db:
    # ... 原有配置 ...
    volumes:
      - ./mysql/master.cnf:/etc/mysql/conf.d/master.cnf:ro
      - ./docker-data/db:/var/lib/mysql

导出主库数据并获取同步位点

锁定主库并备份:

# 进入主库执行
docker exec -it ruoyi-db mysql -uroot -ppassword

在 MySQL 命令行内执行

FLUSH TABLES WITH READ LOCK; -- 锁定只读
SHOW MASTER STATUS;          -- 记录下 File 和 Position 的值

导出数据: 打开另一个终端窗口执行

docker exec ruoyi-db mysqldump -uroot -ppassword --all-databases > master_backup.sql

解锁主库: 回到刚才的 MySQL 命令行执行:

UNLOCK TABLES;

配置并添加从库(ruoyi-db-slave)

准备从库配置 ./mysql/slave.cnf

[mysqld]
server-id=2
relay-log=mysql-relay-bin
read-only=1

更新 docker-compose.yml

ruoyi-db-slave:
    image: mysql:8.0
    container_name: ruoyi-db-slave
    environment:
      - MYSQL_ROOT_PASSWORD=password
    volumes:
      - ./mysql/slave.cnf:/etc/mysql/conf.d/slave.cnf:ro
      - ./docker-data/db-slave:/var/lib/mysql
      - ./master_backup.sql:/docker-entrypoint-initdb.d/master_backup.sql # 自动初始化数据
    networks:
      - ruoyi-net
    depends_on:
      - ruoyi-db

开启主从同步

启动新容器

docker-compose up -d ruoyi-db-slave

执行同步指令(使用第 2 步中记录的 File 和 Position)

CHANGE MASTER TO
  MASTER_HOST='ruoyi-db',
  MASTER_USER='root',
  MASTER_PASSWORD='password',
  MASTER_LOG_FILE='mysql-bin.000001', -- 替换为你记录的文件名
  MASTER_LOG_POS=157;                 -- 替换为你记录的数字

START SLAVE;
SHOW SLAVE STATUS\G; -- 查看 Slave_IO_Running 和 Slave_SQL_Running 是否都为 Yes

部署elk+filebeat

部署 ELK (Elasticsearch, Logstash, Kibana) + Filebeat 是目前主流的日志管理方案(EFK 堆栈)。 RuoYi 项目中,Filebeat 负责轻量化采集容器日志,Logstash 负责清洗,最后由 Kibana 展示。

更新 docker-compose.yml

services:
  # --- Elasticsearch: 存储与索引 ---
  elasticsearch:
    image: elasticsearch:7.17.9
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - ./elk/elasticsearch/data:/usr/share/elasticsearch/data
    networks:
      - ruoyi-net
    ports:
      - "9200:9200"

  # --- Logstash: 日志处理加工 ---
  logstash:
    image: logstash:7.17.9
    container_name: logstash
    volumes:
      - ./elk/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    networks:
      - ruoyi-net
    depends_on:
      - elasticsearch

  # --- Kibana: 可视化面板 ---
  kibana:
    image: kibana:7.17.9
    container_name: kibana
    environment:
      - I18N_LOCALE=zh-CN
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    networks:
      - ruoyi-net
    ports:
      - "5601:5601"
    depends_on:
      - elasticsearch

  # --- Filebeat: 轻量级日志采集 ---
  filebeat:
    image: elastic/filebeat:7.17.9
    container_name: filebeat
    user: root
    volumes:
      - ./elk/filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro # 采集所有容器日志
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - ruoyi-net
    depends_on:
      - logstash

核心配置文件

Logstash 配置 (./elk/logstash/logstash.conf)

input {
  beats {
    port => 5044
  }
}

filter {
  # 1. 处理 RuoYi 后端 Java 日志 (Spring Boot)
  if [container][name] =~ "ruoyi-server" {
    grok {
      match => { "message" => "%{TIMESTAMP_ISO8601:log_time} %{LOGLEVEL:level} %{NUMBER:pid} --- \[%{DATA:thread}\] %{DATA:class} : %{GREEDYDATA:log_content}" }
    }
    
    # 针对慢 SQL 的二次解析 (RuoYi 默认会打印执行耗时超过一定阈值的 SQL)
    if "slow sql" in [log_content] {
      mutate { add_tag => ["slow_sql"] }
    }
    
    # 自动识别异常堆栈
    if "Exception" in [message] or "Error" in [message] {
      mutate { add_tag => ["error_stack"] }
    }
  }

  # 2. 处理 Nginx 访问日志
  if [container][name] =~ "ruoyi-nginx" {
    grok {
      match => { "message" => "%{IPORHOST:client_ip} - %{DATA:remote_user} \[%{HTTPDATE:access_time}\] \"%{WORD:method} %{DATA:url} HTTP/%{NUMBER:http_version}\" %{NUMBER:status} %{NUMBER:body_bytes_sent} \"%{DATA:referrer}\" \"%{DATA:user_agent}\"" }
    }
    # 将状态码转为数字,方便 Kibana 做范围查询(如查询 400 以上的请求)
    mutate {
      convert => { "status" => "integer" }
    }
    # 记录地理位置(需确保 Logstash 容器内有 GeoIP 数据库,可选)
  }
}

output {
  elasticsearch {
    hosts => ["elasticsearch:9200"]
    # 动态索引名称,方便按日期管理
    index => "ruoyi-%{+YYYY.MM.dd}"
  }
  # 调试模式:在控制台打印解析后的数据,方便排查配置是否生效
  # stdout { codec => rubydebug }
}

Filebeat 配置 (./elk/filebeat/filebeat.yml)

filebeat.inputs:
- type: container
  paths:
    - /var/lib/docker/containers/*/*.log # 监控宿主机上的容器日志路径

processors:
- add_docker_metadata: ~ # 自动增加容器名称、镜像等元数据

output.logstash:
  hosts: ["logstash:5044"]

创建目录并赋权

mkdir -p ./elk/elasticsearch/data
chmod 777 ./elk/elasticsearch/data

启动服务

docker-compose up -d elasticsearch kibana logstash filebeat

访问 Kibana: 浏览器打开 http://你的IP:5601

  • 进入 Stack Management -> Index Patterns

  • 创建一个索引模式 ruoyi-*

 

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐