web-dev-qa-db-fra.com

Comment mettre en cache l'instruction d'installation RUN npm lorsque docker crée un fichier Docker

Je suis en train de développer un backend Node pour mon application. Lorsque la dockerizing (construction du docker.), La phase la plus longue est le RUN npm install. L'instruction RUN npm install s'exécute à chaque changement de code sur un petit serveur, ce qui a un impact sur la productivité en obligeant le développeur à attendre la fin de la construction à chaque fois.

J'ai constaté que l'exécution de npm install où le code de l'application vivait et que l'ajout de node_modules au conteneur avec l'instruction ADD résolvent ce problème, , Mais c'est loin d'être la meilleure pratique. Cela brise en quelque sorte l’idée de la dockerisation et donne un poids beaucoup plus important au conteneur.

Une autre solution?

50
ohadgk

Ok, j’ai trouvé ce très bon article sur l’efficacité lors de l’écriture d’un fichier Docker.

Voici un exemple de fichier docker incorrect ajoutant le code de l'application avant d'exécuter l'instruction RUN npm install:

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"]

En divisant la copie de l'application en 2 instructions COPY (une pour le fichier package.json et l'autre pour le reste des fichiers) et en exécutant l'instruction d'installation npm avant d'ajouter le code réel, toute modification de code ne déclenchera l'installation de RUN npm instruction, seules les modifications du package.json le déclencheront. Fichier de docker de meilleure pratique:

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"]

C'est ici que le fichier package.json a été ajouté, installez ses dépendances et copiez-les dans le conteneur WORKDIR, où l'application réside:

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

Pour éviter la phase d'installation de npm sur chaque construction de menu fixe, copiez simplement ces lignes et remplacez le paramètre ^/opt/app ^ par l'emplacement de votre application dans le conteneur.

89
ohadgk

J'ai trouvé que l'approche la plus simple consiste à exploiter la sémantique de la copie de Docker:

L'instruction COPY copie les nouveaux fichiers ou répertoires à partir de et les ajoute au système de fichiers du conteneur situé sur le chemin.

Cela signifie que si vous copiez explicitement le fichier package.json, puis exécutez l'étape npm install, vous pouvez le mettre en cache, puis copier le reste du répertoire source. Si le fichier package.json a changé, il sera nouveau et le système exécutera à nouveau l'exécution de la mise en cache de l'installation npm pour les générations futures.

Un extrait de la fin d'un fichier Dockerfile ressemblerait à ceci:

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

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

Bizarre! Personne ne mentionne 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

Awesome tuto ici: https://codefresh.io/docker-tutorial/node_docker_multistage/

16
Abdennour TOUMI

J'imagine que vous le savez peut-être déjà, mais vous pouvez inclure un fichier .dockerignore dans le même dossier contenant

node_modules
npm-debug.log

éviter de gonfler votre image lorsque vous appuyez sur Docker Hub

5
usrrname

vous n'avez pas besoin d'utiliser le dossier tmp, il vous suffit de copier package.json dans le dossier de votre conteneur, de procéder à l'installation et de copier tous les fichiers ultérieurement. 

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