Docker 部署博客全流程与常见问题总结
最近把博客部署到了腾讯云服务器(OpenCloudOS),用的是 Docker + Docker Compose 一键部署。过程中踩了不少坑,记录一下部署流程和遇到的问题,方便以后自己回顾,也希望能帮到其他打算部署的开发者。
一、部署架构
部署后服务器上会运行 4 个容器:
-
Nginx:对外提供博客前台、后台管理、API 反向代理
-
Spring Boot:后端 API 服务
-
MySQL:数据库
-
Redis:缓存
用户 → Nginx(80) → 博客前台 / 后台 /admin
→ API /api/ → Spring Boot(8000)
→ MySQL(3306) + Redis(6379)
二、部署流程概览
1. 准备工作
- 云服务器(OpenCloudOS / CentOS 等)
- 安全组开放 80 端口(必做,否则外网访问不了)
- 项目代码已推送到 GitHub
2. 部署步骤
bash
# 1. SSH 连接服务器
ssh root@你的IP
# 2. 克隆项目
cd /opt && git clone https://github.com/你的用户名/仓库名.git aricOnline
# 3. 进入 deploy 目录
cd /opt/aricOnline/deploy
# 4. 配置环境变量
cp .env.example .env
vim .env # 修改 MYSQL_PASSWORD、REDIS_PASSWORD、BLOG_URL
# 5. 一键部署
chmod +x deploy.sh
./deploy.sh
首次部署大约 15--30 分钟,主要是拉镜像和构建。
3. 部署后访问
- 博客前台:
http://你的IP/ - 后台管理:
http://你的IP/admin/(注意末尾斜杠)
三、前端部署问题与解决
问题 1:后台管理 JS 加载失败,返回 HTML
现象 :打开 /admin 页面报错:
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html"
原因 :后台管理(shoka-admin)的 Vite 构建时没配置 base,默认是 /,所以构建出的 HTML 里引用的是 /assets/xxx.js。但实际后台在 /admin/ 下,浏览器请求 /assets/xxx.js 时,Nginx 找不到文件,返回了 index.html(前端 SPA 的 fallback),于是 JS 被当成 HTML 请求,MIME 类型错误。
解决 :在 blog-vue/shoka-admin/vite.config.ts 中添加:
ts
export default defineConfig({
base: '/admin/',
plugins: [
// ...
],
});
重新构建后,资源路径会变成 /admin/assets/xxx.js,Nginx 能正确匹配。
问题 2:Nginx 的 /admin 路径配置
现象 :用 alias 时,try_files 和路径处理容易出错。
解决 :在 deploy/nginx.conf 中:
nginx
location /admin/ {
alias /usr/share/nginx/admin/;
index index.html;
try_files $uri $uri/ /admin/index.html;
}
location = /admin {
return 301 /admin/;
}
要点:/admin 重定向到 /admin/,location 用 /admin/ 带尾斜杠。
问题 3:表情包无法加载
现象:评论、说说、消息等页面的表情包不显示,以前本地开发正常。
原因 :表情包在 blog-vue/shoka-admin/static/img/emot/image/ 下,路径是 /static/img/emot/image/xxx.gif。Docker 构建时只复制了 dist,没有复制 static,Nginx 也缺少 /static/ 的配置。
解决:
- 在
deploy/Dockerfile.nginx中复制 static:
dockerfile
# 拷贝静态资源(表情包等)
COPY --from=admin-builder /build/admin/static /usr/share/nginx/static
- 在
deploy/nginx.conf中增加:
nginx
location /static/ {
alias /usr/share/nginx/static/;
expires 30d;
access_log off;
}
问题 4:RightToolbar 组件找不到
现象:admin 构建报错:
Could not load /build/admin/src/components/RightToolbar/index.vue: ENOENT
原因 :实际目录是 RightToolBar(大写 B),导入写成了 RightToolbar(小写 b)。Windows 不区分大小写没问题,Docker 里是 Linux,会报错。
解决 :在 blog-vue/shoka-admin/src/main.ts 中修正导入:
ts
// 错误
import RightToolbar from "@/components/RightToolbar/index.vue";
// 正确
import RightToolbar from "@/components/RightToolBar/index.vue";
四、后端部署问题与解决
问题 1:openjdk:11-jre-slim 镜像拉取 403
现象:构建后端镜像时报错:
failed to resolve source metadata for docker.io/library/openjdk:11-jre-slim: 403 Forbidden
原因 :openjdk 官方镜像已废弃,部分镜像源不再提供或返回 403。
解决 :改用 Eclipse Temurin。在 deploy/Dockerfile 中:
dockerfile
# 原来
FROM openjdk:11-jre-slim
# 修改为
FROM eclipse-temurin:11-jre
问题 2:Docker 健康检查端口错误
现象:后端容器不断重启,健康检查失败。
原因:Dockerfile 里健康检查用的是 8080,但应用实际监听 8000。
解决 :在 deploy/Dockerfile 中:
dockerfile
HEALTHCHECK --interval=30s --timeout=10s --retries=5 --start-period=60s \
CMD curl -f http://localhost:8000/ || exit 1
EXPOSE 8000
并确保运行阶段安装了 curl(openjdk:11-jre-slim 等镜像默认没有)。
问题 3:MySQL / Redis 连接失败
现象:后端启动报错,无法连接 MySQL 或 Redis。
原因 :docker-compose.yml 中 .env 的 MYSQL_PORT=4000、REDIS_PORT=5000 是宿主机映射端口,不是容器内部端口。容器间通信需用 MySQL 3306、Redis 6379。
解决 :在 docker-compose.yml 的 blog-server 环境变量中覆盖:
yaml
environment:
MYSQL_HOST: mysql
MYSQL_PORT: 3306
REDIS_HOST: redis
REDIS_PORT: 6379
SERVER_PORT: 8000
SPRING_PROFILE: dev
问题 4:blog.sql 路径错误
现象:MySQL 启动后没有数据表。
原因 :docker-compose.yml 中写的是 ../blog.sql,实际应在 deploy/ 下,应为 ./blog.sql。
解决:
yaml
volumes:
- ./blog.sql:/docker-entrypoint-initdb.d/init.sql:ro
五、Docker 环境问题与解决
问题 1:docker-compose 命令不存在
现象 :docker-compose: command not found
原因:服务器未安装 Docker Compose。
解决:使用 Docker Compose 插件,通过 dnf 安装(不依赖 curl 下载):
bash
dnf install -y docker-compose-plugin
脚本中改用 docker compose(带空格),不再用 docker-compose。
问题 2:dnf makecache fast 报错
现象 :dnf makecache: error: argument timer: invalid choice: 'fast'
原因 :OpenCloudOS 的 dnf 不支持 fast 参数。
解决 :将 dnf makecache fast 改为 dnf makecache。
问题 3:Docker 镜像拉取超时
现象:拉取 mysql、redis、nginx 等镜像超时或失败。
解决 :配置镜像加速,编辑 /etc/docker/daemon.json:
json
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com"
]
}
执行 systemctl daemon-reload && systemctl restart docker 后重试。
六、部署时需要注意的事项
- 安全组:云服务器安全组必须开放 80 端口,否则外网无法访问。
- base 路径 :后台管理部署在子路径时,Vite 必须配置
base: '/admin/'。 - 静态资源 :
static/等非构建产物要单独复制到 Nginx 容器。 - 大小写:Linux 区分大小写,组件路径、文件名要和导入一致。
- 容器端口 :宿主机端口和容器内部端口不同,
.env中的端口用于宿主机映射,容器间通信用服务默认端口。 - 首次启动 :MySQL 初始化需要时间,后端要等 MySQL 健康后再启动,脚本中已用
depends_on和condition: service_healthy处理。
七、常用运维命令
bash
# 查看容器状态
docker compose ps
# 查看日志
docker compose logs -f
docker compose logs -f blog-server
# 重启
docker compose restart
docker compose restart nginx
# 停止
docker compose down
# 更新代码后重新部署
cd /opt/aricOnline && git pull && cd deploy && docker compose up -d --build
八、总结
部署过程中主要遇到的问题可以归纳为:
- 前端:base 路径、Nginx 配置、静态资源复制、文件名大小写
- 后端:基础镜像选择、健康检查端口、MySQL/Redis 连接参数
- Docker:Compose 安装、dnf 参数、镜像加速
把这些问题记录下来,下次部署或迁移时会更顺畅。详细步骤可参考 deploy/README.md。