这篇文章我们将以官方的配置文件作为基础二次修改,将应用的构建过程放在当前系统环境来完成,最后将产物打包成 Docker 镜像,以实现大小优化。
修改配置
想着之前自己部署 NuxtJS 的时候发现它在生产环境下最终运行的是一个 server.mjs
文件,这意味着我或许并不需要安装一大堆 node_modules
依赖,然后再执行 pnpm build && pnpm start
的方式来启动服务。这些最终构建好的代码,小到不足 50MB。
那么 NextJS 可以吗,简单搜索看了下,它是可以做到的。我是从它们官方提供的 Dockerfile 里面找到的这个设置项 output,比较隐蔽。
Next.js can automatically create a
standalone
folder that copies only the necessary files for a production deployment including select files innode_modules
.To leverage this automatic copying you can enable it in your
next.config.js
:
module.exports = {
output: "standalone",
}
修改成这种模式后,意味着项目生产环境的启动方式不再是 pnpm start
了,继续这样操作的时候 NextJS 的命令行工具也会对此进行提示。
"next start" does not work with "output: standalone" configuration. Use "node .next/standalone/server.js" instead.
旧版 Dockerfile
那么在此之前我是怎么做的呢,这是项目之前的 Dockerfile
,可以看到构建、运行应用的过程均在里面完成(并非阶段构建),也因此导致最后的镜像略大。
FROM node:20.15-alpine AS runner
# 定义一个名为 ENV 的参数,默认值为 dev
ARG BUILD_ENV=prod
# Create app directory
WORKDIR /app
RUN addgroup --system --gid 941 nodejs
RUN adduser --system --uid 941 nextjs
COPY . ./
WORKDIR ./
# 如果 BUILD_ENV 为 dev,则复制 .env.dev 到 .env.local
RUN if [ "$BUILD_ENV" = "dev" ]; then cp .env.dev .env.local; fi
RUN chmod 0777 .
RUN npx --yes pnpm install
RUN npx pnpm build
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["npm", "start"]
调整后的 Dockerfile
考虑到我司已经在使用 CircleCI 负责构建应用,K8S 只负责打包并运行构建结果即可,我根据官方的 Dockerfile
最终整理出了一份自己的,供各位参考:
FROM node:20.15-alpine AS runner
ENV NODE_ENV production
# Create app directory
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY public /app/public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --chown=nextjs:nodejs .next/standalone ./
COPY --chown=nextjs:nodejs .next/static .next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["ls", "-l"]
# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD HOSTNAME="0.0.0.0" node server.js
这份 Dockerfile
相较于前面的版本,他多出了一个复制 static
(位于项目内 .next/static
) 和 public
(位于项目内 /public
)文件的步骤,据官方描述说是这些文件应由 CDN 处理,但实际情况我们用的 CDN 属于融合 CDN(不知道是不是这么说,类似 CloudFlare 那种自动缓存和回源的),因此不需要额外处理单独托管的静态文件。
因为没有在 Dockerfile
里面安装依赖和构建应用了,因此需要在当前的系统环境下,已经通过 pnpm build
完成 NextJS 的构建过程。
使用 Jenkins 或其他方式
我自己的服务器并没有强大的资源和性能,只有一个机器跑多个服务的使用场景。如果改用传统 Jenkins + SSH + PM2 的部署方式,也是一样轻松了不少,以往需要在运行机器上执行极其缓慢的 pnpm build
也将提前在 Jenkins 机器上完成。通过 SCP 的方式传输构建产物,到运行机器上只需替换掉对应的资源,重启 PM2 就能完成,这里就不再具体提供实现过程了,有需要建议自行尝试摸索。
本文作者:Paul
评论列表 (0条):
加载更多评论 Loading...