Here at Appcues, we managed for a long time to avoid needing an in-house backend at all; between Firebase for storage, Keen for analytics, and a small handful of other SaaS offerings, Appcues made it almost two years down the road before we needed more than what other people’s services could provide.

For about a month now, we’ve been building our next platform on Elixir, a modern language which runs on the Erlang VM (a.k.a. BEAM). We were attracted to its approach to concurrency (actors passing messages, shared nothing, immutable everything), its clean web framework Phoenix, and the BEAM VM’s stellar reputation for scalability and near-real-time communications. It felt like a good fit.

We use Wercker CI for test automation on our other projects (traditionally CoffeeScript, lately ES6), so we set out to configure our project to get along with Wercker. Pointing Wercker at our GitHub repo was quite trivial, but then we needed to configure the build process.

CI on Docker

Wercker’s CI system is built around Docker containers. The basic procedure to integrate with Wercker is to add a wercker.yml to the project’s root directory, which indicates the Docker image used to run the project’s tests, as well as any other auxiliary Docker containers to use (e.g., adding a Postgres container to provide a testing database) and the specific steps to execute during a build.

The Docker images can come from Docker Hub, a global repository of official and unofficial Docker images; this made it convenient to search for an Elixir dev image. Unfortunately, though, we could not find an Elixir container which contained everything we needed to test a Phoenix app: a full install of Erlang R18 and Elixir 1.1 for starters, but also the Postgres client (psql), Git, and a few Elixir/Erlang tools like Hex and Rebar.

Eventually, we settled on making an Elixir dev container of our own, publishing it to Docker Hub, and using that as the box in our wercker.yml. (Feel free to use it for your own endeavors!)

Configuration

The rest of the wercker.yml file was fairly straightforward: specifying our test DB setup in services, and entering the commands for our build steps in build:

# Read more about containers on our dev center
# http://devcenter.wercker.com/docs/containers/index.html

box: appcues/elixir-dev

# This is the build pipeline. Pipelines are the core of wercker
# Read more about pipelines on our dev center
# http://devcenter.wercker.com/docs/pipelines/index.html

# You can also use services such as databases. Read more on our dev center:
# http://devcenter.wercker.com/docs/services/index.html

services:
  # http://devcenter.wercker.com/docs/services/postgresql.html
  - id: postgres
    env:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres

build:
  # The steps that will be executed on build
  # Steps make up the actions in your pipeline
  # Read more about steps on our dev center:
  # http://devcenter.wercker.com/docs/steps/index.html

  steps:
    - script:
        name: set env vars
        code: |
          export MIX_ENV=test

    - script:
        name: get and compile dependencies
        code: |
          cd $WERCKER_SOURCE_DIR
          yes | mix do deps.get, deps.compile

    - script:
        name: compile
        code: |
          yes | mix compile

    - script:
        name: initialize test db
        code: |
          mix do ecto.create, ecto.migrate

    - script:
        name: test
        code: |
          mix test

Boom

That’s it. There was a little tweaking to get it working right, like adding yes | before some of the mix commands that got a little permission-happy – nothing too unexpected.

And we’ve been up and running on Wercker ever since, freeing us to get some actual work done.

Hope this helps!