1
votes

What I'm trying to achieve

I want to develop a personal website with Haskell and Yesod. My previous web work is mainly in Python. I use Docker so I can deploy easily on Amazon Web Services once everything is finished. I do all my development in containers - so no software gets installed directly on my machine apart from utilities like vim and git - then just deploy the container. I want to do the same for this site.

What I've tried

My Dockerfile currently looks like this:

FROM haskell:latest
MAINTAINER Garry Cairns
ENV REFRESHED_AT 2015-03-19

# create a haskell user to run our programs
# ADD must be after chown see http://stackoverflow.com/a/26145444/1281947
RUN ["groupadd", "haskell"]
RUN ["useradd", "haskell", "-s", "/bin/bash", "-m", "-g", "haskell", "-G", "haskell"]
ENV HOME /home/haskell
RUN ["mkdir", "/home/haskell", "-p"]
WORKDIR /home/haskell
RUN ["chown", "-R", "haskell:haskell", "/home/haskell"]
ADD ./ /home/haskell

# install yesod
RUN ["apt-get", "install", "-y", "wget"]
RUN ["wget", "http://www.stackage.org/lts/cabal.config"]
RUN ["cabal", "update"]
RUN ["cabal", "install", "yesod"]

# uncomment the line below to use container as a non-root user
# USER haskell:haskell

The instructions under the install yesod comment are from the yesod quick start guide. The container builds but, at the cabal update step while doing so, I see a warning saying:

Config file path source is default config file.
Config file /home/haskell/.cabal/config not found.
Writing default configuration to /home/haskell/.cabal/config
Downloading the latest package list from hackage.haskell.org
Note: there is a new version of cabal-install available.
To upgrade, run: cabal install cabal-install

This may or may not have something to do with the errors that follow.

I run a shell session on this container with sudo docker run -itv /home/garry/projects/personal/api/:/home/haskell garrycairns/haskell /bin/bash and try yesod init, which tells me it can't find the yesod command. Running ghci doesn't let me import Yesod either.

The result is the same whether I cabal install yesod or yesod-bin.

I've also tried running as the haskell user (see my Dockerfile) with the same result.

Expected result

Running yesod init should scaffold my application as described in the quick start guide.

Actual result

The yesod commands are not available in my container.

What I'm asking

How do I set up a Docker container that will let me run yesod init and, later, yesod devel?

2

2 Answers

1
votes

You need to add the location ~/.cabal/bin/ to you path to access programs installed by cabal such as yesod.

Secondly it is probably better to run cabal as the haskell user as it expects to be run by a non-root user (this may be what's stopping you from loading files in ghci).

Finally it is probably better to develop in a sub-folder of the home folder because the cabal sandbox will add hidden files.

You also probably want to install system libraries for you database etc.

The following file seems to work:

FROM haskell:latest
MAINTAINER Garry Cairns
ENV REFRESHED_AT 2015-03-19

# create a haskell user to run our programs
# ADD must be after chown see http://stackoverflow.com/a/26145444/1281947
RUN ["groupadd", "haskell"]
RUN ["useradd", "haskell", "-s", "/bin/bash", "-m", "-g", "haskell", "-G", "haskell"]
ENV HOME /home/haskell
RUN ["mkdir", "/home/haskell", "-p"]
WORKDIR /home/haskell
RUN ["chown", "-R", "haskell:haskell", "/home/haskell"]
ADD ./ /home/haskell



# install wget
RUN ["apt-get", "install", "-y", "wget"]

# set up haskell
USER haskell:haskell
# add cabal installed programs to path
ENV PATH /home/haskell/.cabal/bin:$PATH


# enter working directory
RUN ["mkdir", "yesod"]
WORKDIR /home/haskell/yesod
# install yesod binary
RUN ["wget", "http://www.stackage.org/lts/cabal.config"]
RUN ["cabal", "update"]
RUN ["cabal", "install", "alex", "happy", "yesod-bin"]
1
votes

I ended up doing the following.

Download the global stackage config file and save it in my project root as stackage.

Build the following Dockerfile, which uses the stackage file we just created, up to the point where I say to comment everything else out.

FROM haskell:7.8

# install database dependencies
RUN ["apt-get", "update"]
RUN ["apt-get", "-y", "install", "libpq-dev"]

# update cabal and install yesod
RUN cabal update
ADD ./stackage /root/.cabal/stackage
RUN cat /root/.cabal/config /root/.cabal/stackage > /root/.cabal/config2
RUN ["mv", "/root/.cabal/config2", "/root/.cabal/config"]
RUN cabal update
RUN ["cabal", "install", "yesod-bin", "-j4"]

# Add your .cabal file before the rest of the code so next step caches
# Comment out here on the first run
ADD ./myproject.cabal /opt/server/myproject.cabal

# Docker will cache this command as a layer, freeing us up to
# modify source code without re-installing dependencies
RUN cd /opt/server && cabal install --only-dependencies -j4

# Add and Install Application Code
ADD ./ /opt/server
RUN cd /opt/server && cabal install

# Add installed cabal executables to PATH
ENV PATH /root/.cabal/bin:$PATH

# Default directory for container
WORKDIR /opt/server

Run the new container using your project root as a volume and then run yesod init --bare inside the container. This will also create its files in your project root on the host.

Uncomment the lines in the above Dockerfile that you commented out and build it again. You now have a working Dockerfile.