Docker Community Forums

Share and learn in the Docker community.

Explicit gestion of layers Dockerfile

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…
1 Like

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

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.

I’d like to have that feature, too.

Because for now it is pretty hard to create minimized images when the build process produces a lot of temporary data (eg. apt cache, temporary downloads, etc).

I could live with some cmdline or Dockerfile instruction that squashes all layers into (except those inherited by FROM) into one.

–mtx