Docker Compose 部署
本文档提供使用 Docker Compose 快速部署卷王问卷系统的完整指南。Docker Compose 可以简化多容器应用的部署和管理,让部署过程更加标准化和便捷。
默认配置信息
为了简化部署流程,本文档已预配置了所有服务的默认密码和高位端口:
默认密码:
- MySQL Root 密码:
SurveyKing@2024
- MySQL 用户密码:
Survey@123456
- Redis 密码:
SurveyRedis@2024
服务端口:
- 前端访问: 18000(避免与宿主机冲突)
- 后端 API: 18080
- MySQL: 13306(替代标准 3306)
- Redis: 16379(替代标准 6379)
生产环境部署时,建议修改这些默认密码以提高安全性。
准备工作
部署文件准备
surveyking-xxx.zip
,前端文件surveyking-server.jar
,后端 jar 包surveyking-pro.sql
,数据库脚本
系统要求
- CPU: 建议 2 核以上
- 内存: 建议 4GB 以上(生产环境推荐 8GB+)
- 磁盘: 建议 50GB 以上可用空间
- 操作系统: 支持 Docker 的 Linux 发行版(CentOS 7+、Ubuntu 18.04+、Debian 9+ 等)
- 网络: 确保服务器可以访问外网(用于拉取镜像)
安装 Docker 和 Docker Compose
CentOS/RHEL/Rocky Linux
# 安装 Docker
curl -fsSL https://get.docker.com | bash
sudo systemctl start docker
sudo systemctl enable docker
# 安装 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 验证安装
docker --version
docker-compose --version
Ubuntu/Debian
# 更新包索引
sudo apt-get update
# 安装 Docker
curl -fsSL https://get.docker.com | bash
sudo systemctl start docker
sudo systemctl enable docker
# 安装 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 将当前用户加入 docker 组
sudo usermod -aG docker $USER
部署目录结构
创建部署目录并组织文件:
# 创建部署目录(在当前目录下创建 surveyking-docker 文件夹)
export DEPLOY_DIR="$(pwd)/surveyking-docker"
mkdir -p $DEPLOY_DIR
cd $DEPLOY_DIR
# 创建必要的子目录
mkdir -p {mysql/data,mysql/conf,mysql/init,redis/data,redis/conf,app/jar,app/files,nginx/conf,nginx/html,logs}
# 设置目录权限
chmod -R 755 $DEPLOY_DIR
部署目录说明
$DEPLOY_DIR
变量设置为当前目录下的surveyking-docker
文件夹- 这样可以在任何位置创建部署环境,不依赖固定的系统路径
- 如果您希望在特定位置部署,可以修改
DEPLOY_DIR
的值,例如:export DEPLOY_DIR="/opt/surveyking-docker"
最终的目录结构如下:
$DEPLOY_DIR/
├── docker-compose.yml
├── .env
├── mysql/
│ ├── data/ # MySQL 数据目录
│ ├── conf/
│ │ └── my.cnf # MySQL 配置文件
│ └── init/
│ └── surveyking-pro.sql # 初始化脚本
├── redis/
│ ├── data/ # Redis 数据目录
│ └── conf/
│ └── redis.conf # Redis 配置文件
├── app/
│ ├── jar/
│ │ └── surveyking-server.jar
│ └── files/ # 上传文件存储目录
├── nginx/
│ ├── conf/
│ │ └── nginx.conf # Nginx 配置文件
│ └── html/ # 前端静态文件目录
│ └── dist/ # 解压后的前端文件目录
│ ├── index.html # 前端主页面
│ ├── static/ # 静态资源目录
│ └── ... # 其他前端文件
└── logs/ # 应用日志目录
配置文件
1. 创建环境变量文件
cat > $DEPLOY_DIR/.env << 'EOF'
# 数据库配置
MYSQL_ROOT_PASSWORD=SurveyKing@2024
MYSQL_DATABASE=survey
MYSQL_USER=survey
MYSQL_PASSWORD=Survey@123456
# Redis 配置
REDIS_PASSWORD=SurveyRedis@2024
# 应用配置
APP_PORT=18080
NGINX_PORT=18000
# 数据库和缓存端口
MYSQL_PORT=13306
REDIS_PORT=16379
# 时区设置
TZ=Asia/Shanghai
# JVM 内存配置
JAVA_OPTS=-Xms512m -Xmx2g -Dfile.encoding=UTF-8
# 数据库连接配置
DB_HOST=mysql
DB_PORT=3306
REDIS_HOST=redis
REDIS_PORT=6379
EOF
2. MySQL 配置文件
cat > $DEPLOY_DIR/mysql/conf/my.cnf << 'EOF'
[mysqld]
# 基础配置
port = 3306
datadir = /var/lib/mysql
socket = /var/run/mysqld/mysqld.sock
pid-file = /var/run/mysqld/mysqld.pid
# 字符集配置
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
init_connect = 'SET NAMES utf8mb4'
# 大小写敏感
lower_case_table_names = 1
# 连接配置
max_connections = 400
max_connect_errors = 1000
interactive_timeout = 1800
wait_timeout = 1800
# InnoDB 配置
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_file_per_table = 1
innodb_flush_log_at_trx_commit = 2
# 日志配置
slow_query_log = 1
slow_query_log_file = /var/lib/mysql/slow.log
long_query_time = 3
# 安全配置
skip-host-cache
skip-name-resolve
[mysql]
default-character-set = utf8mb4
[client]
default-character-set = utf8mb4
socket = /var/run/mysqld/mysqld.sock
EOF
3. Redis 配置文件
cat > $DEPLOY_DIR/redis/conf/redis.conf << 'EOF'
# 网络配置
bind 0.0.0.0
port 6379
protected-mode yes
# 安全配置
requirepass SurveyRedis@2024
# 持久化配置
save 900 1
save 300 10
save 60 10000
# AOF 配置
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
# 内存配置
maxmemory 256mb
maxmemory-policy allkeys-lru
# 日志配置
loglevel notice
logfile ""
# 其他配置
timeout 300
databases 16
EOF
4. Nginx 配置文件
cat > $DEPLOY_DIR/nginx/conf/nginx.conf << 'EOF'
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# 基础配置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 30m;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html/dist;
index index.html;
# 前端静态文件
location / {
try_files $uri $uri/ /index.html;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# 验证码代理
location /captcha {
proxy_pass http://app:18080/captcha;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
}
# 后端 API 代理
location /admin-api {
proxy_pass http://app:18080/admin-api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
# WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 文件上传代理
location /files {
proxy_pass http://app:18080/files;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 健康检查
location /health {
access_log off;
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
}
EOF
5. 应用配置文件
cat > $DEPLOY_DIR/app/application.yml << 'EOF'
server:
port: 18080
spring:
# 数据源配置项
application:
name: surveyking
autoconfigure:
exclude:
- com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源
servlet:
multipart:
max-file-size: 30MB
max-request-size: 30MB
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
enabled: true
stat-view-servlet:
enabled: false
allow: # 设置白名单,不填则允许所有访问
url-pattern: /druid/*
login-username: # 控制台管理用户名和密码
login-password:
filter:
stat:
enabled: true
log-slow-sql: true # 慢 SQL 记录
slow-sql-millis: 100
merge-sql: true
wall:
config:
multi-statement-allow: true
dynamic: # 多数据源配置
druid: # Druid 【连接池】相关的全局配置
initial-size: 20 # 初始连接数
min-idle: 20 # 最小连接池数量
max-active: 100 # 最大连接池数量
max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
test-while-idle: true
test-on-borrow: false
test-on-return: false
primary: master
datasource:
master:
url: jdbc:mysql://${DB_HOST:mysql}:3306/${MYSQL_DATABASE:survey}?allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
username: ${MYSQL_USER:survey} # 请替换为您的真实数据库用户名
password: ${MYSQL_PASSWORD:Survey@123456} # 请替换为您的真实数据库密码
# Redis 配置。Redisson 默认的配置足够使用,一般不需 要进行调优
redis:
database: 0 # 数据库索引
host: ${REDIS_HOST:redis}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASSWORD:SurveyRedis@2024}
quartz:
auto-startup: true # 本地开发环境,尽量不要开启 Job
scheduler-name: schedulerName # Scheduler 名字。默认为 schedulerName
job-store-type: jdbc # Job 存储器类型。默认为 memory 表示内存,可选 jdbc 使用数据库。
wait-for-jobs-to-complete-on-shutdown: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
properties: # 添加 Quartz Scheduler 附加属性,更多可以看 http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 文档
org:
quartz:
# Scheduler 相关配置
scheduler:
instanceName: schedulerName
instanceId: AUTO # 自动生成 instance ID
# JobStore 相关配置
jobStore:
# JobStore 实现类。可见博客:https://blog.csdn.net/weixin_42458219/article/details/122247162
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
isClustered: true # 是集群模式
clusterCheckinInterval: 15000 # 集群检查频率,单位:毫秒。默认为 15000,即 15 秒
misfireThreshold: 60000 # misfire 阀值,单位:毫秒。
# 线程池相关配置
threadPool:
threadCount: 25 # 线程池大小。默认为 10 。
threadPriority: 5 # 线程优先级
class: org.quartz.simpl.SimpleThreadPool # 线程池类型
jdbc: # 使用 JDBC 的 JobStore 的时候,JDBC 的配置
initialize-schema: NEVER # 是否自动使用 SQL 初始化 Quartz 表结构。这里设置成 never ,我们手动创建表结构。
# 日志文件配置
logging:
file:
name: /root/logs/surveyking-server.log # 日志文件名,全路径
level:
# 配置自己写的 MyBatis Mapper 打印日志
cn.surveyking.module.infra.dal.mysql: error
cn.surveyking.module.system.dal.mysql: error
cn.surveyking.module.survey: error
EOF
Docker Compose 配置
主要的 docker-compose.yml 文件
cat > $DEPLOY_DIR/docker-compose.yml << 'EOF'
version: "3.8"
services:
# MySQL 数据库
mysql:
image: mysql:8.0
container_name: surveyking-mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
TZ: ${TZ}
ports:
- "${MYSQL_PORT}:3306"
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf
- ./mysql/init:/docker-entrypoint-initdb.d
- ./logs/mysql:/var/log/mysql
command: --default-authentication-plugin=mysql_native_password
networks:
- surveyking-network
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 20s
retries: 10
# Redis 缓存
redis:
image: redis:7-alpine
container_name: surveyking-redis
restart: unless-stopped
environment:
TZ: ${TZ}
ports:
- "${REDIS_PORT}:6379"
volumes:
- ./redis/data:/data
- ./redis/conf/redis.conf:/etc/redis/redis.conf
command: redis-server /etc/redis/redis.conf
networks:
- surveyking-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
timeout: 20s
retries: 5
# 后端应用
app:
image: openjdk:8-jdk-alpine
container_name: surveyking-app
restart: unless-stopped
environment:
JAVA_OPTS: ${JAVA_OPTS}
TZ: ${TZ}
DB_HOST: ${DB_HOST}
DB_PORT: ${DB_PORT}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
REDIS_HOST: ${REDIS_HOST}
REDIS_PORT: ${REDIS_PORT}
REDIS_PASSWORD: ${REDIS_PASSWORD}
ports:
- "${APP_PORT}:18080"
volumes:
- ./app/jar/surveyking-server.jar:/app/surveyking-server.jar
- ./app/application.yml:/app/application.yml
- ./app/files:/root/files
- ./logs:/root/logs
working_dir: /app
command: java ${JAVA_OPTS} -jar surveyking-server.jar --server.port=18080
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
networks:
- surveyking-network
healthcheck:
test:
[
"CMD",
"wget",
"--quiet",
"--tries=1",
"--spider",
"http://localhost:18080/admin-api/system/auth/get-sys-info",
]
timeout: 30s
retries: 5
start_period: 60s
# Nginx 前端
nginx:
image: nginx:alpine
container_name: surveyking-nginx
restart: unless-stopped
environment:
TZ: ${TZ}
ports:
- "${NGINX_PORT}:80"
volumes:
- ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/html:/usr/share/nginx/html
- ./logs/nginx:/var/log/nginx
depends_on:
app:
condition: service_healthy
networks:
- surveyking-network
healthcheck:
test:
[
"CMD",
"wget",
"--quiet",
"--tries=1",
"--spider",
"http://localhost/health",
]
timeout: 10s
retries: 3
networks:
surveyking-network:
driver: bridge
volumes:
mysql-data:
redis-data:
EOF