setting up continuous delivery with drone

Long, long time ago, i started to manage my spare time projects with git, to make life a bit easier there were tools like gitosis and later gitolite - you managed repositories and public keys in plain text files and git hooks on the server. Last year i decided to join the shiny new world of modern self-hosting git services. I choose Gitea - copied it on the server, started one 40 mb binary, and it was just working - and it was fast.

Really impressed about the performance and simple deployments, i wanted to learn that sorcery.

Spoiler: The secret is go…

the old way

Similar to the repository management, my continouse delivery “pipeline” was a git hook (created by hand) and a bash script. That was working well enough for code, not delivered as a binary, like octobercms, playframework projects or hugo sites where you only have to check out the code and run something - the server has to be prepared for that of course.

In a scenario where i have a react-based frontend, have to build a javascript bundle and want it to be packed in a go binary, things get a bit more complex. At HORNBACH we usually build our software with Jenkins CI - but i don’t like the limited groovy pipeline syntax - and the jenkins nodes needs a setup by hand.

I searched for something more intuitive.

starting the drone

After a short stop at CircleCI (it’s only working with github) i found drone.io!

The quickstart is really quick, ~20 lines of yaml and docker-compose up is everything needed:

version: '2'

services:
  drone-server:
    image: drone/drone:0.8

    ports:
      - 8080:8000
      - 9000
    volumes:
      - ./.drone:/var/lib/drone/
    restart: always
    environment:
      - DRONE_OPEN=false
      - DRONE_HOST=https://mydroneurl.net
      - DRONE_SECRET=123456
      - DRONE_GITEA=true
      - DRONE_GITEA_URL=https://mygiteaurl.net

  drone-agent:
    image: drone/agent:0.8

    command: agent
    restart: always
    depends_on:
      - drone-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - DRONE_SERVER=drone-server:9000
      - DRONE_SECRET=123456

You can now login to drone with your gitea account and activate the drone webhook per simple click.

debugrenderer

Hint: at first i forgot a field in the gitea config. For working webhooks, make sure your server config, especially the ROOT_URL is set correctly.

pipelines

Alright, let’s deliver some code!

My pipeline should:

  • test and build a react frontend to a bundle.js
  • take that bundle and embed it in a go binary
  • upload the go binary to a server
  • start the binary

Drone is loooking for a .drone.yml file in the repository root. Everything is pretty straight forward. I love that i can just use every docker image for my build step, no need to manually install nodejs or go or any other environment by hand.

workspace:
  base: /go
  path: src/drailing.net/go-project

pipeline:
  frontend:
    image: node
    commands:
      - cd frontend
      - npm install
      - npm test
      - npm run build

  build:
    image: cdreier:packr
    commands:
      - go get
      - packr build

  copyToServer:
    image:  appleboy/drone-scp
    host: drailing.net
    username: ssh_username
    secrets: [ ssh_key ]
    target: ~/apps/go-project
    source: go-project

  startServer:
    image: appleboy/drone-ssh
    host: drailing.net
    username: ssh_username
    secrets: [ ssh_key ]
    port: 22
    script:
      - pkill go-project
      - cd ~/apps/go-project
      - nohup ./go-project -port 3033 > /dev/null &
branches: master

The drone docs are awesome. Everything i need to know has a short description and good examples. And the plugin registry offers everything you need for publishing and deyployments.

In the second step, I use packr to embed static files in the go binary. For a small speed boost, i created a custom docker image with packr preinstalled.

With the secrets (in the 3rd and 4th step), i can place the password or the private key in the drone server, so i don’t have to check in plaintext passwords or something.

Thanks to go and packr, i do not have any requirements to the server. For simplicity, i just run the binary - no need to dockerize one simple binary in that case.

In conclusion: really good CI/CD solution, easy to setup and everything is just working!

Last posts

Tags