之前没搞过这个,没得经验,全凭感觉搞。设计的部署目录如下:
在config目录下是服务的配置文件,比如nginx的 nginx.conf,前端html资源等,java-app 里面是构建java镜像的Dockerfile 和jar包。所有的数据,包括日志等都挂载到的data对应的目录下。
我想的是快速部署一个项目,而且方便后续服务器的迁移。比如后续需要更换服务器直接把qt_project这个目录拷贝到其他服务器上即可。
这里直接把 qt_project 这个目录丢到服务器根目录即可,我是在虚拟机里面测试的:
然后给整个部署项目755权限
sudo chmod -R 755 /qt_project
最后执行脚本即可部署整个项目。
cd /qt_project/publish
./start_project.sh
部分代码如下
docker-compose.yml
# version: '3.8' (已过时)
# 定义网络配置
networks:
d-net: # 直接定义网络名称,无需嵌套 `name`
driver: bridge # 显式指定驱动(默认是 bridge)
# 定义所有服务
services:
# Redis 服务配置
redis:
image: redis:alpine
container_name: redis # 指定容器名称
restart: always # 容器退出时自动重启
ports:
- "6379:6379" # 暴露 Redis 默认端口(主机端口:容器端口)
volumes:
- ${DATA_DIR}/redis:/data # 挂载宿主机/data/redis到容器的/data目录(持久化数据)
- ${CONFIG_DIR}/redis/redis.conf:/usr/local/etc/redis/redis.conf # 挂载自定义配置文件
environment:
- TZ=Asia/Shanghai # 设置时区为上海
command: redis-server --appendonly yes # 启动命令,启用AOF持久化
networks:
- d-net # 直接引用网络名称
# MySQL 5.7 服务配置
mysql:
image: mysql:5.7
container_name: mysql # 指定容器名称
restart: always # 自动重启
ports:
- "3306:3306" # 暴露 MySQL 默认端口
volumes:
- ${DATA_DIR}/mysql/data:/var/lib/mysql # 数据文件
- ${DATA_DIR}/mysql/log:/var/log/mysql # 日志目录(关键挂载)
- ${CONFIG_DIR}/mysql/conf:/etc/mysql/conf.d # 挂载自定义配置文件目录
environment:
- MYSQL_ROOT_PASSWORD=root@123 # 设置root密码(请修改)
# - MYSQL_DATABASE=your_database # 初始化时创建的数据库名
# - MYSQL_USER=your_user # 创建普通用户
# - MYSQL_PASSWORD=your_password # 普通用户密码
- TZ=Asia/Shanghai # 时区设置
networks:
- d-net
# Nginx 服务配置
nginx:
image: nginx:1.21.6-alpine
container_name: nginx # 容器名称
restart: always # 自动重启
ports:
- "9999:9999"
# - "80:80" # HTTP 端口
# - "443:443" # HTTPS 端口
volumes:
- ${DATA_DIR}/nginx/log:/var/log/nginx # 挂载日志目录
- ${CONFIG_DIR}/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
- ${CONFIG_DIR}/nginx/html:/usr/share/nginx/html # 挂载网站根目录
depends_on:
- java-app # 声明依赖关系(等待java-app启动)
networks:
- d-net
# Java 应用服务配置
java-app:
build:
context: ${CONFIG_DIR}/java-app # 构建上下文的目录
dockerfile: ./Dockerfile # Dockerfile 路径
container_name: java-app # 容器名称
restart: always # 自动重启
ports:
- "8002:8002" # 暴露应用端口(假设Spring Boot默认8080)
depends_on:
- mysql # 依赖 MySQL 服务
- redis # 依赖 Redis 服务
environment:
- SPRING_PROFILES_ACTIVE=prod # 设置Spring Boot使用生产环境配置
- TZ=Asia/Shanghai # 时区设置
networks:
- d-net
# # RocketMQ NameServer 配置
# rocketmq-namesrv:
# image: apache/rocketmq:4.9.4
# container_name: rocketmq-namesrv
# restart: always
# ports:
# - "9876:9876"
# volumes:
# - ${DATA_DIR}/rocketmq/namesrv/logs:/home/rocketmq/logs
# environment:
# - JAVA_OPT_EXT=-server -Xms128m -Xmx128m -Xmn128m
# - TZ=Asia/Shanghai
# command: sh mqnamesrv
# networks:
# - d-net
# # RocketMQ Broker 配置
# rocketmq-broker:
# image: apache/rocketmq:4.9.4
# container_name: rocketmq-broker
# restart: always
# ports:
# - "10909:10909"
# - "10911:10911"
# - "10912:10912"
# volumes:
# - ${DATA_DIR}/rocketmq/broker/logs:/home/rocketmq/logs
# - ${DATA_DIR}/rocketmq/broker/store:/home/rocketmq/store
# - ${CONFIG_DIR}/rocketmq/broker.conf:/opt/rocketmq/conf/broker.conf
# environment:
# - JAVA_OPT_EXT=-server -Xms2g -Xmx2g -Xmn1g # 固定 JVM 内存
# - TZ=Asia/Shanghai
# command: sh mqbroker -c /opt/rocketmq/conf/broker.conf
# depends_on:
# - rocketmq-namesrv
# networks:
# - d-net
# 定义命名卷(虽然主要使用主机目录挂载,但保留命名卷作为备用)
# volumes:
# mysql-data:
# driver: local # 本地驱动
# redis-data:
# driver: local
# nginx-data:
# driver: local
# java-app-data:
# driver: local
.env
# 项目名称
PROJECT_NAME=qt
# 项目的数据挂载目录
DATA_DIR=../data
# 项目的配置文件目录
CONFIG_DIR=../config
start_project.sh
#!/bin/bash
# 启动项目脚本,会启动该项目所有docker服务
# 检查.env文件是否存在
if [ ! -f ".env" ]; then
echo "错误:.env文件不存在,无法读取配置。"
exit 1
fi
# 加载 .env 并删除所有 \r
source <(tr -d '\r' < .env)
# 定义变量
COMPOSE_FILE="docker-compose.yml"
SUB_DIRS=(
"redis"
"mysql/data"
"mysql/log"
"nginx/log"
"java-app"
"rocketmq/namesrv/logs"
"rocketmq/namesrv/store"
"rocketmq/broker/logs"
"rocketmq/broker/store"
)
# 检查docker-compose文件是否存在
if [ ! -f "$COMPOSE_FILE" ]; then
echo "错误:docker-compose文件 $COMPOSE_FILE 不存在,无法启动项目。"
exit 1
fi
# 创建数据目录及其子目录
create_directory() {
local dir="$1"
if [ ! -d "$dir" ]; then
echo "创建目录: $dir"
mkdir -p "$dir"
if [ $? -ne 0 ]; then
echo "错误:无法创建 $dir 目录,请检查权限。"
exit 1
fi
else
echo "目录已存在,跳过创建: $dir"
fi
}
echo "检查数据目录结构..."
create_directory "$DATA_DIR"
for sub_dir in "${SUB_DIRS[@]}"; do
full_sub_dir="$DATA_DIR/$sub_dir"
create_directory "$full_sub_dir"
done
echo "数据目录结构检查完成。"
# 停止并移除旧的容器、网络等
DOWN_OUTPUT=$(docker compose -f $COMPOSE_FILE -p $PROJECT_NAME down 2>&1)
DOWN_STATUS=$?
if [ $DOWN_STATUS -ne 0 ]; then
echo "错误:停止并移除旧服务失败。详细信息如下:"
echo "$DOWN_OUTPUT"
exit 1
fi
# 1. 先构建服务(前台显示构建日志)
echo "正在构建服务..."
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME build
BUILD_STATUS=$?
if [ $BUILD_STATUS -ne 0 ]; then
echo "错误:构建失败!"
exit 1
fi
# 2. 后台启动服务(不显示持续日志)
echo "启动服务到后台..."
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME up -d
echo "启动成功!"
遇到的几个错误和解决办法
问题1:当执行 start_project.sh 脚本的时候发现在shell脚本里面老是报目录找不到
目录是配置在 .env 文件里面的,这样 docker-compose.yml 可以直接读取。这让我很抓狂,目录其实就在旁边,就是报目录找不到。。。。.env 里面配置的也是shell脚本的开始执行的路径,不存在什么相对路径错误的问题。
然后我发现当我重新在服务器上修改了.env文件后可以运行了,但是给我创建了两个data目录。
最后定位到问题原因:shell脚本读取的时候把换行符也读了,后面带上了 \r所以导致找不到目录。比如本来是/data 目录读出来就变成了/data\r。
问题2:当执行 start_project.sh 脚本的时候控制台报version警告
WARN[0000] /project/projectConfig/publish/docker-compose.yml: `version` is obsolete
解决办法:version 是旧版 docker compose 需要的声明,现在不需要了,去掉 docker-compose.yml 顶部的 version 字段即可。
问题3:docker-compose 没有显示里面每个服务的构建过程
表现为卡了半天,我都以为哪里没弄好报错了,结果只是没有显示日志。
最后发现因为我在shell脚本里面把构建命令拿来做了判断,最后去掉这个判断直接用原始的这个命令执行就行了,这个错误完全是自找的。。。
直接用下面这个就行了,不要做多余的操作。
# 1. 先构建服务(前台显示构建日志)
echo "正在构建服务..."
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME build
BUILD_STATUS=$?
if [ $BUILD_STATUS -ne 0 ]; then
echo "错误:构建失败!"
exit 1
fi
# 2. 后台启动服务(不显示持续日志)
echo "启动服务到后台..."
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME up -d
echo "启动成功!"
问题4:nginx 页面地址未访问成功
这个就是单纯的配置出问题了,参考我之前的docker 同时部署两个前端项目就行了,我用的这个镜像:nginx:1.21.6-alpine。
我是直接拿的之前的配置,但是之前的里面是同时部署的两个前端服务,然后我这边的目录 qt_project/config/nginx/html 里面是直接放的前端dist资源,这个改下nginx.conf 配置就好了
# 指定前端项目所在位置
location / {
root /usr/share/nginx/html/lzkj/;
index index.html index.htm;
}
改为
# 指定前端项目所在位置
location / {
root /usr/share/nginx/html/;
index index.html index.htm;
}