¿Cómo evitar la reinstalación de paquetes al crear una imagen de Docker para proyectos de Python?

Mi Dockerfile es algo como

FROM my/base ADD . /srv RUN pip install -r requirements.txt RUN python setup.py install ENTRYPOINT ["run_server"] 

Cada vez que construyo una nueva imagen, es necesario reinstalar las dependencias, lo que podría ser muy lento en mi región.

Una forma en la que pienso para cache en cache paquetes que se han instalado es anular la imagen my/base con imágenes más nuevas como esta:

 docker build -t new_image_1 . docker tag new_image_1 my/base 

Así que la próxima vez que compile con este Dockerfile, mi / base ya tiene algunos paquetes instalados.

Pero esta solución tiene dos problemas:

  1. No siempre es posible anular una imagen base
  2. La imagen base crece cada vez más a medida que se superponen imágenes nuevas.

Entonces, ¿qué mejor solución podría usar para resolver este problema?

EDITAR##:

Alguna información sobre la ventana acoplable en mi máquina:

 ☁ test docker version Client version: 1.1.2 Client API version: 1.13 Go version (client): go1.2.1 Git commit (client): d84a070 Server version: 1.1.2 Server API version: 1.13 Go version (server): go1.2.1 Git commit (server): d84a070 ☁ test docker info Containers: 0 Images: 56 Storage Driver: aufs Root Dir: /var/lib/docker/aufs Dirs: 56 Execution Driver: native-0.2 Kernel Version: 3.13.0-29-generic WARNING: No swap limit support 

Trate de construir con debajo de Dockerfile.

 FROM my/base WORKDIR /srv ADD ./requirements.txt /srv/requirements.txt RUN pip install -r requirements.txt ADD . /srv RUN python setup.py install ENTRYPOINT ["run_server"] 

Si hay algunos cambios en . (su proyecto), docker omita la línea de pip install usando caché.

Docker solo ejecuta pip install en la comstackción cuando edita el archivo Requirements.txt.


Escribo simple Hello, World! progtwig.

 $ tree . ├── Dockerfile ├── requirements.txt └── run.py 0 directories, 3 file # Dockerfile FROM dockerfile/python WORKDIR /srv ADD ./requirements.txt /srv/requirements.txt RUN pip install -r requirements.txt ADD . /srv CMD python /srv/run.py # requirements.txt pytest==2.3.4 # run.py print("Hello, World") 

A continuación se muestra la salida.

 Step 1 : WORKDIR /srv ---> Running in 22d725d22e10 ---> 55768a00fd94 Removing intermediate container 22d725d22e10 Step 2 : ADD ./requirements.txt /srv/requirements.txt ---> 968a7c3a4483 Removing intermediate container 5f4e01f290fd Step 3 : RUN pip install -r requirements.txt ---> Running in 08188205e92b Downloading/unpacking pytest==2.3.4 (from -r requirements.txt (line 1)) Running setup.py (path:/tmp/pip_build_root/pytest/setup.py) egg_info for package pytest .... Cleaning up... ---> bf5c154b87c9 Removing intermediate container 08188205e92b Step 4 : ADD . /srv ---> 3002a3a67e72 Removing intermediate container 83defd1851d0 Step 5 : CMD python /srv/run.py ---> Running in 11e69b887341 ---> 5c0e7e3726d6 Removing intermediate container 11e69b887341 Successfully built 5c0e7e3726d6 

Actualizo solo run.py y trato de construir de nuevo.

 # run.py print("Hello, Python") 

A continuación se muestra la salida.

 Sending build context to Docker daemon 5.12 kB Sending build context to Docker daemon Step 0 : FROM dockerfile/python ---> f86d6993fc7b Step 1 : WORKDIR /srv ---> Using cache ---> 55768a00fd94 Step 2 : ADD ./requirements.txt /srv/requirements.txt ---> Using cache ---> 968a7c3a4483 Step 3 : RUN pip install -r requirements.txt ---> Using cache ---> bf5c154b87c9 Step 4 : ADD . /srv ---> 9cc7508034d6 Removing intermediate container 0d7cf71eb05e Step 5 : CMD python /srv/run.py ---> Running in f25c21135010 ---> 4ffab7bc66c7 Removing intermediate container f25c21135010 Successfully built 4ffab7bc66c7 

Como se puede ver arriba, la ventana acoplable utiliza la memoria caché. Y actualizo Requirements.txt esta vez.

 # requirements.txt pytest==2.3.4 ipython 

A continuación se muestra la salida.

 Sending build context to Docker daemon 5.12 kB Sending build context to Docker daemon Step 0 : FROM dockerfile/python ---> f86d6993fc7b Step 1 : WORKDIR /srv ---> Using cache ---> 55768a00fd94 Step 2 : ADD ./requirements.txt /srv/requirements.txt ---> b6c19f0643b5 Removing intermediate container a4d9cb37dff0 Step 3 : RUN pip install -r requirements.txt ---> Running in 4b7a85a64c33 Downloading/unpacking pytest==2.3.4 (from -r requirements.txt (line 1)) Running setup.py (path:/tmp/pip_build_root/pytest/setup.py) egg_info for package pytest Downloading/unpacking ipython (from -r requirements.txt (line 2)) Downloading/unpacking py>=1.4.12 (from pytest==2.3.4->-r requirements.txt (line 1)) Running setup.py (path:/tmp/pip_build_root/py/setup.py) egg_info for package py Installing collected packages: pytest, ipython, py Running setup.py install for pytest Installing py.test script to /usr/local/bin Installing py.test-2.7 script to /usr/local/bin Running setup.py install for py Successfully installed pytest ipython py Cleaning up... ---> 23a1af3df8ed Removing intermediate container 4b7a85a64c33 Step 4 : ADD . /srv ---> d8ae270eca35 Removing intermediate container 7f003ebc3179 Step 5 : CMD python /srv/run.py ---> Running in 510359cf9e12 ---> e42fc9121a77 Removing intermediate container 510359cf9e12 Successfully built e42fc9121a77 

Y la ventana acoplable no utiliza la memoria caché de comstackción. Si no funciona, revisa la versión de tu docker.

 Client version: 1.1.2 Client API version: 1.13 Go version (client): go1.2.1 Git commit (client): d84a070 Server version: 1.1.2 Server API version: 1.13 Go version (server): go1.2.1 Git commit (server): d84a070 

Para minimizar la actividad de la red, puede apuntar pip a un directorio de caché en su máquina host.

Ejecute su contenedor docker con el enlace del directorio de caché pip de su host montado en el directorio de caché pip de su contenedor. docker run comando de docker run debería verse así:

 docker run -v $HOME/.cache/pip/:/root/.cache/pip image_1 

Luego, en su Dockerfile, instale sus requisitos como parte de la statement ENTRYPOINT (o statement CMD ) en lugar de como un comando RUN . Esto es importante porque (como se señaló en los comentarios) el assembly no está disponible durante la creación de la imagen (cuando se ejecutan las instrucciones RUN ). El archivo Docker debería verse así:

 FROM my/base ADD . /srv ENTRYPOINT ["sh", "-c", "pip install -r requirements.txt && python setup.py install && run_server"] 

Probablemente sea mejor si el directorio pip del sistema host se utilizará como caché (por ejemplo, $HOME/.cache/pip/ en Linux o $HOME/Library/Caches/pip/ en OSX), tal como sugerí en la docker run ejemplo docker run comando

Descubrí que una mejor manera es simplemente agregar el directorio de paquetes de sitios de Python como un volumen.

 services: web: build: . command: python manage.py runserver 0.0.0.0:8000 volumes: - .:/code - /usr/local/lib/python2.7/site-packages/ 

De esta manera, puedo instalar nuevas bibliotecas sin tener que hacer una reconstrucción completa.

EDITAR : Ignorar esta respuesta, la respuesta de jkukul anterior funcionó para mí. Mi intención era almacenar en caché la carpeta de paquetes de sitio . Eso habría parecido algo más como:

 volumes: - .:/code - ./cached-packages:/usr/local/lib/python2.7/site-packages/ 

Sin embargo, almacenar en caché la carpeta de descarga es mucho más limpio. Eso también guarda las ruedas, por lo que logra la tarea correctamente.