GitLab, Docker & Jekyll

We recently re-developed our website using Jekyll; GitLab and Docker; we experimented with a few other ideas including Middleman, Wordpress and DIY using PHP but we eventually settled on Jekyll.

Why not Wordpress?

Our first thought when we set about rebuilding our site was “we want a blog with some static pages - this is Wordpress’s bread and butter!”

  • Security issues: we’re always hearing of new vulnerabilities being found in Workpress and we didn’t want to have to update it every week.
  • Templating: creating templates in Wordpress seemed to strongly encourage building HTML the way they build HTML; this made our lives difficult as we had bought a HTML template and just wanted to replace the content without changing the structure of the HTML.
  • Documentation: while WordPress is quite extensively documented we often found it difficult to find the page we wanted - there were times where I couldn’t get back to a page I knew I had seen just a few minutes ago other than by using my browser history.
  • Overly complex: over complicating things is a mistake we’ve seen made a lot over the years and for our fairly basic requirement (static site with a blog) Wordpress seemed like too much of a solution.

Why not DIY it in PHP?

After playing with (and discounting as overkill) Wordpress we though “all we need is a template and some pages - some of the pages might have a bit of logic to list other pages but that should be pretty simple to throw together in PHP.”

We could pretty quickly throw something together in PHP and it would work; we could store everything on the filesystem so we wouldn’t need a database and listing posts and resizing/optimising images wouldn’t be much work; there are lots of simple templating libraries for PHP and we could probably get by (although it wouldn’t be nice) using includes if we had to.

Using PHP would have had a few downsides though:

  • Reinventing the wheel: we’re not the first people to want a simple static site with a blog; our time is better spent not solving problems that have already been solved.
  • Crowd sourcing: if we use an existing solution there’s probably a community of users who faced and hopefully solved most of the challenges we’re likely to encounter.
  • Security: PHP has had a few security issues; do we needs a server side scripting language for a such a simple site?

In the end we decided that we should try to find an existing solution rather than writing our own.

How about Middleman?

We settled on using a static site generator; Middleman was the first option we evaluated as it seemed to be used (and contributed to) by some respectable companies.

Middleman resolved most of the downsides we found in using Wordpress or DIYing: it supported plugins and we were hopeful that a lot of the wants we had would already have been solved and it created a static site which could be served easily from any web server (or cloud service such as S3).

Middleman looked promising but after a few hours of experimenting we found it had a few of it’s own problems:

  • Multiple Versions: why not in itself a bad thing we found that a lot of the plugins we wanted to use weren’t compatible with the latest version of Middleman (v4 at the time of writing) despite it having been officially released in December 2015 (two and a half years ago).
  • Stalled Development: there hadn’t been a release for 18 months when we looked at Middleman.

The impression we got was that the Middleman community wasn’t as active as it had been and perhaps Middleman wasn’t the best tool for starting a new project.

So why Jekyll?

The second static site generator we tried was Jekyll; it’s used by Github pages and has a large community supporting it and writing plugins to provide extra functionality.

We’ve stumbled upon a few bugs/issues with Jekyll but they’ve all been minor and easily overcome - they’re so insignificant that I won’t list them else you’ll think I’m being petty.

The biggest reason against using Jekyll for us was that it was written in Ruby - a language no one on our team has any experience in; since this was an internal project we decided that it was a good opportunity to learn a little ( and it turned out to be very little - you don’t really need to know any Ruby to use Jekyll).

How we’re using Jekyll and Docker

We’ve been developing using Docker Compose to run a custom command in a Dockerfile that’s also used to build an NGINX image serving the static site.

The Dockerfile is a multistage file with:

  • build: a ruby environment with our dependant gems installed; we can use this for developing or as a base to build the site from.
  • publish: this stage copies our code into the previously created environment and uses Jekyll to build a static site suitable for serving from any web server.
  • serve: this final stage takes the static files created by Jekyll and drops them into a NGINX Docker image which will happily serve them on port 80.
FROM ruby:2.5 AS build
RUN bundle config --global frozen 1
RUN gem install jekyll
WORKDIR /usr/src/app
COPY Gemfile Gemfile.lock ./
RUN bundle install

FROM build AS publish
COPY . ./
ENV JEKYLL_ENV=production
RUN bundle exec jekyll build

FROM nginx AS serve
COPY --from=publish /usr/src/app/_site /usr/share/nginx/html

We also have a Docker Compose file; this is only used for development but allows us to develop in the same environment that is used to build the production site.

We start with the build stage of out Dockerfile and then customise the command to run; we mount the current directory (assumed to be the root of our site) into the containers working directory and expose some ports.

By default jekyll serve will only listen for connections on localhost; this prevents us from being able to connect to the container from our host machine so we pass -H 0.0.0.0 telling Jekyll to listen on all interfaces.

version: '3.6'
services:
  jekyll:
    build:
      context: .
      target: build
    command: bundle exec jekyll serve -H 0.0.0.0 --force_polling
    volumes:
    - type: bind
      source: ./
      target: /usr/src/app
    ports:
    - "4000:4000"
    - "35729:35729"
    - "3000:3000"

We had the main pages of the site done within a day and found the development process using Jekyll to be pretty nice; we couldn’t get watched folders to work on Windows so we had to fallback to polling for changes but Jekyll supports this out of the box.