Deploy with edeliver and GitLab CI/CD

Create an Alpine docker image to build and deploy your edeliver projects.

GitLab is a great tool for using continuous integration and deployment.

In this post I will go through the steps I took to get GitLab CD up and running with edeliver. We’re currently using this approach for Robin Good.

  1. Build a bare-minimum Alpine Docker image that will be built and hosted by GitLab in a separate project
  2. Run a Pipeline on each push that deploys your project using Edeliver.

Prerequisites:

I will assume that you …

  • … have a production server up and running (We’re using DigitalOcean)
  • … that is already deployed using edeliver from your local machine
This guide will only walk through the GitLab specific steps of building a Docker image to build your project so that you don't have to do it on your local machine. It will not guide you through the full configuration of edeliver.

1. Build a Docker Image

Jobs in a GitLab pipeline is executed in a Docker container. That means that we can easily build a custom Docker image to be used for building and deploying our project.

Let’s get to it.

We will use the official elixir repository as a base and install the necessary applications to use Edeliver. The Dockerfile for this docker image will look like this:

FROM elixir:1.6-alpine

RUN \
    apk update && \
    apk --no-cache --update add \
        bash openssh-client make git ncurses-libs


RUN mix local.hex --force && \
    mix local.rebar --force

You should be able to build this Dockerfile using the command docker build. You could just push this image to Docker hub and call it a day.

But we wanted to make use of GitLab’s Registry feature and host this image in a separate project. And we want this image to build and publish automatically when we update our Dockerfile. So let’s add a .gitlab-ci file to the project so that GitLab will know what to do when we push changes to this repository.

This file says that we should build a docker image with the tag :latest every time we push to the master branch of the repository. For every other branch we tag the image with the branch- or tag name.

image: docker:latest

services:
  - docker:dind

before_script:
  - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY

build-master:
  stage: build
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE:latest" .
    - docker push "$CI_REGISTRY_IMAGE:latest"
  only:
    - master

build-other:
  stage: build
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME" .
    - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME"
  except:
    - master

Our repository is public if you’d like to have a look. But please resist the temptation to use this repository in your build step. It might change without warning.

2. Deploy automatically on every push

Edeliver uses ssh and git to deploy code to your server. Make sure your server is setup to use SSH key-based authentication and not password authentication.

Add your ssh private key to your GitLab project as a secret variable: in:

Project Settings -> Secret variables -> Add a variable.

Name it SSH_PRIVATE_KEY and make sure to include the lines -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY-----.

Let’s put our Docker image to good use. Create a .gitlab-ci.yml file in your elixir project. It will use the new Docker image; add the ssh key; upgrade production and finally perform migrations.

image: registry.GitLab.com/robin-good/docker-build-image:latest

deploy:
  stage: production
  only:
    - master
  environment: production
  before_script:
    - eval $(ssh-agent)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
    - mkdir -p ~/.ssh
    - echo -e "StrictHostKeyChecking no" >> ~/.ssh/config
    - mix deps.get
  script:
    - mix edeliver upgrade production
    - mix edeliver migrate production

It will probably take a few minutes to build. The time it takes depends highly on fast your build server is. But one thing that improves on the speed is to cache the build.

cache:
  paths:
    - _build
    - deps
  key: "$CI_JOB_NAME"
  untracked: true

I’ve had mixed results with caching in GitLab pipelines. Sometimes it takes ages to download and extract the cache. It seems to be a known issue.

Bam! You’re “done”.

You’ve got the bare minimum up and running. Your next step should be to add a testing stage to your pipeline so that your deploy job only runs when all the tests passes.

I might do a post on our complete setup in the future. Including how to get up and running with edeliver and phoenix. Give me a shout-out on Twitter if that’s something you’d like to read.

Published by using 731 words.