基本上,foo
和bar
这两个服务都依赖于一个名为common
的库。
我们假设common
包已经发布到npm注册表中了。
|
├── packages
| ├── common
| | ├── src
| | ├── package.json
| | ├── tsconfig.build.json
| | ├── tsconfig.json
| ├── foo
| | ├── src
| | ├── Dockerfile
| | ├── package.json
| | ├── tsconfig.build.json
| | ├── tsconfig.json
| ├── bar
| | ├── src
| | ├── Dockerfile
| | ├── package.json
| | ├── tsconfig.build.json
| | ├── tsconfig.json
├── tsconfig.json
├── package.json
├── yarn.lock
├── docker-compose.init.yml
├── docker-compose.yml
├── Dockerfile
├── Dockerfile.init
├── .dockerignore
我已经将所有与根目录下的 package.json 相关的包共同依赖项添加为 devDependencies,具体如下:
"scripts": {
"build": "lerna run build --stream",
"setup": "yarn && yarn build",
"docker:bootstrap": "docker-compose --file=docker-compose.init.yml build",
"docker:up": "docker-compose up --build"
},
"devDependencies": {
"@nestjs/cli": "^7.5.1",
"@nestjs/common": "^7.4.4",
"@nestjs/core": "^7.4.4",
"@nestjs/platform-express": "^7.4.4",
"@nestjs/schematics": "^7.1.2",
"@nestjs/testing": "^7.4.4",
"@types/express": "^4.17.8",
"@types/jest": "^26.0.13",
"@types/node": "^14.10.2",
"@types/supertest": "^2.0.10",
"@typescript-eslint/eslint-plugin": "^4.1.1",
"@typescript-eslint/parser": "^4.1.1",
"eslint": "^7.9.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.4",
"express": "^4.17.1",
"husky": "^4.3.0",
"jest": "^26.4.2",
"lerna": "^3.22.1",
"lint-staged": "^10.4.0",
"prettier": "^2.1.2",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^6.6.3",
"supertest": "^4.0.2",
"ts-jest": "^26.3.0",
"ts-loader": "^8.0.3",
"ts-node": "^9.0.0",
"typescript": "3.9.5"
}
foo
包需要使用关系型数据库,因此我已经单独安装了以下的包。
$ yarn workspace foo add @nestjs/typeorm mysql typeorm
为了解决错误消息 " has unmet peer dependency ",我执行了以下命令。
$ yarn workspace foo add @nestjs/common @nestjs/core @nestjs/platform-express rxjs
我有点困惑。如果我需要在多个应用程序中以monorepo的方式组织代码,为什么我要重复安装相同的软件包呢?这让我编写Dockerfile变得更加困难。
我的第一个问题是,当开发人员在单体代码库上工作时,如果必要的话,将库安装到特定的软件包中是否是正常行为?
这是我的Dockerfile的样子:
// docker-compose.init.yml
# This file triggers the initial build
version: "3.8"
services:
pkg_builder:
image: pkg-builder
build:
context: .
dockerfile: Dockerfile.init
首先,执行以下命令。
$ yarn docker:bootstrap
Dockerfile.init
创建一个初始的构建镜像,用于“真正”的构建镜像复制构建目录。
// Dockerfile.init
FROM scratch
# Copy files from the root to build directory
COPY package.json lerna.json yarn.lock tsconfig.json /build/
# This line is required to install dependencies from foo's package.json
COPY ./packages/foo/package.json /build/packages/foo/package.json
从那时开始,使用命令构建图像:
$ yarn docker:up
// docker-compose.yml
version: "3.8"
services:
pkg_builder:
image: pkg-builder
build: .
mariadb:
image: mariadb:10.3
ports:
- "3306:3306"
environment:
- MYSQL_USER=root
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=tutorial
restart: always
foo:
container_name: foo
build: ./packages/foo
ports:
- "8000:8000"
depends_on:
- mariadb
restart: always
// Dockerfile
FROM node:12-alpine
COPY --from=pkg-builder /build /build
WORKDIR /build
RUN rm -rf node_modules
RUN yarn
CMD ["true"]
问题在于图像的大小实在是太大了。原因是所有开发所需的依赖都从
pkg-builder
中复制过来了。// foo's Dockerfile
FROM node:12-alpine
WORKDIR /app/current
COPY --from=pkg-builder /build/node_modules /app/current/packages/foo/node_modules
COPY --from=pkg-builder /build/tsconfig.json ./tsconfig.json
WORKDIR /app/current/packages/foo
COPY . .
RUN yarn build
EXPOSE 8000
CMD [ "node", "./dist/main" ]
最后,我应该如何缩小图像大小?在这种情况下,我认为多阶段构建不是减小图像大小的正确策略。我错了哪里吗?