Thomas Venturini
Drone CI on your Raspberry Pi

Drone CI on your Raspberry Pi

In this article, we are going to set up a drone server on a raspberry pi. Drone is an open source continuous integration project that comes as a docker image and is very easy to use and therefore easy to integrate.

Drone is a Continuous Delivery platform that helps your organization optimize and automate software delivery. You can test your project within docker containers and together with capistrano you can even deploy your project to different environments.

In this article we are goning to set up a drone server connected to a github account. We will basically follow the installation guide for github in the drone documentation but I will point out the things you need to look out for if you plan to install drone on your raspberry pi.

Prerequisites

  • Of course you will need a raspberry pi with headless raspbian running on it. I am going to use a raspberry pi 3 b+.
  • SSH access to your raspberry pi.
  • Docker installed on your raspberry pi.
  • And your raspberry must be available through the internet. I simply set up a port forwarding rule for this purpose.

Setup

Create a GitHub OAuth Application

From the drone documentation: Create a GitHub OAuth application. The Consumer Key and Consumer Secret are used to authorize access to Bitbucket resources. The Authorization callback URL must match the below format and path, and must use your exact server scheme and host.

Create an GitHub OAuth Application GitHub OAuth Secret

Make sure to use HTTPS in your URL because we are going to use drone behind a nginx webserver.

Nginx

Run the following commands from within a terminal to update your package lists and install nginx.

sudo apt-get update
sudo apt-get install nginx

Update the default nginx host configuration to match your needs in /etc/nginx/sites-available/default. Enter ether a domain name or an IP address.

server_name drone.example.com;

Firewall

Raspbian doesn't ship with a firewall so we need to install one.

sudo apt-get install ufw

Ufw allows us to use predefined rule-sets, so we can simply tell ufw to use these.

sudo ufw allow 'Nginx HTTP'
sudo ufw allow 'Nginx HTTPS'
sudo ufw allow 'OpenSSH'

Now we have the ports 80, 443 and 22 open.

HTTPS / SSL

We are going to use certbot from let's encrypt project to create and maintain a SSL certificate for our service. Certbot is available through the raspbian package manager so we can simply install it.

sudo apt-get install python-certbot-nginx

Next we need to create an SSL certificate. For this purpose, we need to verify that we own the domain and server. Certbot can do this for us.

sudo certbot --authenticator standalone --installer nginx -d drone.example.com --pre-hook "service nginx stop" --post-hook "service nginx start"

This will stop nginx, run the verification test and restart nginx. Also it should configure your default host. You can test this by accessing https://your-ip-or-domain.

Certbot uses HTTP to authenticate your pi, but by now it should be save to disable the Nginx HTTP rule and only allow HTTPS access.

sudo ufw delete allow 'Nginx HTTP'

Drone

Now let's install drone. First we will need to pull the docker image.

docker pull drone/drone:1.0.0-rc.3

And then we can already start it. I am using the following code to start my drone server. Replace the github values with the ones from your github OAuth application.

docker run \
    --volume=/var/run/docker.sock:/var/run/docker.sock \
    --volume=/var/lib/drone:/data \
    --env=DRONE_GITHUB_SERVER=https://github.com \
    --env=DRONE_GITHUB_CLIENT_ID=your-github-client-id \
    --env=DRONE_GITHUB_CLIENT_SECRET=your-github-client-secret \
    --env=DRONE_RUNNER_CAPACITY=4 \
    --env=DRONE_SERVER_HOST=drone.example.com \
    --env=DRONE_SERVER_PROTO=http \
    --env=DRONE_TLS_AUTOCERT=true \
    --env=DRONE_LOGS_DEBUG=true \
    --env=DRONE_LOGS_TEXT=true \
    --env=DRONE_LOGS_PRETTY=true \
    --env=DRONE_LOGS_COLOR=true \
    --env=DRONE_OPEN=false \
    --publish=8000:80 \
    --restart=always \
    --detach=true \
    --env=DRONE_USER_CREATE=username:your-github-user,admin:true \
    --env=DRONE_USER_FILTER=your-github-user \
    drone/drone:1.0.0-rc.3

For further information about this part please visit the drone documentation.

Drone behind Nginx

To make drone accessible through our nginx webserver we only need to make a small change in our default nginx host configuration. Change the location section in /etc/nginx/sites-available/default to the following content.

server {
    listen 80;
    server_name drone.example.com;

    location / {
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $http_host;

        proxy_pass http://127.0.0.1:8000;
        proxy_redirect off;
        proxy_http_version 1.1;
        proxy_buffering off;

        chunked_transfer_encoding off;
    }
}

Restart the nginx server to apply the changes.

sudo service nginx restart

Since we have installed the SSL certificate with certbot it should already be set up in the default configuration host so your drone server is waiting for you at https://your-ip-or-domian.

Ask for password when sudo

Now that your pi is accessible through the internet, you should always ask for passwords if a user runs sudo. To do so, we change the content of /etc/sudoers.d/010_pi-nopasswd. Normally this file contains only one line so make sure that the file looks like shown below.

pi ALL=(ALL) PASSWD: ALL

Activate Sample Project

Now let's test our setup by running some builds. Drone provides a hello world repository that you can fork and update to trigger some builds.

To trigger a build you need to activate the project in drone. Visit your drone installation in your browser, login using github and sync your repository list. Your forked hello world project should be listed.

Now, every time you push to your repository on github, drone will trigger a new build for you.

If you try this out right now, the build will fail. Thats because a last thing in our setup is missing.

ARM

Raspberry Pi runs on an arm based architecture. We need to tell drone and therefore docker to use images that are made for the arm architecture, because others won't run.

Go to your fork of the hello world repository on github and update the .drone.yml file to match the following.

kind: pipeline
name: greeting

platform:
    os: linux
    arch: arm

...

Commit the changes and go back to drone. A new build should be triggered within seconds. This time the build should work perfectly.

Remember to check that the docker images that you want to use, are available for the arm architecture.

Done!

Thats it, you now have your own continuous integration server!

Consider to sign up for my newsletter if you want to learn more about this topic. In my next articles I will show how to use this setup to test and deploy a laravel project.

Have fun with your new drone server!