1- # 阶段1:基础镜像准备
1+ # ========= base =========
22FROM node:20-alpine AS base
3-
4- # 设置工作目录
53WORKDIR /app
64
7- # # 配置国内镜像源
8- # RUN npm config set registry https://registry.npmmirror.com/
9-
10- # 安装必要的系统依赖(例如 CA 证书)
11- RUN apk add --no-cache ca-certificates openssl && update-ca-certificates
5+ # 1) 系统 CA 与 openssl
6+ RUN apk add --no-cache ca-certificates openssl tzdata curl && update-ca-certificates
127
8+ # 2) 让 Node 在构建/运行都用系统 CA(同时告知底层库)
139ENV NODE_OPTIONS="--dns-result-order=ipv4first --use-openssl-ca"
1410ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
1511ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
1612
17- # 阶段2:构建应用程序
18- FROM base AS builder
13+ # 3) 让 yarn/npm 也指向系统 CA(yarn v1 会读取 npm_*)
14+ ENV npm_config_strict_ssl=true
15+ ENV npm_config_cafile=/etc/ssl/certs/ca-certificates.crt
1916
17+ # ========= builder =========
18+ FROM base AS builder
2019WORKDIR /app
2120
22- # 复制依赖文件
2321COPY package.json yarn.lock ./
2422
25- # 配置镜像源
26- ARG REGISTRY_LIST="https://registry.npmmirror.com/ https://registry.npmjs.org/ https://registry.yarnpkg.com/"
27- ARG YARN_NETWORK_TIMEOUT="300000"
23+ # 显式告诉 yarn 使用系统 CA(双保险)
24+ RUN yarn config set cafile /etc/ssl/certs/ca-certificates.crt
2825
26+ # --- 探针 A:时间是否正常 ---
27+ RUN date -u
2928
30- RUN yarn config set cafile /etc/ssl/certs/ca-certificates.crt
29+ # --- 探针 B:OpenSSL 能否信任 npmjs 证书链(会打印 notBefore/notAfter)---
30+ RUN openssl s_client -connect registry.npmjs.org:443 -servername registry.npmjs.org </dev/null 2>/dev/null \
31+ | openssl x509 -noout -subject -issuer -dates
32+
33+ # --- 探针 C:Node https 是否能连通 npm registry(不经 yarn)---
34+ RUN node -e "require('https').get('https://registry.npmjs.org',r=>{console.log('node https ok',r.statusCode);r.resume()}).on('error',e=>{console.error('node https FAIL:',e.message);process.exit(1)})"
3135
32- # 多镜像源回退安装:开发依赖 + 构建所需
36+ # 可选 sanity:curl 试一下(系统 CA 路径)
37+ RUN curl -I https://registry.npmjs.org
38+
39+ # 多镜像源 + 缓存挂载(避免 EBUSY,不再在挂载目录里 yarn cache clean)
40+ ARG REGISTRY_LIST="https://registry.npmmirror.com/ https://registry.npmjs.org/ https://registry.yarnpkg.com/"
41+ ARG YARN_NETWORK_TIMEOUT="300000"
42+
43+ # 开发依赖
3344RUN --mount=type=cache,id=yarn-cache,target=/usr/local/share/.cache/yarn \
3445 set -eux; success=0; \
3546 for registry in $REGISTRY_LIST; do \
@@ -38,27 +49,19 @@ RUN --mount=type=cache,id=yarn-cache,target=/usr/local/share/.cache/yarn \
3849 if yarn install --frozen-lockfile --network-timeout "$YARN_NETWORK_TIMEOUT" ; then \
3950 echo "成功使用镜像源: $registry" ; success=1; break; \
4051 else \
41- echo "镜像源 $registry 失败,清缓存并尝试下一个..." ; yarn cache clean || true; \
52+ echo "镜像源 $registry 失败,尝试下一个(不在挂载目录里清缓存以避免 EBUSY)" ; \
53+ rm -rf /tmp/yarn-cache || true; \
4254 fi; \
4355 done; test "$success" -eq 1
4456
45- # # 安装所有依赖,包括开发依赖
46- # RUN yarn install
47-
48- # 复制项目源代码
57+ # 构建
4958COPY . .
50-
51- # 构建应用程序
5259RUN yarn build
5360
54- # 删除 node_modules 目录
61+ # 清理再装生产依赖
5562RUN rm -rf node_modules
56-
57- # 设置 NODE_ENV 为 production
5863ENV NODE_ENV=production
5964
60- # 安装生产依赖
61- # RUN yarn install --production --ignore-scripts --prefer-offline
6265RUN --mount=type=cache,id=yarn-cache,target=/usr/local/share/.cache/yarn \
6366 set -eux; success=0; \
6467 for registry in $REGISTRY_LIST; do \
@@ -67,49 +70,35 @@ RUN --mount=type=cache,id=yarn-cache,target=/usr/local/share/.cache/yarn \
6770 if yarn install --frozen-lockfile --production --ignore-scripts --network-timeout "$YARN_NETWORK_TIMEOUT" ; then \
6871 echo "成功使用镜像源(生产依赖): $registry" ; success=1; break; \
6972 else \
70- echo "镜像源 $registry 失败,清缓存并尝试下一个..." ; yarn cache clean || true ; \
73+ echo "镜像源 $registry 失败,尝试下一个" ; \
7174 fi; \
7275 done; test "$success" -eq 1
7376
74- # 清理 yarn 缓存
75- RUN yarn cache clean --all || true
76-
77- # 阶段3:构建最终的生产镜像
77+ # ========= runtime =========
7878FROM node:20-alpine
79-
80- # 设置工作目录
8179WORKDIR /app
82-
83- # 运行时同样装 CA 证书(以防某些运行时场景需要出网)
8480RUN apk add --no-cache ca-certificates && update-ca-certificates
8581
86- # 创建非 root 用户
87- RUN addgroup -g 1001 appgroup && \
88- adduser -D -u 1001 -G appgroup appuser
82+ ENV NODE_ENV=production
83+ ENV HOSTNAME=0.0.0.0
84+ ENV PORT=13000
8985
90- # 复制应用程序文件
86+ # 运行期也保持一致
87+ ENV NODE_OPTIONS="--dns-result-order=ipv4first --use-openssl-ca"
88+ ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
89+ ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
90+
91+ # 非 root
92+ RUN addgroup -g 1001 appgroup && adduser -D -u 1001 -G appgroup appuser
93+
94+ # 拷贝产物
9195COPY --from=builder /app/server.js /app/server.js
9296COPY --from=builder /app/dist /app/dist
9397COPY --from=builder /app/api /app/api
9498COPY --from=builder /app/node_modules /app/node_modules
9599COPY --from=builder /app/package.json /app/package.json
96100
97- # 修改文件权限,使 appuser 拥有所有权
98101RUN chown -R appuser:appgroup /app
99-
100- # 设置环境变量
101- ENV NODE_ENV=production
102- ENV HOSTNAME="0.0.0.0"
103- ENV PORT=13000
104- ENV NODE_OPTIONS="--dns-result-order=ipv4first --use-openssl-ca"
105- ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
106- ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
107-
108- # 暴露端口
109102EXPOSE 13000
110-
111- # 使用非 root 用户
112103USER appuser
113-
114- # 启动命令
115104CMD ["node" , "server.js" ]
0 commit comments