I’ve written before about how I deploy this blog using Drone.io. It works well, and does exactly what you’d expect.
Lately I’ve started looking into reducing complexity in homelab systems that I use — and using “a Continuous Integration platform for busy development teams” felt a bit overkill for this tiny blog.
So I switched to something simple; GNU Make.
Table of contents
Using Drone.io
Let’s quickly recap my Drone.io setup — this was the production entry in my .drone.yml
file:
---
kind: pipeline
type: ssh
name: production
trigger:
event:
- promote
target:
include:
- production
server:
host: build.lan.uctrl.net
user: hebron
password:
from_secret: password
steps:
- name: initialize
commands:
- git submodule update --init
- hugo version
- ln -s /home/hebron/hugo_resources/production resources
- name: build
commands:
- hugo --gc -b https://blog.cavelab.dev/
- name: cleanup
commands:
- rm public/style.css
- rm public/assets/main.js
- rm public/assets/prism.js
- rm public/assets/style.css
- name: s3-deploy
environment:
AWS_ACCESS_KEY_ID:
from_secret: AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: AWS_SECRET_ACCESS_KEY
commands:
- hugo deploy
- name: s3-aliases
environment:
AWS_ACCESS_KEY_ID:
from_secret: AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY:
from_secret: AWS_SECRET_ACCESS_KEY
commands:
- ./aliases_s3.sh
- name: algolia-index
environment:
ALGOLIA_APP_ID: B9W2KAEOUF
ALGOLIA_ADMIN_KEY:
from_secret: ALGOLIA_ADMIN_KEY
ALGOLIA_INDEX_NAME: content
ALGOLIA_INDEX_FILE: public/algolia.json
commands:
- atomic-algolia
Three services are involved here:
- Drone.io (docker container)
- Drone.io SSH runner (docker container)
- Build machine (LXC container)
The production deployment triggered when a build was promoted to production
.
Briefly explained; here is what happened:
- The git repository and submodules were cloned
- Symbolic link for Hugo’s
resources
folder created (to preserve processed images) - Site was built
- Leftover files from the theme were removed
- Deployed to AWS S3
- Hugo aliases converted to redirects
- Content pushed to Algolia
The process took about two and a half minute — with the clone step taking the longest, at almost one minute.
Having to clone the repository every time felt unnecessary, the repository for this blog is fairly large at 808 MiB. And keeps growing with every publish.
Most of that are images — you could store images outside the repository, but I like to have everything together. The images are a critical part of the site, so they have to be kept in sync somehow.
Alright, enough of that. Over to Make 🙂
Using Make
This is the Makefile
I’m currently using:
-include .env
export
UID=dev
GIT_ID=$(shell git rev-parse --short HEAD)
HOSTNAME=$(shell hostname)
export FOOTER_BUILD_INFO=$(GIT_ID)
.PHONY: server
server:
hugo -D server --renderStaticToDisk
# The UID can be overwritten from the CLI: make deploy UID=`uuidgen`
.PHONY: deploy_dev
deploy_dev:
hugo -D -b https://blog-${UID}.staging.mydomain.no/
rsync -ah --stats public/ staging:/var/www/html/blog/${UID}
@echo Deployed to https://blog-${UID}.staging.mydomain.no/
.PHONY: deploy_production
deploy_production: build_only initialize
hugo -b https://blog.cavelab.dev/
rm public/style.css
rm public/assets/main.js
rm public/assets/prism.js
rm public/assets/style.css
hugo deploy
./aliases_s3.sh
atomic-algolia
.PHONY: initialize
initialize:
git pull
git submodule update --init
rm -r public/
.PHONY: build_only
build_only:
ifneq ($(HOSTNAME),build)
$(error Must be run on build machine.)
endif
content/homelab/cover.png: rack.diag
rackdiag rack.diag -o $@
A phony target is one that is not really the name of a file; rather it is just a name for a recipe to be executed when you make an explicit request. (…) — Make manual
I don’t know about you — but this syntax just speaks to me 😃 Each step, or rules as they are called, is laid out with its dependencies and shell commands.
Make can also be used like NPM scripts — the server
rule in my Makefile simply starts a Hugo server, with drafts and static rendering to disk. Quick and easy 🙂
The FOOTER_BUILD_INFO
environment variable is used to show the current git commit hash in the site footer.
The last rule, for content/homelab/cover.png
, is used to rebuild the rack drawing for my homelab — using rackdiag.
Deploy
Let’s look closer at the deploy_production
rule; we can see that it depends on build_only
and initialize
. build_only
ensures that it can only be done on the build machine, while initialize
does a git pull, submodule update, and clears the public folder.
After that; the same steps as before is done: build, clean up, deploy, make redirects, and push to Algolia 👍
So; to deploy to production — I SSH into by build machine, navigate to the cavelab-blog
folder and type: make deploy_production
.
Credentials
Credentials are stored as environment variables, in a .env
file:
AWS_ACCESS_KEY_ID=xxxx
AWS_SECRET_ACCESS_KEY=xxxx
ALGOLIA_APP_ID=xxxx
ALGOLIA_ADMIN_KEY=xxxx
ALGOLIA_INDEX_NAME=xxxx
ALGOLIA_INDEX_FILE=xxxx
Performance
Let’s take a quick look at performance; using Drone.io took 2 minutes 24 seconds, with the longest step being clone.
$ time make deploy_production
…
Start building sites …
| EN
-------------------+--------
Pages | 514
Paginator pages | 153
Non-page files | 2088
Static files | 32
Processed images | 10813
Aliases | 144
Sitemaps | 1
Cleaned | 0
Total in 26098 ms
…
real 1m15.423s
user 0m17.833s
sys 0m14.397s
Now it takes 1 minute 15 seconds 🎉 Most, if not all, of that can be attributed to the lack of a clone step — instead I’m now doing a git pull, which is much faster 🙂
Conclusion time
Using Make instead of Drone.io means less moving parts — reduced complexity. But it’s also faster and more suited for my use case 🙂
It may not be for everyone; I now have to run a terminal command to deploy the site — as before I could do it through a web interface.
This isn’t a problem for me — I do my writing in the terminal anyway, with Vim.
🖖
Last commit 2024-11-11, with message: Add lots of tags to posts.