使用Docker构建Yarn工作区

6

考虑以下yarn工作区的文件结构:

.
├── docker-compose.yaml
├── package.json
├── packages
│   └── pkg-1
│       ├── dist
│       ├── package.json
│       ├── src
│       └── tsconfig.json
├── services
│   ├── api-1
│   │   ├── dist
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   ├── src
│   │   ├── tsconfig.json
│   │   └── yarn.lock
│   └── client-1
│       ├── package.json
│       ├── src
│       └── yarn.lock
├── tsconfig.json
└── yarn.lock

我已经编写了 Dockerfile 以创建 api-1 的镜像:

ARG APP_DIR=/usr/app

# Build stage
FROM node:16.2-alpine AS build

ARG APP_DIR

WORKDIR ${APP_DIR}
COPY package.json ./
COPY yarn.lock ./
COPY tsconfig.json ./

WORKDIR ${APP_DIR}/packages/pkg-1
COPY packages/pkg-1/package.json ./
RUN yarn --pure-lockfile --non-interactive
COPY packages/pkg-1/tsconfig.json ./
COPY packages/pkg-1/src/ ./src
RUN yarn build

WORKDIR ${APP_DIR}/services/api-1
COPY services/api-1/package.json ./
COPY services/api-1/yarn.lock ./
RUN yarn --pure-lockfile --non-interactive
COPY services/api-1/tsconfig.json ./
COPY services/api-1/src/ ./src
RUN yarn build

# Production stage
FROM node:16.2-alpine AS prod

ARG APP_DIR

WORKDIR ${APP_DIR}
COPY --from=build ${APP_DIR}/package.json ./
COPY --from=build ${APP_DIR}/yarn.lock ./

WORKDIR ${APP_DIR}/packages/pkg-1
COPY --from=build ${APP_DIR}/packages/pkg-1/package.json ./
RUN yarn --pure-lockfile --non-interactive --production
COPY --from=build ${APP_DIR}/packages/pkg-1/dist ./dist

WORKDIR ${APP_DIR}/services/api-1
COPY --from=build ${APP_DIR}/services/api-1/package.json ./
COPY --from=build ${APP_DIR}/services/api-1/yarn.lock ./
RUN yarn --pure-lockfile --non-interactive --production
COPY --from=build ${APP_DIR}/services/api-1/dist ./dist

CMD ["node", "dist"]

构建正在从根docker-compose.yaml运行,以获得正确的上下文:

services:
  api-1:
    image: project/api-1
    container_name: api-1
    build:
      context: ./
      dockerfile: ./services/api-1/Dockerfile
      target: prod
    ports:
      - 3000:3000

这个方法虽然能够工作,但应用程序增长时会出现很多重复的问题。问题在于构建包的方式。

包可以是一组规范化的组件集合,用于客户端服务,也可以是一组规格化的错误,用于api服务。

每当我构建某个服务时,我需要先构建它所依赖的包,这是不必要的重复任务。更不用说,各自包的构建步骤在使用包的每个单独服务的Dockerfile中都被反复定义了。

那么我的问题是:是否有一种方法,例如创建包的镜像,可用于构建服务,以避免在服务Dockerfile中定义包的构建步骤?

2个回答

1

前一段时间,我发布了一个答案,详细介绍了如何使用多个服务和包构建monorepo的结构

“诀窍”是复制您的服务所依赖的所有包,以及项目根目录下的package.json。然后运行yarn --pure-lockfile --non-interactive --production一次,将为所有子包安装依赖项,因为它们是工作区的一部分。

链接的示例未使用typescript,但我认为可以在每个package.json中使用postinstall脚本轻松实现此目标,该脚本将运行yarn build


你所描述的是我所做的事情,但没有使用TypeScript编译。对于你来说,只需复制包并安装生产依赖项即可满足要求。在第一阶段,我需要为每个包安装所有依赖项以获取TypeScript,然后可以构建该包。在第二阶段,我只需复制构建文件夹并仅安装生产依赖项。这是我需要为pkg-1执行的过程。请参见我的Dockerfile。当我构建docker镜像时,我正在寻找一种避免在service-1、service-2、service-3等中反复定义它的方法。 - Tomáš Vavřinka

0

看起来你正在寻找一种方法,可以让你拥有一个“父”package.json,这样你只需要在其中一个上调用“build”,就可以构建整个依赖树。

e.g:

- package.json // root package
  | - a
    | - package.json // module a package
  | - b
    | - package.json // module b package

你可能想要了解以下内容:

两者都支持像提到的那样的结构,但 lerna 具有更多功能。要快速了解差异,请查看此处:NPM 7.0.0 的工作区是否还需要 Lerna?


我使用yarn工作区和lerna,因此我有一个父级package.json。我刚刚意外地从我的文件结构图中删除了它,但是你可以在我的Dockerfile中读取它。我正在寻找的是类似于docker的父构建(软件包构建)。 - Tomáš Vavřinka
@TomášVavřinka 对不起,看起来我在你的问题中错过了那个。你所说的“父构建(软件包构建)”是什么意思?你只想构建相关依赖项而不是整个图形,还是有什么问题? - MauriceNino
没问题。当我为service-1构建docker镜像时,我需要在Dockerfile中定义pkg-1的构建步骤。当我为service-2构建docker镜像时,我也需要在Dockerfile中定义pkg-1的构建步骤,因为该服务也使用pkg-1。当我为service-3构建docker镜像时,我也需要在Dockerfile中定义pkg-1的构建步骤,因为该服务也使用pkg-1。因此,我希望避免在Dockerfile中重复这些步骤。我想要一个可重用的docker构建工具,用于任何服务的Dockerfile中。 - Tomáš Vavřinka
@TomášVavřinka 抱歉,我真的很难理解你的意思。为什么不直接构建完整的树形结构,并从每个Dockerfile中选择所需的路径呢? - MauriceNino

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