Docker is a lightweight container for applications – think of a Docker as an app in a box, except that the box in this case isn’t an entire VM, but the bare necessities required to run a process. Consequently, you can run many Dockers in a VM. In essence, Docker replaces installation steps for a particular app. Rather than having to execute a series of steps to get, say, MongoDB running, you can simply fire up a Mongo Docker image.
Docker images can be created from a
Dockerfile, which is similar to a
Vagrantfile or even a build script – it’s a prescription for how to assemble an image. You don’t need to have a
Dockerfile to create a Docker image, however, creating one makes image creation repeatable. It also provides a means for others to verify an image.
There are a few key instructions you should be aware of when creating
Dockerfiles – mainly,
CMD. To demonstrate how easy this process is, I’m going to create a
Dockerfile that runs Amazon’s DynamoDB Local.
DynamoDB Local is a simple Java application that emulates AWS DynamoDB. The benefit of using DynamoDB Local is that you can iterate quickly without using bandwidth against the real DynamoDB and you’ll save a few coins in the process.
Running DynamoDB Local isn’t terribly difficult; in fact, provided you have Java installed, it’s as easy as:
1 $ java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar
Of course, if you aren’t developing a Java application and don’t have Java installed, you would need to, of course, install Java. Then you’d need to download the DynamoDB Local package and install it. And then you’d need to run it.
Alternatively, you could just
pull a Docker image,
run it, and get back to work.
Creating a Dockerfile
Dockerfile is simple. Fire up your favorite editor and follow along.
The first required element,
FROM, indicates the base image or parent from which a docker image is built upon. In many cases, this’ll be something like
centos, for example. In the case of an image for DynamoDB Local, I’m going to base it off another image that already has Oracle’s Java 8 installed. That image is based upon Ubuntu. Note, basing your
FROM off of another image implies the image is available in an accessible Docker index. You can run your own local or remote indexes or use Docker’s public index.
Consequently, the first two lines of my
1 FROM aglover/java8-pier 2 MAINTAINER Andy Glover "email@example.com"
Have a look at my java8-pier project and you’ll see its
Dockerfile has the line
FROM ubuntu. The
MAINTAINER line is self evident.
The second most important instruction of a
RUN. Think of
bash commands required to set up your Docker image. In the case of setting up DynamoDB Local, there are a few things I would like done on the image. First and foremost, I’d like to update base aspects of the underlying Ubuntu OS via an
apt-get update. Then I’d like to download the DynamoDB Local archive, however, I’d like to use
wget, which isn’t available on base Ubuntu installs, however. Consequently, I’ll install
wget while I’m at it.
1 RUN apt-get update -y 2 RUN apt-get install wget -y
Next, I’m going to
wget the latest version of DynamoDB Local via an AWS URL that points to the latest version (which obviously changes); thus, the
-O flag forces the downloaded file to the generic name of
dynamo.tar.gz (rather than something like
dynamodb_local_2014-04-24.tar.gz where the date can change depending on when AWS releases an update). Finally, after the download completes, the file is moved into a directory dubbed
1 RUN wget http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest -O dynamo.tar.gz 2 RUN tar xvzf dynamo.tar.gz && mv dynamodb_local_* dynamodb_local
Docker images, by default, don’t expose any ports through the host on which they are running. You must expose desired ports via the
EXPOSE command. In my case, DynamoDB Local defaults to port 8000; accordingly, I’ll specify in my
Dockerfile that I wish this port to be open:
1 EXPOSE 8000
Finally, as I wish to run a service via my Docker image, I need to fire it up! DynamoDB Local is simply a Java process that requires, at a minimum, two parameters. If I were to run DynamoDB Local manually, the corresponding command would be:
1 $ java -Djava.library.path=./dynamodb_local/DynamoDBLocal_lib -jar ./dynamodb_local/DynamoDBLocal.jar
Consequently, to execute this command in a
Dockerfile I’ll need to use the
CMD instruction (which is probably the most important instruction for creating Dockers!). This instruction takes an array of values – logically, just take the corresponding manual command and tokenize it by a space and you’ve got your
1 CMD ["java", "-Djava.library.path=./dynamodb_local/DynamoDBLocal_lib", "-jar", "./dynamodb_local/DynamoDBLocal.jar"]
That’s it – eight lines and you’ve got a
Dockerfile that’ll yield Docker image running DynamoDB Local as a service.
Creating images from Dockerfiles
Dockerfile I can now create an image via the
build command. Thus, in a terminal window, I’ll change directories to where I’ve saved my
Dockerfile and run the following:
1 $ docker build -t aglover/dynamodb-pier .
aglover/dynamodb-pier is the desired name of my image. After you run this command, you will see a whole lot of commands executed, including the ones specified in your
Dockerfile. Once things finish successfully, you should be able to see the resultant image via the
1 $ docker images 2 REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE 3 aglover/dynamodb-pier latest aa51ccc5dc3f 14 seconds ago 1.089 GB 4 aglover/java8-pier latest cb8436bb816a 4 weeks ago 1.026 GB 5 base latest b750fe79269d 13 months ago 175.3 MB 6 base ubuntu-12.10 b750fe79269d 13 months ago 175.3 MB 7 base ubuntu-quantal b750fe79269d 13 months ago 175.3 MB 8 base ubuntu-quantl b750fe79269d 13 months ago 175.3 MB
I can run my newly minted Docker image via its ID, which, if you look closely in the listing above, is
1 $ docker run aa51ccc5dc3f 2 2014-05-05 17:04:14.037:INFO:oejs.Server:jetty-8.1.12.v20130726 3 2014-05-05 17:04:14.119:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8000
Note, by default, Docker will run the image in the foreground; accordingly, you can see things are working via the output coming from the DynamoDB Local instance running.
You can run a Docker image as a daemon via the
1 $ docker run -d aa51ccc5dc3f 2 7be2708d94eedaa82432d239659ddb696d66004516174a6e2f79f4ec465eb9fc
You can now see what Docker images are running via the
1 $ docker ps 2 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3 7be2708d94ee aglover/dynamodb-pier:latest java -Djava.library. 17 seconds ago Up 16 seconds 8000/tcp compassionate_bardeen
Finally, you can stop an image via the
stop command. You must provide the ID of the image, which you can see via a
1 $ docker stop 7be2708d94ee
Docker has a public repository can you publish to, provided you have an account. Ultimately, publishing is done via the
push command. For example, I’ve published my DynamoDB Local image via:
1 $ docker push aglover/dynamodb-pier
Once an image has been published, it can correspondingly be downloaded via the
1 $ docker pull aglover/dynamodb-pier
pulling as simply downloading and registering a Docker. To use a "pulled" Docker, you must still execute the
Docker makes it super easy to distribute pre-packaged applications – rather than installing various binaries on different operating systems (like MongoDB on OSX for development and a different MongoDB binary on Ubuntu for production), you can use the same package across environments.
Dockerfiles make creating Dockers repeatable. And hopefully I’ve shown you that crafting a
Dockerfile isn’t terribly difficult. Go forth and Docker.
This story, "Dockerfiles in a jiffy" was originally published by The Disco Blog.