Jekyll's Docker image

Jekyll's ecosystem

I was pretty excited when I found out about Jekyll about a month ago.

It not only gives me the most of the content authoring functionality I need, it also allows me to gain nearly complete control over the site's features and aesthetics. If I knew Ruby, or if the plugins did exactly what I need, I would probably have to say "...gain total control".

The platform is extendable by means of Ruby plugins. They can greatly increase the value of this software and I find that usually they are indispensable. Anybody can create such a plugin. As I understand it, Jekyll plugins are normally shipped as gems. Gems often depend on other gems. Some gems manifest need to have non-gem binary pre-installed on you system in order to work (e.g. jekyl-assets dependency on graphicsmagick binary).

On top of that I was experimenting with some JS build tools (Gulp and Grunt namely) solely for this setup. Needless to say that required more code to be dumped into my environment. Code I don't normally need.

Docker and Jekyll

Jekyll with Docker

I have found experimentation with Jekyll much easier and cleaner with the use of Docker image.

It allowed me to describe my Jekyll setup as code.

I am consciously not stating infrastructure as code as there are some manual steps I need to perform to provision the infrastructure. These steps are small, need to be done once per site, they are asynchronous in nature, some cross-depend and they span across multiple cloud services. I decided not to bother.

That means I can automatically and repeatably create a container with fresh Jekyll setup, ready to fiddle with it.

It allowed me to contain the messy zone to a single directory, which is mounted in the container.

All sounds good, but I had one annoying problem with the image as it is.

Jekyll's Docker image

The Dockerfile creates a jekyll user/group as following:

1RUN addgroup -Sg 1000 jekyll
2RUN adduser  -Su 1000 -G \
3  jekyll jekyll

and then changes ownership of Jekyll locations:

1RUN chown -R jekyll:jekyll $JEKYLL_DATA_DIR

all data generated by Jekyll platform in this container would be owned by Jekyll user/group. In container this translates to uid of 1000 and gid of 1000. The issue is that my host system could not use that uid/gid pair.

Instead I wanted the generated "_site" to be owned by the user which runs docker container. I didn't want to modify the Dockerfile source as it would mean complex merging in case upstream provides me with wildly different future revision. I wanted to patch it over the source.

Dockerfile with desirable uid/gid

Here's what works very well for me:

 1FROM jekyll/jekyll:builder
 3ENV TZ=Europe/London
 4RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
 6ARG to_uid
 7ARG to_gid
 9RUN usermod -u ${to_uid} jekyll && groupmod -g ${to_gid} jekyll
11RUN find / -user $(cat /tmp/from_uid) -exec chown ${to_uid}: {} +
12RUN find / -group $(cat /tmp/from_gid) -exec chown :${to_gid} {} +
14RUN apk add --update 'graphicsmagick>=1.3.27-r0' nano

Building the image requires uid/gid arguments:

1docker build --rm -t my-jekyll-image --build-arg to_uid=$(id -u) --build-arg to_gid=$(id -g) .

I am aware it is not ideal, because I am baking uid/gid in the image, while desirable uid/gid may vary for different user. Same problem may occur as with the original Jekyll image definition. At least I can now configure it though. It was a quick workaround that allowed me to continue experimentation with Jekyll.

You may notice timezone change in the image. While unrelated to uid/gid problem, this is another example of hardcoded variable. In the original Dockerfile, timezone is set to America/Chicago. I was getting annoyed about timestamp differences so fixed it to my timezone.

Remaining references