如何在lerna monorepo中构建Docker镜像而不发布

34
这种方法的用例是在 Lerna Monorepos 中进行分支构建和部署。
问题在于,Lerna Monorepos 要么将依赖项集中到 NPM 中,要么使用 yarn workspaces 实现相同的功能,将所有依赖项收集到工作区/ Monorepo 的 node_modules 文件夹中。这意味着,在子文件夹中构建 Dockerfiles 时,它们将无法访问。
我想,这里需要一种“较低”(与 hoist 相反)的函数,将包依赖项拉入 Docker/package.json 项目的 node_modules 中,然后再运行 docker build。
问题是,是否有更好的方法或已经存在的方法来解决这个问题?

2
我使用的方法是将本地依赖项发布到本地npm服务器(verdaccio),并在需要构建和运行的每个包中创建Dockerfile,并使用-f选项运行docker build,并使用本地npm服务器安装每个包。 - user2473015
1
这是我一直在考虑的选项。你对这种方法的复杂度和速度满意吗? - Gudlaugur Egilsson
1
我们使用这种方法:https://dev59.com/kVMI5IYBdhLWcg3waqs4#59576981 - Felix
1
由于我只需要将几个软件包docker化(并且不使用yarn),所以我一直在使用“tar chf。”来吸收node_modules(使用'h'参数取消符号链接引用),然后将tarball添加到Docker中。这很丑陋而且慢,但很容易。 - jamey graham
3个回答

5

对于我的项目,解决方案是使用docker BuildKit,首先构建所有的工作空间,然后重新使用之前构建的文件来构建项目工作区的docker镜像。

具体实现方法是在docker文件中将顶层package.json和yarn lock复制进去,然后选择所需工作区的package.json。 接着运行yarn install和yarn build以使一切正常运转。

这就是我的项目:

# base image
FROM @myscope/base:latest as base

# set working directory
WORKDIR /app

# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH

# install and cache app dependencies
COPY ["package.json","yarn.lock", "./"]
COPY ./packages/server/package.json ./packages/server/
COPY ./packages/shared/package.json ./packages/shared/
COPY ./packages/app/package.json ./packages/app/

RUN yarn install --frozen-lockfile --non-interactive --production=false --ignore-scripts
COPY . /app
RUN yarn build



FROM nodejs:14.15 as serverapp

WORKDIR /app

COPY ["package.json","yarn.lock", "./"]
COPY ./packages/server/package.json ./packages/server/
COPY ./packages/shared/package.json ./packages/shared/

RUN yarn install --frozen-lockfile --non-interactive --production=true --ignore-scripts

# copy artifact build from the 'build environment'
COPY --from=base /app/packages/shared/dist /app/packages/shared/dist

COPY ["./packages/server/", "./packages/server/"]

WORKDIR /app/packages/server
VOLUME ["/app/packages/server/logs", "/app/packages/server/uploads"]
EXPOSE $PORT
CMD ["yarn", "start"]

shared 是一个私有工作区,是 server 工作区的依赖。


2
这对于小型工作区来说效果很好,但不易扩展,因为您需要为所有更改重新构建顶级Docker。一旦您拥有数十个软件包和项目,这将变得非常昂贵。 - Gudlaugur Egilsson
@GudlaugurEgilsson,你的意见很有用,但你有什么建议呢? - Sergey Mell
1
我最终采取的做法是使用esbuild来打包可移植的上游依赖项,而不是在构建docker步骤中执行npm ci/install,并将打包结果嵌入到镜像中。然后,基础容器安装非可移植的依赖项(如数据库驱动程序等)。这种方法在大约50个容器中表现得相当不错。 - Gudlaugur Egilsson

5

由于没有一个令我满意的答案,我构建了一个npm包,用于为lerna项目生成Dockerfile。它使用Docker的stage功能,并为每个包创建阶段。

当前版本:

运行以下命令,让lerna-dockerize设置所有所需配置。

npx lerna-dockerize init

Translated Version:

您只需要至少两个Docker文件:

基础Docker文件包含全局设置

Dockerfile.base:

FROM node:14 as base
COPY ./package.json ./
RUN npm i
COPY ./lerna.json ./

同时还需要一个用于软件包的模板

Dockerfile.template

FROM base as build
COPY ./package.json ./
RUN npm install
RUN --if-exists npm run build

您也可以为软件包添加自定义的Dockerfile,只需在软件包内添加自己的Dockerfile即可。这将用自定义的Dockerfile替换模板。

然后,您可以通过npx运行命令来生成您的Dockerfile:

npx lerna-dockerize

1
这是一个很好的问题。对我来说,使用yarn工作区的整个目的就是为了摆脱私有npm注册表。
我的方法是与webpack一起使用`webpack-node-externals`和`generate-package-json-webpack-plugin`,请参见npmjs.com/package/generate-package-json-webpack-plugin
通过node externals,我们可以将其他工作区(libs)的所有依赖项捆绑到应用程序中(这使得私有npm注册表过时)。使用generate package json插件,创建一个新的package json,其中包含除我们工作区依赖项以外的所有依赖项。在包bundle旁边有了这个package json后,我们可以在dockerfile中执行npm或yarn install。
设置webpack配置花费了几个小时,但我认为它很好地扩展,并保持了dockerfile的清洁。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接