Tenemos el siguiente bloque en nuestro Dockerfile
:
RUN yum -y update
RUN yum -y install epel-release
RUN yum -y groupinstall "Development Tools"
RUN yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel
Me han dicho que deberíamos unir estos RUN
comandos para reducir las capas acopladas creadas:
RUN yum -y update \
&& yum -y install epel-release \
&& yum -y groupinstall "Development Tools" \
&& yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel
Soy muy nuevo en Docker y no estoy seguro de entender completamente las diferencias entre estas dos versiones de especificar múltiples comandos RUN. ¿Cuándo uniría los RUN
comandos en uno solo y cuándo tiene sentido tener múltiples RUN
comandos?
docker
dockerfile
alecxe
fuente
fuente
Respuestas:
Una imagen acoplable es en realidad una lista vinculada de capas del sistema de archivos. Cada instrucción en un Dockerfile crea una capa del sistema de archivos que describe las diferencias en el sistema de archivos antes y después de la ejecución de la instrucción correspondiente. El
docker inspect
subcomando se puede usar en una imagen acoplable para revelar su naturaleza de ser una lista vinculada de capas del sistema de archivos.El número de capas utilizadas en una imagen es importante.
Esto tiene varias consecuencias sobre cómo se deben construir las imágenes. El primer y más importante consejo que puedo dar es:
La razón de esto es que todos los pasos anteriores se almacenarán en caché y no será necesario descargar las capas correspondientes una y otra vez. Esto significa compilaciones más rápidas y lanzamientos más rápidos, que es probablemente lo que desea. Curiosamente, es sorprendentemente difícil hacer un uso óptimo de la memoria caché del acoplador.
Mi segundo consejo es menos importante, pero lo encuentro muy útil desde el punto de vista del mantenimiento:
Un Dockerfile siguiendo este consejo sería
y así. El consejo de vincular varios comandos
&&
solo tiene un alcance limitado. Es mucho más fácil escribir con scripts, donde puede usar funciones, etc. para evitar redundancias o con fines de documentación.Las personas interesadas por los preprocesadores y dispuestos a evitar los pequeños gastos generales causados por los
COPY
pasos y en realidad están generando sobre la marcha un Dockerfile donde ellas secuencias son reemplazadas por
donde
…
es la versión codificada en base64 deapt_setup.sh
.Mi tercer consejo es para las personas que desean limitar el tamaño y el número de capas al posible costo de construcciones más largas.
Un archivo agregado por alguna instrucción acoplable y eliminado por alguna instrucción posterior no está presente en el sistema de archivos resultante, pero se menciona dos veces en las capas acoplables que constituyen la imagen del acoplador en la construcción. Una vez, con el nombre y el contenido completo en la capa resultante de la instrucción que lo agrega, y una vez como un aviso de eliminación en la capa resultante de la instrucción que lo elimina.
Por ejemplo, supongamos que necesitamos temporalmente un compilador de C y alguna imagen y considere el
(Un ejemplo más realista construiría algún software con el compilador en lugar de simplemente afirmar su presencia con la
--version
bandera).El fragmento de Dockerfile crea tres capas, la primera contiene el paquete completo de gcc, de modo que incluso si no está presente en el sistema de archivos final, los datos correspondientes siguen siendo parte de la imagen de la misma manera y deben descargarse, cargarse y desempacarse siempre que La imagen final es.
El
with
-idiom es una forma común en la programación funcional para aislar la propiedad del recurso y la liberación del recurso de la lógica que lo usa. Es fácil transponer este modismo al scripting de shell, y podemos reformular los comandos anteriores como el siguiente script, para usarloCOPY & RUN
como en el Consejo # 2.Los comandos complejos se pueden convertir en funciones para que se puedan alimentar al
with_c_compiler
. También es posible encadenar llamadas de variaswith_whatever
funciones, pero tal vez no sea muy deseable. (Usando características más esotéricas del shell, ciertamente es posible hacer que loswith_c_compiler
comandos complejos sean aceptados, pero es preferible en todos los aspectos incluir estos comandos complejos en funciones).Si queremos ignorar el Consejo # 2, el fragmento de Dockerfile resultante sería
que no es tan fácil de leer y mantener debido a la ofuscación. Vea cómo la variante shell-script
gcc --version
resalta la parte importante mientras que la&&
variante encadenada entierra esa parte en medio del ruido.fuente
Cada instrucción que cree en su Dockerfile da como resultado que se cree una nueva capa de imagen. Cada capa trae datos adicionales que no siempre son parte de la imagen resultante. Por ejemplo, si agrega un archivo en una capa, pero lo elimina en otra capa más tarde, el tamaño de la imagen final incluirá el tamaño del archivo agregado en forma de un archivo especial "blanco" aunque lo haya eliminado.
Digamos que tiene el siguiente Dockerfile:
El tamaño de la imagen resultante será
Como opuesto, con Dockerfile "similar":
El tamaño de la imagen resultante será
Obtendrá un tamaño aún más pequeño si limpia la memoria caché de yum en una sola instrucción RUN.
Por lo tanto, desea mantener el equilibrio entre la legibilidad / facilidad de mantenimiento y el número de capas / tamaño de imagen.
fuente
Las
RUN
declaraciones representan cada una de las capas. Imagine que uno descarga un paquete, lo instala y desea eliminarlo. Si uno usa tresRUN
declaraciones, el tamaño de la imagen no se reducirá, ya que hay capas separadas. Si uno ejecuta todos los comandos usando unaRUN
instrucción, el tamaño de la imagen del disco podría reducirse.fuente