Lakruzz

Blogs by Lars Kruse

Lakruzz Blog WolfWare
Category Blogs in English  
By:  lakruzz  
On: Saturday, March 03. 2018
Tags: | Docker |  Docker machine |  Jekyll |  MacOS | 

Docker Jekyll - 5 easy steps

Jekyll is a static web page generator made in Ruby. It’s the engine that runs GitHub Pages. In the following you will get five easy steps to run jekyll locally, without even installing it, but simply through running a docker image.

The following instructions assumes that you are on a Mac, but it’s even easier if you are on Linux. On linux you can simply skip steps 2+3, since you don’t need a virtual host machine for your Docker.

Docker Jekyll

1. Get Docker on your machine

If you already have Docker installed and knows that it’s working for you - you are already onto the next step.

The easiest way to install Docker on Mac is to use the Homebrew package manager. If you don’t have it setup already you must do it straight away, it’s an absolute must.

Run this:

ruby -e "$(curl -fsSL \
  https://raw.githubusercontent.com/Homebrew/install/master/install)"

Once Homebrew is installed on your Mac, Docker installation is as easy as:

brew cask install virtualbox
brew install docker
brew install docker-machine

2. Create a “default” Docker Machine

Since your Mac isn’t running Linux natively and your Docker container depends on it, you must have a docker-machine available. This is simply how Docker works on non-linux OS, including MacOS and Windows. I’ll use the name “default” in my example, but if you want to call it something else, go ahead, just replace my instances of “default” with you own name in the following instructions.

I you already have a “default” docker machine running then you can move directly onto the next step. If not this is what you need to do:

docker-machine create --driver virtualbox default

OK that was easy - “default” docker-machine created! Now you need to start it.

If you just created it, then it will be running. To be sure you can run docker-machine ls. If your “default” machine isn’t running, you need to start it again.

Like this:

docker-machine start default

But it’s even more convenient to configure your Mac to start it up automatically at each reboot.

The way to do that is to configure a launcher. Create a file called com.docker.machine.default.plist in the ~/Library/LaunchAgents/ directory, with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>EnvironmentVariables</key>
        <dict>
            <key>PATH</key>
            <string>/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin</string>
        </dict>
        <key>Label</key>
        <string>com.docker.machine.default</string>
        <key>ProgramArguments</key>
        <array>
            <string>/usr/local/bin/docker-machine</string>
            <string>start</string>
            <string>default</string>
        </array>
        <key>RunAtLoad</key>
        <true/>
    </dict>
</plist>

Next time you reboot your Mac, the Docker-machine will start automatically.

3. Prepare your shell to use the “default” docker-machine

Before you can use the docker run command you will need to configure your environment. You just simply have to run:

eval "$(docker-machine env default)"

Unfortunately you need to do this every time you open a new terminal. If you find that slightly annoying, then it’s highly recommended that you just add the command to your environment file (~/.zshrc, ~/.bashrc or what ever you are using.)

4. Define a “jekyll” alias

We want jekyll to be available as a native command, without actually installing it, so now when I have Docker working for me, I can use a docker container (lakruzz/jekyll-plus1) that I’ve made available from the public Docker registry. So all we need is an alias, it looks like this:

alias jekyll='docker run -i -t --rm \
  -v $(pwd):/app:rw --workdir /app --publish 80:4000 \
  --entrypoint jekyll lakruzz/jekyll-plus'

Like in the previous step, this alias is not one you want to define every time you open a new terminal, so to make the alias permanent, simply open your environment resource file (~/.zshrc, ~/.bashrc …) again and add it there.

And while you have your resource file open I have another useful alias that I use frequently:

alias stage='open http://`docker-machine ip default`'

It defines an alias stage. When you run it, it will open a web browser, pointing to the jekyll site hosted from your “default” Docker machine.

5. Create a local config file in you jekyll website

To serve a Jekyll site you could simply run:

jekyll serve

However, when you run jekyll serve from a docker container, there are a few additional settings that needs to be applied as switches. Typically you would need to define --host 0.0.0.0 and since you are mounting the local disk into the docker container, you will typically also have to force the watch to poll with --force_polling.

But there is more: Often when I run Jekyll in development mode I also want to build all unpublished pages, build incremental, run in verbose mode etc.

So the command I should use look like this

jekyll serve --host 0.0.0.0 --force_polling \
   --incremental --drafts --future --unpublished --verbose

It starts to get kinda lengthy.

So instead of stacking all these switches on top of the jekyll serve command, I’ve created an extra jekyll configuration file, alongside the default _config.yml. I’ve called it _dev_config.yml and it contains the following:

# Required when running from a Docker container
host: 0.0.0.0
force_polling: true

# Speed it up a bit
incremental: true

# How much to render? These all default to false - But I want them all when I develop.
show_drafts: true
future: true
unpublished: true

# Make the machine talk to you
verbose: true

Now, with everything set up, I can change directory into the folder that contains my jekyll site and build and serve is like this:

jekyll serve --config _config.yml,_dev_config.yml

I’ve even created an alias for that as well. The things I end up adding to my .zshrc (… or .bashrc) file sums up to:

# Docker-machine env setup
eval $(docker-machine env default)

# Docker Jekyll aliases
alias stage='open http://`docker-machine ip default`'
alias htmlproofer='docker run -it --rm\
  -v $(pwd):/site --workdir /site 18fgsa/html-proofer'
alias jekyll='docker run -i -t --rm \
  -v $(pwd):/app:rw --workdir /app --publish 80:4000 \
  --entrypoint jekyll lakruzz/jekyll-plus'
alias dev-jekyll='docker run -i -t --rm \
  -v $(pwd):/app:rw --workdir /app --publish 80:4000 \
  --entrypoint jekyll lakruzz/jekyll-plus serve \
  --config _config.yml,_dev_config.yml'

Docker Jekyll - anything as code

The approached described here, for running Jekyll locally, without actually installing it taps perfectly into the contemporary anything as code buzz; If you build your web site for production using the same image as you use for development it’s game over for all the snowflake servers - I’ll touch on this topic in a future blog.

  1. The lakruzz/jekyll-plus Docker image is an image that installs the stack used for GitHub Pages, It relies on the Ruby gem that is maintained by GitHub. In addition I’ve added a few jekyll plugins that are really neat but unsupported by GitHub pages. Most prominent is the jekyll-responsive-image plugin, but if you use it, you will have to become self-hosted. I’ll get back to that in another blog later.