web-dev-qa-db-ja.com

糸のワークスペースを含むモノレポでnodejsプロジェクトからDockerイメージを構築する方法

現在、私たちのウェブサイトのチームとCI/CDを調査しています。私たちは最近、依存関係と概要をずっと簡単に保つことができるように、monorepo構造にも適応しました。現在、CIのテストなどの準備ができていますが、今はデプロイメントに取り掛かっています。必要なパッケージのDockerイメージを作成したいと思います。

私が検討したこと:

1)完全なMonorepoをDockerプロジェクトに取り込みますが、プロジェクトで糸のインストールを実行すると、プロジェクトの合計サイズは約700MBになります。これは主に、Dockerイメージさえもない反応ネイティブアプリが原因です。また、これにより、新しいリリースを展開する必要があるたびに、イメージのプル時間が長くなるはずです。

2)プロジェクトを何らかの方法でバンドルする。フロントエンドを使用すると、問題なく動作するように設定されています。しかし、私はエクスプレスapiにwebpackを追加しようとしたところ、この問題が原因でバンドル内にエラーが発生しました: https://github.com/mapbox/node-pre-gyp/issues/308 =

3)必要なプロジェクト内でのみ、yarn installを実行してみましたが、すべてのプロジェクトにnode_modulesが引き続きインストールされます。

4)npmパッケージを実行します: pkg 。これにより、特定のノードバージョンを持つ特定のシステムで実行できる単一のファイルが作成されます。これは機能しますが、これがエラーとクラッシュをどの程度うまく処理できるかはわかりません。

5)別の解決策は、プロジェクトをワークスペースからコピーし、その上で糸のインストールを実行することです。これの問題は、yarnワークスペース(暗黙的にリンクされた依存関係)の使用がなくなったことと同じです。他のワークスペースの依存関係を明示的に追加する必要があります。可能性は、特定のコミットハッシュからそれらを参照することです。これを今テストします。 (編集:サブディレクトリを糸のパッケージとして参照することはできません)

6)???

Dockerイメージを小さく保つことができるように、特定のプロジェクトに必要なnode_modulesのみを含めるオプションがないかどうかを知りたいです。

20
33Fraise33

私はあなたに似た構造に従ってプロジェクトに取り組みました、それは次のようでした:

project
├── package.json
├── packages
│   ├── package1
│   │   ├── package.json
│   │   └── src
│   ├── package2
│   │   ├── package.json
│   │   └── src
│   └── package3
│       ├── package.json
│       └── src
├── services
│   ├── service1
│   │   ├── Dockerfile
│   │   ├── package.json
│   │   └── src
│   └── service2
│       ├── Dockerfile
│       ├── package.json
│       └── src
└── yarn.lock

services/フォルダーには、サブフォルダーごとに1つのサービスが含まれます。すべてのサービスはnode.jsで記述され、独自のpackage.jsonとDockerfileを持っています。これらは通常、WebサーバーまたはREST Expressに基づくAPIです。

packages/フォルダには、サービスではないすべてのパッケージ(通常は内部ライブラリ)が含まれています。

サービスは1つ以上のパッケージに依存できますが、別のサービスには依存できません。パッケージは別のパッケージに依存できますが、サービスには依存できません。

メインのpackage.json(プロジェクトのルートフォルダーにあるもの)には、eslint、テストランナーなどの一部のdevDependenciesのみが含まれています。

個々のDockerfileは、service1は両方に依存package1package3

FROM node:8.12.0-Alpine AS base

WORKDIR /project

FROM base AS dependencies

# We only copy the dependencies we need
COPY packages/package1 packages/package1
COPY packages/package3 packages/package3

COPY services/services1 services/services1

# The global package.json only contains build dependencies
COPY package.json .

COPY yarn.lock .

RUN yarn install --production --pure-lockfile --non-interactive --cache-folder ./ycache; rm -rf ./ycache

私が使用した実際のDockerfilesは、サブパッケージの作成、テストの実行などを行う必要があったため、より複雑でした。しかし、このサンプルでアイデアを得る必要があります。

ご覧のとおり、トリックは特定のサービスに必要なパッケージのみをコピーすることでした。 yarn.lockファイルには、正確なバージョンと依存関係が解決されたpackage @ versionのリストが含まれています。すべてのサブパッケージなしでそれをコピーすることは問題ではありません、yarnは含まれているパッケージの依存関係をインストールするときにそこで解決されたバージョンを使用します。

あなたの場合、それはサービスのどれにも依存していないので、多くのスペースを節約するので、react-nativeプロジェクトはいかなるDockerfileの一部にもなりません。

簡潔にするために、その回答では詳細の多くを省略しました。何かが本当に明確でない場合は、コメントで正確さを求めてもかまいません。

多くの試行錯誤の末、ファイル.dockerignoreを注意深く使用することは、最終的な画像を制御するための優れた方法であることがわかりました。これは、monorepoの下で実行して「その他」のパッケージを除外する場合にうまく機能します。

パッケージごとに、ビルドの直前にライブの.dockerignoreファイルを置き換える、類似した名前のdockerignoreファイルがあります。

例:cp admin.dockerignore .dockerignore

以下はadmin.dockerignoreの例です。そのファイルの先頭にある*は、「すべて無視」を意味することに注意してください。接頭辞!は、「無視しない」、つまり保持することを意味します。組み合わせは、指定されたファイル以外のすべてを無視することを意味します。

*
# Build specific keep
!packages/admin

# Common Keep
!*.json
!yarn.lock
!.yarnrc
!packages/common

**/.circleci
**/.editorconfig
**/.dockerignore
**/.git
**/.DS_Store
**/.vscode
**/node_modules
0
Simeon

最近、バックエンドサービスをモノレポに配置しましたが、これは解決しなければならないいくつかのポイントの1つでした。糸にはこの点で私たちを助けるものは何もないので、他の場所を探す必要がありました。

最初に @ zeit/ncc を試しましたが、いくつかの問題がありましたが、最終的には最終ビルドを取得することができました。これは、すべてのコードとすべての依存関係コードを含む1つの大きなファイルを生成します。それは素晴らしかった。いくつかのファイル(js、ソースマップ、静的アセット)のみをdocker imageにコピーする必要がありました。画像ははるかに小さく、アプリは機能しました。しかし、ランタイムメモリの消費量は大幅に増加しました。 〜70MBの代わりに、実行中のコンテナーは〜250MBを消費しました。私たちが何か間違ったことをしたかどうかはわかりませんが、解決策が見つからず、これについて言及している issue は1つしかありません。ほとんど使用されていないにもかかわらず、Node.jsの読み込みは、バンドルからすべてのコードを解析して読み込みます。

必要なのは、各パッケージのプロダクション依存関係を分離して、スリムなDockerイメージを構築することだけです。簡単なことではないようですが、結局ツールを見つけました。

fleggal/monopack を使用しています。コードをWebpackにバンドルし、それをBabelにトランスパイルします。したがって、1つのファイルバンドルも生成されますが、すべての依存関係は含まれず、コードのみが含まれます。このステップは、私たちが実際に必要としないものですが、そこにあることを気にしません。私たちにとって重要な部分は次のとおりです-Monopackは、パッケージの本番依存関係ツリーのみをdist /バンドルされたnode_modulesにコピーします。それがまさに私たちが必要としていたことです。 Dockerイメージのサイズが700MBではなく100MB-150MBになりました。

簡単な方法が1つあります。 node_modulesに本当に大きなnpmモジュールが少ししかない場合は、ルートpackage.jsonnohoist を使用できます。そうすれば、yarnはこれらのモジュールをパッケージのローカルnode_modulesに保持し、他のすべてのサービスのDockerイメージにコピーする必要がなくなります。

例えば。:

"nohoist": [
  "**/puppeteer",
  "**/puppeteer/**",
  "**/aws-sdk",
  "**/aws-sdk/**"
]
0
Pavel