前言
最近我把一个基于 ASP.NET Core 8.0 后端 + Vue 3 前端的个人作品集项目部署到了云服务器上。之前也踩了不少坑——镜像拉取超时、413上传文件大小限制、图标缓存、Docker Compose版本兼容问题……网上资料比较零散,我干脆把这次部署的完整过程整理成一篇文章,希望能给同样在折腾Docker部署的朋友一些参考。
项目基本情况:
后端:ASP.NET Core 8.0 Web API,提供 RESTful 接口
前端:Vue 3 + Vite + Element Plus
数据库:远程 MySQL(部署在同一台云服务器上)
服务器:Ubuntu(x86_64架构)
部署方式:Docker Compose(前端Nginx容器 + 后端ASP.NET Core容器)
最终访问方式:
前端入口:
http://你的服务器IP:8888后端API通过Nginx反向代理转发,不对外直接暴露
一、环境准备
1.1 安装 Docker 和 Docker Compose
bash
# 安装 Docker sudo apt update sudo apt install docker.io # 安装 Docker Compose sudo apt install docker-compose
1.2 查看服务器架构(选择正确的镜像)
bash
lscpu | grep "Architecture" # 输出 x86_64 → 对应 linux-x64
1.3 创建项目目录
bash
mkdir -p /data/MyPortfolio cd /data/MyPortfolio
二、准备项目文件
2.1 目录结构
text
/data/MyPortfolio/ ├── docker-compose.yml ├── backend/ │ ├── Dockerfile │ └── publish/ # dotnet publish 发布文件 ├── frontend/ │ ├── Dockerfile │ ├── default.conf # Nginx 配置 │ └── dist/ # npm run build 构建产物
2.2 构建后端发布文件(本地或服务器上)
bash
# 在项目根目录执行 dotnet publish -c Release -o ./publish
然后将publish文件夹上传到/data/MyPortfolio/backend/。
2.3 构建前端产物
bash
npm run build
将dist文件夹上传到/data/MyPortfolio/frontend/。
三、核心配置文件
3.1 后端 Dockerfile
/data/MyPortfolio/backend/Dockerfile
dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 8000 FROM base AS final WORKDIR /app COPY ./publish . ENTRYPOINT ["dotnet", "Portfolio.Api.dll"] # 替换为你的项目名
3.2 前端 Nginx 配置
/data/MyPortfolio/frontend/default.conf
注意:
proxy_pass中的backend是docker-compose.yml中定义的后端服务名,Docker内部DNS会自动解析。
nginx
server { listen 80; server_name your_domain_or_ip; # 允许上传最大 100MB 的文件(解决 413 错误) client_max_body_size 100M; root /usr/share/nginx/html; index index.html; # Vue Router 支持(刷新页面不404) location / { try_files $uri $uri/ /index.html; } # API 请求代理到后端容器 location ^~/api/ { proxy_pass http://backend:8000/api/; 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; } }3.3 前端 Dockerfile
/data/MyPortfolio/frontend/Dockerfile
dockerfile
FROM nginx:alpine COPY default.conf /etc/nginx/conf.d/default.conf COPY dist /usr/share/nginx/html EXPOSE 80
3.4 Docker Compose 编排
/data/MyPortfolio/docker-compose.yml
yaml
version: '3.8' services: backend: build: context: ./backend dockerfile: Dockerfile container_name: portfolio-backend environment: - ASPNETCORE_URLS=http://+:8000 # 数据库连接字符串(请替换为实际信息) - ConnectionStrings__DefaultConnection=Server=your_db_host;Port=3306;Database=your_db;User=your_user;Password=your_password; restart: always frontend: build: context: ./frontend dockerfile: Dockerfile container_name: portfolio-frontend ports: - "8888:80" depends_on: - backend restart: always
四、部署过程中遇到的问题与解决
4.1 镜像拉取失败(DNS / 网络超时)
报错信息:
text
failed to resolve reference "docker.io/library/nginx:alpine": dial tcp: lookup docker.mirrors.ustc.edu.cn on 127.0.0.53:53: no such host
原因分析:
服务器 DNS 解析有问题(
127.0.0.53无法解析镜像源域名)配置的镜像加速器(中科大源)已失效
解决方案(临时):直接修改系统 DNS,并清空 Docker 镜像加速器。
bash
# 修改系统 DNS sudo systemctl stop systemd-resolved sudo systemctl disable systemd-resolved sudo rm -f /etc/resolv.conf sudo bash -c 'echo "nameserver 8.8.8.8" > /etc/resolv.conf' sudo bash -c 'echo "nameserver 114.114.114.114" >> /etc/resolv.conf' # 修改 Docker 配置 sudo nano /etc/docker/daemon.json
写入:
json
{ "registry-mirrors": [], "dns": ["8.8.8.8", "114.114.114.114"] }重启 Docker:
bash
sudo systemctl daemon-reload sudo systemctl restart docker
如果还是拉取失败,可以手动导入镜像:
bash
# 在能联网的机器上 docker pull nginx:alpine docker save nginx:alpine -o nginx-alpine.tar # 上传到服务器后 docker load -i nginx-alpine.tar
4.2 上传文件报 413 Request Entity Too Large
原因:Nginx 默认client_max_body_size为 1MB。
解决方案:在default.conf的server块中添加:
nginx
client_max_body_size 100M;
然后重新构建前端镜像并重启:
bash
sudo docker-compose build --no-cache frontend sudo docker-compose up -d
4.3 Docker Compose 启动报错KeyError: 'ContainerConfig'
报错信息:
text
KeyError: 'ContainerConfig'
原因:Docker Compose 版本较旧(1.29.2),或容器元数据损坏。
解决方案:
bash
# 彻底清理 sudo docker-compose down --volumes --remove-orphans # 重新构建并启动 sudo docker-compose up -d
这个小技巧建议收藏,遇到奇奇怪怪的容器启动问题时特别好用。
4.4 Favicon 图标不更新
现象:部署新项目后,浏览器标签页还是显示旧项目的图标。
原因:浏览器独立缓存了favicon.ico,清除页面缓存无效。
解决方案:
硬刷新:
Ctrl + F5(Windows)或Cmd + Shift + R(Mac)或使用无痕模式验证
永久解决:在
index.html中给图标加版本号:
html
<link rel="icon" href="/favicon.ico?v=2" />
五、常用运维命令
5.1 查看容器状态
bash
sudo docker ps
5.2 查看容器日志
bash
# 查看后端日志 sudo docker logs -f portfolio-backend # 查看前端日志 sudo docker logs -f portfolio-frontend
5.3 进入容器调试
bash
# 进入前端容器 sudo docker exec -it portfolio-frontend /bin/sh # 进入后端容器 sudo docker exec -it portfolio-backend /bin/bash
5.4 停止并清理
bash
sudo docker-compose down sudo docker-compose down --volumes --remove-orphans # 完全清理
5.5 重启服务
bash
sudo docker-compose restart
六、小结
这次部署不算复杂,但踩的坑都挺典型的。总结几点经验:
国内服务器一定要配好DNS和镜像源,不然拉取镜像能卡半天。建议直接用阿里云或网易的镜像加速器,中科大的源现在不太稳定。
Nginx 的
client_max_body_size要记得配,否则文件上传超1MB就报413,排查起来容易被忽略。遇到容器启动报
KeyError,先docker-compose down --volumes --remove-orphans再重新up,能解决大部分元数据问题。前端用相对路径
/api/xxx请求,配合Nginx反向代理,可以避免跨域问题,部署也更灵活。图标缓存问题,加
?v=版本号是最高效的解决方式。
整个部署流程跑通后,后续更新就很简单了:本地修改代码 →publish/build→ 上传替换文件 →docker-compose build --no-cache→docker-compose up -d。一次配置,长期受益。
相关资源:
Docker 官方文档
Nginx 配置文档
ASP.NET Core Docker 部署文档
希望这篇博客能帮到正在折腾Docker部署的你。如果遇到问题,欢迎在评论区留言交流!