1. 背景说明
- 后端使用JDK8,前端为普通Vue项目
- 前端访问后端接口,统一带了前缀
/api
2. 项目配置
2.1 后端
yml文件里配置统一访问前缀/api
2.2 前端
API路径配置为相对路径:
说明:我这边前后端应用都是部署在同一台服务器上,所以用相对路径
更灵活省事,因为在相对路径配置下,接口请求会基于当前前端页面的域名和端口拼接基础地址。
如果前后端应用需要分开部署在不同的服务器上,配置绝对路径
就好了,如下:
3. 打包
前后端分别打包好,将后端的jar包
和前端的dist
目录上传到服务器,我这边的目录结构如下,一个项目的前后端都放在一个文件夹下,用api
和web
目录区分
└── sa-admin
├── api
│ ├── Dockerfile
│ └── sa-admin-prod-3.0.0.jar
└── web
│ ├── dist
│ ├── Dockerfile
│ ├── nginx.conf
├── deploy.sh
├── docker-compose.yml
4 编写 Dockerfile 与 docker-compose.yml
在后端jar包
和前端dist
的目录下分别创建一个Dockerfile
文件
4.1 后端的Dockerfile
# 使用 OpenJDK 8 作为基础镜像
FROM openjdk:8-jdk
# VOLUME 指定了临时文件目录为/tmp。
# 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp
VOLUME /tmp
#设置时区
RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone
# 复制jar包到容器内(注意jar包名称与实际一致)
COPY sa-admin-prod-3.0.0.jar app.jar
# 暴露后端服务端口(根据实际项目端口修改)
EXPOSE 9090
# 容器启动时执行的命令
ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-jar","/app.jar"]
4.2 前端的Dockerfile
FROM nginx
# 删除nginx默认配置、默认静态文件
RUN rm -rf /usr/share/nginx/html/*
# 删除禁用nginx默认配置(为避免冲突,使自定义的sa-admin-web-nginx.conf生效)
RUN mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak
# 复制自定义的配置文件
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 复制前端dist目录到nginx静态文件目录
COPY dist/ /usr/share/nginx/html/
# 暴露80端口(nginx默认端口)
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
4.3 前端的nginx配置文件
server {
listen 80;
server_name localhost; # 可替换为实际域名
# 前端静态文件目录(对应Dockerfile中复制的dist目录)
root /usr/share/nginx/html;
index index.html index.htm;
# 支持前端路由(history模式),刷新页面不404
location / {
try_files $uri $uri/ /index.html;
}
# 反向代理到后端服务(核心配置)
# 假设前端请求后端的API路径以 /api 开头(需与前端代码一致)
location /api/ {
# 后端容器名+端口(docker内部可直接用服务名访问,无需映射到宿主机)
proxy_pass http://sa-admin-api:9090/api/; # 注意结尾的斜杠与后端一致
# 代理相关的头信息(解决跨域和后端获取真实IP等问题)
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;
}
# 跨域配置(如果需要更宽松的跨域规则)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Origin, Content-Type, Authorization';
}
这一行配置:proxy_pass http://sa-admin-api:9090/api/;
为什么地址写的是sa-admin-api
,看下面的配置说明
(关键)
4.4 docker-compose.yml
回到api
和web
的根目录下(项目目录/sa-admin),创建docker-compose.yml
文件:
version: '3.8' # 兼容主流Docker版本
services:
# 后端服务
sa-admin-api:
build:
context: ./api # 后端Dockerfile所在目录
image: sa-admin-api # 镜像名
container_name: sa-admin-api # 容器名
ports:
- "9090:9090" # 宿主机端口:容器端口(根据后端实际端口调整)
restart: unless-stopped # 异常退出时自动重启
environment:
- SPRING_PROFILES_ACTIVE=prod # 指定环境配置
networks:
- sa-admin-network # 加入自定义网络(前后端可通过服务名通信)
volumes:
- /docker/sa-admin/log:/home/smart-admin # 使用命名卷
# 前端服务
sa-admin-web:
build:
context: ./web # 前端Dockerfile所在目录
image: sa-admin-web # 镜像名
container_name: sa-admin-web # 容器名
ports:
- "9091:80" # 宿主机80端口映射到容器80(可自定义宿主机端口)
restart: unless-stopped
networks:
- sa-admin-network
depends_on:
- sa-admin-api # 确保后端先启动
volumes:
- ./web/dist/:/usr/share/nginx/html/
# 自定义网络(避免端口冲突,支持服务名访问)
networks:
sa-admin-network:
driver: bridge
4.4.1 配置说明:
networks: 创建docker网络
网络连接不通的问题
在docker中,容器的网络不等于宿主机的网络。
比如:按正常思维,前后端部署在一台机器上,前端访问后端地址配置为http://localhost:9090
是肯定可以访问到的,但在docker中不行。
因为docker容器内的localhost不等于宿主机的localhost
,Docker 容器有独立的网络命名空间,容器内部的localhost(127.0.0.1)
仅指向容器自身,而非宿主机或其他容器。
若前端 Nginx 配置中用localhost:后端端口
代理后端服务(例如proxy_pass http://localhost:9090
),Nginx 会尝试访问当前前端容器内部的 9090端口,但后端服务通常运行在另一个容器或宿主机上,因此会出现 “连接拒绝”。
解决方案
要解决这个问题,就需要将前后端容器处于同一网络下。分为两步:
- 创建自定义网络
(上面前端nginx配置文件中的sa-admin-api)
,将前端、后端容器加入同一网络 - 修正 Nginx 代理配置,用后端容器名作为代理目标(同一网络内可直接访问):
http://sa-admin-api:9090/api/
,http后面直接接上后端的容器名
4.5 一键部署脚本
在docker-compose.yml同目录下
创建deploy.sh
文件:
#!/bin/bash
# 定义颜色变量,用于美化输出
GREEN="\033[0;32m"
RED="\033[0;31m"
NC="\033[0m" # 无颜色
echo -e "${GREEN}开始部署sa-admin项目...${NC}"
# 停止并删除所有相关容器、网络,同时删除关联镜像
echo -e "${GREEN}正在停止并清理旧容器和镜像...${NC}"
docker-compose down --rmi all
# 检查上一条命令是否执行成功
if [ $? -ne 0 ]; then
echo -e "${RED}清理旧容器和镜像失败!${NC}"
exit 1
fi
# 重新构建镜像并启动容器
echo -e "${GREEN}正在构建新镜像并启动容器...${NC}"
docker-compose up --build -d
# 检查部署是否成功
if [ $? -eq 0 ]; then
echo -e "${GREEN}部署成功!${NC}"
echo -e "${GREEN}正在运行的容器:${NC}"
docker ps --filter "name=sa-admin"
else
echo -e "${RED}部署失败!${NC}"
exit 1
fi
脚本执行顺序说明:
- 删除旧的镜像、容器
- 构建新镜像
- 创建新容器并启动
给脚本添加可执行权限:chmod +x deploy.sh
5. 一键部署
进入deploy.sh
文件目录下,执行命令:./deploy.sh