前端项目 Docker 打包实操指南

🐳 前端项目 Docker 打包实操指南

------ 从零到跑通,在你的电脑上一步一步把 Vue 项目打包成 Docker 镜像

📋 本文目录

  1. 准备工作(确认环境)
  2. 第一步:本地构建前端
  3. 第二步:创建 Docker 三件套
  4. 第三步:构建 Docker 镜像
  5. 第四步:运行容器并验证
  6. 日常开发常用命令
  7. 常见问题 FAQ

1. 准备工作:确认环境就绪

1.1 Docker Desktop 正在运行?

看右下角任务栏有没有 Docker 鲸鱼图标。打开 PowerShell 运行:

shell 复制代码
docker version --format "{{.Server.Version}}"

如果能输出版本号(如 24.0.7),说明 Docker daemon 正常。如果报错,先启动 Docker Desktop 等它变成绿色。

1.2 Node.js 和依赖

shell 复制代码
node -v    # 需要 Node 16+
npm -v     # 任意版本
# 项目根目录下要有 node_modules/ 目录
Test-Path node_modules   # PowerShell,返回 True 才对

1.3 确认项目结构

你的项目根目录应该长这样:

text 复制代码
webName/
├── src/                    ← 前端源码
├── package.json            ← 依赖和构建脚本
├── vite.config.js          ← Vite 配置
├── docker/
│   ├── Dockerfile          ← 要创建的
│   ├── nginx.conf           ← 要创建的
│   └── static_file/         ← 已存在,头像图标等
└── dist/                    ← 构建产物(下一步生成)
    ├── index.html
    ├── static/
    └── ...

2. 第一步:本地构建前端

在项目根目录打开 PowerShell,运行:

shell 复制代码
cd D:\pro\webName
$env:NODE_OPTIONS="--max-old-space-size=8192"   # Node 默认 2GB 不够,加内存
npm run build:prod

⚠️ 为什么要加 NODE_OPTIONS?

你的项目有 4500+ 模块,默认 Node 堆内存 2GB 不够用,会报 JavaScript heap out of memory。设置 --max-old-space-size=8192 给 8GB 就够了。这个设置只在当前 PowerShell 窗口生效,关掉窗口要重新设置。

构建成功后,dist/ 目录里会有 index.html、static/、font/ 等文件,大小约 30MB。

遇到构建错误?

如果报 Vue 模板语法错误(Invalid end tag)或导入路径错误,说明代码里有 bug,先修掉再继续。这次构建就是帮你发现这些问题的好机会。


3. 第二步:创建 Docker 三件套

在 docker/ 目录下创建 3 个文件。

3.1 Dockerfile

在 docker/Dockerfile 写入:

dockerfile 复制代码
# 基础镜像:nginx:alpine(~5MB,超小)
FROM nginx:alpine

# 设置时区
ENV TZ=Asia/Shanghai

# 复制 Nginx 配置文件
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf

# 复制构建产物到 Nginx 静态文件目录
COPY dist /usr/share/nginx/html

# 复制静态资源文件(头像、图标等)
COPY docker/static_file /usr/share/static_file
RUN chown -R nginx:nginx /usr/share/static_file

# 声明监听端口
EXPOSE 80

# 启动 Nginx(daemon off = 前台运行,Docker 要求)
CMD ["nginx", "-g", "daemon off;"]

3.2 nginx.conf

在 docker/nginx.conf 写入:

nginx 复制代码
server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # ============ SPA 路由 fallback(重要!)============
    # Vue Router history 模式下,刷新子路由会 404
    # 先找 $uri 文件 → 再找 $uri/ 目录 → 都没有就返回 index.html
    location / {
        try_files $uri $uri/ /index.html;
    }

    # ============ API 反向代理 ============
    # 等后端部署好再打开,把 8080 改成后端端口
    # location /prod-api/ {
    #     proxy_pass http://host.docker.internal:8080/;
    #     proxy_set_header Host $host;
    # }

    # ============ 静态资源缓存 ============
    location ~* \.(js|css|png|jpg|svg|woff2?)$ {
        expires 7d;
        add_header Cache-Control "public, immutable";
    }

    # ============ 禁止访问隐藏文件 ============
    location ~ /\. { deny all; }
}

3.3 .dockerignore(项目根目录)

在项目根目录创建 .dockerignore,告诉 Docker 构建时忽略哪些文件:

text 复制代码
node_modules
*.log
.git
.github
.vscode
.idea
.env.local
npm-debug.log*
docker/docs
docker/*.tar.gz
*.md
.trae
.kilo
.mimocode

💡 为什么要用单阶段而不是多阶段构建?

多阶段构建(在 Docker 容器内跑 npm install + vite build)理论上更"专业",但你的项目有 4500+ 模块,Hyper-V VM 内存不够会崩。所以先用"主机 build + Docker 只打包运行时"的方式,稳定、快、好调试。等服务器上部署时再考虑多阶段。


4. 第三步:构建 Docker 镜像

在项目根目录运行:

shell 复制代码
docker build -t webName:v1.0 -f docker/Dockerfile .

参数拆解:

参数 含义
-t webName:v1.0 给镜像打标签,格式是 名字:版本
-f docker/Dockerfile 指定 Dockerfile 路径(不写的话默认找当前目录的 Dockerfile)
最后的 . 构建上下文目录,Docker 会把这个目录下所有文件发给构建引擎

成功后会看到:

text 复制代码
#10 naming to docker.io/library/webName:v1.0 done
#10 DONE 0.3s

验证镜像:

shell 复制代码
docker images webName
# REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
# webName      v1.0      0c670d47a203   22 seconds ago   99.4MB

✅ 镜像 99.4MB 正常

nginx:alpine 基础 ~5MB + dist ~30MB + static_file ~几十MB,加起来 99MB 没问题。如果是多阶段构建最终镜像会更小(~35MB),但当前方式够用。


5. 第四步:运行容器并验证

shell 复制代码
# 启动容器,映射端口 8080 → 80
docker run -d --name tds-web -p 8080:80 webName:v1.0
#           ^^  ^^^^^^^^^^  ^^^^^^^^^^  ^^^^^^^^^^^^^
#           |   |            |          镜像名:版本号
#           |   |            主机8080 → 容器80
#           |   容器名
#           后台运行

# 验证容器在跑
docker ps --filter "name=tds-web"

# 浏览器访问
# http://localhost:8080

浏览器打开 http://localhost:8080,应该能看到登录页面。🎉

🎯 如果页面空白或 404

检查 Nginx 配置里的 try_files $uri $uri/ /index.html; 是否正确。没有这行,Vue Router 的 history 模式刷新子路由会 404。

快速验证清单:

验证项 命令 / 操作 期望结果
容器在跑 docker ps STATUS 列显示 Up
HTTP 可访问 浏览器打开 localhost:8080 看到登录页面
刷新子路由 点一个菜单再 F5 不 404
进容器内部 docker exec -it tds-web sh 能 ls /usr/share/nginx/html

🎊 恭喜!你已经跑通了

刚才的完整流程回顾:

shell 复制代码
# 1. 本地构建前端
npm run build:prod

# 2. 创建 Dockerfile + nginx.conf + .dockerignore(已做好)

# 3. 构建 Docker 镜像
docker build -t webName:v1.0 -f docker/Dockerfile .

# 4. 运行容器
docker run -d --name tds-web -p 8080:80 webName:v1.0

# 5. 浏览器访问 http://localhost:8080 ✅

6. 日常开发常用命令

代码改了,重新部署:

shell 复制代码
# 停止并删除旧容器
docker rm -f tds-web

# 重新构建前端
npm run build:prod

# 重新构建镜像(tag 改版本号,或用 latest)
docker build -t webName:v1.1 -f docker/Dockerfile .

# 启动新容器
docker run -d --name tds-web -p 8080:80 webName:v1.1

查看日志:

shell 复制代码
# 查看容器日志
docker logs tds-web

# 实时追踪最后 100 行(Ctrl+C 退出)
docker logs -f --tail 100 tds-web

进容器调试:

shell 复制代码
docker exec -it tds-web sh
# 进去后可以:
ls /usr/share/nginx/html          # 看文件在不在
cat /etc/nginx/conf.d/default.conf  # 看 Nginx 配置
nginx -t                           # 测试 Nginx 配置语法

清理:

shell 复制代码
# 停容器
docker stop tds-web

# 删容器
docker rm tds-web

# 删镜像
docker rmi webName:v1.0

# 一键清理所有没用的镜像和容器(谨慎!)
docker system prune -a

7. 常见问题 FAQ

Q1: docker build 报 COPY dist not found

A: dist 目录被 .dockerignore 排除了。检查 .dockerignore 里有没有写 dist,有的话删掉(单阶段构建需要它)。

Q2: docker build 报 pull access denied 或超时

A: Docker Hub 在国内很慢。在 Docker Desktop → Settings → Docker Engine 里加镜像加速器:

json 复制代码
{
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://docker.xuanyuan.me"
  ]
}

点 Apply & Restart。

Q3: npm run build:prod 报 heap out of memory

A: Node 默认 2GB 不够。PowerShell 先设:$env:NODE_OPTIONS="--max-old-space-size=8192",再跑构建。

Q4: 页面能打开但 API 请求跨域

A: 这是前端和后端不在同一个 origin。两种解法:

  1. 推荐:Nginx 反向代理。在 nginx.conf 里取消 API 代理注释,把后端地址改成你实际的后端服务。
  2. 临时:后端开 CORS(不推荐长期用)。

Q5: Docker Desktop 启动报 WSL 错误

A: 你的系统用的是 Hyper-V 后端(settings.json 里 wslEngineEnabled: false)。不要改回 WSL,保持 Hyper-V 就行。

Q6: 端口被占用

shell 复制代码
# 查找谁占了 8080
Get-NetTCPConnection -LocalPort 8080 -ErrorAction SilentlyContinue | 
  Select-Object LocalPort, OwningProcess, @{N='Process';E={(Get-Process -Id $_.OwningProcess).Name}}

# 换个端口
docker run -d --name tds-web -p 9090:80 webName:v1.0
相关推荐
tedcloud1231 小时前
Docker Compose 部署 Immich:手机照片自动备份与常见故障排查
运维·前端·docker·容器·智能手机·开源·流程图
古城小栈1 小时前
Docker Compose 云原生的底座
docker·云原生·容器
时间的情敌1 小时前
《WebGIS 前端的成长路线,三维可视化工程师需要掌握什么》
前端·状态模式
漫步人生走在路上1 小时前
用小语种SEO突破外贸B2B天花板:法语、德语市场的实测数据
开发语言·前端·javascript·人工智能·搜索引擎·ecmascript
变与不变8061 小时前
jQuery 核心语法与 jQuery AJAX
前端·ajax·jquery
文章永久免费只为良心1 小时前
Ctfshow_Web应用安全与防护_第二章_无字母数字命令执行
前端·python·安全·网络安全·渗透测试·ctf·红队渗透测试
小羊没烦恼!1 小时前
在.net中读写config文件的各种方法
java·大数据·运维·服务器·前端·数据库·oracle
卜锦元2 小时前
Docker Compose 部署 Nginx 1.30.6 完整指南
nginx·docker·容器