Tutorial: Drone CI Setup Part One

For a beginner that had only used GitHub Actions, I found most tutorials slightly lacking in details to get a good drone pipeline up and running from scratch.

Here's what we'll accomplish:

  • Part One: (This Article)
    • Create a docker repository
    • Create a drone server
    • Create a drone runner
  • Part Two: (Not Yet Released)
    • Create a real world example pipeline

Assumptions

  • We have created 2 subdomains:
    • drone.mydomain.com
    • docker.mydomain.com
  • We have apache2-utils installed
    Ubuntu / Debian based:
    sudo apt install apache2-utils
    
  • We have docker and docker-compose already installed
  • We have a reverse proxy already operating
    • I recommend nginx-proxy-manager for those new to reverse proxies.
    • NOTE: Drone does have the option to generate it's own SSL Cert via Let's Encrypt, however the registry image does not so we will opt to use a reverse proxy to manage certs for both.
    • We will not go over setting up Nginx Proxy Manager or other reverse proxies in this tutorial. Here is a good tutorial to get you started.

Create Compose Files

Everyone has their own base directory they use for docker-compose. Personally, I put all my compose files under each stack's own directory under /usr/local/docker. Feel free to use whatever you feel is best for your setup.

mkdir /usr/local/docker/cicd/

Copy the following compose file to this newly created directory:

version: '3.6'

services:
  drone:
    container_name: drone
    image: drone/drone:${DRONE_VERSION:-2}
    restart: unless-stopped
    environment:
      - DRONE_DATABASE_DRIVER=sqlite3
      - DRONE_DATABASE_DATASOURCE=/data/database.sqlite
      - DRONE_RPC_SECRET=${DRONE_RPC_SECRET}
      - DRONE_SERVER_PROTO=${DRONE_SERVER_PROTO:-https}
      - DRONE_SERVER_HOST=${DRONE_SERVER_HOST:-drone}
      - DRONE_GITHUB_CLIENT_ID=${DRONE_GITHUB_CLIENT}
      - DRONE_GITHUB_CLIENT_SECRET=${DRONE_GITHUB_SECRET}
    ports:
      - "4000:80"
      - "9000:9000"
    networks:
      - ${DOCKER_NETWORK_NAME:-cicd_net}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./drone:/data

  drone-runner:
    container_name: drone-runner
    image: drone/drone-runner-docker:${DRONE_RUNNER_VERSION:-1}
    restart: unless-stopped
    depends_on:
      - drone
    environment:
      # https://docs.drone.io/runner/docker/installation/linux/
      # https://docs.drone.io/server/metrics/
      - DRONE_RPC_PROTO=http
      - DRONE_RPC_HOST=drone
      - DRONE_RPC_SECRET=${DRONE_RPC_SECRET}
      - DRONE_RUNNER_NAME="${DRONE_RUNNER_NAME:-drone-runner}
      - DRONE_RUNNER_CAPACITY=${DRONE_RUNNER_CAPACITY:-2}
      - DRONE_RUNNER_NETWORKS=${DOCKER_NETWORK_NAME:-cicd_net}
      - DRONE_DEBUG=false
      - DRONE_TRACE=false
    ports:
      - "3000:3000"
    networks:
      - ${DOCKER_NETWORK_NAME:-cicd_net}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  registry:
      image: registry:2
      ports:
        - 5000:5000
      environment:
        REGISTRY_AUTH: htpasswd
        REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
        REGISTRY_AUTH_HTPASSWD_PATH: /auth/.htpasswd
        REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
      restart: unless-stopped
      volumes:
        - ./registry/auth:/auth
        - ./registry/data:/data

networks:
  ${DOCKER_NETWORK_NAME:-cicd_net}:
    name: ${DOCKER_NETWORK_NAME:-cicd_net}

All of those variables enclosed in ${} will be fed with values from a .env file we will create with the following contents:

MYDOMAIN=mydomain.com

DOCKER_NETWORK_NAME=cicd_net

DRONE_VERSION=2
DRONE_HOSTNAME=drone
DRONE_SERVER_HOST=$DRONE_HOSTNAME.${MYDOMAIN}
DRONE_RPC_SECRET="$(echo ${DRONE_SERVER_HOST} | openssl dgst -md5 -hex)"
DRONE_SERVER_PROTO=https
DRONE_GITHUB_CLIENT_ID=<YOUR GITHUB OAUTH CLIENT ID>
DRONE_GITHUB_CLIENT_SECRET=<YOUR GITHUB OAUTH CLIENT SECRET>

DRONE_RUNNER_VERSION=1
DRONE_RUNNER_CAPACITY=2
DRONE_RUNNER_NAME=${DRONE_HOSTNAME}-runner
  • MYDOMAIN: Your domain name
  • DOCKER_NETWORK_NAME: can be just about anything you want (no spaces)
  • DRONE_VERSION: Here you can specify a specific version (2.12.1), the newest stable release in major version (1 or 2), or latest (not recommended). Available Tags
  • DRONE_HOSTNAME: Whatever your subdomain is
  • DRONE_SERVER_HOST: Automatically generated using your DRONE_HOSTNAME and MYDOMAIN
  • DRONE_RPC_SECRET: Automatically generated using DRONE_SERVER_HOST
  • DRONE_SERVER_PROTO: Set to https if you will use SSL (STRONGLY RECOMMENDED)
  • DRONE_GITHUB_CLIENT_ID: Generated from GitHub (See Below)
  • DRONE_GITHUB_CLIENT_SECRET: Generated from GitHub (See Below)
  • DRONE_RUNNER_VERSION: Here you can specify a specific version. Available Tags
  • DRONE_RUNNER_CAPACITY: Max Number of pipelines to execute. Too many and it will bog down your system.
  • DRONE_RUNNER_NAME: Automatically Generated using your DRONE_HOSTNAME

GitHub OAuth Client ID and Client Secret Generation

To obtain your Github Client ID and Client Secret, follow my example.
NOTE:all Client ID's and Client Secrets have been deleted from this process)

Login to your GitHub account and follow the GitHub OAuth Workflow:

  1. Click your account avatar and select Settings
  2. Scroll down to Developer settings
  3. Select OAuth Apps and click New OAuth App
  4. Fill in required fields marked with an asterik and click Register Application
  5. Click Generate a new client secret
    Use the information on this page to fill in DRONE_GITHUB_CLIENT_ID and DRONE_GITHUB_CLIENT_SECRET in your .env file.

Docker Registry

We will use HTTP Authentication for our registry. To accomplish this, run the following commands:

mkdir registry
mkdir registry/auth
htpasswd -Bc registry/auth/.htpasswd my-username

Bring up the stack

Now that we have everything all defined, let's bring up the stack:

sudo docker-compose up -d

Login to Drone!

Simply visit your new drone install and it will bring you through the GitHub OAuth Process

Part Two Coming Soon

Part Two will go over creating a drone.yml file in your GitHub Repository