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 80CMD ["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模式),刷新頁面不404location / {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-stoppednetworks:- sa-admin-networkdepends_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 ]; thenecho -e "${RED}清理舊容器和鏡像失敗!${NC}"exit 1
fi# 重新構建鏡像并啟動容器
echo -e "${GREEN}正在構建新鏡像并啟動容器...${NC}"
docker-compose up --build -d# 檢查部署是否成功
if [ $? -eq 0 ]; thenecho -e "${GREEN}部署成功!${NC}"echo -e "${GREEN}正在運行的容器:${NC}"docker ps --filter "name=sa-admin"
elseecho -e "${RED}部署失敗!${NC}"exit 1
fi
腳本執行順序說明:
- 刪除舊的鏡像、容器
- 構建新鏡像
- 創建容器并啟動
給腳本添加可執行權限:chmod +x deploy.sh
5. 一鍵部署
進入deploy.sh
文件目錄下,執行命令:./deploy.sh