NextJs monorepo 项目 docker 化

155 阅读2分钟

起因

公司的项目为 monorepo 构建,主项目为 app,NextJs 14 + react 构建,其余项目为 ui 库以及一些组件库

项目结构如下

project
│   package.json
│
└───app
│   │   package.json
│   │   next.config.js
│   │   pnpm-workspace.yaml
│   
└───ui
│   │   xxx
│   │   xxx
│
└───components 组件库
│   │   xxx
│   │   xxx
│
└───deployments 部署用到的 docker 系列文件
│   │   dockerfile

现在需要将它 docker 化,由于使用了 SSR 的特性,编译后文件为非静态文件,中途也踩了不少坑

配置

  1. NextJs 配置
    next.config.js 中添加 output: 'standalone' 这样输出的文件会将运行时的依赖一起扔出来

  2. 环境变量的处理方式
    由于业务是 to b ,所以需要满足一份 docker image ,到处使用。这里的问题在于,需要在镜像运行时加载环境变量,但是 .env 是在编译阶段就注入了,所以这里有些特殊的处理。

详情参考这篇文章

juejin.cn/post/732761…

值得注意的是,在 NextJs 的 getInitialProps 中为 Node 环境,可以直接使用 process.env.xxx 获取到环境变量

  1. dockerfile 配置
# 编译命令
# docker build -t app ./ -f ./deployments/Dockerfile

FROM node-18-alpine AS builder

ARG HTTPS_PROXY
ARG HTTP_PROXY

# set http proxy
ENV http_proxy=${HTTP_PROXY}
ENV https_proxy=${HTTPS_PROXY}

# RUN npm config set proxy=${HTTP_PROXY}
RUN npm config set registry https://registry.npmmirror.com/

WORKDIR /app

# 复制项目依赖组件,等下要安装依赖,这里也可以只复制 package.json
COPY ./components ./components
COPY ./types ./types
COPY ./ui ./ui

COPY ./app/package*.json ./app/
COPY ./package*.json ./
COPY ./pnpm-lock.yaml ./
COPY ./pnpm-workspace.yaml ./

RUN pnpm i

# 复制所有文件,然后编译
COPY ./app ./app
COPY ./app/.env.dev.example ./app/.env

RUN pnpm build --filter "app"

# 分层构建
FROM node:18-alpine AS production
WORKDIR /

# 关键点: 这里的复制路径不能弄错,否则一些文件会 404
COPY --from=builder /app/app/.next/standalone /web
COPY --from=builder /app/app/.next/static /web/app/.next/static

# i18n 在 public 里面
COPY --from=builder /app/app/public /web/app/public
COPY --from=builder /app/app/next-i18next.config.js /web/app

# 参考动态注入文章,如果没有这个脚本就去掉
COPY --from=builder /app/app/entrypoint.sh /web

WORKDIR /web

EXPOSE 3000
ENV PORT 3000
ENTRYPOINT ["sh", "./entrypoint.sh"]
CMD ["node", "./app/server.js"]
# 调试模式,注释掉上面的 CMD ,ENTRYPOINT 看情况注释
# 调试模式下会可以镜像,但不运行 nextjs ,方便查看文件进行调试
# CMD ["sh", "-c", "while true; do sleep 1; done"]

核心就是上面的 dockerfile,主要是最后的输出文件在 copy 时文件目录结构要写好,否则会启动不了项目或者找不到依赖文件