惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
Malwarebytes
Malwarebytes
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
Cybersecurity and Infrastructure Security Agency CISA
F
Future of Privacy Forum
C
Cisco Blogs
T
The Exploit Database - CXSecurity.com
A
Arctic Wolf
S
Securelist
K
Kaspersky official blog
S
Schneier on Security
T
ThreatConnect
T
Tenable Blog
Spread Privacy
Spread Privacy
T
True Tiger Recordings
AWS News Blog
AWS News Blog
F
Fox-IT International blog
量子位
T
Threatpost
V
Vulnerabilities – Threatpost
C
CERT Recently Published Vulnerability Notes
Cisco Talos Blog
Cisco Talos Blog
GbyAI
GbyAI
宝玉的分享
宝玉的分享
腾讯CDC
G
Google Developers Blog
aimingoo的专栏
aimingoo的专栏
Cyberwarzone
Cyberwarzone
有赞技术团队
有赞技术团队
S
SegmentFault 最新的问题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
U
Unit 42
雷峰网
雷峰网
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
The Register - Security
The Register - Security
MyScale Blog
MyScale Blog
小众软件
小众软件
A
About on SuperTechFans
Last Week in AI
Last Week in AI
Y
Y Combinator Blog
博客园 - 三生石上(FineUI控件)
美团技术团队
Google Online Security Blog
Google Online Security Blog
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog

博客园 - lizhigang

使用 pnpm 构建 Vue2 项目操作总结(Node 16 → Node 22) Windows 11 下使用 MySQL Workbench 还原多数据库备份文件操作指南 在 WSL2 + Docker Desktop 环境下构建前后端 Docker 镜像 - lizhigang 从内网私有仓库迁移镜像到阿里云 ACR 完整指南 wsl网络设置允许访问ssh(端口22) 在 Windows 11 上安装 Docker Nginx配置 访问数据库报错 Windows系统运行RuoYi-Vue完整指南 RuoYi-Vue 项目结构分析 win11 报错 windows 11 如何使用 Microsoft Hyper-V VMware 替代产品 IntelliJ IDEA 社区版支持 Spring Boot 开发说明文档 imes开发部署(IDEA社区版 差异) IntelliJ IDEA 社区版默认支持 Spring Boot 吗? imes开发部署 IDEA 端口被占用 解决办法 使用MySQL Workbench进行数据库备份 ruoyi-nbcio ktg-mes、ktm-mes-ui部署 Widows下安装和配置Redis Windows下Redis安装与配置全攻略 mes开源 imes:注意 若依框架:开源
前端项目 Docker 镜像构建完整操作总结
lizhigang · 2026-05-25 · via 博客园 - lizhigang

https://chat.deepseek.com/share/ig4uqvz52enmzv2fj1

前端项目 Docker 镜像构建完整操作总结

一、背景与问题

1.1 初始现象

在 CI 环境中使用 Docker 构建前端项目(Vue + pnpm)时,出现两种错误:

  1. JavaScript heap out of memory
    日志:FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed
  2. destination cannot be a symlink /bin
    日志:destination cannot be a symlink /bin(通常发生在 COPY . . 时)

1.2 原因分析

错误 直接原因 解决方案
堆内存溢出 Node.js 默认堆内存上限仅 1.4GB,前端构建需要更大内存(峰值 > 2GB) 通过环境变量增加内存限制
符号链接错误 工作目录变为根目录 /,导致复制文件时与系统目录冲突 使用绝对路径作为工作目录(如 /app-pnpm),避免变量失效

二、解决方案总览

  1. 使用官方 node:22-slim 基础镜像(Debian 精简版,兼容性好,体积适中)。
  2. 在 Dockerfile 中设置 Node.js 堆内存上限(4GB 或 8GB)。
  3. 采用硬编码工作目录/app-pnpm),避免使用 ARG 变量可能引发的作用域问题。
  4. node:22-slim 推送至公司私有仓库,供 CI 使用。

三、详细操作步骤

3.1 获取并推送 node:22-slim 到私有仓库

如果 CI 服务器无法直接访问 Docker Hub,需要先在有外网的机器上获取镜像,再推送到公司私有仓库。

步骤 1:拉取官方镜像

docker pull node:22-slim

步骤 2:打标签(指向私有仓库)

假设私有仓库地址为 devops.inspur.com:80/ite/mes/repo/local_repo/imes-docker/base

docker tag node:22-slim devops.inspur.com:80/ite/mes/repo/local_repo/imes-docker/base/node:22-slim

步骤 3:登录私有仓库(如需认证)

docker login devops.inspur.com:80
# 输入用户名和密码

步骤 4:推送镜像

docker push devops.inspur.com:80/ite/mes/repo/local_repo/imes-docker/base/node:22-slim

步骤 5:在 CI 服务器上验证

docker pull devops.inspur.com:80/ite/mes/repo/local_repo/imes-docker/base/node:22-slim
docker run --rm -it devops.inspur.com:80/ite/mes/repo/local_repo/imes-docker/base/node:22-slim node -v
# 应输出 v22.22.3 或更高版本

备选方案(离线传输)
如果 CI 服务器完全隔离,可使用 docker save 导出 tar 包,通过 scp 传输后 docker load 导入。


3.2 编写最终的 Dockerfile

以下 Dockerfile 采用硬编码绝对路径,无任何 ARG 变量依赖,可直接用于构建。

# 定义基础镜像来源(可根据需要修改为私有仓库地址)
ARG build_from=devops.inspur.com:80/ite/mes/repo/local_repo/imes-docker/base/node:22-slim
ARG run_from=devops.inspur.com:80/ite/mes/repo/local_repo/imes-docker/base/nginx:alpine

# ========== 阶段一:构建前端产物 ==========
FROM ${build_from} AS build

# 设置绝对路径工作目录
WORKDIR /app-pnpm

# 复制项目所有文件
COPY . .

# 【关键】增加 Node.js 堆内存上限(解决 OOM)
ENV NODE_OPTIONS="--max-old-space-size=4096"   # 可改为 8192

# 启用 pnpm,设置镜像源,安装依赖并构建
RUN corepack enable && corepack prepare pnpm@latest --activate && \
    pnpm config set registry https://registry.npmmirror.com && \
    pnpm install && \
    pnpm run build:prod

# ========== 阶段二:Nginx 运行静态文件 ==========
FROM ${run_from}

# 从构建阶段复制编译产物(使用绝对路径)
COPY --from=build /app-pnpm/dist /usr/share/nginx/html

# 复制 Nginx 配置模板(支持环境变量替换)
COPY nginx.conf.template /etc/nginx/nginx.conf.template
WORKDIR /etc/nginx/

EXPOSE 80

# 启动 Nginx,并替换 ${BACKEND_SERVICE} 变量
ENTRYPOINT envsubst '$BACKEND_SERVICE' < nginx.conf.template > ./conf.d/default.conf && \
    cat ./conf.d/default.conf && \
    nginx -g 'daemon off;'

说明

  • 工作目录固定为 /app-pnpm,复制和引用时均使用此绝对路径。
  • ENV NODE_OPTIONS="--max-old-space-size=4096" 确保 Node.js 构建时内存充足。
  • 若项目需要 --openssl-legacy-provider,可合并设置:
    ENV NODE_OPTIONS="--max-old-space-size=4096 --openssl-legacy-provider"

3.3 构建镜像

在项目根目录(包含 Dockerfile)执行:

# 本地构建测试
docker build -t frontend:latest .

# 推送到私有仓库(可选)
docker tag frontend:latest devops.inspur.com:80/your-project/frontend:tag
docker push devops.inspur.com:80/your-project/frontend:tag

CI 流水线集成:将上述构建命令直接放入 CI 脚本即可,无需额外调整。


四、验证与常见问题

4.1 验证内存设置是否生效

在 Dockerfile 中临时添加一行诊断(位于 ENV NODE_OPTIONS 之后):

RUN node -e "console.log('Heap limit:', require('v8').getHeapStatistics().heap_size_limit / 1024 / 1024, 'MB')"

构建时输出应显示 4096 MB8192 MB

4.2 常见问题排查

问题 可能原因 解决方法
仍然 OOM 分配的内存不够 --max-old-space-size 提高到 8192,并确保 Docker 容器内存 ≥ 8GB(docker run --memory=8g
COPY --from=build 找不到 /app-pnpm/dist 构建阶段未成功生成 dist 目录 检查构建命令 pnpm run build:prod 是否正常输出到 dist
envsubst: command not found 基础镜像缺少 envsubst nginx:alpine 默认包含,若使用其他镜像需安装 gettext
构建时网络超时 镜像源访问慢 已配置淘宝镜像源,若仍需代理可设置 HTTP_PROXY
私有仓库证书错误 自签名证书 在 Docker 客户端配置 insecure-registries

五、最终总结

5.1 核心修改点

原问题 修复措施
Node.js 堆内存溢出 添加 ENV NODE_OPTIONS="--max-old-space-size=4096"
工作目录错误导致符号链接冲突 使用硬编码绝对路径 WORKDIR /app-pnpm,避免变量依赖
基础镜像不稳定 统一使用官方 node:22-slim 并推送至私有仓库

5.2 操作清单

5.3 构建结果示例

### 镜像构建成功 ...
Pushed image to devops.inspur.com:80/ite/mes/repo/local_repo/imes-docker/imes/imes-ui-pnpm:develop-pnpm-9-...

本总结可直接交付给开发或运维团队,作为标准操作文档使用。