Running Jekyll in Docker

Reading time ~6 minutes

Introduction

Jekyll is a great platform for publishing content, but it can be quite difficult to get up and running on a local environment due to its dependencies. Jekyll is a blog-aware, static site generator in Ruby and in order to install it you need to ensure that you have the

  • correct version of Ruby installed
  • RubyGems installed
  • GCC / Make installed

If you’re not familiar with these tools (ruby , gem, bundle, ….) then getting up and running can be time consuming and cumbersome.

Depending on your OS, you might already have an existing version of Ruby, and you might need to upgrade or install other packages, potentially risking the sanity of other applications depending on those runtimes.

There must be a better way….

Enter Docker, the container technology that can help us encapsulate the jekyll specifics and its dependencies by keeping them contained.

What is Jekyll

Jekyll is a static site generator, typically used for blogs. It processes a folder containing different items like posts, drafts, layouts and converts it into a fully fledged static html site that you can publish. The folder is typically stored in version control, and a build pipeline takes care of processing that folder and publishing a new site.

In order to process that folder, you need to have the jekyll executable and all of its dependencies.

  • jekyll new my-blog (to create a new folder structure)
  • jekyll build (to process the folder structure, and generate an html site)
  • jekyll serve (to run an http server on your local environment)

However, as stated before, in order to run the jekyll executable on your environment, you’ll need to have a lot of dependencies in place.

Jekyll in docker

In the following github project, you can find a containerized version of jekyll where all of these dependencies are available in the container.

As such, in order to get started, the only thing you need to do is this:

export JEKYLL_VERSION=3.5
mkdir -p ~/Projects/NewBlog ; cd ~/Projects/NewBlog
docker run --rm --volume="$PWD:/srv/jekyll" -it jekyll/jekyll:$JEKYLL_VERSION jekyll new .

you should see the following output


Running bundle install in /srv/jekyll... 
  Bundler: The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
  Bundler: Fetching gem metadata from https://rubygems.org/...........
  Bundler: Fetching version metadata from https://rubygems.org/..
  Bundler: Fetching dependency metadata from https://rubygems.org/.
  Bundler: Resolving dependencies...
  Bundler: Fetching public_suffix 3.0.2
  Bundler: Installing public_suffix 3.0.2
  Bundler: Using bundler 1.15.4
  Bundler: Using colorator 1.1.0
  Bundler: Fetching ffi 1.9.23
  Bundler: Installing ffi 1.9.23 with native extensions
  Bundler: Using forwardable-extended 2.6.0
  Bundler: Fetching rb-fsevent 0.10.3
  Bundler: Installing rb-fsevent 0.10.3
  Bundler: Fetching ruby_dep 1.5.0
  Bundler: Installing ruby_dep 1.5.0
  Bundler: Fetching kramdown 1.16.2
  Bundler: Installing kramdown 1.16.2
  Bundler: Using liquid 4.0.0
  Bundler: Using mercenary 0.3.6
  Bundler: Using rouge 1.11.1
  Bundler: Using safe_yaml 1.0.4
  Bundler: Using addressable 2.5.2
  Bundler: Using rb-inotify 0.9.10
  Bundler: Fetching pathutil 0.16.1
  Bundler: Installing pathutil 0.16.1
  Bundler: Using sass-listen 4.0.0
  Bundler: Fetching listen 3.1.5
  Bundler: Installing listen 3.1.5
  Bundler: Fetching sass 3.5.6
  Bundler: Installing sass 3.5.6
  Bundler: Fetching jekyll-watch 1.5.1
  Bundler: Installing jekyll-watch 1.5.1
  Bundler: Fetching jekyll-sass-converter 1.5.2
  Bundler: Installing jekyll-sass-converter 1.5.2
  Bundler: Using jekyll 3.5.2
  Bundler: Fetching jekyll-feed 0.9.3
  Bundler: Installing jekyll-feed 0.9.3
  Bundler: Fetching jekyll-seo-tag 2.4.0
  Bundler: Installing jekyll-seo-tag 2.4.0
  Bundler: Fetching minima 2.4.1
  Bundler: Installing minima 2.4.1
  Bundler: Bundle complete! 4 Gemfile dependencies, 24 gems now installed.
  Bundler: Bundled gems are installed into /usr/local/bundle.
New jekyll site installed in /srv/jekyll. 

What happened here ?

  • We’ve started a docker jekyll container
  • We’ve mounted the current folder as /srv/jekyll in the container
  • We’ve passed the jekyll new command
  • A new site was created in the current folder by the container

Because the volume was mounted on our host, the generated files end up on the host as well.

At this point you have a very minimalistic set of files. These files are primarily configuration files and a sample post. The site itself hasn’t been built yet.

find .

.
./.gitignore
./404.html
./_config.yml
./_posts
./_posts/2018-04-01-welcome-to-jekyll.markdown
./about.md
./Gemfile
./Gemfile.lock
./index.md

To build it, we execute the following command:

docker run --rm --volume="$PWD:/srv/jekyll" -it jekyll/jekyll:$JEKYLL_VERSION jekyll build

You’ll get the following output

docker run --rm --volume="$PWD:/srv/jekyll" -it jekyll/jekyll:$JEKYLL_VERSION jekyll build

The following gems are missing
 * public_suffix (3.0.2)
 * ffi (1.9.23)
 * rb-fsevent (0.10.3)
 * sass (3.5.6)
 * jekyll-sass-converter (1.5.2)
 * ruby_dep (1.5.0)
 * listen (3.1.5)
 * jekyll-watch (1.5.1)
 * kramdown (1.16.2)
 * pathutil (0.16.1)
 * jekyll-feed (0.9.3)
 * jekyll-seo-tag (2.4.0)
 * minima (2.4.1)
Install missing gems with `bundle install`
Fetching gem metadata from https://rubygems.org/...........
Fetching version metadata from https://rubygems.org/..
Fetching dependency metadata from https://rubygems.org/.
Fetching public_suffix 3.0.2
Installing public_suffix 3.0.2
Using bundler 1.15.4
Using colorator 1.1.0
Fetching ffi 1.9.23
Installing ffi 1.9.23 with native extensions
Using forwardable-extended 2.6.0
Fetching rb-fsevent 0.10.3
Installing rb-fsevent 0.10.3
Fetching ruby_dep 1.5.0
Installing ruby_dep 1.5.0
Fetching kramdown 1.16.2
Installing kramdown 1.16.2
Using liquid 4.0.0
Using mercenary 0.3.6
Using rouge 1.11.1
Using safe_yaml 1.0.4
Using addressable 2.5.2
Using rb-inotify 0.9.10
Fetching pathutil 0.16.1
Installing pathutil 0.16.1
Using sass-listen 4.0.0
Fetching listen 3.1.5
Installing listen 3.1.5
Fetching sass 3.5.6
Installing sass 3.5.6
Fetching jekyll-watch 1.5.1
Installing jekyll-watch 1.5.1
Fetching jekyll-sass-converter 1.5.2
Installing jekyll-sass-converter 1.5.2
Using jekyll 3.5.2
Fetching jekyll-feed 0.9.3
Installing jekyll-feed 0.9.3
Fetching jekyll-seo-tag 2.4.0
Installing jekyll-seo-tag 2.4.0
Fetching minima 2.4.1
Installing minima 2.4.1
Bundle complete! 4 Gemfile dependencies, 24 gems now installed.
Bundled gems are installed into /usr/local/bundle.
Configuration file: /srv/jekyll/_config.yml
            Source: /srv/jekyll
       Destination: /srv/jekyll/_site
 Incremental build: disabled. Enable with --incremental
      Generating... 
                    done in 1.135 seconds.
 Auto-regeneration: disabled. Use --watch to enable.

Not how our output folder has grown a bit :

find .

.
./.gitignore
./.sass-cache
./.sass-cache/6f185a96dff45864ec708ea7d5aed927991ce39e
./.sass-cache/6f185a96dff45864ec708ea7d5aed927991ce39e/minima.scssc
./.sass-cache/bf0d24d96991851c620c912ab9fea583ebd85dad
./.sass-cache/bf0d24d96991851c620c912ab9fea583ebd85dad/_base.scssc
./.sass-cache/bf0d24d96991851c620c912ab9fea583ebd85dad/_layout.scssc
./.sass-cache/bf0d24d96991851c620c912ab9fea583ebd85dad/_syntax-highlighting.scssc
./404.html
./_config.yml
./_posts
./_posts/2018-04-01-welcome-to-jekyll.markdown
./_site
./_site/404.html
./_site/about
./_site/about/index.html
./_site/assets
./_site/assets/main.css
./_site/assets/minima-social-icons.svg
./_site/feed.xml
./_site/index.html
./_site/jekyll
./_site/jekyll/update
./_site/jekyll/update/2018
./_site/jekyll/update/2018/04
./_site/jekyll/update/2018/04/01
./_site/jekyll/update/2018/04/01/welcome-to-jekyll.html
./about.md
./Gemfile
./Gemfile.lock
./index.md

Notice also how a _site folder was created containing your actual site. (the generated html based on the markdown posts)

Now that you’ve got a site, you’ll probably want to run it locally.

Execute following command :

docker run --name newblog --volume="$PWD:/srv/jekyll" -p 3000:4000 -it jekyll/jekyll:$JEKYLL_VERSION jekyll serve --watch --drafts

As you make changes to your blog, they will automatically be picked up the jekyll process running in the docker container.

Themes

We’re going to update our blog with a new template.

We’ll need to add the following gems to our Gemfile.

group :jekyll_plugins do
   gem "jekyll-feed", "~> 0.6"
   gem "jekyll-gist", "~> 1.4"
   gem "jekyll-paginate", "~> 1.1"
   gem "jekyll-theme-hydeout", "~> 3.4"   
end

Next, in our _config.yml file, we’ll enable pagination, set the theme to jekyll-theme-hydeout add add some plugins

paginate:         5

# Build settings
markdown: kramdown
theme: jekyll-theme-hydeout
plugins:
  - jekyll-feed
  - jekyll-gist
  - jekyll-paginate  

Finally, we’ll need to remove the standard index.md with an index.html that contains this:

---
layout: index
title: Home
---

Simply running the jekyll build

docker run --name newblog --volume="$PWD:/srv/jekyll" -p 3000:4000 -it jekyll/jekyll:$JEKYLL_VERSION jekyll serve --watch --drafts

or restarting your docker container

docker restart newblog

will get you your newly themes site:

Commands

To recap, here our some commands you’ll frequently use :

Creating a new site

docker run --rm --volume="$PWD:/srv/jekyll" -it jekyll/jekyll:$JEKYLL_VERSION jekyll new newblog

Building an existing site

docker run --rm --volume="$PWD:/srv/jekyll" -it jekyll/jekyll:$JEKYLL_VERSION jekyll build

Serving the blog

docker run --name myblog --volume="$PWD:/srv/jekyll" -p 4000:4000 -it jekyll/jekyll:$JEKYLL_VERSION jekyll serve --watch --drafts

Executing commands in the container

docker exec -ti myblog gem install "jekyll-theme-hydeout"

Executing a shell in the container

docker exec -ti myblog /bin/sh

Removing container

docker rm -f myblog

Running Docker Swarm on Azure

IntroductionThis document outlines some of my experiences with setting up Docker Swarm on an Azure Cloud. This post targets people who ha...… Continue reading

Using KVM on CentOS

Published on March 20, 2017

HTTP communication with Apache NiFi

Published on December 29, 2016