Docker and Dancer
Tags: perl, docker, aws, dancer
Published: 2019-05-19 18:27:05

---
title: Docker and Dancer
published: true
description: 
tags: perl, docker, aws, dancer
series: Into the Cloud
cover_image: https://thepracticaldev.s3.amazonaws.com/i/r172e0ipwn9t9tkgkmfx.jpg
---

I have made a start on the project I mentioned in my [last post](https://dev.to/davorg/moving-into-the-cloud-4p4/). 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](https://github.com/davorg/succession-docker/) containing a `Dockerfile` that was supposed to build an image for the application. It looks like I copied it from [this blog post](https://robn.io/docker-perl/). 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](https://github.com/davorg/succession.git) 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`](https://github.com/davorg/succession/blob/master/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.

**Update:** I've already had two people giving me some really useful updates to this. It seems that the `Dockerfile` I borrowed heavily from wasn't really very good. I'll try and improve it over the next couple of days - in the meantime, please don't copy this version.