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
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.
Use image layers whenever you can. This picture illustrates how image layers look like:
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.
For better understanding I will start from MySQL container example. I will set USER and PASS variables in MySQL Dockerfile:
ENV USER root ENV PASS SiHRDZ3Tt13uVVyH0ZST
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:
mysql -h $MYSQL_PORT_3306_TCP_ADDR -u $MYSQL_ENV_USER -p$MYSQL_ENV_PASS < <EOF CREATE DATABASE test; GRANT ALL PRIVILEGES ON test.* TO 'test'@'%' IDENTIFIED BY 'test'; EOF
Or, if I need some environment variable to be available in all containers I can just put it in Ubuntu Dockerfile:
ENV DEBIAN_FRONTEND noninteractive
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:
docker run -i -t -volumes-from wordpress komljen/wordpress /bin/bash
After you are in the new container, you can go to /data/app directory and make changes there or add some files.
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:
until $(: < /dev/tcp/$REDIS_PORT_6379_TCP_ADDR/$REDIS_PORT_6379_TCP_PORT) do sleep 1 done
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.