Docker, Swimming with Dockerfile

Docker has kept me excited for this long, means there is something very nice about it. They have managed to keep things very simple at the core giving you the tools create a plethora of some swanky containers. So my next adventure was to take docker experience to the next level. To create an application packaged container; I chose Redis for this.

There are several ways to do this. I will leave the simple way, of launching a docker base container, installing redis on top of it, committing it as a new image and reluanching it with redis-server as the command to run, to the official docs to talk about. I would rather tell you an even simpler way of doing this using a “Dockerfile”.

Dockefile is a definition file of how to go about creating container image. I feel it is the most flexible yet consistent way of creating a required image with all the required packages installed and bundled into it. All you need is a base image to start FROM. Then you would specify the set of commands you would need to RUN to shape the container, that install required packages. Optionally you would want to ADD your custom configurations for redis to use. And then specify the port your like to EXPOSE for public access. Finally, set the ENTRYPOINT to your instance. Considering all this my Dockerfile looks like this

FROM ubuntu
RUN apt-get install -y python-software-properties
RUN add-apt-repository -y ppa:chris-lea/redis-server
RUN apt-get update -y
RUN apt-get install -y redis-server
ADD https://gist.github.com/samof76/6666627/raw/d7e302a06ac1c00a2c1831d5b66ce2c885c5f141/redis.conf /etc/redis/
RUN service redis-server restart
EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server"]

Let me expand what I had explained before.

Each line of the Dockerfile consists of an Instruction and a set of Arguments. Instructions are always in uppercase to differentiate from the Arguments.

The first non comment statement should be a FROM, that specify which is the base image to build your image up. In my Dockerfile this is “ubuntu”.

The FROM is followed by a set of RUN statements, which could be as many as possible, specifying how setup the redis ppa and install redis-server.

The ADD statement pulls a file specified by an url(the first argument) into the specified directory(the second argument). In my case this is to overwrite the default configuration with my custom redis configuration.

ADD is followed again by the a RUN that restarts the redis-server service. 

To make your redis accessible to public applications or client we EXPOSE its port.

The ENTRYPOINT dicrective completes our intention of running this container as redis-server. There can be only one ENTRYPOINT per Dockerfile; even if multiple ENTRYPOINT’s are specified the the last entry will override the rest.

This ends my Dockerfile specific. Now its time to build an image from the Dockerfile. If you have named your Dockerfile “Dockerfile” run the following from the directory that holds it.

root@precise64 ~/docker# docker build -t samof76/redis-server .
Uploading context 10240 bytes
Step 1 : FROM ubuntu
 ---> 8dbd9e392a96
Step 2 : RUN apt-get install -y python-software-properties
 ---> Running in f486ce368613
...
 ---> 1defd6dffdf9
Step 3 : RUN add-apt-repository -y ppa:chris-lea/redis-server
 ---> Running in dff5338313e8
...
 ---> 3de32a03f971
Step 4 : RUN apt-get update -y
 ---> Running in a9d454d49d0e
...
 ---> 80e88c8a202f
Step 5 : RUN apt-get install -y redis-server
 ---> Running in 103767e198f3
...
 ---> 75c34ce500d8
Step 6 : ADD https://gist.github.com/samof76/6666627/raw/d7e302a06ac1c00a2c1831d5b66ce2c885c5f141/redis.conf /etc/redis/
 ---> 3998156a8386
Step 7 : RUN service redis-server restart
 ---> Running in 187a57c0a790
Stopping redis-server: redis-server.
Starting redis-server: redis-server.
 ---> eeeb1a570780
Step 8 : EXPOSE 6379
 ---> Running in 39b8acc60570
 ---> 19def405be09
Step 9 : ENTRYPOINT ["/usr/bin/redis-server"]
 ---> Running in 72031a4a2277
 ---> 8ca6a0bc3446
Successfully built 8ca6a0bc3446

Well you could see that redis-server image is built and ready to serve. Simple! You could in above output snippet every step of the Dockerfile getting executed. If the Dockerfile is not named so, you need explicitly pass the filename to the build command.

The other thing to note in the above output is that every RUN instruction does commit a new image. Thus using that image to build on for the next command. This ensures that if step fails the correction and rebuild will start form the previous successful commit rather than running the entire build process again.

Let us list and see the image that we just created

root@precise64 ~/docker#
# docker images
REPOSITORY             TAG                 ID                  CREATED             SIZE
samof76/redis-server   latest              8ca6a0bc3446        10 minutes ago      12.29 kB (virtual 240.6 MB)
ubuntu                 12.04               8dbd9e392a96        5 months ago        131.5 MB (virtual 131.5 MB)
ubuntu                 latest              8dbd9e392a96        5 months ago        131.5 MB (virtual 131.5 MB)
ubuntu                 precise             8dbd9e392a96        5 months ago        131.5 MB (virtual 131.5 MB)
ubuntu                 12.10               b750fe79269d        6 months ago        24.65 kB (virtual 180.1 MB)
ubuntu                 quantal             b750fe79269d        6 months ago        24.65 kB (virtual 180.1 MB)

Now is the time to run samof76/redis-server as a docker container.

root@precise64 ~/docker# docker run -d -h=redis-server samof76/redis-server
b96207c3a97f
root@precise64 ~/docker# docker ps        
ID                  IMAGE                         COMMAND                CREATED             STATUS              PORTS
b96207c3a97f        samof76/redis-server:latest   /usr/bin/redis-serve   15 seconds ago      Up 14 seconds       49153->6379 

Note that we have not specified the what to run on the instance at start because the ENTRYPOINT instruction took care of that. -d specifies to run the container in the background.

Also note the “ps” listing that the redis-server is running with the entry point specified. And all there is localhost port, 49153, is setup with redirection ready. All that remains is to test by firing up a redis client to connect on that port(make sure the redis-cli installed locally)

root@precise64 ~/docker# redis-cli -p 49153
redis 127.0.0.1:49153> set name sam
OK
redis 127.0.0.1:49153> set age 37
OK

I hope this will get you started with the using Dockerfile to create your docker images. I had great fun writing this, I hope you will have great fun writing a Dockerfile.

Show Comments