docker-compose一键部署Springboot+Vue前后端分离项目

1. 背景说明

  • 后端使用JDK8,前端为普通Vue项目
  • 前端访问后端接口,统一带了前缀/api

2. 项目配置

2.1 后端

yml文件里配置统一访问前缀/api
在这里插入图片描述

2.2 前端

API路径配置为相对路径:

在这里插入图片描述
说明:我这边前后端应用都是部署在同一台服务器上,所以用相对路径更灵活省事,因为在相对路径配置下,接口请求会基于当前前端页面的域名和端口拼接基础地址。

如果前后端应用需要分开部署在不同的服务器上,配置绝对路径就好了,如下:
在这里插入图片描述

3. 打包

前后端分别打包好,将后端的jar包前端的dist目录上传到服务器,我这边的目录结构如下,一个项目的前后端都放在一个文件夹下,用apiweb目录区分

└── 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

回到apiweb的根目录下(项目目录/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端口,但后端服务通常运行在另一个容器或宿主机上,因此会出现 “连接拒绝”。

解决方案

要解决这个问题,就需要将前后端容器处于同一网络下。分为两步:

  1. 创建自定义网络(上面前端nginx配置文件中的sa-admin-api),将前端、后端容器加入同一网络
  2. 修正 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

脚本执行顺序说明:

  1. 删除旧的镜像、容器
  2. 构建新镜像
  3. 创建容器并启动

给脚本添加可执行权限:chmod +x deploy.sh

5. 一键部署

进入deploy.sh文件目录下,执行命令:./deploy.sh

6. 执行效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/91798.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/91798.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity_数据持久化_XML基础

Unity数据持久化 三、XML数据持久化 3.1 XML基础概念 3.1.1 什么是XML XML(eXtensible Markup Language)**是一种可扩展的标记语言,用于存储和传输数据。它具有以下特点: 结构化:数据以层次结构组织可读性:…

大语言模型的解码策略:贪婪解码与波束搜索

在自然语言生成任务(如机器翻译、文本摘要、图像描述等)中,语言模型通常会输出一个词的概率分布,但模型本身并不会自动告诉你应该选哪些词作为最终的输出句子。因此,我们需要设计一个“解码策略”来从这些概率中生成可…

智慧园区:中小企业的 “减压阀” 与数字化招商革命

在当前的经济环境下,中小企业的生存发展面临着诸多挑战,其中选址成本俨然成为了创业路上的 “第一道坎”。传统招商模式中,信息不对称的问题尤为突出,初创企业常常因此陷入选址失误的困境。有的企业选在交通不便的地方&#xff0c…

从零开始配置pytorch环境

总结了一下几篇热门文章和自己的经验,方便以后换设备配置环境 一、安装Anaconda 这一步是为了不污染全局环境,很有必要。 直接清华源镜像下载:Index of /anaconda/archive/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 根据自…

离线录像文件视频AI分析解决方案

前言 在安防领域,视频的价值不言而喻,尤其是录像文件的价值显得更是尤为重要。在一个安防项目上视频录像一般存储1个月、3个月甚至更长时间,这就形成了海量的离线录像文件数据。传统安防项目对录像文件的处理还有一定的局限性: 事…

人工智能与金融:金融服务的重塑

1. AI 驱动金融变革:从 “标准化” 到 “智能化”1.1 传统金融的痛点与 AI 的破局传统金融行业长期面临三大瓶颈:服务效率低下:银行柜台办理一笔贷款需 3-5 个工作日,人工审核流程繁琐,客户等待时间长;风险…

Qwen大模型关键参数解析:缓存与滑动窗口

QwenLLM "use_cache": true Qwen "use_sliding_window": false 在大语言模型(如Qwen系列)的生成配置中,"use_cache": true 和 "use_sliding_window": false 是两个与模型推理效率和长文本处理相关的重要参数,具体含义如下: 1. …

Flask 框架全面详解

Flask 是一个轻量级的 Python Web 框架,以其简洁、灵活和易扩展的特性广受欢迎。接下来我将从多个维度详细介绍 Flask 框架。 1. Flask 核心特性 微框架设计 轻量级:核心功能精简,只包含基本组件可扩展:通过扩展添加所需功能无…

概率 多维随机变量与分布

一、二维1、二维随机变量及其分布假设E是随机试验,Ω是样本空间,X、Y是Ω的两个变量;(X,Y)就叫做二维随机变量或二维随机向量。X、Y来自同一个样本空间。联合分布函数 F(x,y)P(X≤x,Y≤y),即F(x,y)表示求(x,y)左下方的面积。 F(x,…

Spring AI MCP:解锁大模型应用开发新姿势

一、AI 浪潮下的新利器 ——Spring AI MCP 登场在当今数字化时代,人工智能(AI)无疑是最耀眼的技术明星,正以前所未有的速度渗透到各个领域,深刻改变着我们的生活和工作方式。从智能语音助手到图像识别技术,…

ThinkPHP5x,struts2等框架靶场复现

ThinkphpThinkphp5x远程命令执行及getshell首先我们先找一个环境,或者自己搭建一个环境fofa:body"ThinkPHP V5"搭建:vulhub/thinkphp/5-rcedocker-compose up -d然后去访问我们的环境远程命令执行/?sindex/think\app/invokefuncti…

Hyperliquid:揭秘高性能区块链共识引擎HyperBFT

大家好,今天我们一起探讨Hyperliquid这个高性能区块链项目以及它背后的共识引擎。Hyperliquid能在拥挤的去中心化交易赛道(DEX)中脱颖而出,很大程度上要归功于其高效的共识机制——HyperBFT。 为了彻底搞懂HyperBFT,我…

大模型开发框架LangChain之构建知识库

1.前言 为了避免 llm正确的废话和幻觉,知识库可以说是现在开发 agent的必备了。同时,作为 rag中的 r,知识库召回的成功率会极大的影响 llm的最终回复效果。一般,会把知识库召回的内容作为背景知识给到 llm,并在 prompt…

NPM打包时,报reason: getaddrinfo ENOTFOUND registry.nlark.com

先说解决方法:将 package-lock.json 文件中的 registry.nlark.com 改为 registry.npmmirror.com现象:npm ERR! code ENOTFOUND npm ERR! syscall getaddrinfo npm ERR! errno ENOTFOUND npm ERR! network request to https://registry.nlark.com/url-too…

python内置库os与sys的区别是什么?分别能实现什么功能?

Python 的 os 和 sys 是两个功能截然不同但都非常重要的内置库,它们分别服务于不同的交互场景:前者专注于与操作系统交互,后者专注于与 Python 解释器本身交互。以下是详细解析: 一、os 库:操作系统交互接口 os 库&…

【云计算】云主机的亲和性策略(一):快乐旅行团

《云主机的亲和性策略》系列,共包含以下文章: 1️⃣ 云主机的亲和性策略(一):快乐旅行团2️⃣ 云主机的亲和性策略(二):集群节点组3️⃣ 云主机的亲和性策略(三&#xf…

USRP捕获手机/路由器数据传输信号波形(下)

目录: USRP捕获手机/路由器数据传输信号波形(上) USRP捕获手机/路由器数据传输信号波形(中) USRP捕获手机/路由器数据传输信号波形(下) 四、路由器MIMO-OFDM系统 本文深入分析采集手机与路由…

位运算在权限授权中的应用及Vue3实践

在现代前端应用中,权限管理是一个至关重要的功能模块。随着应用复杂度的提示功能,权限细粒度越来越精细,如何高效地管理和判断权限成为前端开发的一大挑战。位运算作为一种高效的运算方式,在权限管理领域有着独特的优势。本文将详…

面试实战,问题二十二,Java JDK 17 有哪些新特性,怎么回答

Java JDK 17 新特性面试回答指南 作为一名Java开发者,了解JDK 17的新特性是面试中的关键点。JDK 17(Java SE 17)于2021年9月发布,是一个长期支持(LTS)版本,引入了多项改进以提升开发效率、安全性…

【MySQL安全】什么是SQL注入,怎么避免这种攻击:前端防护、后端orm框架、数据库白名单

基本概念SQL注入是OWASP Top 10安全风险之一,它利用了应用程序对用户输入数据的不当处理。当应用程序直接将用户输入拼接到SQL查询中而没有进行适当的过滤或转义时,就可能发生SQL注入攻击。攻击原理假设有一个登录表单的SQL查询:SELECT * FRO…