[Docker] Est-il suffisant de l'appeler une construction en plusieurs étapes? → L'histoire qui est devenue si bonne

Conclusion

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

Procédure de vérification

environnement

Créer une application Nuxt

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.

Ajoutez les fichiers suivants au répertoire racine

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.

Construisez chaque image et vérifiez le fonctionnement

Pour une seule étape

$ 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!)

Pour multi-étapes

$ 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.

Comment utiliser la construction en plusieurs étapes

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.

De côté

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:

Dans 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)

référence

Recommended Posts

[Docker] Est-il suffisant de l'appeler une construction en plusieurs étapes? → L'histoire qui est devenue si bonne
L'histoire de rendre possible la construction d'un projet qui a été construit par Maven avec Ant
À propos du sujet qui a tendance à être confondu avec ARG de Dockerfile qui est une construction en plusieurs étapes
Je voudrais résumer Apache Wicket 8 car c'est une bonne idée
Script Shell qui construit une image Docker et la pousse vers ECR
[Docker] Comment créer lorsque le code source est monté en liaison sur le conteneur
[Petite histoire Java] Surveiller lorsqu'une valeur est ajoutée à la liste
Trouvez une valeur pratique pour avoir une méthode et en faire un ValueObject
Le patchForObject ajouté à RestTemplate ne peut pas être utilisé efficacement s'il s'agit d'une implémentation par défaut (celle qui utilise HttpURLConnection).
L'histoire que .java est également construite dans Unity 2018
[Swift] L'histoire qui change est souvent utilisée pour le jugement d'énumération
Une histoire qui a souffert d'un espace qui ne disparaît pas même s'il est taillé avec Java La cause est BOM
Une histoire sur la création d'un Builder qui hérite du Builder
Principes de base de la gestion des erreurs Java - L'histoire qui capture n'est prise qu'au premier plan
PATH ne passe pas ... La cause est le code du caractère
L'histoire selon laquelle la mise à jour forcée n'a pas pu être mise en œuvre
[Docker] Est-il suffisant de l'appeler une construction en plusieurs étapes? → L'histoire qui est devenue si bonne
Une histoire qui a mis du temps à établir une connexion
Une histoire sur la création d'un Builder qui hérite du Builder
[Rails] [Docker] Le copier-coller est OK! Comment créer un environnement de développement Rails avec Docker
La fin de la programmation catastrophique # 03 "Comparaison d'entiers, si" a> b ", supposons que c'est" a --b> 0 ""
Une histoire sur le fait d'avoir du mal à construire PHP 7.4 sur CentOS 8 de GCE
Créez un package qui est une partie de développement commune d'Automation Anywhere A2019 # 1 ~ Commencez par créer et utiliser l'exemple de SDK tel quel