マルチステージビルドによるDockerイメージの軽量化-Reactアプリ編


はじめに

はじめまして、最近Docker、Kubernetes辺りをいじるのにハマっております。
今回はDockerイメージの軽量化に挑戦してみました!

今回は create-react-app コマンドを用いてデフォルトで作成したものをコンテナ化しております。

  • 事前準備
    • create-react-appでアプリ作成
// アプリ作成
$ create-react-app sample-react-app
$ cd sample-react-app

問題のDockerfile

Dockerfileを準備します。流れとしては
- production用にbuild
- 静的ファイルを実行するモジュールをインストール、実行

という感じです。

Dockerfile
FROM node:12
COPY . /react-app
WORKDIR /react-app
RUN npm install && npm run build && npm install -g serve
CMD ["serve","-s","build" ]

これでデフォルトだと5000番でListenするので以下のようにポートフォワードして実行すれば localhost:5000 でアプリが動くことが確認できると思います。

$ docker run -p 5000:5000 sample-react-app:0.0.1

昨日までの私はおー!Reactアプリコンテナ化できたじゃんと満足していました。
けど思いました。

最終的に静的ファイル実行するだけなんだからnodeの環境要らなくない?

ちなみにここでDockerイメージのサイズを見てみると...

$ docker images
REPOSITORY                                                   TAG                 IMAGE ID            CREATED             SIZE
sample-react-app                                             0.0.1               6e7bc9096dd7        9 minutes ago       1.31GB

...でかいっす。

ただ、gitにproductionのファイル群をあげたりはそんなにしないかなと思うので、CIツールとか使ってgitのリポジトリからビルドしていくならnpm install, npm run buildはDockerでビルドしていく段階で欲しいと思うのです。

そこでマルチステージ!これがあるじゃん。

ということでマルチステージを使ってproductionのファイル群をnginxの方に持っていく、というのをやってみました。

改良Dockerfile

改良Dokerfile
#第一段階(productionファイル生成まで)
FROM node:12 as node
COPY . /react-app
WORKDIR /react-app
RUN npm install && npm run build

#第二段階(一段階目のコンテナの中身から静的ファイル群だけをコピーする)
FROM nginx:1.19.2-alpine
COPY --from=node ./react-app/build /usr/share/nginx/html
CMD nginx -g "daemon off;"

ドキドキの起動です。。。タグを0.0.2にしてビルド、実行してみます

$ docker build -t sample-react-app:0.0.2 .
$ docker run -p 5000:80 sample-react-app:0.0.2

無事起動できました!

そしてサイズは...

$ docker images
REPOSITORY                                                   TAG                 IMAGE ID            CREATED             SIZE
sample-react-app                                             0.0.2               9148ac06ddbe        3 minutes ago       22.5MB
かなりスマートになりました!サイズだけなら1/60になりました!

おわりに

個人的にここまで劇的に変えられたと結構な達成感を持てました!
今後はコンテナ化だけで満足せず、どのように作っていくかもじっくり考えてみたいと思います。