Docker Community Forums

Share and learn in the Docker community.

Explicit gestion of layers Dockerfile


(Dorian Amouroux) #1

An idea I got in my mind since a little while.

Every time you build an image from a Dockerfile, each instruction will create a new layer. That’s a great way to leverage caching and reusability of layers amongst different projects.

However, keeping the number of layers small can be a bit challenging. For instance, if you need to install multiple shell commands, you need to call RUN for each command, leading to a significant number of addition and unnecessary layers. You can separate each command with ; or &&, to have all your commands in one unique layers, making it harder to read and maintain.

Example for the Docker Whalesay (https://hub.docker.com/r/docker/whalesay/)

FROM ubuntu:14.04

# install cowsay, and move the "default.cow" out of the way so we can overwrite it with "docker.cow"
RUN apt-get update && apt-get install -y cowsay --no-install-recommends && rm -rf /var/lib/apt/lists/* \
    && mv /usr/share/cowsay/cows/default.cow /usr/share/cowsay/cows/orig-default.cow

# ...

My idea would be to wrap RUN commands inside blocks, defining explicitly what the layer is.

It would give something like this:

FROM ubuntu:14.04

LAYER # Create one single layer
RUN apt-get update
RUN apt-get install -y cowsay --no-install-recommends
RUN rm -rf /var/lib/apt/lists/
RUN mv /usr/share/cowsay/cows/default.cow /usr/share/cowsay/cows/orig-default.cow
ENDLAYER # End of the layer

or

FROM ubuntu:14.04

LAYER # Create one single layer
|RUN apt-get update
|RUN apt-get install -y cowsay --no-install-recommends
|RUN rm -rf /var/lib/apt/lists/
|RUN mv /usr/share/cowsay/cows/default.cow /usr/share/cowsay/cows/orig-default.cow
RUN echo "I'm not part of the layer because I don't start with a pipe"

This will allow more readable images, easier to write, read and maintain. I think it would be also useful to have this idea for CP or ADD.

Some images in which this would help (sorry can’t copy the links as I’m new user):

  • MariaDB
  • MongoDB
  • Redis
  • Ruby
  • Most of the official images…

(Psoaresgqls) #2

I’d add to that that it would be nice to be able to give some kind of human readable identifier to a layer so we can pull it into other Dockerfiles.

Something like:
-Dockerfile 1

FROM ubuntu:14.04
LAYER foo/bar/baz
|RUN apt-get update
|RUN apt-get install -y cowsay --no-install-recommends
|RUN rm -rf /var/lib/apt/lists/
|RUN mv /usr/share/cowsay/cows/default.cow /usr/share/cowsay/cows/orig-default.cow

-Dockerfile 2

FROM ubuntu:14.04
ADDLAYER foo/bar/baz

(David Maze) #3

That’s exactly what the standard Docker image tag is. If you docker build -t firstimage something, then your second image can begin FROM firstimage and it will pick up where the first Dockerfile left off.

Syntactically, I tend to write my Dockerfiles like

RUN apt-get update \
 && apt-get install -y --no-install-recommends cowsay \
 && ...

which isn’t too far off the proposed syntax.