Suffix

Published by Simon Schoeters

Continuous intergration with Drone

Drone is a continuous integration server with a fully hosted version which you can self-host as well. We gave it a spin for our Rails application: RSpec integration tests with some PhantomJS stuff.

Base

We started off with an Ubuntu 14.04 LTS base image on a 1.6Ghz CPU system with 1GB of RAM and a 10GB drive running on Google Cloud. As always, upgrade the system:

apt update
apt upgrade

See the new apt syntax? Since version 1.0 `apt-get` and `apt-cache` have been merged in a single interface (you even get some nice colors and a progress bar).

Firewall

Let's lock the system down a bit by enabling the firewall via UFW.

ufw allow ssh
ufw enable

You can lock yourself out if you are not allowing SSH connections, check to see if you can still log in.

Disable root access

Edit `/etc/ssh/sshd_config` and disable the root login.

PermitRootLogin no

Restart the SSH daemon.

service sshd restart

Automatic updates

Set up automatic updates. This will tell Ubuntu to look for and install security patches every so often, not a luxury as you probably won't log in to the CI server every day.

dpkg-reconfigure --priority=low unattended-upgrades
Or in a more recent version of Ubuntu:
apt-config-auto-update

Make sure the `update-notifier-common` package is installed (it was for me) and edit `/etc/apt/apt.conf.d/50unattended-upgrades` to make the server reboots when it needs to.

Docker

Let's install Docker. Bonus hipster points.

curl -fsSL https://get.docker.com/ | sh

A quick hello-world will show if Docker was installed correctly.

docker run hello-world

Drone

Drone needs some kind of database to store its things. I went with SQLite as it's super easy to install but PosgreSQL or MySQL are probably better suited for production systems. Drone doesn't mind and can run with MySQL, PostgreSQL or SQLite.

apt install sqlite3 libsqlite3-dev

Now you can tell Docker to fetch the latest Drone image (0.4 at the time of writing):

docker pull drone/drone:0.4

Let's configure Drone:

mkdir /etc/drone
vi /etc/drone/dronerc

Add Github as a remote driver: get the client id and secret from a developer oAuth application created on Github and point it to the database.

REMOTE_DRIVER=github
REMOTE_CONFIG=https://github.com?client_id=CLIENT&client_secret=SECRET
DATABASE_DRIVER=sqlite3
DATABASE_CONFIG=/var/lib/drone/drone.sqlite

Once done you can run Drone:

docker run \
--volume /var/lib/drone:/var/lib/drone \
--volume /var/run/docker.sock:/var/run/docker.sock \
--env-file /etc/drone/dronerc \
--restart=always \
--publish=80:8000 \
--detach=true \
--name=drone \
drone/drone:0.4

There you go, open your browser an point it to the server's IP address. Drone will do its oAuth dance with Github when you log in and list your repositories.

Build

Drone looks for a `.drone.yml` configuration file in your project's root directory. You start from a Docker image of your choosing, run some commands and wait for Drone to tell you if everything works.

build:
  image: cimm/ruby-phantomjs
  environment:
    - RAILS_ENV=test
  commands:
    - bundle install --without production --without staging
    - cp config/database.drone.yml config/database.yml
    - bundle exec rake db:create
    - bundle exec rake db:test:prepare
    - bundle exec rspec spec

compose:
  database:
    image: postgres

notify:
  slack:
    webhook_url: $$SLACK_WEBHOOK
    channel: general
    username: drone

The first 'build' part is the most important one. You can use whatever Docker image you want as a base to start from. We built our own as we need a more recent version of PhantomJS for to run our tests.

The 'commands' section is where you configure your build and get it running, pretty standard Rails stuff here.

The 'enviroment' section can be used to set… well… environment variables. Really useful for twelve-factor apps.

The 'compose' section behaves like Docker's compose feature and lets you pull other Docker images needed for your build. Isn't that awesome?

And finally, the 'notify' section to let everyone know how good of a tester you are.

Secrets

Noticed the $$SLACK_WEBHOOK variable in the example? It's possible to pull in variables from a `.drone.sec` file from your project's root folder. This is usefull for API tokens & passwords you rather don't expose.

Drone knows how to read and decrypt this file but you'll need to encrypt it yourself. Go to your project's "Secrets" tab in the Drone web interface and add your variables.

environment:
  SLACK_WEBHOOK: https://hooks...

Generate and save the encrypted version in the `.drone.sec` file. Save, commit, push and watch Drone do its magic.