Strapi (v4) 用のDockerfile
実際に自分が使ってるもの。ベースイメージはNode.jsの公式イメージ。
- 非rootユーザーで実行される。SQLiteのデータベースファイルをホストからマウントして使う場合はパーミッションに注意。
Dockerfile
パッケージマネージャーは pnpm
を使ってる。
なお .env
を runner ではなく builder の時点で用意してる理由は、実行時ではなくビルド時に必要な環境変数も .env
に書いてるから。具体的には ./config/server.ts
の url
にセットしてる値がそう。
なのでそういうことをしてない人は、 .env
をリネームするのは builder の時点でもいいと思う。
FROM node:20-bookworm-slim as base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
WORKDIR /app
# 依存関係をインストール
FROM base as deps
COPY ./package.json ./pnpm-lock.yaml ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --prod
# ビルド
FROM base as builder
ENV NODE_ENV production
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY .env.production .env
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run build
# 実際に稼働するやつ
FROM base as runner
ENV NODE_ENV production
RUN groupadd -g 1100 nodejs && \
useradd -r -u 1100 -g nodejs nodejs
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder /app/.strapi ./.strapi
COPY --from=builder /app/public ./public
COPY --from=builder /app/config ./config
COPY --from=builder /app/tsconfig.json ./tsconfig.json
COPY --from=builder /app/favicon.png ./favicon.png
COPY --from=builder /app/.env ./.env
RUN chown nodejs:nodejs /app
USER nodejs
EXPOSE 1337
CMD ["node", "dist/server.js"]
最後の CMD
で指定してる dist/server.js
については後述。
もし npm
を使う場合、だいたい以下の部分を替えればよいはず。
-ENV PNPM_HOME="/pnpm"
-ENV PATH="$PNPM_HOME:$PATH"
-RUN corepack enable
-COPY ./package.json ./pnpm-lock.yaml ./
-RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --prod
+COPY ./package.json ./package-lock.json ./
+RUN npm install --omit-dev
-RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
-RUN pnpm run build
+RUN npm install
+RUN npm run build
追記: Dockerfile (distroless版)
いったんこの記事を書いたあとでdistroless版を作ってみたらちゃんと動いたので、載せておく。
runner だけをdistroless (nonroot) なイメージに変更している。CMD
の引数には dist/server.js
のみを指定する。
FROM node:20-bookworm-slim as base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
WORKDIR /app
# 依存関係をインストール
FROM base as deps
COPY ./package.json ./pnpm-lock.yaml ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --prod
# ビルド
FROM base as builder
ENV NODE_ENV production
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY .env.production .env
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
RUN pnpm run build
# 実際に稼働するやつ (distroless)
FROM gcr.io/distroless/nodejs20-debian12:nonroot as runner
ENV NODE_ENV production
WORKDIR /app
COPY --from=builder --chown=nonroot:nonroot /app/node_modules ./node_modules
COPY --from=builder --chown=nonroot:nonroot /app/dist ./dist
COPY --from=builder --chown=nonroot:nonroot /app/.strapi ./.strapi
COPY --from=builder --chown=nonroot:nonroot /app/public ./public
COPY --from=builder --chown=nonroot:nonroot /app/config ./config
COPY --from=builder --chown=nonroot:nonroot /app/package.json ./package.json
COPY --from=builder --chown=nonroot:nonroot /app/tsconfig.json ./tsconfig.json
COPY --from=builder --chown=nonroot:nonroot /app/favicon.png ./favicon.png
COPY --from=builder --chown=nonroot:nonroot /app/.env ./.env
EXPOSE 1337
CMD ["dist/server.js"]
server.ts
上記の Dockerfile に出てくる dist/server.js
は、Strapiプロジェクトにデフォルトでは存在しないファイルなので、別途作る必要がある。
これ自体は公式ドキュメントの以下のページに載っているもの。
TypeScript | Strapi Documentation
プロジェクト直下に server.ts
を作成し、中身を以下の通りにする。
import path from 'path';
import strapi from '@strapi/strapi';
const app = strapi({ distDir: path.resolve(__dirname) });
app.start();
これがあると npm
が無くても node
コマンドからこれ叩いてStrapiを起動できるので、 distroless なイメージでも大丈夫。
.dockerignore
無くてもいいが覚え書き。
ビルド時に必要なファイルを把握できてないのが個人的に嫌なので、必要なファイルだけ持っていく方法を使っている。
**
!.strapi/**
!config/**
!public/**
!src/**
!.env.production
!favicon.png
!package.json
!pnpm-lock.yaml
!server.ts
!tsconfig.json
この書き方は以下の記事を参考にした。
軽量・セキュアな .dockerignore の書き方 #Docker - Qiita
以上。