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.
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!