Docker上部署前后端分离项目

Docker上部署前后端分离项目 目录一、Docker上部署后端spring boot项目前提准备1.1 核心文件Dockerfile 编写标准版 Dockerfile适配 Spring Boot 2.x/3.x最常用1.2 完整部署步骤终端操作步骤 1进入文件目录步骤 2构建 Docker 镜像参数说明构建成功验证步骤 3启动 Docker 容器核心参数详解必看按需调整启动成功验证二、Docker上部署前端项目1、开发环境前提准备Windows 必做方案 1Dockerfile Docker Compose推荐适合开发 / 部署步骤 1在前端项目根目录创建 3 个文件1. .dockerignore忽略不必要文件减少镜像体积避免冲突注意文件名以 . 开头2. Dockerfile核心定义 Node 镜像、项目构建 / 运行步骤3. docker-compose.yml简化启动命令配置热更新、端口映射比直接 docker run 更易用步骤 2构建并启动容器步骤 3访问项目方案 2直接 docker run快捷方案适合临时测试步骤 1拉取指定新版本的 Node 镜像步骤 2进入项目根目录用 Docker 启动新项目命令参数解释关键必须理解特殊说明Windows 路径问题步骤 3安装项目依赖关键步骤 4停止容器2、正式环境1、部署思路2、完整部署步骤1. 准备工作2. 编写 Dockerfile3. 可选自定义 Nginx 配置4. 构建并运行 Docker 镜像1构建镜像2运行容器5. 验证部署注意nginx.conf修改了需要重新构建并运行 Docker 镜像一、原因解释二、完整的更新步骤修改 nginx.conf 后三、接口代理连接拒绝错误ECONNREFUSED场景 1后端跑在 Windows 本地或同一个docker容器中最常用优先看这个问题根源解决方案两步走缺一不可步骤 1修改 Vite或vue 代理的target地址替换 Windows 本地的容器可访问地址步骤 2确保 Docker 启动命令的端口映射 网络参数正确无需额外改之前的命令已满足场景 2后端也跑在另一个 Docker 容器中前后端都容器化未试用问题根源解决方案三步走标准化容器网络步骤 1创建 Docker 自定义网络让前后端容器互通步骤 2修改后端容器的启动命令加入同一个自定义网络步骤 3修改 Vite 代理 前端 Docker 配置加入同一网络用容器名访问额外避坑Vite 热更新失效Docker 中常见提前解决快速验证测试代理是否连通一、Docker上部署后端spring boot项目前提准备Spring Boot 项目已打包为可执行 JAR 包mvn clean package -DskipTests打包JAR 包在target目录下 :使用指定版本的jdk打包jar包$env:JAVA_HOME C:\Program Files\Java\jdk-17; $env:PATH $env:JAVA_HOME\bin;$env:PATH; mvn clean package部署机器已安装Docker将打包好的 JAR 包和后续写的 Dockerfile 放在同一目录下方便构建镜像。1.1 核心文件Dockerfile 编写推荐使用多阶段构建的 Dockerfile生产环境首选优点是最终镜像体积极小仅包含 JRE剔除 Maven、JDK 等构建依赖同时避免手动安装 JDK/JRE步骤如下标准版 Dockerfile适配 Spring Boot 2.x/3.x最常用在 JAR 包同级目录新建文件文件名必须是Dockerfile无后缀内容如下dockerfile# 第一阶段构建阶段使用Maven镜像打包若已本地打JAR包可跳过此阶段直接用第二阶段 # FROM maven:3.8.8-openjdk-17 AS build # WORKDIR /app # COPY pom.xml . # COPY src ./src # # 打包跳过测试 # RUN mvn clean package -DskipTests # 第二阶段运行阶段核心使用轻量的OpenJDK JRE镜像体积小 FROM openjdk:17-jre-slim # 设定容器内的工作目录 WORKDIR /app # 复制本地的Spring Boot JAR包到容器内注意替换为你的实际JAR包名称如demo-0.0.1-SNAPSHOT.jar # 若用了第一阶段构建替换为 COPY --frombuild /app/target/你的JAR包名称.jar app.jar COPY your-project-0.0.1-SNAPSHOT.jar app.jar # 暴露Spring Boot项目的端口替换为你的项目实际端口如8080、9090 EXPOSE 8080 # 容器启动时执行的命令运行JAR包添加JVM参数优化可选 ENTRYPOINT [java, -jar, -Xmx512m, -Xms256m, app.jar]镜像选择openjdk:17-jre-slim是轻量级 JRE 镜像比完整 JDK 镜像小 80% 以上适合生产环境Spring Boot 3.x 要求 JDK172.x 可改用openjdk:8-jre-slim(eclipse-temurin:17-jre-alpineOpenJDK 官方替代标签稳定)JAR 包重命名将你的实际 JAR 包复制为app.jar简化启动命令必须替换为自己的 JAR 包名称端口暴露EXPOSE仅声明容器要使用的端口实际启动时需要映射到宿主机JVM 参数-Xmx512m最大堆内存、-Xms256m初始堆内存可根据服务器配置调整避免内存溢出。1.2 完整部署步骤终端操作假设你的文件目录结构如下务必保证路径正确/your-project/ ├── target/ │ └── demo-0.0.1-SNAPSHOT.jar # 打包好的JAR包 └── Dockerfile # 编写的Dockerfile步骤 1进入文件目录终端切换到Dockerfile 和 JAR 包所在的目录核心否则构建会找不到文件cd /your-project/target # 示例若JAR包在targetDockerfile也放在这里步骤 2构建 Docker 镜像使用docker build命令构建镜像命令格式docker build -t springboot-demo:v1 .参数说明-t springboot-demo:v1为镜像打标签springboot-demo是镜像名v1是版本号可自定义如my-app:latest最后的.表示构建上下文为当前目录Docker 会从当前目录读取 Dockerfile 和 JAR 包。构建成功验证执行docker images能看到刚构建的镜像如springboot-demo说明构建成功。步骤 3启动 Docker 容器使用docker run命令基于镜像启动容器核心是端口映射和后台运行命令格式docker run -d --name sb-demo -p 8080:8080 -v /data/logs:/app/logs springboot-demo:v1核心参数详解必看按需调整参数作用-d后台运行容器守护进程模式生产环境必加--name sb-demo给容器命名自定义如my-springboot方便管理-p 8080:8080端口映射宿主机端口:容器内端口前者是服务器对外的端口后者是 Dockerfile 中EXPOSE的端口-v /data/logs:/app/logs数据卷挂载可选但推荐将容器内的日志目录映射到宿主机/data/logs避免容器删除后日志丢失springboot-demo:v1要启动的镜像名版本号和构建时的标签一致启动成功验证执行docker ps能看到STATUS为Up的容器如sb-demo说明启动成功访问项目在浏览器 / Postman 中输入http://服务器IP:宿主机端口/接口路径如http://192.168.1.100:8080/hello能正常返回结果即部署成功。二、Docker上部署前端项目1、开发环境windows上已经装了node,然后想在docker上装新版本的node然后新项目使用新的node启动Docker 的核心优势就是环境隔离能完美解决多 Node 版本的运行问题。下面分步可落地的方案从 Docker 基础准备到项目容器化启动包含通用 Dockerfile 方案适合自定义配置和直接 docker run 快捷方案适合快速启动新手也能直接套用。前提准备Windows 必做安装并启动 Docker Desktop下载地址https://www.docker.com/products/docker-desktop/安装后双击桌面图标启动右下角出现 Docker 鲸鱼图标蓝色 正常运行必须开启 WSL2 后端安装时会自动提示按步骤开启即可否则 Windows Docker 性能差。验证 Docker 环境打开 PowerShell/CMD执行以下命令出现版本号即正常docker -v docker compose -v # 新版Docker已内置compose确保项目目录无中文 / 特殊字符方案 1Dockerfile Docker Compose推荐适合开发 / 部署这是前端项目容器化的标准做法支持热更新开发时修改代码容器内实时生效、端口映射、依赖缓存后续部署也能直接复用配置步骤如下步骤 1在前端项目根目录创建 3 个文件进入项目目录新建以下文件和 package.json 同级1..dockerignore忽略不必要文件减少镜像体积避免冲突注意文件名以 . 开头# 忽略本地依赖包容器内会重新安装 node_modules # 忽略npm锁文件可选防止版本冲突 package-lock.json yarn.lock # 忽略日志/缓存文件 npm-debug.log yarn-debug.log yarn-error.log .DS_Store # 忽略本地环境配置 .env.local .env.development.local .env.test.local .env.production.local # 忽略构建产物 dist2.Dockerfile核心定义 Node 镜像、项目构建 / 运行步骤选择高版本 Node LTS 版当前最新是 20.xVite 完美支持基于node:alpine轻量镜像体积仅几十 M适配 Vite 开发环境# 基础镜像高版本Node LTS alpine轻量Linux FROM node:20-alpine # 设置工作目录容器内的项目目录固定路径即可 WORKDIR /app # 复制package.json和package-lock.json先复制锁文件利用Docker缓存避免每次改代码都重装依赖 COPY package*.json ./ # 安装项目依赖Alpine镜像需加--registry换国内源否则安装慢 RUN npm install --registryhttps://registry.npmmirror.com # 复制项目所有文件到容器工作目录 COPY . . # 暴露Vite默认开发端口必须和vite.config.js的port一致默认3000 EXPOSE 3000 # 启动命令和本地npm run dev一致 CMD [npm, run, dev]关键说明node:20-alpine内置了 npm/yarn无需额外安装且已支持所有 ES2021 新语法包括彻底解决本地版本低的问题。3.docker-compose.yml简化启动命令配置热更新、端口映射比直接 docker run 更易用version: 3.8 # Docker Compose版本和Docker Desktop兼容即可 services: app-frontend: # 服务名自定义即可 build: . # 基于当前目录的Dockerfile构建镜像 container_name: app-ai-front # 容器名自定义 ports: - 3000:3000 # 端口映射本地3000端口 → 容器3000端口本地访问http://localhost:3000 volumes: - .:/app # 目录挂载本地项目目录 → 容器工作目录实现热更新本地改代码容器实时同步 - /app/node_modules # 匿名挂载保留容器内的node_modules避免本地node_modules旧版本覆盖容器内的高版本依赖 environment: - NODE_ENVdevelopment # 开发环境 - VITE_DEV_SERVER_HOST0.0.0.0 # 关键Vite监听0.0.0.0否则容器内服务无法被本地访问 stdin_open: true # 保持容器前台运行 tty: true核心亮点volumes的两行配置实现热更新 依赖隔离既保证本地代码修改实时同步到容器又避免本地旧 Node 的 node_modules 干扰容器内的高版本依赖。步骤 2构建并启动容器在前端项目根目录打开 PowerShell执行以下命令# 构建镜像首次执行会下载Node基础镜像稍等片刻 docker compose build # 启动容器-d表示后台运行不加则前台打印日志 docker compose up -d常用辅助命令# 查看容器运行状态是否up docker compose ps # 查看容器日志排查启动失败问题 docker compose logs -f # 停止容器 docker compose down # 停止并删除镜像/容器/数据卷彻底重建解决缓存问题 docker compose down -v --rmi all步骤 3访问项目容器启动成功后直接在本地浏览器访问http://localhost:3000和本地启动效果完全一致且修改本地代码会实时热更新Vite 的热更新功能在容器内正常生效。方案 2直接 docker run快捷方案适合临时测试如果不想创建配置文件可直接通过一行docker run命令启动容器适合临时快速运行项目核心是挂载目录 映射端口 指定高版本 Node 镜像步骤 1拉取指定新版本的 Node 镜像Node 官方镜像仓库https://hub.docker.com/_/node镜像标签对应 Node 版本如18-alpine、20、21-ltsalpine是轻量版推荐生产 / 开发使用。拉取命令# 拉取指定版本推荐轻量alpine版体积小 docker pull node:20-alpine # 也可以拉取最新稳定版 # docker pull node:latest拉取完成后验证镜像docker images能看到node镜像即成功。步骤 2进入项目根目录用 Docker 启动新项目打开终端cd 到你的新项目根目录比如D:\projects\my-new-node-project执行以下命令直接在 Docker 容器内启动项目# Windows PowerShell/CMD通用命令核心版映射端口挂载目录执行启动命令 docker run -it --rm -p 3000:3000 -v ${PWD}:/app -w /app node:20-alpine npm run dev命令参数解释关键必须理解参数作用-it交互式终端能看到容器内 Node 的日志输出比如项目启动日志、报错--rm容器停止后自动删除避免产生无用容器开发环境推荐-p 3000:3000端口映射本地端口容器内端口比如项目启动在 3000本地访问localhost:3000即可-v ${PWD}:/app目录挂载将本地当前项目目录映射到容器内的/app文件夹容器内仅操作 /app本地会同步-w /app设置容器的工作目录为/app相当于容器内自动 cd /appnode:20-alpine指定使用的 Node 镜像版本拉取的哪个版本就写哪个npm run dev容器内执行的启动命令替换为你项目的实际启动命令如node app.js/npm start特殊说明Windows 路径问题如果在CMD中执行上述命令报错路径识别问题将${PWD}替换为%cd%# Windows CMD专用 docker run -it --rm -p 3000:3000 -v %cd%:/app -w /app node:20-alpine npm run dev如果是WSL 2 终端比如 Ubuntu 子系统直接用${PWD}即可和 Linux 一致。其他windows上进入项目根目录用 Docker 中的node启动新项目打开终端cd 到你的新项目根目录比如D:\projects\my-new-node-project执行以下命令直接在 Docker 容器内启动项目docker run -it --rm -p 3000:3000 -v ${PWD}:/app -w /app node:20-alpine npm install docker run -it --rm -p 3000:3000 -v ${PWD}:/app -w /app node:20-alpine npm run dev使用指定版本的java打包jar包$env:JAVA_HOME C:\Program Files\Java\jdk-17; $env:PATH $env:JAVA_HOME\bin;$env:PATH; mvn clean package步骤 3安装项目依赖关键因为容器内的 Node 环境和本地隔离本地的 node_modules 不能直接给容器用系统 / 架构不同会报依赖错误所以需要在容器内重新安装依赖保持项目根目录执行以下命令在容器内安装依赖会在本地生成node_modules容器内同步使用# PowerShell docker run -it --rm -v ${PWD}:/app -w /app node:20-alpine npm install # CMD docker run -it --rm -v %cd%:/app -w /app node:20-alpine npm install安装完成后再执行步骤 2 的启动命令即可正常启动项目。步骤 4停止容器直接在启动容器的终端中按Ctrl C容器会停止并自动删除因为加了--rm不残留任何文件。启动成功后同样访问http://localhost:3000即可缺点是每次启动都会重新安装依赖无缓存适合临时使用。2、正式环境1、部署思路选择轻量级的 Web 服务器如 Nginx作为基础镜像将本地的 dist 文件夹复制到容器内的 Nginx 静态文件目录配置 Nginx可选默认配置已能满足基础需求构建并运行 Docker 镜像2、完整部署步骤1. 准备工作确保你的项目根目录下有打包好的dist文件夹目录结构示例your-project/ ├── dist/ # 前端打包后的文件夹 │ ├── index.html │ ├── css/ │ └── js/ └── Dockerfile # 新建的Dockerfile文件2. 编写 Dockerfile在项目根目录新建Dockerfile文件内容如下推荐使用 Alpine 版本的 Nginx体积更小# 第一步选择基础镜像轻量级Nginx FROM nginx:alpine # 第二步删除Nginx默认的静态文件可选清理无用文件 RUN rm -rf /usr/share/nginx/html/* # 第三步将本地dist文件夹复制到容器的Nginx静态目录 COPY ./dist /usr/share/nginx/html # 第四步可选复制自定义Nginx配置文件如果需要特殊配置 # COPY ./nginx.conf /etc/nginx/conf.d/default.conf # 第五步暴露容器的80端口Nginx默认端口 EXPOSE 80 # 启动Nginx容器启动时自动执行Nginx镜像默认已包含此命令可省略 CMD [nginx, -g, daemon off;]3. 可选自定义 Nginx 配置如果需要配置反向代理、gzip、缓存等可新建nginx.conf文件server { listen 80; server_name localhost; root /usr/share/nginx/html; index index.html; # 解决Vue/React路由刷新404问题history模式 location / { try_files $uri $uri/ /index.html; add_header Cache-Control no-cache, no-store; # html不缓存保证更新生效 } # 静态资源css/js/img/fonts开启缓存Gzip提升加载速度 location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf)$ { expires 30d; # 30天缓存 gzip on; gzip_buffers 4 16k; gzip_comp_level 6; gzip_types text/css application/javascript image/png image/jpeg image/gif image/svgxml; } # 可选前端Nginx反向代理后端接口生产环境推荐避免跨域统一域名 # 前端请求/api/* 会转发到后端服务容器名backend端口8080Docker网络内通信 location /api/ { proxy_pass http://host.docker.internal:8080; # 注意末尾/避免路径拼接错误 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; } }如果使用此配置需要取消 Dockerfile 中COPY ./nginx.conf这一行的注释。4. 构建并运行 Docker 镜像打开终端进入项目根目录执行以下命令1构建镜像# 构建镜像命名为 frontend-app可自定义标签为 latest docker build -t frontend-app:latest .2运行容器# 运行容器将主机的 8080 端口映射到容器的 80 端口 # --name 自定义容器名-d 后台运行--restartalways 开机自启 docker run -d --name frontend-container -p 8080:80 --restartalways frontend-app:latest5. 验证部署访问http://localhost:8080如果是服务器部署替换为服务器 IP即可看到前端页面。注意nginx.conf修改了需要重新构建并运行 Docker 镜像一、原因解释Docker 镜像是 “分层构建” 的COPY ./nginx.conf /etc/nginx/conf.d/default.conf这一步会把本地的nginx.conf复制到镜像层中。一旦镜像构建完成镜像内的文件就固定了修改本地的nginx.conf不会自动同步到已构建的镜像 / 运行的容器中。简单来说镜像 基础环境 你复制进去的文件dist、nginx.conf 执行的指令修改本地文件 → 镜像内的文件不变 → 必须重新构建镜像才能让修改生效二、完整的更新步骤修改 nginx.conf 后1. 停止并删除旧容器避免端口占用# 停止运行中的容器 docker stop frontend-container # 删除旧容器容器名重复会导致新容器无法创建 docker rm frontend-container2. 重新构建镜像让新的 nginx.conf 生效docker build -t frontend-app:latest .3. 重新运行容器docker run -d --name frontend-container -p 8080:80 --restartalways frontend-app:latest三、接口代理连接拒绝错误ECONNREFUSED后端服务的部署位置只有两种可能场景 1后端跑在Windows 本地最常见比如本地 IDEA/VS Code 启动的 Java/Node 后端场景 2后端也跑在另一个 Docker 容器中前后端都容器化场景 1后端跑在 Windows 本地或同一个docker容器中最常用优先看这个问题根源Docker 容器内的localhost/127.0.0.1指向容器自身而不是 Windows 本地你在 Vite 配置中写的target: http://localhost:8080在容器内执行时会去访问容器内的 8080 端口容器内没启动后端所以必然连接拒绝。解决方案两步走缺一不可步骤 1修改 Vite或vue 代理的target地址替换 Windows 本地的容器可访问地址Windows 上 Docker 容器访问本地主机需要用专属的网关地址 / 别名推荐用跨平台的别名无需查 IP更方便WSL 2 后端的 DockerWindows 默认直接用host.docker.internalDocker 官方提供的本地主机别名备用方案查 Windows 的 WSL 网关 IPcmd中执行ipconfig找WSL 2 以太网适配器的 IPv4 地址如172.28.0.1修改vite.config.js/vite.config.ts的代理配置示例后端本地端口 8080import { defineConfig } from vite import vue from vitejs/plugin-vue // 如果你是Vue项目其他框架同理 export default defineConfig({ plugins: [vue()], server: { host: 0.0.0.0, // 关键让容器内的Vite服务允许外部访问Docker必须加 port: 3000, // 容器内端口和Docker映射的一致 proxy: { /api: { // 核心修改用host.docker.internal替换localhost target: http://host.docker.internal:8080, changeOrigin: true, // 必须保留解决跨域 // rewrite: (path) path.replace(/^\/api/, ) // 按需开启根据后端接口规则 } } } })✅关键必加server.host: 0.0.0.0Docker 容器内的服务默认绑定127.0.0.1外部Windows 本地 / 其他容器无法访问加这个配置让 Vite 服务绑定容器的所有网络接口才能正常被访问。步骤 2确保 Docker 启动命令的端口映射 网络参数正确无需额外改之前的命令已满足你之前的 Docker 启动命令docker run/docker compose只要做了-p 3000:3000端口映射就无需额外加网络参数Docker 默认的bridge网络已经支持容器访问host.docker.internal。重启前端容器即可修改配置后必须重启基础命令重新执行docker run的启动命令Composedocker compose down docker compose up -d。场景 2后端也跑在另一个 Docker 容器中前后端都容器化未试用问题根源两个独立的 Docker 容器默认在各自的网络中无法通过localhost/IP直接访问需要将前端、后端容器加入同一个 Docker 自定义网络通过容器名 / 服务名互相访问。解决方案三步走标准化容器网络步骤 1创建 Docker 自定义网络让前后端容器互通# 创建自定义桥接网络命名为game-network可自定义 docker network create game-network步骤 2修改后端容器的启动命令加入同一个自定义网络启动后端容器时添加--network game-network参数并指定--name容器名供前端访问# 示例后端是Java端口8080容器名backend-server docker run -d --name backend-server --network game-network -p 8080:8080 你的后端镜像名 # 如果后端用Docker Compose在docker-compose.yml中添加networks配置文末附示例步骤 3修改 Vite 代理 前端 Docker 配置加入同一网络用容器名访问修改 Vite 代理的target用后端容器名 / Compose 服务名替换localhost示例server: { host: 0.0.0.0, port: 3000, proxy: { /api: { target: http://backend-server:8080, // 后端容器名:后端容器内端口 changeOrigin: true } } }前端容器加入同一网络基础docker run命令添加--network game-network# PowerShell示例 docker run -it --rm --network game-network -p 3000:3000 -v ${PWD}:/app -w /app node:20-alpine npm run devCompose 配置在docker-compose.yml中添加networks推荐更规范version: 3.8 services: node-app: build: . ports: - 3000:3000 volumes: - .:/app - /app/node_modules command: npm run dev stdin_open: true tty: true networks: # 加入自定义网络 - game-network # 声明网络 networks: game-network: external: true # 表示使用已创建的外部网络重启前后端容器此时前端容器就能通过容器名访问后端容器代理不再报错。额外避坑Vite 热更新失效Docker 中常见提前解决你用 Docker 启动 Vite 后可能会遇到修改本地代码容器内 Vite 不热更新的问题这是因为 Vite 的文件监听在 Docker 挂载目录中失效了只需在 Vite 配置中添加server.watch配置即可和代理配置写在一起server: { host: 0.0.0.0, port: 3000, watch: { // 禁用文件监听的缓存确保Docker挂载目录的文件变化能被检测到 usePolling: true }, proxy: { // 你的代理配置 } }usePolling: true是 Vite 适配 Docker 文件挂载的标准配置开启后热更新就能正常工作。快速验证测试代理是否连通修改配置并重启容器后可通过curl 命令在容器内测试确认能访问后端接口打开新终端进入项目根目录执行命令进入前端容器的交互式终端# PowerShell docker run -it --rm --network game-network -v ${PWD}:/app -w /app node:20-alpine sh # 如果是场景1去掉--network game-network即可容器内执行 curl 命令访问代理的接口替换为你的实际接口# 测试/api/game/scripts接口 curl http://localhost:3000/api/game/scripts如果返回后端接口的正常数据说明代理连通成功如果仍报错检查后端服务是否真的启动、端口是否正确、Vite 配置是否改对。按上述步骤修改后重启前端容器/api代理的连接拒绝错误就会消失。