De multiples FROM - ce que cela signifie

112

Je souhaite créer une image docker pour le projet Linkurious sur github, qui nécessite à la fois la base de données Neo4j et Node.js pour fonctionner.

ma première approche a été de déclarer une image de base pour mon image, contenant Neo4j. Les documents de référence ne définissent pas «image de base» de manière utile:

Image de base: une image sans parent est une image de base

d'où j'ai lu que je ne peux avoir une image de base que si cette image n'a pas d'image de base elle-même.

mais qu'est-ce qu'une image de base? cela signifie-t-il que si je déclare neo4j / neo4j dans une directive FROM, que lorsque mon image est exécutée, la base de données neo s'exécutera automatiquement et sera disponible dans le conteneur sur le port 7474?

en lisant la référence Docker (voir: https://docs.docker.com/reference/builder/#from ) Je vois:

FROM peut apparaître plusieurs fois dans un même Dockerfile afin de créer plusieurs images. Notez simplement le dernier ID d'image généré par le commit avant chaque nouvelle commande FROM.

est-ce que je veux créer plusieurs images? il semblerait que ce que je veux, c'est avoir une seule image contenant le contenu d'autres images, par exemple neo4j et node.js

Je n'ai trouvé aucune directive pour déclarer les dépendances dans le manuel de référence. n'y a-t-il pas de dépendances comme dans RPM où, pour exécuter mon image, le contexte appelant doit d'abord installer les images dont il a besoin?

Je suis confus...

ekkis
la source
Remarque: mai 2017, vous en avez maintenant plusieurs FROMdans un fichier Dockerfile. Voir ma réponse modifiée ci-dessous.
VonC
Voyez si vous trouvez ma réponse plus propre. Et si oui, pensez à l'accepter.
Evan Carroll le

Réponses:

113

qu'est-ce qu'une image de base?

Un ensemble de fichiers, plus EXPOSE'd ports ENTRYPOINTet CMD.
Vous pouvez ajouter des fichiers et construire une nouvelle image basée sur cette image de base, avec une nouvelle Dockerfilecommençant par une FROMdirective: l'image mentionnée après FROMest "l'image de base" pour votre nouvelle image.

cela signifie-t-il que si je déclare neo4j/neo4jdans une FROMdirective, que lorsque mon image est exécutée, la base de données neo s'exécutera automatiquement et sera disponible dans le conteneur sur le port 7474?

Seulement si vous n'écrasez pas CMDet ENTRYPOINT.
Mais l'image en elle-même suffit: vous utiliseriez a FROM neo4j/neo4jsi vous deviez ajouter des fichiers liés à neo4jpour votre utilisation particulière de neo4j.

FROM peut apparaître plusieurs fois dans un même Dockerfile

Ne pas: il y a une proposition pour supprimer cette "fonctionnalité" de toute façon ( problème 13026 )

Le numéro 14412 mentionne:

Utiliser plusieurs FROMn'est pas vraiment une fonctionnalité mais un bogue (eh bien, la limite est serrée et il y a peu de cas d'utilisation pour plusieurs FROMdans un Dockerfile).


Mise à jour de mai 2017 (18 mois plus tard), avec docker (moby) 17.05-ce .

Plusieurs FROM peuvent être utilisés dans un seul Dockerfile.
Voir « Modèle de générateur contre builds multi-étapes dans Docker » (par Alex Ellis ) et PR 31257 par Tõnis Tiigi .

Avant:

Le modèle de générateur implique l'utilisation de deux images Docker - une pour effectuer une construction et une autre pour expédier les résultats de la première construction sans la pénalité de la chaîne de construction et des outils dans la première image.

Après:

La syntaxe générale implique l'ajout d' FROMheures supplémentaires dans votre Dockerfile - quelle que soit la dernière FROMinstruction est l'image de base finale. Pour copier des artefacts et des sorties d'images intermédiaires, utilisez COPY --from=<base_image_number>.

Première partie du Dockerfile:

FROM golang:1.7.3 as builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go    .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

Deuxième partie du même (!) Dockerfile:

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app    .
CMD ["./app"]  

Le résultat serait deux images, une pour la construction, une avec juste l'application résultante (beaucoup, beaucoup plus petite)

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

multi               latest              bcbbf69a9b59        6 minutes ago       10.3MB  
golang              1.7.3               ef15416724f6        4 months ago        672MB  
VonC
la source
2
dommage de supprimer plusieurs FROM. il me semble très utile, notamment en l'absence de mécanisme de dépendance. avec les RPM, par exemple, je peux déclarer que mon paquet a besoin d'un autre paquet pour s'exécuter donc au moment de l'installation, tout est configuré pour moi. la réalité est que presque tout va nécessiter plusieurs dépendances, alors en l'absence de plusieurs FROM, comment est-ce censé fonctionner?
ekkis
3
@ekkis comme je l'ai mentionné dans ma réponse précédente ( stackoverflow.com/a/33295292/6309 ), vous exécutez votre système en orchestrant plusieurs conteneurs, chacun fournissant un service particulier, et en communiquant via --link ( docs.docker.com/ userguide / dockerlinks /… ).
VonC
2
@VonC Bien sûr, dans un monde idéal, avec une nouvelle application et tous les modèles compris. En attendant, je pense qu'il y aura plus d'instances de personnes essayant de migrer leurs solutions vers docker et ont des besoins qui ne sont pas résolus par le réseau, tels que les dépendances logicielles, utilisant toutes une base compatible, mais à partir de plusieurs fichiers Dockerfiles. Au lieu de cela, le mieux que je puisse comprendre jusqu'à présent est de pirater leurs fichiers Docker pour créer les miens.
rainabba
@rainabba D'accord. Les monolithes hérités ne seront pas migrés facilement. Lectures intéressantes: martinfowler.com/articles/… , threedots.tech/post/microservices-or-monolith-its-detail , hackernoon.com
...
2

La première réponse est trop complexe, historique et peu informative à mon goût.


C'est en fait assez simple. Docker fournit une fonctionnalité appelée builds en plusieurs étapes, l'idée de base ici est de,

  • Vous évitez d'avoir à supprimer manuellement ce que vous ne voulez pas, en vous obligeant à mettre ce que vous voulez en liste blanche,
  • Ressources gratuites qui seraient autrement utilisées en raison de l'implémentation de Docker.

Commençons par le premier. Très souvent, avec quelque chose comme Debian, vous verrez.

RUN apt-get update \ 
  && apt-get dist-upgrade \
  && apt-get install <whatever> \
  && apt-get clean

Nous pouvons expliquer tout cela en termes de ce qui précède. La commande ci-dessus est enchaînée afin de représenter un seul changement sans images intermédiaires requises. Si c'était écrit comme ça,

RUN apt-get update ;
RUN apt-get dist-upgrade;
RUN apt-get install <whatever>;
RUN apt-get clean;

Il en résulterait 3 images intermédiaires temporaires supplémentaires. Après l'avoir réduit à une image, il reste un problème: apt-get cleanne nettoie pas les artefacts utilisés dans l'installation. Si un responsable Debian inclut dans son installation un script qui modifie le système, cette modification sera également présente dans la solution finale (voir quelque chose comme pepperflashplugin-nonfreepour un exemple de cela).

En utilisant une construction en plusieurs étapes, vous bénéficiez de tous les avantages d'une seule action modifiée, mais cela vous obligera à mettre manuellement sur liste blanche et à copier les fichiers qui ont été introduits dans l'image temporaire en utilisant la COPY --fromsyntaxe documentée ici. De plus, c'est une excellente solution là où il n'y a pas d'alternative (comme une apt-get clean), et vous auriez autrement beaucoup de fichiers inutiles dans votre image finale.

Voir également

Evan Carroll
la source
merci mais je ne vois pas comment vous abordez mon problème. pour moi, FROM est un mécanisme d'héritage et avoir plusieurs directives signifie que je peux hériter de plusieurs parents. dans votre réponse, vous ne faites aucune mention de FROM ou du concept de tirer parti de l'empaquetage de logiciels par d'autres
ekkis
1
C'est peut-être la confusion. FROMest principalement une déclaration d'espace de noms. Le qualificatif là-bas ressemble plus à une extension qu'à un héritage. Vous pouvez déclarer plusieurs espaces de noms. Et chacun de ces espaces de noms peut étendre un autre espace de noms. @ekkis Si l'autre réponse fonctionne pour vous, alors respectez-la.
Evan Carroll le