Varios FROM: lo que significa

112

Quiero crear una imagen de la ventana acoplable para el proyecto Linkurious en github, que requiere tanto la base de datos Neo4j como Node.js para ejecutarse.

mi primer enfoque fue declarar una imagen base para mi imagen, que contiene Neo4j. Los documentos de referencia no definen "imagen base" de ninguna manera útil:

Imagen base: una imagen que no tiene padre es una imagen base

del cual leí que solo puedo tener una imagen base si esa imagen no tiene una imagen base en sí.

pero ¿qué es una imagen base? ¿Significa que si declaro neo4j / neo4j en una directiva FROM, cuando se ejecute mi imagen, la base de datos neo se ejecutará automáticamente y estará disponible dentro del contenedor en el puerto 7474?

leyendo la referencia de Docker (ver: https://docs.docker.com/reference/builder/#from ) veo:

FROM puede aparecer varias veces dentro de un solo Dockerfile para crear varias imágenes. Simplemente tome nota de la última ID de imagen generada por la confirmación antes de cada nuevo comando FROM.

¿Quiero crear varias imágenes? parece que lo que quiero es tener una sola imagen que contenga el contenido de otras imágenes, por ejemplo, neo4j y node.js

No encontré ninguna directiva para declarar dependencias en el manual de referencia. ¿No hay dependencias como en RPM donde para ejecutar mi imagen, el contexto de llamada debe instalar primero las imágenes que necesita?

Estoy confundido...

ekkis
fuente
Nota: Mayo de 2017, ahora tiene múltiples FROMen un Dockerfile. Vea mi respuesta editada a continuación.
VonC
Vea si encuentra mi respuesta más limpia. Y si es así, considere aceptarlo.
Evan Carroll

Respuestas:

113

¿Qué es una imagen base?

Un conjunto de archivos, más EXPOSE'd ports ENTRYPOINTy CMD.
Puede agregar archivos y crear una nueva imagen basada en esa imagen base, con un nuevo Dockerfilecomienzo con una FROMdirectiva: la imagen que se menciona después FROMes "la imagen base" para su nueva imagen.

¿Significa que si declaro neo4j/neo4jen una FROMdirectiva, que cuando se ejecute mi imagen, la base de datos neo se ejecutará automáticamente y estará disponible dentro del contenedor en el puerto 7474?

Solo si no sobrescribe CMDy ENTRYPOINT.
Pero la imagen en sí misma es suficiente: usaría un FROM neo4j/neo4jsi tuviera que agregar archivos relacionados neo4jpara su uso particular de neo4j.

FROM puede aparecer varias veces dentro de un solo Dockerfile

No: hay una propuesta para eliminar esa "función" de todos modos ( problema 13026 )

El número 14412 menciona:

El uso de múltiples FROMno es realmente una característica sino un error (bueno, el límite es estrecho y hay pocos casos de uso para múltiples FROMen un Dockerfile).


Actualización de mayo de 2017 (18 meses después), con Docker (moby) 17.05-ce .

Se pueden usar varios FROM en un solo Dockerfile.
Consulte " Patrón de constructor frente a compilaciones de varias etapas en Docker " (por Alex Ellis ) y PR 31257 por Tõnis Tiigi .

Antes de:

El patrón del constructor implica el uso de dos imágenes de Docker: una para realizar una compilación y otra para enviar los resultados de la primera compilación sin la penalización de la cadena de compilación y las herramientas en la primera imagen.

Después:

La sintaxis general implica agregar FROMtiempos adicionales dentro de su Dockerfile; la última FROMdeclaración es la imagen base final. Para copiar artefactos y resultados de imágenes intermedias, use COPY --from=<base_image_number>.

Primera parte del 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 .

Segunda parte del mismo (!) 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"]  

El resultado serían dos imágenes, una para la construcción, otra con solo la aplicación resultante (mucho, mucho más pequeña)

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

multi               latest              bcbbf69a9b59        6 minutes ago       10.3MB  
golang              1.7.3               ef15416724f6        4 months ago        672MB  
VonC
fuente
2
lástima por eliminar varios FROM. me parece más útil, sobre todo en ausencia de un mecanismo de dependencia. con RPM, por ejemplo, puedo declarar que mi paquete necesita otro paquete para ejecutarse, así que en el momento de la instalación todo se configura para mí. la realidad es que casi todo requerirá múltiples dependencias, así que en ausencia de múltiples FROM, ¿cómo se supone que funcione?
ekkis
3
@ekkis como mencioné en mi respuesta anterior ( stackoverflow.com/a/33295292/6309 ), usted ejecuta su sistema organizando múltiples contenedores, cada uno brindando un servicio particular y comunicándose a través de --link ( docs.docker.com/ userguide / dockerlinks /… ).
VonC
2
@VonC Claro, en un mundo ideal, con una nueva aplicación y todos los patrones entendidos. Mientras tanto, espero que haya más casos de personas que intenten migrar sus soluciones a la ventana acoplable y tengan necesidades que no se resuelvan mediante la red, como las dependencias de software, todas usando una base compatible, pero DESDE varios Dockerfiles. En cambio, lo mejor que he podido descubrir hasta ahora es hackear sus Dockerfiles para crear los míos.
rainabba
@rainabba De acuerdo. Los monolitos heredados no se migrarán fácilmente. Lecturas interesantes: martinfowler.com/articles/… , threedots.tech/post/microservices-or-monolith-its-detail , hackernoon.com/…
VonC
2

La primera respuesta es demasiado compleja, histórica y poco informativa para mi gusto.


En realidad, es bastante simple. Docker proporciona una funcionalidad llamada compilaciones de múltiples etapas, la idea básica aquí es,

  • Libérate de tener que eliminar manualmente lo que no quieres, obligándote a incluir en la lista blanca lo que sí quieres.
  • Recursos gratuitos que de otro modo se utilizarían debido a la implementación de Docker.

Empecemos por el primero. Muy a menudo con algo como Debian verá.

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

Podemos explicar todo esto en términos de lo anterior. El comando anterior está encadenado, por lo que representa un único cambio sin imágenes intermedias requeridas. Si estuviera escrito así,

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

El resultado sería 3 imágenes intermedias temporales más. Habiéndolo reducido a una imagen, queda un problema restante: apt-get cleanno limpia los artefactos utilizados en la instalación. Si un mantenedor de Debian incluye en su instalación un script que modifica el sistema, esa modificación también estará presente en la solución final (vea algo así como pepperflashplugin-nonfreeun ejemplo de eso).

Al usar una compilación de múltiples etapas, obtiene todos los beneficios de una sola acción modificada, pero requerirá que ingrese manualmente en la lista blanca y copie los archivos que se introdujeron en la imagen temporal utilizando la COPY --fromsintaxis documentada aquí. Además, es una gran solución donde no hay alternativa (como una apt-get clean), y de lo contrario tendría muchos archivos innecesarios en su imagen final.

Ver también

Evan Carroll
fuente
gracias, pero no veo cómo está abordando mi problema. para mí, FROM es un mecanismo de herencia y tener varias directivas significa que puedo heredar de varios padres. en su respuesta, no menciona FROM o el concepto de aprovechar el paquete de software por parte de otros
ekkis
1
Quizás esa sea la confusión. FROMes principalmente una declaración de espacio de nombres. El calificativo se parece más a una extensión que a una herencia. Puede declarar varios espacios de nombres. Y cada uno de esos espacios de nombres puede ampliar otro espacio de nombres. @ekkis Si la otra respuesta funciona para usted, entonces quédese con ella.
Evan Carroll