I have made a start on the project I mentioned in my last post. I decided that no matter what approach I'm going to take in order to move this web site into the cloud, I'm certainly going to want to run the main application in a Docker container - so that's what I have been concentrating on this week.

It turns out that I've tried this before. There was an existing Github repo containing a Dockerfile that was supposed to build an image for the application. It looks like I copied it from this blog post. I can't remember why I stopped working on that, but it's been pretty easy to get it up and running.

Here's the current version of the Dockerfile :

FROM perl:latest MAINTAINER Dave Cross dave@perlhacks.org RUN apt-get install openssl libssl-dev libz-dev libexpat1-dev RUN curl -L http://cpanmin.us | perl - App::cpanminus RUN cpanm Carton Starman RUN git clone http://github.com/davorg/succession.git RUN cd succession && carton install --deployment EXPOSE 1701 WORKDIR succession CMD carton exec starman --port 1701 Succession/bin/app.psgi

Let's go through it in a some detail.

FROM perl:latest

Docker images tend to be built on top of other images. I've chosen an image which contains an up to date version of Perl.

MAINTAINER Dave Cross dave@perlhacks.org

When I'm happy with this image, I'll upload it to a public Docker hub. This line will allow people to get in touch with me about it.

RUN apt-get install openssl libssl-dev libz-dev libexpat1-dev

RUN commands are run as the image is being built. Here we're loading some fairly standard libraries that underlie some of the Perl modules I'll be loading later. Actually, I'm not sure that these are necessary; they might well be included in the underlying image.

RUN curl -L http://cpanmin.us | perl - App::cpanminus RUN cpanm Carton Starman

Here, I'm installing cpanm and then using it to install Carton (a mechanism for installing known versions of Perl modules) and Starman (the software that we'll use to run our web service).

RUN git clone https://github.com/davorg/succession.git

On this line we clone the latest version of the Github repo that contains the actual code for the web service.

RUN cd succession && carton install --deployment

And here, we change into the newly-cloned subdirectory and use carton to install all of the Perl modules that we need.

EXPOSE 1701

This line tells Docker that port 1701 on the container should be made available to the outside world.

WORKDIR succession

WORKDIR sets the working directory that we use when the container starts up.

CMD carton exec starman --port 1701 Succession/bin/app.psgi

And finally, CMD defines the command that is run when you start up a container using your new image. Here we're using a pretty standard command line that will start our Dancer application running under Starman.

Having created our Dockerfile , we can turn it into a Docker image by running the docker build command:

$ docker build -t succession .

The -t succession gives the image a tag and the . means "use the Dockerfile in the current directory.

Once the command has finished, you'll have a new image. You can confirm that using the command docker image ls .

$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE succession latest 6a6fbfcbebbc 2 hours ago 1.17GB perl latest 9a41aacaefa5 11 days ago 891MB

But having a Docker image is only half the battle. We now need to create and run a container. And we can do this using docker run . The naive approach would be something like this:

$ docker run succession

And that works - but it doesn't do anything useful. For many reasons.

Firstly, although we've asked Docker to expose port 1701 on the container (with the EXPOSE command in the Dockerfile ) we haven't done anything useful with that port. We need to use the -p option to docker run in order to make that port visible on the host system. So our command becomes:

$ docker run -p 1701:1701 succession

This makes port 1701 on the container available as port 1701 on the host.

And at this point, I was actually able to connect to my Dancer application (on http://localhost:1701/) running on the container. It was an error message, sure, but at least the communication was working.

The error message was interesting. As we've seen, the Dockerfile uses a Perl tool called Carton to ensure that all the correct libraries are installed. And that uses a file called cpanfile to work out what libraries are needed. All that was happening was that my cpanfile didn't have all of the required listed. I admit it took a few iterations to get that right!

There was one final problem. The application needs a database and nothing in the Dockerfile sets up that database. That's ok as I don't want the database running in the same container. But the application needs to know where its database is. It works that out by looking at some environment variables and those variables weren't being set in the container. So I had to use the -e option (multiple times) to pass the host's environment variables to the container. By this time, the docker run command was looking a bit complicated, so I wrote a bash script to make my life easier.

docker run --name succession \ -e SUCC_DB_HOST \ -e SUCC_DB_NAME \ -e SUCC_DB_USER \ -e SUCC_DB_PASS \ -p 1701:1701 succession

You'll see I've also added --name to give the container a name.

That looked a lot better. But I hadn't quite got to the bottom of all of the networking problems. The database host variable ( SUCC_DB_HOST ) was set to localhost . And on the container, that wasn't right. A quick Google and I discovered that the option --network="host" would allow the container to see the network from the host's perspective, so I could just change the setting to 127.0.0.1 and, suddenly, it all started working.

And that's where I currently am. After just a few hours work over the last week or so, I now have a working containerised version of my web application. This makes me happy. I feel that this could well work.

So, over to any Docker experts that might be reading this. Is what I'm doing sensible or have I missed some obvious improvements? All advice is welcome.