Getting (re)started with Yesod and Docker

Last updated by Garry Cairns on 31 July 2016 12:17


A new daughter and a new job conspired to make the gap between part one and part two of this blog over a year longer than I ever intended. Sorry for the delay. But major changes in both the Haskell and Docker ecosystems make refreshing some of what we did in part one appropriate in any case. In this post we'll:

  • recap on setting up our development environment; and
  • start building a simple Yesod web application with authentication.

I've also improved on my previous publishing approach by writing parts three and four in advance.

What's new

About a week after I originally published part one, the Haskell stack tool was released. As far as I'm concerned you no longer need to build a Docker container simply to develop in. My original purpose in doing so was to make all the pain and suffering of getting Haskell up-and-running a one time cost. Stack goes one better by taking the pain and suffering away entirely.

There have also been changes to Docker Compose, which is a crucial part of our site. We'll use the improvements here to effectively eliminate code changes from our deployment steps later on.

Before you continue

Building a blog site is a tutorial cliché. I'm doing it anyway because this is aimed at people, like me, with no prior Yesod experience and very little Haskell experience. My goal here is to introduce the early steps in a non-intimidating way to get you started with this framework. The site you're reading is the first and only one I've built with Yesod so please don't consider any of what follows as best practice. If you still think you're in the right place read on. You will need around 1-2 hours to follow along.

Getting set up

Part one is still worth reading but not coding along with. Skim over it just now if you haven't already. We're going to go through the setup work part one covers quickly here to avoid repetition. I'll only point out the big changes.

Using stack

The quickstart instructions for Yesod will tell you everything you need to know about getting stack and Yesod working on your machine. It's absurdly painless now. Create a parent directory to hold the whole docker setup before running the stack new command. Use yesod-postgres instead of yesod-sqlite when following step 2 to get a site that will work with our Docker setup. Stop after step 4. Step 5 won't work until we've got our database set up.

Setting up Docker and Compose

Follow the relevant instructions to install Docker. Installing Docker Compose, on Ubuntu at least, takes more steps than are documented. The official instructions ask that you run a command like:

curl -L https://github.com/docker/compose/releases/download/1.7.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

But that will give you a permission denied error that sudo won't help. This is easy to fix by breaking what that command is doing into separate steps. First run a slightly changed version of the command like this:

curl -L https://github.com/docker/compose/releases/download/1.7.1/docker-compose-`uname -s`-`uname -m` > ./compose

Then move it into place with:

sudo mv ./compose /usr/local/bin/docker-compose

You don't want to run Compose with sudo so remember to follow the instructions for creating a docker group. This will leave you with a working Compose installation.

Connecting your site to our Docker containers

We're just a couple of steps away from having the development site running and starting the fun work. First set up a directory structure like the following, where site is the directory stack created for you when you were following the Yesod setup instructions.

parent_directory/
    site/
        ...
    database/
        dev_env
    webserver/
    binary/
    dev.yml

Right now webserver/ and binary/ are just empty directories and dev.yml and dev_env are empty files.

Note: We'll be using a number of environment files (ending in env or simply called env). Don't commit any of them to source control. If you ever commit a production env file by accident, note the settings in the file and never use them for any purpose again.

Open up dev_env first and enter the following:

POSTGRES_USER=your_site_name
POSTGRES_DB=your_site_name
POSTGRES_PASSWORD=supersecretpassword

Now open the file at ./site/config/settings.yml and look for the following values

database:
    user:     "_env:PGUSER:your_site_name_LOWER"
    password: "_env:PGPASS:your_site_name_LOWER"
    host:     "_env:PGHOST:localhost"
    port:     "_env:PGPORT:5432"
    # See config/test-settings.yml for an override during tests
    database: "_env:PGDATABASE:your_site_name_LOWER"
    poolsize: "_env:PGPOOLSIZE:10"

Change the values that look like your_site_name_LOWER to match those in the dev_env file. Now open dev.yml and enter the following:

version: "2.0"
services:
  database:
    image: postgres
    env_file: ./database/dev_env
    ports:
        - "5432:5432"

Run docker-compose --file=dev.yml up from your parent_directory to set up the database. Once it's started, stop it then enter the command docker-compose --file=dev.yml up -d to restart it in the background. Now cd into your site directory and run stack exec -- yesod devel. If you see an error like yesod: cabal: createProcess: runInteractiveProcess: exec: does not exist (No such file or directory) then run stack install yesod-bin cabal-install then try again. Your site should build then start, and you can visit it. If you're using git then create a .gitignore file similar to that below then commit your work.

/your_site_name/.ghci/
/your_site_name/.stack-work/
/your_site_name/dist/
/database/
/your_site_name/yesod-devel/
/your_site_name/config/client_session_key.aes
/your_site_name/.ghci
/your_site_name/.dir-locals.el

We're ready to start building a site so please head to part three.