Writing Dockerfile

Tweet about this on Twitter0Share on Facebook24Share on Google+8Share on LinkedIn5

In my last post about docker you could see how easily you can spin up WordPress from docker: http://www.techbar.me/wordpress-docker/

Here I will talk about some notes on writing Dockerfiles. Writing Dockerfile isn’t an complex job, but there are some tips and best practices to get best from Docker. I already created bunch of Dockerfile examples and you can find them here: https://github.com/komljen/dockerfile-examples

Dockerfiles

Each line in Dockerfile is a new layer which means if some layer isn’t cached, all steps after that one will generate a new layer. If you look at my Dockerfile examples on github, you will see that I put ADD operation almost at the end of the Dockerfile and I’m using it just in last layers. For example, if I add this operation to ubuntu Dockerfile I would brake all caching at upstream images. See below.

Image layers

Use image layers whenever you can. This picture illustrates how image layers look like:

image_layers

From this example if I need new nodejs application I can just start from komljen/nodejs image (Dockerfile – FROM komljen/nodejs). This will speed up process of building new image as I already have
Ubuntu with latest updates and nodejs installed. Also it is easier to do troubleshooting if images are divided into small pieces.

Environment variables

For better understanding I will start from MySQL container example. I will set USER and PASS variables in MySQL Dockerfile:

After I link application container to mysql container (-link mysql:mysql) I will have those variables. Then I can easily create new database from application container:

Or, if I need some environment variable to be available in all containers I can just put it in Ubuntu Dockerfile:

Volumes

With volumes you can simply share directories between containers or mount directory from docker host. To use this feature you need to add VOLUME operation:

somewhere in your Dockerfile. It will also automatically create new directory if doesn’t exists. Then when some container with volume is running, you can start new container with -volumes-from option:

After you are in the new container, you can go to /data/app directory and make changes there or add some files.

Links

Link feature is introduced with Docker 0.6.5 and more about it you can find on official Docker website. The main problem here could be when you are using bash wrapper script to start multiple containers. Usually, if you have some database backend, that container will start first and application container will link to it. For example, I will use hipache container which is using redis as a backend. My wrapper script will start redis container and than hipache. But starting redis container doesn’t mean that the redis service is started immediately or is ready to accept connections. Simple solution is to make start.sh script in application container and before starting hipache check if redis is running on it’s port:

Hipache example: https://github.com/komljen/dockerfile-examples#hipache-example

If you have some tip on writing Dockerfiles or I did something wrong in my examples feel free to leave a comment or send me a pull request on github.

Tweet about this on Twitter0Share on Facebook24Share on Google+8Share on LinkedIn5
Posted in Useful tips and tagged , .

Alen Komljen

I'm a DevOps/Cloud engineer with experience that spans a broad portfolio of skills, including cloud computing, software deployment, process automation, shell scripting and configuration management, as well as Agile development and Scrum. This allowed me to excel in solving challenges in cloud computing, and the entire IT infrastructure along with my deep interest in OpenStack, Ceph, Docker and the open-source community.

  • Pingback: Tips on Writing Dockerfiles | Enjoying The Moment()

  • jfkw

    Thanks for the article, very informative. Can you expand on the phrase “Ubuntu with latest updates” referring to the komljen/ubuntu layer:

    – What is the workflow (e.g. stopping docker before, committing after?) when you decide it is time to apply new updates to the ubuntu:precise base image as specified in:

    https://github.com/komljen/docker/blob/master/ubuntu/Dockerfile#L14

    – Do the derived images see those updates the next time they are started?

    – If so, are derived images considered changed by docker, even though their own layer has not changed? If so, would that changed status require, a new commit for each layer?

    The specific, likely-to-happen scenario I’m wondering about is configuration under /etc for hypothetical software ‘foo’ that does not support leaving the default config untouched, allowing the user to use a /etc/foo/foo.d directory for isolated default overrides. A package update causes that config to change, requiring edits just to stay current with the upstream changes. Does that change in the base layer mark all the derived layers as changed?

    Thanks again for the article,

    Jeff