Dev and Deploy Haskell on Docker

August 11, 2015

Christopher Biscardi shares his Docker wisdom, showing how to package the whole Haskell dev environment inside a container and how to optimize it for production release.


  • How do we build Haskell code locally?
  • Docker is one answer
  • In the Dockerfile copy your source code into the image, then cabal update and cabal install
  • This works but it is naive
    • Changing any file causes you to rebuild everything (the whole cabal sandbox!)
  • So we could try to optimize the Dockerfile
    • Have to determine the individual pieces and where they will end up and how long that should take
  • Heavily optimizing Dockerfiles takes work, and it’s more fun to build your application than burn time tweaking the Dockerfile
  • A better solution is to use Docker as your development environment
    • Clone your project
    • Docker run an interactive tty
    • Mount the directory
    • At that point you’re in the container and can install deps, build the sandbox, etc
    • Container changes are persisted to a volume so you can kill it and resume work later
  • This way you don’t need Haskell installed in the host system at all
  • Easy to switch GHC version between projects
  • How do we ship the dev work to production?
    • Building a new Docker image containing the binary built in dev results in shared library errors
    • Solution: build a static binary
    • Works, and plays well with Circle CI etc
  • The production image unfortunately can be rather big, like 150mb
    • Solution: compile GHC with MUSL
    • …or if you want to cheat, just use the nilcons/ghc-musl image
    • Chris’ production image (based on Alpine) shrank down to 36mb