はじめに
はじめまして、最近Docker、Kubernetes辺りをいじるのにハマっております。
今回はDockerイメージの軽量化に挑戦してみました!
今回は create-react-app コマンドを用いてデフォルトで作成したものをコンテナ化しております。
- 事前準備
- create-react-appでアプリ作成
// アプリ作成
$ create-react-app sample-react-app
$ cd sample-react-app
問題のDockerfile
Dockerfileを準備します。流れとしては
- production用にbuild
- 静的ファイルを実行するモジュールをインストール、実行
という感じです。
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
#第一段階(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になりました!
#おわりに
個人的にここまで劇的に変えられたと結構な達成感を持てました!
今後はコンテナ化だけで満足せず、どのように作っていくかもじっくり考えてみたいと思います。