¿Por qué las imágenes de contenedores Docker son tan grandes?


Hice una imagen simple a través de Dockerfile desde Fedora (inicialmente 320 MB).

Se agregó Nano (este pequeño editor de tamaño 1MB), y el tamaño de la imagen ha aumentado a 530 MB. He añadido Git encima de eso (30 MB), y luego mi tamaño de imagen sky-rockets a 830 MB.

¿No es una locura?

He intentado exportar e importar contenedores para eliminar el historial/imágenes intermedias. Este esfuerzo ahorró hasta 25 MB, ahora mi tamaño de imagen es de 804 MB. También he intentado ejecutar muchos comandos en uno RUN, pero todavía estoy recibiendo los mismos 830MB iniciales.

Estoy teniendo mis dudas si vale la pena usar Docker en absoluto. Quiero decir, apenas instalé nada y estoy golpeando 1GB más. Si voy a tener que añadir algunas cosas serias como una base de datos y así sucesivamente que podría quedarse sin espacio en disco.

Alguien sufre de tamaño ridículo de las imágenes? ¿Cómo lo lidias?

A menos que mi Dockerfile sea horriblemente incorrecto?

FROM fedora:latest
MAINTAINER Me NotYou <[email protected]>
RUN yum -y install nano
RUN yum -y install git

Pero es difícil imaginar lo que podría salir mal aquí.

 123
Author: halfer, 2014-06-24

8 answers

Como dijo @rexposadas, las imágenes incluyen todas las capas y cada capa incluye todas las dependencias para lo que instaló. También es importante tener en cuenta que las imágenes base (como fedora:latest tienden a ser muy simples. Es posible que se sorprenda por la cantidad de dependencias que tiene su software instalado.

Pude hacer su instalación significativamente más pequeña agregando yum -y clean all a cada línea:

FROM fedora:latest
RUN yum -y install nano; yum -y clean all
RUN yum -y install git; yum -y clean all

Es importante hacer eso para cada EJECUCIÓN, antes de que la capa se confirme, o de lo contrario en realidad, las eliminaciones no eliminan los datos. Es decir, en un sistema de archivos union/copy-on-write, la limpieza al final no reduce realmente el uso del sistema de archivos porque los datos reales ya están comprometidos con las capas inferiores. Para evitar esto debes limpiar en cada capa.

$ docker history bf5260c6651d
IMAGE               CREATED             CREATED BY                                      SIZE
bf5260c6651d        4 days ago          /bin/sh -c yum -y install git; yum -y clean a   260.7 MB
172743bd5d60        4 days ago          /bin/sh -c yum -y install nano; yum -y clean    12.39 MB
3f2fed40e4b0        2 weeks ago         /bin/sh -c #(nop) ADD file:cee1a4fcfcd00d18da   372.7 MB
fd241224e9cf        2 weeks ago         /bin/sh -c #(nop) MAINTAINER Lokesh Mandvekar   0 B
511136ea3c5a        12 months ago                                                       0 B
 85
Author: Andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-24 22:48:15

Las imágenes de Docker no son grandes, solo estás construyendo imágenes grandes.

La imagen scratch es 0B yd puede usarla para empaquetar su código si puede compilar su código en un binario estático. Por ejemplo, puede compilar su programa Go y empaquetarlo encima de scratch para hacer una imagen completamente utilizable que es menos de 5MB.

La clave es no usar las imágenes oficiales de Docker, son demasiado grandes. Scratch tampoco es tan práctico, así que recomiendo usar Alpine Linux como tu imagen base. Es ~5MB, luego solo agregue lo que se requiere para su aplicación. Este post sobre Microcontainers te muestra cómo construir imágenes muy pequeñas basadas en Alpine.

ACTUALIZACIÓN: las imágenes oficiales de Docker se basan en alpine ahora, por lo que son buenas para usar ahora.

 44
Author: Travis Reeder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-01 18:12:55

Sí, esos tamaños son ridículos, y realmente no tengo idea de por qué tan pocas personas lo notan.

Hice una imagen de Ubuntu que en realidad es mínima (a diferencia de otras imágenes llamadas "mínimas"). Se llama textlab/ubuntu-essential y tiene 60 MB.

FROM textlab/ubuntu-essential
RUN apt-get update && apt-get -y install nano

La imagen de arriba es de 82 MB después de instalar nano.

FROM textlab/ubuntu-essential
RUN apt-get update && apt-get -y install nano git

Git tiene muchos más requisitos previos, por lo que la imagen se hace más grande, alrededor de 192 MB. Eso es aún menos que el tamaño inicial de la mayoría de las imágenes.

También puede echar un vistazo a el script que escribí para hacer la imagen mínima de Ubuntu para Docker . Quizás pueda adaptarlo a Fedora, pero no estoy seguro de cuánto podrá desinstalar.

 18
Author: michau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-09 17:08:19

Aquí hay algunas cosas más que puedes hacer :

  • Evite múltiples comandos RUN donde pueda. Ponga tanto como possbile en un comando RUN (usando &&)
  • limpie herramientas innecesarias como wget o git (que solo necesita para descargar o construir cosas, pero no para ejecutar su proceso)

Con estos dos Y las recomendaciones de @Andy y @michau pude cambiar el tamaño de mi imagen de nodejs de 1.062 GB a 542 MB.

Editar: Uno más importante: "Me tomó un tiempo entender realmente que cada comando Dockerfile crea un nuevo contenedor con los deltas. [...] No importa si rm-rf los archivos en un comando posterior; continúan existiendo en algún contenedor de capa intermedia." Así que ahora me las arreglé para poner apt-get install, wget, npm install (con dependencias de git) y apt-get remove en un solo comando RUN, por lo que ahora mi imagen tiene solo 438 MB.

Editar 29/06/17

Con Docker v17. 06 viene un nuevo características para Dockerfiles: Puede tener varias sentencias FROM dentro de un archivo acoplable y solo las cosas de la última FROM estarán en su imagen acoplable final. Esto es útil para reducir el tamaño de la imagen, por ejemplo:

FROM nodejs as builder
WORKDIR /var/my-project
RUN apt-get install ruby python git openssh gcc && \
    git clone my-project . && \
    npm install

FROM nodejs
COPY --from=builder /var/my-project /var/my-project

Resultará en una imagen que tenga solo la imagen base de nodejs más el contenido de /var/my-project desde los primeros pasos - pero sin ruby, python, git, openssh y gcc!

 18
Author: Munchkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-29 10:38:07

Lo siguiente me ayudó mucho:

Después de eliminar los paquetes no utilizados (por ejemplo, redis 1200 mb freed) dentro de mi contenedor, he hecho lo siguiente:

  1. docker export [containerId]- o containername.tar
  2. docker import-m "commit message here" containername.nombre de imagen: tag

Las capas se aplanan. El tamaño de la nueva imagen será más pequeño porque he eliminado paquetes del contenedor como se indicó anteriormente.

Esto llevó mucho tiempo para entender esto y por eso he añadido mi comentario.

 12
Author: Jeffrey Schmitz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-25 11:21:04

Para las mejores prácticas, debe ejecutar un solo comando de ejecución, porque cada instrucción de ejecución en el Dockerfile escribe una nueva capa en la imagen y cada capa requiere espacio adicional en el disco. Con el fin de mantener el número de capas al mínimo, cualquier manipulación de archivos como instalar, mover, extraer, eliminar, etc, idealmente debe hacerse bajo una sola instrucción de ejecución

FROM fedora:latest
RUN yum -y install nano git; yum -y clean all
 5
Author: tmz83,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-30 13:51:59

Docker Squash es una solución muy buena para esto. puede $packagemanager clean en el último paso en lugar de en cada línea y luego simplemente ejecute un docker squash para deshacerse de todas las capas.

Https://github.com/jwilder/docker-squash

 4
Author: jeremyjjbrown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-26 15:42:33

Sí, el sistema de capas es bastante sorprendente. Si tiene una imagen base y la incrementa haciendo lo siguiente:

# Test
#
# VERSION       1

# use the centos base image provided by dotCloud
FROM centos7/wildfly
MAINTAINER JohnDo 

# Build it with: docker build -t "centos7/test" test/

# Change user into root
USER root

# Extract weblogic
RUN rm -rf /tmp/* \
    && rm -rf /wildfly/* 

La imagen tiene exactamente el mismo tamaño. Eso significa esencialmente, usted tiene que manejar para poner en sus pasos de EJECUCIÓN una gran cantidad de extraer, instalar y limpiar la magia para hacer que las imágenes tan pequeñas como el software instalado.

Esto hace la vida mucho más difícil...

Al dockerBuild le faltan pasos de ejecución sin confirmación.

 0
Author: 99Sono,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-16 18:10:07