Skip to content

Experimenting with various development/deployment tools for a Haskell app.

Notifications You must be signed in to change notification settings

naushadh/hello-world

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hello-world

A simple hello world app.

A bare minimum haskell application, with a library and executable component to test various development and deployment tools aimed at improving Developer Experience and Operational efficiency.

See specific sections below to learn more.

Example 1: Ultra light docker image

Haskell <3 Docker

Unlike most mainstream languages, Haskell applications require very few dependencies from the target machine/host thanks to the RTS (RunTime System) being bundled with the built binary/executable.

One could argue docker is moot; i.e., the app itself is self-contained and uncaring of the host environment dependencies or the lack-thereof. However, we may still want containerization to achieve disposable computation environments. Ex: on a giant beefy central machine, launch an instance of a task or web-service and then tear it down when the need or traffic load subsides.

And docker-izing a Haskell application is rather beautiful, as the ENTRY POINT is the executable.

Why Alpine

Not all container images are equal. You loose the feeling of "light"/cheap instances when images push towards hundreds of MBs or a few GBs (interpreted or VM languages).

Haskell apps require very little from the host OS. So why not cut the chase and get as close to "metal" as possible with a barebones OS? We achieve some nice benefits:

  • quick upload (of the whole build app image)
  • quick cloud deployment
  • reduced attack surface / principle of least privilege; i.e., there isn't really much else besides your app to compromise security

Learn more about Alpine.

Usage

Haskell applications are best compiled/built on the same architecture/OS as the deployment target. May feel like a hassle when you already have say stack/cabal already pre-configured, but it's worth it. The cost to set up a "dev" or "build" env from scratch dramatically goes down in the Docker way as you'd only require Docker. In cases where your app requires system/foreign dependencies (ex: a C lib), the Docker way ensures you work with the exact same runtime from development to production.

  • Build and run hello-world (a pure haskell CLI app)

    $ docker-compose build hello-world # builds, tests, packages executable(s), and produces a tagged Docker image "hello-world:latest"
    $ docker-compose run hello-world
    someFunc
  • Build and run hello-postgresql (a haskell CLI app with C lib dependency)

    $ docker-compose build hello-postgresql # builds, tests, packages executable(s), and produces a tagged Docker image "hello-postgresql:latest"
    $ docker-compose up --build
    Creating hello-world_hello-world_1 ... done
    Creating hello-world_postgres_1    ... done
    Creating hello-world_hello-postgresql_1 ... done
    hello-postgresql_1  | dbFour
    hello-postgresql_1  | 4
    hello-world_hello-postgresql_1 exited with code 0
  • Marvel at how compact app images are

    $ docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    hello-postgresql    latest              04198bd1418d        8 minutes ago       21.6MB
    hello-world         latest              6f085d084f4a        About an hour ago   7.36MB

Caveats

  • GHC version
    • the version of ghc shipped with a stackage resolver MUST match the version of ghc available on Alpine.
    • otherwise stack will try to build ghc from source. This usually doesn't go so well.
    • the official alpine ghc version can be found here.

References/Inspirations

Example 2: .env

.env file can be used to store configurations that can then be consumed as ENV vars. Despite being so simple, it addresses config management in an elegant way when paired with Docker.

Docker-compose supports .env out of the box. Your (dockerized) application can also access the same .env vars by whitelisting/passing the env vars in docker-compose. In addition, the same vars can be used to bootstrap other services like database credentials. This simply makes the env file the source of truth for configs.

Alternatively, if docker-compose is not desired/applicable, dotenv can be used to consume .env as ENV vars directly from your application.

About

Experimenting with various development/deployment tools for a Haskell app.

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published