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.