nuxt の 軽量なコンテナイメージを作成する


ポイント

  • distroless イメージを利用
  • nuxt の起動は nuxt ではなく nuxt-start を使う
  • nuxt の standalone ビルドにより node_modules を削減

https://github.com/GoogleContainerTools/distroless
https://github.com/nuxt/nuxt.js/tree/dev/distributions/nuxt-start
https://nuxtjs.org/docs/configuration-glossary/configuration-build/#standalone

手順

ラインタイムイメージ用の package.json を別途作成。

package.runtime.json
{
  "name": "hoge",
  "version": "1.0.0",
  "dependencies": {
    "nuxt-start": "^2.15.8"
  }
}

Dockerfile はマルチステージビルドで、3 ステージに分かれている。

最終的な node_modules には nuxt-start のみを含めるのだが、 distroless イメージにはシェルがなく、RUN コマンドが実行できないので nuxt-start をインストールするためだけのステージを作成する。

# build-env
FROM node:16 as build-env
WORKDIR /app

COPY package.json yarn.lock /app/
RUN yarn install

COPY . /app
RUN yarn build --standalone

# install-env
FROM node:16 as install-env
WORKDIR /app

COPY package.runtime.json /app/package.json
COPY yarn.lock /app/
RUN yarn install --production

# runtime-env
FROM gcr.io/distroless/nodejs:16

ENV HOST=0.0.0.0
WORKDIR /app
COPY --from=build-env /app/.nuxt /app/.nuxt
COPY --from=install-env /app/node_modules /app/node_modules
COPY static /app/static
# srcDir: 'src' の場合でも static は直下
# COPY src/static /app/static

CMD ["node_modules/nuxt-start/bin/nuxt-start.js"]

これで 250 MB くらいだったイメージが 100 MB まで削減できた。