Hello everyone,

Let’s talk about how to create a blog using Docker running a containerized Jekyll to publish posts on GitHub Pages.

If you don’t know, Jekyll is a famous blog engine written in Ruby that uses Markdown files as blog posts, avoiding use of databases to store stuff. Jekyll is nice due for simplicity: you need only to create a single .markdown or .md file inside _posts directory and run the following command in your terminal to see your blog running:

$ ruby -S jekyll serve

I’ve used Octopress, a framework written above Jekyll. It’s nice, but you have some effort to create blog skeleton and make it working well with GitHub Pages. I decided to be more simplistic today, changing to Jekyll.

Well, it looks great but where Docker enter? Some months ago, I’m moving from Vagrant to Docker to have more agility because containers are MUCH more thin than entire VM’s running in your machine. After some research on the interwebs, I decided to create a blog from scratch using Docker and Jekyll. I will presume that you already know how Docker works and have some contact with Dockerfile config files.

At first, you need to create a Dockerfile. Let’s see an example:

FROM	salizzar/centos-7-ruby

WORKDIR	/root

RUN	ruby -S gem install jekyll therubyracer

EXPOSE	4000

It installs jekyll and therubyracer gems. The Ruby Racer gem is required to build markdown as Html files. To create a Docker image with Jekyll run:

$ docker build -t myblog .

You probably will see an output similar to this:

Sending build context to Docker daemon 60.93 kB
Sending build context to Docker daemon
Step 0 : FROM salizzar/centos-7-ruby
 ---> 760b5cd8a959
Step 2 : WORKDIR /root
 ---> Using cache
 ---> c36149f0cadd
Step 3 : RUN ruby -S gem install jekyll therubyracer
 ---> Running in a03f0553e865
Successfully installed liquid-2.6.1
Successfully installed kramdown-1.5.0
Building native extensions.  This could take a while...
(... some gems later ...)
Installing ri documentation for therubyracer-0.12.1
34 gems installed
 ---> ac45b6e4eec3
Removing intermediate container a03f0553e865
Step 5 : EXPOSE 4000
 ---> Running in 33f300b8822c
 ---> c986a07888b9
Removing intermediate container 33f300b8822c
Successfully built c986a07888b9

Now your Docker image with Jekyll is ready to be used. Let’s create blog skeleton now:

$ docker run -it -v `pwd`:/root myblog ruby -S jekyll new . --force

Now check the resulting skeleton:

$ ls -lh
total 40
-rw-r--r--  1 salizzar  staff   101B Nov  6 21:19 Dockerfile
-rw-r--r--  1 salizzar  staff   350B Nov  6 21:19 _config.yml
drwxr-xr-x  5 salizzar  staff   170B Nov  6 20:05 _includes
drwxr-xr-x  5 salizzar  staff   170B Nov  6 20:05 _layouts
drwxr-xr-x  6 salizzar  staff   204B Nov  6 21:24 _posts
drwxr-xr-x  5 salizzar  staff   170B Nov  6 20:05 _sass
drwxr-xr-x  9 salizzar  staff   306B Nov  6 21:21 _site
-rw-r--r--  1 salizzar  staff   1.5K Nov  6 20:42 about.md
drwxr-xr-x  3 salizzar  staff   102B Nov  6 20:05 css
-rw-r--r--  1 salizzar  staff   1.3K Nov  6 20:05 feed.xml
-rw-r--r--  1 salizzar  staff   506B Nov  6 20:05 index.html

Jekyll will create the structure above. The --force parameter forces Jekyll to create skeleton inside a non-empty folder; default behavior will display a error message because it expects to create inside a empty directory.

Now is time to run Jekyll HTTP server to see the magic happening:

$ docker run -it -v $(pwd):/root -p 4000:4000 myblog \
	ruby -S jekyll serve --host=0.0.0.0 --watch --force_polling

The command above do this:

  • Run a interactive TTY from docker (--it)

  • Mounts current directory inside container at /root (-v $(pwd):/root)

  • Expose port 4000 from container to host (-p 4000:4000)

  • Uses myblog image to run container

  • Ups Jekyll server using ruby -S jekyll serve

  • Sets Jekyll host to 0.0.0.0 (--host=0.0.0.0)

  • Forces Jekyll to watch modifications inside blog skeleton (--watch)

  • Forces Jekyll to polling periodically in order to detect changes (--force_polling)

Open your browser and type Docker IP (setted by DOCKER_HOST envvar) followed by :4000 (Jekyll HTTP Server port) and you see your blog running on Docker. If you run OSX, type in your terminal:

$ open `echo $DOCKER_HOST | sed 's/tcp/http/' | sed 's/2376/4000/'`

I recommend you to look at Jekyll Documentation and GitHub Pages post explaining how to use Jekyll to configure your personal information inside _config.yml file, setting custom templates / add plugins.

To create a post, generate a markdown file inside _posts directory:

$ touch _posts/`date +%Y-%m-%d`-my-first-post.md

Add a content in your file, respecting markdown identations:

---
author:		Marcelo Pinheiro
title:		My First Post
layout:		post
date:		2014-11-06 20:20:00
---
Hello, stalker! This is my first post.

It’s time to commit to your GitHub repository. Follow the steps on Github Pages to create a repository - named your-github-user.github.io. After this, start a empty git repository in your working directory and set repository URL:

$ git init .
$ git remote add origin git@github.com:<your-github-user>.github.io.git

Add Jekyll skeleton, commit and push.

$ git add .
$ git commit -m "Big Bang commit, oh yeah."
$ git push origin master

Open your GitHub Pages URL - http://your-github-user.github.io - and check the result.

That’s all folks.