私は Node.js アプリケーションをコンテナ化するために、かなり標準的な Dockerfile を使用しています。
# Simplified version
FROM node:alpine
# Copy package.json first for docker build's layer caching
COPY package.json package-lock.json foo/
RUN npm install
COPY src/ foo/
RUN npm run build
2 つの部分に分割すると、COPY
Docker が (長い) ステップをキャッシュできるようになり、有利になりましたnpm install
。
しかし最近、package.json
semver を使用してバージョンを上げ始めました。これにより、ステップの Docker キャッシュが無効になるという副作用がありnpm install
、ビルド時間が大幅に長くなりました。
npm install
依存関係が変更された場合にのみ実行される代替のキャッシュ戦略はありますか?
ベストアンサー1
これは他の回答に基づいた私の見解ですが、より短く、 を使用していますjq
。
Dockerファイル:
FROM endeveit/docker-jq AS deps
# https://stackoverflow.com/a/58487433
# To prevent cache invalidation from changes in fields other than dependencies
COPY package.json /tmp
RUN jq '{ dependencies, devDependencies }' < /tmp/package.json > /tmp/deps.json
FROM node:12-alpine
WORKDIR /app
COPY --from=deps /tmp/deps.json ./package.json
COPY package-lock.json .
RUN npm ci
# https://docs.npmjs.com/cli/ci.html#description
COPY . .
RUN npm run build
LABEL maintainer="Alexey Vishnyakov <[email protected]>"
dependencies
フィールドをdevDependencies
別のファイルに抽出し、次のビルド ステップで前のステップからそれをpackage.json
( COPY --from=deps /tmp/deps.json ./package.json
) としてコピーします。
の後にRUN npm ci
、元のCOPY . .
ファイルで上書きします( afterコマンドpackage.json
を追加することでテストできます) 。RUN cat package.json
COPY . .
ご了承くださいnpm-scripts コマンドは実行されません。なぜならpostinstall
、それらはファイル中に存在しないからですnpm ci
。また、npm ci
から逃げているroot
そして、--unsafe-perm
後にコマンドを実行するかCOPY . .
、必要に応じてコマンドを経由するかjq
(コマンドを変更するとキャッシュレイヤーが無効になります)、または追加します。--unsafe-perm
Dockerファイル:
FROM endeveit/docker-jq AS deps
COPY package.json /tmp
RUN jq '{ dependencies, devDependencies, peerDependencies, scripts: (.scripts | { postinstall }) }' < /tmp/package.json > /tmp/deps.json
# keep postinstall script
FROM node:12-alpine
WORKDIR /app
COPY --from=deps /tmp/deps.json ./package.json
COPY package-lock.json .
# RUN npm ci --unsafe-perm
# allow postinstall to run from root (security risk)
RUN npm ci
# https://docs.npmjs.com/cli/ci.html#description
RUN npm run postinstall
...