One Command Blog Posting

Posted by Brad on Sat 07 July 2018

My blog has a problem. I have a handful of articles in progress, but I haven't posted anything since January. Part of this has been life and the blog being lower on the priority list. Another part is my messy dual git system ( I have an internal private git server in addition to my public one). And the final part is my natural tendency to not finish projects that I start. Today, I'm going to make some changes to the blog process in hopes of solving at least some of these problems.

First, I need a single script to update the blog. Up to now I have been using a git repo for the blog posts. After I write a post I push it to git and then on the blog server I pull it down. Then I run the new content through pelican and copy it over to the web content folder that nginx serves up. It's not a terrible process but it has too many manual steps. I could simply throw all these manual steps into a bash script and call it a day, but I got the idea that maybe this would be a good reason to check out the gitlab CI features.

It turns out I'm not the first person to think about doing this and gitlab already has an example for using the CI to publish a pelican blog to their gitlab pages. Since I have my own server for the blog I did things a little differently but definitely used their example as the starting point.

Initially I was tried out the docker runner which worked well enough for processing the blog, but had a couple issues. The first is that it basically had to re-download pelican and other dependencies every time it ran. That's not a big deal, but just not very efficient. The second issue was getting the artifact to the destination server. Since the docker container got created every time it didn't have a persistent ssh config/keypair.

So I moved over to a standard shell runner. I set up a python venv that will persist, ssh keypair, and the other minor dependencies. Along the way I found out with multiple runners it appears gitlab will round-robin the jobs so I simply assigned the docker runner to another project I plan to use it on, forcing the shell runner to be used for the blog.

yum install epel-release
yum install python36
sudo -iu gitlab-runner
python36 -m venv blogpy
ssh-keygen
git clone https://github.com/gilsondev/pelican-clean-blog.git ~/data/pelican-theme

The runner was now ready for use so I updated the .gitlab-ci.yml accordingly.

blog:
  script:
  - source ~/blogpy/bin/activate
  - pip install -r requirements.txt
  - pelican -s pelicanconf.py
  - rsync -av -e ssh --delete public/ blogserver:/var/www/blog/
  artifacts:
    paths:
    - public/

With that all said and done my blog is now updated every time I do a git push. I'm sure I could take it a bit further with a test phase, but for the blog it's not really necessary. Also, it goes without saying, but there was a fair amount of trial and error to get the runner and pelican config sorted out. Most of the errors along the way were trivial parts of learning how the CI feature worked and one instance of my firewall blocking outbound traffic.

To wrap things up, now there is no effort required to update the blog. I'm fairly impressed with gitlab overall as well as the CI and am excited to throw some ansible at it. I've also done some work to my storage server and backups that will likely be the next thing I write about.

tags: git, scripting