Strapi を開発環境と本番環境のDockerで動かしたい【その2】
【その1】では開発環境の Docker で Strapi を動かすことができました。
今回は、本番環境向けにデプロイするために、Next.js プロジェクト同様にマルチステージビルドができないかどうかを試していこうと思います。
開発環境向けのDockerfile
開発環境向けのDockerfile
は以下のようになっています。
FROM node:16
# Installing libvips-dev for sharp Compatability
RUN apt-get update && apt-get install libvips-dev -y
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
WORKDIR /opt/app
COPY ./ .
RUN yarn build
EXPOSE 1337
CMD ["yarn", "develop"]
これを元にDockerイメージを作成した場合、できあがったイメージは2.61GBあります。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
donuts-strapi-image latest 4ecbe41a55a9 27 hours ago 2.61GB
かなり大きいなと感じます。Next.js プロジェクトを本番環境向けにデプロイしたイメージは約120MBという軽さだったので(多分これが軽すぎるのもある)、マルチステージビルドがうまくできれば軽くなるんじゃないかなというので試してみようと思います。
マルチステージビルドを利用した形を考える
今回は本番環境とほぼ同じ環境で構築するステージング環境用のファイルで試してみます。
stg.Dockerfile
を用意します。
# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi
# Dockerfile を作成する
$ touch stg.Dockerfile
Node.js を軽量版にしてみる(失敗😢)
まずはNode.js
をalpine
(軽量版)に変更してうまくできるかを試します。
alpine版を利用する場合には不足しがちなlibc6-compat
も追加します。
FROM node:16-alpine
RUN apk add --no-cache libc6-compat
# Installing libvips-dev for sharp Compatability
RUN apt-get update && apt-get install libvips-dev -y
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
WORKDIR /opt/app
COPY ./ .
RUN yarn build
EXPOSE 1337
CMD ["yarn", "develop"]
# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi
# Docker イメージを作成する
$ docker build -f stg.Dockerfile -t donuts-strapi-image-staging .
エラーが出ました。軽量版ではapt-get
がないのでダメそう。
> [2/8] RUN apt-get update && apt-get install libvips-dev -y:
#6 0.344 /bin/sh: apt-get: not found
deps ステージと builder ステージを作る
Node.js の alpine 版を利用した方法ではうまく依存ライブラリをインストールすることができませんでした。
次に、依存ライブラリをインストールするためのdeps
ステージとビルドを担当するbuilder
ステージに分けてみます。
### deps ステージ ###
FROM node:16 AS deps
RUN apt-get update && apt-get install libvips-dev -y
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
### builder ステージ ###
FROM node:16-alpine AS builder
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/app
# deps ステージでインストールしたライブラリをコピーする
COPY --from=deps /opt/node_modules ./node_modules
COPY . .
RUN yarn build
EXPOSE 1337
CMD ["yarn", "develop"]
この Dockerfile
を元にビルドしてみます。
# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi
# Docker イメージを作成する
$ docker build -f stg.Dockerfile -t donuts-strapi-image-staging .
# イメージを確認する
REPOSITORY TAG IMAGE ID CREATED SIZE
donuts-strapi-image-staging latest e88ac351b4a3 About a minute ago 467MB
おお。これがちゃんと動くかどうかですね。
前回の方法1のやり方で、MySQLのコンテナを作成して、そこに Strapi コンテナを接続します。
# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi
# ネットワークを作成する
$ docker network create donuts-strapi-network-staging
# MySQLのコンテナを作成する
# docker run --name コンテナ名 -dit --net=ネットワーク名 -p ポートの指定 環境の設定
$ docker run --name donuts-strapi-mysql -dit --net=donuts-strapi-network-staging -p 3306:3306 -e MYSQL_ROOT_PASSWORD=donuts-strapi -e MYSQL_DATABASE=donuts-strapi -e MYSQL_USER=donuts-strapi -e MYSQL_PASSWORD=donuts-strapi mysql --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --default-authentication-plugin=mysql_native_password
# コンテナを確認
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
101a871614aa mysql "docker-entrypoint.s…" 11 seconds ago Up 11 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp donuts-strapi-mysql
# Strapi のコンテナを作成
# docker run -p ポート --net=ネットワーク名 --name コンテナの名前 元になるイメージ
$ docker run -p 1337:1337 --net=donuts-strapi-network-staging --name donuts-strapi donuts-strapi-image-staging
yarn run v1.22.19
$ strapi develop
Starting the compilation for TypeScript files in /opt/app
[2022-09-22 14:49:33.663] debug: ⛔️ Server wasn't able to start properly.
[2022-09-22 14:49:33.665] error: Could not load js config file /opt/app/node_modules/@strapi/plugin-upload/strapi-server.js:
Something went wrong installing the "sharp" module
Cannot find module '../build/Release/sharp-linuxmusl-x64.node'
だめですね。
以下のようにalpine
ではないものを利用して同様にやってみるとうまくいきました。
### deps ステージ ###
FROM node:16 AS deps
RUN apt-get update && apt-get install libvips-dev -y
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
### builder ステージ ###
FROM node:16 AS builder
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/app
# deps ステージでインストールしたライブラリをコピーする
COPY --from=deps /opt/node_modules ./node_modules
COPY . .
RUN yarn build
EXPOSE 1337
CMD ["yarn", "develop"]
# イメージを作り直す
$ docker build -f stg.Dockerfile -t donuts-strapi-image-staging .
# イメージを確認
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
donuts-strapi-image-staging latest af335accb0cf 3 minutes ago 1.26GB
# コンテナを起動
$ docker run -p 1337:1337 --net=donuts-strapi-network-staging --name donuts-strapi donuts-strapi-image-staging
無事に起動しています。とりあえずSIZEは半分になりましたね!
runner ステージを作る
deps
ステージとbuilder
ステージでのマルチステージビルドには無事成功しました。
次に builder
ステージをさらにrunner
ステージに分けてみようと思います。
以下のように分けてみました。
### deps ステージ ###
FROM node:16 AS deps
RUN apt-get update && apt-get install libvips-dev -y
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
### builder ステージ ###
FROM node:16 AS builder
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
WORKDIR /opt/app
# deps ステージでインストールしたライブラリをコピーする
COPY --from=deps /opt/node_modules ./node_modules
COPY . .
RUN yarn build
### runner ステージ ###
FROM node:16 AS runner
WORKDIR /opt/app
ARG NODE_ENV=development
ENV NODE_ENV=${NODE_ENV}
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 strapi
COPY --from=builder /opt/app/public ./public
COPY --from=builder /opt/app/package.json ./package.json
COPY --from=builder /opt/app/favicon.ico ./favicon.ico
# builder で生成された dist ディレクトリをコピー
COPY --from=builder --chown=strapi:nodejs /opt/app/dist ./
COPY --from=builder --chown=strapi:nodejs /opt/app/node_modules ./node_modules
COPY --from=builder --chown=strapi:nodejs /opt/app/.env ./.env
EXPOSE 1337
ENV PORT 1337
CMD ["yarn", "start"]
ビルドしてみます。
# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi
# Dockerイメージを作成
# docker build -f Dockerfile のファイル名 -t 作成するするイメージ名 もとになるDockerfileの場所
$ docker build -f stg.Dockerfile -t donuts-strapi-image-staging .
# イメージを確認する
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
donuts-strapi-image-staging latest 8e4375bfe733 17 seconds ago 1.26GB
# コンテナを起動
$ docker run -p 1337:1337 --net=donuts-strapi-network-staging --name donuts-strapi donuts-strapi-image-staging
node_modules
をそのまま持っていくしかないので、特にサイズは小さくなりません。Next.js の standalone すごいんだなと思いました。
余計なものを持ち込まないという意味ではrunner
ステージはあったほうがいい気がするので、このまま行きます。
本番環境向けにNODE_ENV=production
に設定してビルドするとデータ構造の変更等ができない状態になるそうです。
以下の画像の右上にデータ構造を変更するボタンが見当たりません。
本番環境向けへのビルド方法について色々と勉強させていただきました。
本番環境のDockerfileを作成する
ステージング環境と同様に本番環境用のprod.Dockerfile
を作成します。
# 作業ディレクトリに移動する
$ cd ~/StrapiProjects/donuts-strapi
# Dockerfile を作成する
$ touch prod.Dockerfile
### deps ステージ ###
FROM node:16 AS deps
RUN apt-get update && apt-get install libvips-dev -y
ENV NODE_ENV=production
WORKDIR /opt/
COPY ./package.json ./yarn.lock ./
ENV PATH /opt/node_modules/.bin:$PATH
RUN yarn config set network-timeout 600000 -g && yarn install
### builder ステージ ###
FROM node:16 AS builder
ENV NODE_ENV=production
WORKDIR /opt/app
# deps ステージでインストールしたライブラリをコピーする
COPY --from=deps /opt/node_modules ./node_modules
COPY . .
RUN yarn build
### runner ステージ ###
FROM node:16 AS runner
WORKDIR /opt/app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 strapi
COPY --from=builder /opt/app/public ./public
COPY --from=builder /opt/app/package.json ./package.json
COPY --from=builder /opt/app/favicon.ico ./favicon.ico
COPY --from=builder --chown=strapi:nodejs /opt/app/dist ./
COPY --from=builder --chown=strapi:nodejs /opt/app/node_modules ./node_modules
COPY --from=builder --chown=strapi:nodejs /opt/app/.env ./.env
EXPOSE 1337
ENV PORT 1337
CMD ["yarn", "start"]
おわりに
今回は本番環境のDockerfileの作成を行いました。
これまでは、MySQLのコンテナを適当に作成してそのコンテナに接続を行なっていました。
データベース自体は Strapi に完全依存しない方がバックアップが取りやすいのかな〜とかぼんやり考えています。
その辺も含めて、次回はデータベースとの接続について考えていこうと思います。