Tirer parti des builds en plusieurs étapes peut réduire considérablement la taille des images de conteneur. Voici un exemple d'application Nuxt.js.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nuxt single-stage fba421d5de5b About a minute ago 371MB
nuxt multi-stage a40d0000d0a8 10 minutes ago 22MB
Créez une application Nuxt.js avec npx create-nuxt-app <nom de l'application>
. La composition est gratuite. Peu importe comment vous le définissez, vous obtiendrez le même résultat avec quelques différences de taille.
Dockerfile-Single
FROM node:lts-alpine
WORKDIR /app
COPY . ./
RUN npm install -g http-server && \
npm install && \
npm run build
EXPOSE 8080
CMD [ "http-server", "dist" ]
Pour plus de commodité, les versions non à plusieurs étapes sont appelées des versions à une seule étape dans cet article. Je n'ai pas compris le terme correct, alors faites-le moi savoir si vous le connaissez!
J'ai amené le http-server
pour exécuter l'application et y mettre les fichiers construits.
Dockerfile-Multi
FROM node:lts-alpine AS build-stage
WORKDIR /app
COPY . ./
RUN npm install && \
npm run build
FROM nginx:stable-alpine AS production-stage
COPY --from=build-stage /app/dist /usr/share/nginx/html
EXPOSE 80
CMD [ "nginx", "-g", "daemon off;" ]
L'étape de construction utilise l'image node.js et l'étape d'exécution utilise l'image nginx. Vous pouvez nommer la scène avec ʻaset spécifier de quelle étape le fichier est avec
--from`.
Le répertoire finalement généré lors de la phase de construction est placé dans la racine du document nginx.
.dockerignore
.dockerignore
node_modules
dist
Dockerfile*
Le Dockerfile est comme une erreur, mais les node_modules
et dist
gonflent en fonction de ce que vous utilisez. Excluez-les pendant la phase de création d'image car ils sont exécutés à l'intérieur du conteneur par npm install
et npm build
, respectivement.
$ docker build -t nuxt:single-stage --file Dockerfile-Single .
$ docker run -dit -p 8080:8080 --name nuxt-single nuxt:single-stage
$ docker exec nuxt-single wget -S -O- localhost:8080
Connecting to localhost:8080 (127.0.0.1:8080)
HTTP/1.1 200 OK
(Omis ci-dessous: OK si HTML est renvoyé comme données de réponse!)
$ docker build -t nuxt:multi-stage --file Dockerfile-Multi .
$ docker run -dit -p 80:80 --name nuxt-multi nuxt:multi-stage
$ docker exec nuxt-multi wget -S -O- localhost:80
Connecting to localhost:80 (127.0.0.1:80)
HTTP/1.1 200 OK
(Omis ci-dessous: OK si HTML est renvoyé comme données de réponse!)
Si vous comparez chaque taille d'image à ce stade, vous obtiendrez le résultat affiché au début.
Dans l'exemple donné cette fois, la taille de l'image est réduite en supprimant ce qui est nécessaire lors de la construction de l'application mais pas lors de son exécution. En d'autres termes, on peut dire que la construction en plusieurs étapes est efficace lors de la création d'une image d'un conteneur ne nécessitant qu'un environnement d'exécution. Par exemple, un conteneur pour CI / CD doit uniquement être un livrable de la génération, mais les fichiers requis uniquement au moment de la génération entraîneront une augmentation inutile de la taille du conteneur. C'est une bonne utilisation pour la construction en plusieurs étapes.
Vous pouvez réduire la communication réseau causée par npm install
en supprimant node_modules
de .dockerignore
et en omettant npm install
. Il n'y a pas beaucoup de décalage horaire entre l'envoi de node_modules
au démon Docker une fois et l'exécution de npm install
, selon l'environnement réseau.
De plus, lors de l'utilisation de la construction en plusieurs étapes, l'image intermédiaire reste comme «<none: none>». Pour éviter cela, effectuez l'une des opérations suivantes:
--target
(bien sûr, les images marquées restent)docker image prune
après une compilation réussie de la dernière imageDans Problème GitHub associé, il est tronqué par "Spécification (traduction gratuite)", mais il ne peut pas être géré facultativement, ou le générateur d'image est mis à jour Il semble qu'il y ait eu un débat sur la question de savoir si cela pouvait être réglé. Actuellement, il semble que l'objectif principal soit de faire du nouveau générateur (Build Kit) la valeur par défaut. (Personnellement, même si j'utilise BuildKit, je me demande quelle différence y a-t-il entre le pruneau d'image docker et le pruneau docker builder ...? ... Seulement les images intermédiaires et les caches correspondant à une construction spécifique Je veux supprimer)
Recommended Posts