こんにちは。HRBrainでSREをしている桜庭です。 この記事は HRBrain AdventCalender 17日目の記事です。
今日はこの記事で紹介した組織分析のDockerイメージを pkg を使ってどのようにして圧縮していったのかを紹介したいと思います。
Before
まずは改善前のDockerfileから。
FROM node:12-stretch-slim WORKDIR /app COPY yarn.lock /app/yarn.lock COPY package.json /app/package.json RUN yarn install WORKDIR /app ENV NODE_ENV=production COPY . /app RUN yarn build EXPOSE 3500 CMD ["node", "./dist/main.js"]
一般的なDockerfileです。
もちろんこれでも動作しますし問題はないのですが、サイズを見てみると 958MB
かなり大きめで docker push
と docker pull
の速度に影響しそうです...
After
お次は改善後。
FROM node:12-stretch-slim AS builder RUN yarn global add pkg WORKDIR /app COPY package.json /app/package.json COPY yarn.lock /app/yarn.lock RUN yarn install COPY . /app ENV NODE_ENV=production RUN yarn build && \ pkg --target node12-linux --output bin ./dist/main.js FROM node:12-stretch-slim AS native-builder WORKDIR /app RUN yarn add grpc FROM debian:stretch-slim WORKDIR /app COPY --from=builder /app/bin /app/bin COPY --from=native-builder /app/node_modules /app/node_modules EXPOSE 3500 CMD ["/bin"]
このように大胆に書き換えたところイメージのサイズは213MB
!なんと1/5 程度まで小さくすることができました。
どうしてそこまで削れるのかを次から説明していきます。
vercel/pkg を使ってアプリケーションを一つのバイナリにする
まず最初にdependenciesの中にはビルド時には必要だが実行時に不要な物も多くあるのでそれを削ることはできないか考えました。で、いろいろ考えた結果シングルバイナリにまとめれば不要な物を削れるのでは?と考えpkg を使うことにしました。
pkg はNext.jsなどで有名なVercel社が開発しているOSSで、Node.jsのプロジェクトを実行可能な一つのバイナリにすることができます。
これを使用してアプリケーションをバイナリにまとめることによって実行時に必要のない依存関係がイメージに含まれなくなり、大幅にイメージサイズの削減をすることができました。
vercel/pkg を使う時の注意点
大幅なファイルサイズ削減に成功しましたがいくつか注意すべき点はあります。
リポジトリのREADMEにも書かれていることですがファイルシステム周りの挙動が普通に実行したときと異なります。
特に process.argv[0], process.argv[1]
などはCLIを作るときによく使うので注意が必要でしょう。
またネイティブモジュール(gRPC)などを使うときも同様です。
Dockerでビルドするときは以下のように別途ネイティブモジュールのみをインストールして node_modules
をコピーするなどちょっとした対策が必要になります。
FROM node:12-stretch-slim AS builder # 省略 FROM node:12-stretch-slim AS native-builder WORKDIR /app RUN yarn add grpc FROM debian:stretch-slim # 省略 COPY --from=native-builder /app/node_modules /app/node_modules
まとめ
今回使った vercel/pkg
によるNest.jsアプリケーションのシングルバイナリ化ですが、Nest.jsに限らず他のNode.jsプロジェクトでももちろん動作します。個人的にはシングルバイナリにできるならTypeScriptでCLIを作って配布するのが楽しそうだなーと思っています。
書いてる最中に NODE_ENV=production yarn install
とすれば devDependencies
がインストールされないからもっと小さくできるのでは?と気づいてしまったのは秘密です。
以上、なかなかニッチな内容ですがお役に立てれば幸いです。