ASP.NET Core API + Vue 前后端分离项目 Docker 部署完整指南(Windows/WSL2)
# ASP.NET Core API + Vue 前后端分离项目 Docker 部署完整指南(Windows/WSL2) > 适用场景:使用 ASP.NET Core 9.0 开发后端 API,Vue 3 开发前端,本地使用 MySQL 数据库,希望通过 Docker 一键部署整个应用。 ## 目录 1. [环境准备](#环境准备) 2. [项目结构建议](#项目结构建议) 3. [编写后端 Dockerfile](#编写后端-dockerfile) 4. [编写前端 Dockerfile 与 Nginx 配置](#编写前端-dockerfile-与-nginx-配置) 5. [编写 docker-compose.yml](#编写-docker-composeyml) 6. [构建与运行](#构建与运行) 7. [常见问题及解决方案](#常见问题及解决方案) 8. [管理命令](#管理命令) --- ## 环境准备 - 安装 [Docker Desktop for Windows](https://www.docker.com/products/docker-desktop/)(使用 WSL 2 后端) - 确保你的代码已经通过 Git 或直接复制到本地,**建议将整个项目放在 WSL 2 文件系统中**(例如 `\\wsl.localhost\Ubuntu\home\用户名\项目名`),以避免 Windows 文件系统性能问题和路径空格问题。 - 本地 MySQL 数据库需要允许外部连接(若仍使用宿主机 MySQL),并将连接字符串中的 `localhost` 改为 `host.docker.internal`(见下文)。 --- ## 项目结构建议
MyFullStackProject/
├── docker-compose.yml
├── backend/ # ASP.NET Core API 项目
│ ├── Dockerfile
│ ├── VidCase.sln
│ └── VidCase.Api/
│ ├── VidCase.Api.csproj
│ ├── Program.cs
│ ├── appsettings.json
│ └── ...
└── frontend/ # Vue 3 项目(注意文件夹名不要有空格)
├── Dockerfile
├── nginx.conf
├── package.json
├── vite.config.js
├── src/
└── ...
text
> 如果你的前端文件夹叫 `vidcase-web`,在 `docker-compose.yml` 中需对应修改 `build: ./frontend` 为 `build: ./vidcase-web`。 --- ## 编写后端 Dockerfile 在 `backend` 目录下创建 `Dockerfile`,内容如下(以 .NET 9 为例,若项目是 .NET 8 则将 `9.0` 改为 `8.0`): ```dockerfile # 构建阶段 FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build-env WORKDIR /app # 复制解决方案文件和项目文件(保持目录结构) COPY VidCase.sln . COPY VidCase.Api/*.csproj ./VidCase.Api/ # 还原依赖 RUN dotnet restore # 复制所有源代码并发布 COPY . . RUN dotnet publish VidCase.Api/VidCase.Api.csproj -c Release -o out # 运行时阶段 FROM mcr.microsoft.com/dotnet/aspnet:9.0 WORKDIR /app COPY --from=build-env /app/out . # 注意:这里的 DLL 名称必须与你的项目名称一致 ENTRYPOINT ["dotnet", "VidCase.Api.dll"]
关键点:
使用
COPY *.csproj的替代方式,因为项目文件在子文件夹中。
ENTRYPOINT必须使用 JSON 数组格式(双引号、方括号),且换行符应为 LF(避免 Windows CRLF 导致解析错误)。
编写前端 Dockerfile 与 Nginx 配置
1. 前端 Dockerfile(frontend/Dockerfile)
dockerfile
# 阶段一:构建 Vue 应用 FROM node:lts-alpine AS build-stage WORKDIR /app COPY package*.json ./ RUN npm install COPY . . # 如果你的项目使用了 TypeScript 但是实际是纯 JS 项目,请确保 package.json 中的 build 脚本为 "vite build"(而不是 "tsc && vite build") RUN npm run build # 阶段二:使用 Nginx 提供静态文件服务 FROM nginx:stable-alpine AS production-stage COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --from=build-stage /app/dist /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
2. Nginx 配置文件(frontend/nginx.conf)
nginx
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html; # 解决 Vue Router 刷新 404
}
# API 代理到后端容器(必须使用 docker-compose 中的服务名,而非 localhost)
location /api {
proxy_pass http://backend:5000; # 注意端口与后端实际监听端口一致
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
后端服务名在
docker-compose.yml中定义为backend,且后端监听端口为 5000,所以代理地址为http://backend:5000。
编写 docker-compose.yml
在项目根目录创建 docker-compose.yml:
yaml
services:
backend:
build: ./backend
ports:
- "5000:5000" # 暴露宿主机 5000 端口,映射到容器 5000
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:5000
# 若使用宿主机 MySQL,连接字符串需要将 localhost 改为 host.docker.internal
- ConnectionStrings__DefaultConnection=Server=host.docker.internal;Port=3306;Database=VidCaseDB;Uid=root;Pwd=your_password;
networks:
- app-network
frontend:
build: ./frontend # 如果前端文件夹不是 frontend,请修改
ports:
- "80:80"
depends_on:
- backend
networks:
- app-network
networks:
app-network:
driver: bridge
注意:
环境变量中的
ConnectionStrings__DefaultConnection使用了__(双下划线),这是 ASP.NET Core 读取连接字符串的约定。如果你直接在
appsettings.json中修改了连接字符串为host.docker.internal,就不需要在docker-compose.yml中重复设置。
构建与运行
-
打开终端(PowerShell 或 WSL 终端),切换到项目根目录(包含
docker-compose.yml)。 -
执行以下命令:
bash
# 构建镜像并启动所有服务 docker-compose up --build # 若要在后台运行,添加 -d 参数 docker-compose up -d --build
首次启动会拉取基础镜像(.NET SDK、Node、Nginx 等),可能需要几分钟。后续构建会利用缓存,速度较快。
-
访问应用:
-
前端:
http://localhost -
后端 API(如 Swagger):
http://localhost:5000/swagger
-
常见问题及解决方案
1. 前端构建失败:error TS18003: No inputs were found
原因:项目是纯 JavaScript(没有 .ts 文件),但 package.json 中的 build 脚本包含了 tsc 命令。
解决:将 "build": "tsc && vite build" 修改为 "build": "vite build"。
2. 后端构建失败:error MSB1003 或 找不到项目文件
原因:Dockerfile 中 COPY *.csproj ./ 无法匹配到子文件夹中的 .csproj。
解决:按本文提供的 Dockerfile 写法,先复制解决方案文件和项目文件到对应子目录。
3. 后端启动报错:/bin/sh: 1: [dotnet,: not found
原因:ENTRYPOINT 中的 JSON 数组因 Windows CRLF 或不可见字符被错误解析。
解决:确保 Dockerfile 换行符为 LF(可在 VS Code 右下角切换),并重新手打 ENTRYPOINT ["dotnet", "YourDll.dll"]。
备选:改用 shell 格式 ENTRYPOINT dotnet YourDll.dll。
4. 后端无法连接本地 MySQL:Unable to connect to any of the specified MySQL hosts
原因:容器内的 localhost 指向容器自身,而非宿主机。
解决:将连接字符串中的 localhost 改为 host.docker.internal。同时确保 MySQL 允许远程连接(bind-address=0.0.0.0 且用户授权 %)。
5. 前端无法调用后端 API(404 或 CORS)
原因:Nginx 代理配置中的 proxy_pass 写成了 http://localhost:5000 或端口错误。
解决:检查 nginx.conf,代理地址必须为 http://backend:5000(服务名与 docker-compose.yml 中定义的名称一致,端口为后端实际监听端口)。
6. 构建非常慢或拉取镜像失败
原因:网络问题。
解决:配置 Docker 镜像加速器(阿里云、中科大等),或提前手动拉取基础镜像:
bash
docker pull mcr.microsoft.com/dotnet/sdk:9.0 docker pull mcr.microsoft.com/dotnet/aspnet:9.0 docker pull node:lts-alpine docker pull nginx:stable-alpine
7. 端口冲突:bind: address already in use
原因:宿主机 80 或 5000 端口被占用。
解决:修改 docker-compose.yml 中的端口映射,例如 "8080:80" 将宿主机 8080 映射到容器 80,访问 http://localhost:8080。
管理命令
| 操作 | 命令 |
|---|---|
| 构建并启动(前台) | docker-compose up --build |
| 后台启动 | docker-compose up -d |
| 停止并删除容器 | docker-compose down |
| 查看日志 | docker-compose logs -f [服务名] |
| 重启某个服务 | docker-compose restart backend |
| 进入后端容器 shell | docker exec -it vidcase-backend-1 sh |
| 清理未使用的镜像/容器 | docker system prune -a |
总结
通过 Docker Compose,我们成功地将 ASP.NET Core 后端和 Vue 前端容器化,并解决了跨平台、数据库连接、构建缓存等一系列问题。该方案适用于开发、测试甚至小型生产环境。你可以根据自己的项目结构调整路径、端口和连接字符串,一键启动整个应用。
更多推荐
所有评论(0)