こうこく
作 ▸
改 ▸

Strapi (v4) 用のDockerfile

実際に自分が使ってるもの。ベースイメージはNode.jsの公式イメージ。

  • 非rootユーザーで実行される。SQLiteのデータベースファイルをホストからマウントして使う場合はパーミッションに注意。
Strapi 4.20.5

Dockerfile

パッケージマネージャーは pnpm を使ってる。

なお .env を runner ではなく builder の時点で用意してる理由は、実行時ではなくビルド時に必要な環境変数も .env に書いてるから。具体的には ./config/server.tsurl にセットしてる値がそう。

なのでそういうことをしてない人は、 .env をリネームするのは builder の時点でもいいと思う。

/Dockerfile
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 のみを指定する。

/Dockerfile
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 を作成し、中身を以下の通りにする。

/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

無くてもいいが覚え書き。

ビルド時に必要なファイルを把握できてないのが個人的に嫌なので、必要なファイルだけ持っていく方法を使っている。

/.dockerignore
**
!.strapi/**
!config/**
!public/**
!src/**
!.env.production
!favicon.png
!package.json
!pnpm-lock.yaml
!server.ts
!tsconfig.json

この書き方は以下の記事を参考にした。

軽量・セキュアな .dockerignore の書き方 #Docker - Qiita

以上。

この記事に何かあればこちらまで (非公開)