web-dev-qa-db-ja.com

DockerがDockerfileをビルドするときにRUN npmインストール命令をキャッシュする方法

現在、アプリケーションのNodeバックエンドを開発しています。 Docker化するとき(docker build)、最も長いフェーズはRUN npm installです。 RUN npm install命令は、小さなサーバーコードの変更ごとに実行され、開発者が毎回ビルドの完了を待つようにすることで生産性に影響を与えます。

アプリケーションコードが存在する場所でnpm installを実行し、ADD命令でnode_modulesをコンテナに追加すると、この問題が解決することがわかりましたが、ベストプラクティスとはほど遠いものです。それは、それをドッキングするというアイデア全体を壊し、コンテナをより重くします。

他の解決策はありますか?

64
ohadgk

わかりましたので、私は見つけました この素晴らしい記事 dockerファイルを書くときの効率について。

これは、RUN npm install命令を実行する前にアプリケーションコードを追加する不正なdockerファイルの例です。

FROM ubuntu

RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get -y install python-software-properties git build-essential
RUN add-apt-repository -y ppa:chris-lea/node.js
RUN apt-get update
RUN apt-get -y install nodejs

WORKDIR /opt/app

COPY . /opt/app
RUN npm install
EXPOSE 3001

CMD ["node", "server.js"]

アプリケーションのコピーを2つのCOPY命令(package.jsonファイル用とその他のファイル用)に分割し、実際のコードを追加する前にnpmインストール命令を実行することにより、コードの変更はRUN npmインストールをトリガーしません指示、package.jsonの変更のみがトリガーします。 Dockerファイルのより良い練習:

FROM ubuntu
MAINTAINER David Weinstein <[email protected]>

# install our dependencies and nodejs
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
RUN apt-get -y install python-software-properties git build-essential
RUN add-apt-repository -y ppa:chris-lea/node.js
RUN apt-get update
RUN apt-get -y install nodejs

# use changes to package.json to force Docker not to use the cache
# when we change our application's nodejs dependencies:
COPY package.json /tmp/package.json
RUN cd /tmp && npm install
RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

# From here we load our application's code in, therefore the previous docker
# "layer" thats been cached will be used if possible
WORKDIR /opt/app
COPY . /opt/app

EXPOSE 3000

CMD ["node", "server.js"]

これはpackage.jsonファイルが追加された場所であり、その依存関係をインストールし、アプリが存在するコンテナーWORKDIRにそれらをコピーします。

ADD package.json /tmp/package.json
RUN cd /tmp && npm install
RUN mkdir -p /opt/app && cp -a /tmp/node_modules /opt/app/

すべてのdockerビルドでnpmインストールフェーズを回避するには、これらの行をコピーし、^/opt/app ^をコンテナー内のアプリの場所に変更します。

104
ohadgk

変だ! multi-stage buildについては誰も言及していません。

# ---- Base Node ----
FROM Alpine:3.5 AS base
# install node
RUN apk add --no-cache nodejs-current tini
# set working directory
WORKDIR /root/chat
# Set tini as entrypoint
ENTRYPOINT ["/sbin/tini", "--"]
# copy project file
COPY package.json .

#
# ---- Dependencies ----
FROM base AS dependencies
# install node packages
RUN npm set progress=false && npm config set depth 0
RUN npm install --only=production 
# copy production node_modules aside
RUN cp -R node_modules prod_node_modules
# install ALL node_modules, including 'devDependencies'
RUN npm install

#
# ---- Test ----
# run linters, setup and tests
FROM dependencies AS test
COPY . .
RUN  npm run lint && npm run setup && npm run test

#
# ---- Release ----
FROM base AS release
# copy production node_modules
COPY --from=dependencies /root/chat/prod_node_modules ./node_modules
# copy app sources
COPY . .
# expose port and define CMD
EXPOSE 5000
CMD npm run start

素晴らしいチュートリアル: https://codefresh.io/docker-tutorial/node_docker_multistage/

25
Abdennour TOUMI

最も簡単なアプローチは、Dockerのコピーセマンティクスを活用することです。

COPY命令は、新しいファイルまたはディレクトリをコピーし、コンテナのファイルシステムのパスに追加します。

これは、最初にpackage.jsonファイルを明示的にコピーしてから、キャッシュできるnpm installステップを実行してから、残りのソースディレクトリをコピーできることを意味します。 package.jsonファイルが変更された場合、そのファイルは新しくなり、将来のビルド用にnpmインストールキャッシングが再実行されます。

Dockerfileの最後のスニペットは次のようになります。

# install node modules
WORKDIR  /usr/app
COPY     package.json /usr/app/package.json
RUN      npm install

# install application
COPY     . /usr/app
17
J. Fritz Barnes

既に知っているかもしれませんが、同じフォルダに.dockerignoreファイルを含めることができます。

node_modules
npm-debug.log

dockerハブにプッシュしたときに画像が肥大化するのを防ぐため

5
usrrname

tmpフォルダーを使用する必要はなく、package.jsonをコンテナーのアプリケーションフォルダーにコピーし、インストール作業を行い、すべてのファイルを後でコピーします。

COPY app/package.json /opt/app/package.json
RUN cd /opt/app && npm install
COPY app /opt/app
1
Mike Zhang