Dockerイメージサイズをできるだけ小さくする際に試行錯誤した結果、nccを使ってイメージサイズを減らせたので備忘録
ncc使う前 | ncc使った後 | 結果 |
---|---|---|
599MB | 245MB | 354MB削減! |
ビルド手順
nccはTypeScriptをサポートしています。ですが、tsconfig.jsonの指定ができないためtsconfig.app.json
のような複数の設定ファイルを保持している場合、うまく使用することができません。
そこで次の手順を踏みます。
例: api
というアプリをビルド
- nest-cliでwebpackモードでビルドする:
nest build api --webpack
- 1の成果物をnccで更にビルドする
ncc build dist/api.js -m -o dist/api
するとアプリに必要なファイルをまとめて出力してくれます。 Dockerイメージにはこれを含めればいいだけ。
nccすごいですよ。webpackのやつを更にビルドできるの。
これにより、node_modulesが必要なくなり必要最低限のファイルのみがDockerイメージに含まれることになりました。
(node_modulesはもちろんnpm ci --production
でインストールしたもの)
... attempted to require "@nestjs/microservices" but could not be resolved, assuming external.
(↑正確なエラー文忘れて記録にも残ってないので前半ぼかしてます...)
nccでビルドしたファイルを実行すると、@nestjs/microservices
のインポートがうまく解決できないエラーが発生しました。関連issueはこちら: https://github.com/zeit/ncc/issues/463
私の場合、@nestjs/microservicesはメインで使っておらず@nestjs/terminus
が動的に読み込みを行っているようです。terminusはヘルスチェックに必要ですが、少し前にサーバーレスに移行したため、重要度が低くなりました。なので@nestjs/terminus
自体を削除しました。
nccの成果物にtypescriptが含まれる
場合によって、typescriptがまるっと含まれる可能性があります。47.8MB、めちゃくちゃでかい。当たり前なんですが、typescriptフォルダ自体削除しても特に動作に支障はありませんでした。
え、300MBも削減されてんの?動くのこれ?という不安
↑の結果を初めて見た時、かなり不安になりました。本当に最適化されただけ...?何か重要なファイル消えてない..?と言う感じで。
e2eテストをこのnccで行いましたが、ちゃんとテストは通っているので問題無しとしています(テスト書いててよかった)
あと、パッケージによっては古いバージョンのライブラリを参照してることがあります。バージョンの異なる同じパッケージが含まれているか調べましたが、ちゃんと含まれているようです(uuidのパッケージが4つも含まれてた...)。
更にpkgでシングルファイルにすれば完璧では...!?
alpine + pkg の組み合わせは動かなかった。static link周りでエラーが出る。
https://github.com/zeit/pkg-fetch/pull/72
そもそもpkgはサーバーレス用途では使わないでってREADMEに書いてあるし使うのは辞めた。
https://github.com/zeit/pkg/blob/master/README.md