Human → Computer

Building Plone Docker images with S2I

written by Patrick Gerken on 2017-10-13

Docker images with Dockerfile

Many Paintings of different size on a wall
Painting under public domain

When you want to package a Plone or Pyramid project as a Docker image, you usually write a Dockerfile. If you work on many projects, you will, over time, have many different Dockerfiles with only minor differences. Just like with your buildout configs1.

You now have many beautiful Dockerfiles, but they are all different.

Docker images with S2I

When you use S2I to package your project into a Docker image, you run the S2I command and tell him which build image to use with which repository.

The build images and your project must follow some conventions and then it builds everything without the need to configure anything.

Red Hat provides build-images for the most common programming languages and their most common build sysem.

Buildout is not one of them.

Using S2I with buildout

For testing purposes I wrote a builder image that supports buildout.

Before you can play with it, follow the instructions to install S2I.

Next, create new directory with a single file named buildout.cfg:

parts = instance
extends =
versions = versions

recipe = plone.recipe.zope2instance
eggs =
user = admin:admin
event-log = disable
z2-log = disable

Finally, build your project:

$s2i build -c . do3cc/buildout-centos7 minimal-build

That is it, you have a working Docker image with Plone inside:

$docker run --interactive --tty --rm \
    --publish 8080:8080 \

If you access http://localhost:8080, you will now get asked to create a Plone site. Don't do that just yet.

Before you do that, let us prepare a persistent zope storage.

Plone assumes that on startup there are already the necessary directories for storing data, and the zope2instance recipe created this structure, in our image.

Let us extract that structure:

$docker run --interactive --tty --rm \
    minimal-build \
    tar cf - var | tar xf -

Start a new container again, this time with the file system::

$docker run --interactive --tty --rm \
    --publish 8080:8080 --volume=$(PWD)/var:/opt/app-root/src/var \

Now create a Plone site, then stop and start the docker container again. While the --rm flag ensured that our container got deleted, the volume still contains our data.

Inspect the generated image

Looking into the var directory you just mounted into the container, you'll notice that no log files were generated.

Docker can handle logs for you, if you send them to stdout. You are doing this. See for more information.

Let us inspect the docker image itself:

$docker run --interactive --tty --rm \
    minimal-build \

My name is default, that certainly isn't root. Your container will never run as root and has no sudo permissions.

When you inspect the docker images, you notice the size is huge:

$docker inspect do3cc/buildout-centos7
$docker insepct minimal-build

Our builder image is 750 MB in size, our Plone image 1.1 GB.

Our image still contains the whole requirements to build our Plone site.

S2I allows to specify a different Runtime image for running your app. This can make the image a bit smaller, but not much. It can help with security though. So if this is important for you, you might want to check out the documenation about runtime-image


You can have easily comparable buildout configs by using templates like the Starzel buildout structure, together with the normalize_buildout tool from the buildout-helpers package. Which you really should </shameless plug>