久々にブログシステムの環境をアップグレードしたメモです。

はじめに

このサイトでは 過去の記事 にあるように、Minimal Mistakes という Jekyll のテーマを利用しています。2 年とちょっと前 には Gem 化された Minimal Mistakes のパッケージを使って当時の最新バージョンにアップグレードしたのですが、それから時間が経過して Minimal Mistakes も随分とバージョンが進んでいたので、久々にアップグレードをすることにしました。

なお今回は単にアップグレード・マイグレーションをするだけに留まらず、Ruby のバージョンを含めてブログシステムの環境を安定したものにすることを目的として Docker ベースの環境への移行も合わせて実現することにしました。

Jekyll 環境の Docker 化

まずは Jekyll の環境を Docker 化するところから始めます。

Docker イメージの構築

Jekyll と Docker というと、例えば Jekyll Docker など既にいくつかの Dockerfile / Docker イメージが存在していますが、以前に Gem 化された Minimal Mistakes で用意した Gemfile を利用することを前提に、今回は自前で Docker イメージを作ることにします。

# Gemfile の例
source 'https://rubygems.org'

gem 'jekyll', '3.8.5'
gem 'minimal-mistakes-jekyll', '4.16.4'

# ブログシステムで必要とするプラグインを以下に記述する
# group :jekyll_plugins do
#   gem 'jekyll-archives'
# end

Docker イメージには以下の 3 つのみを含めることにし、実際のブログサイトに関わる各種リソースや設定 (_config.yml など) は含めないことにします。

  • Ruby
  • Jekyll
  • Minimal Mistakes

よって、Dockerfile は次のようになります。

FROM ruby:2.6.3-stretch

COPY Gemfile /work/Gemfile

RUN set -ex \
  && apt-get update \
  && apt-get install -y \
    locales \
    locales-all \
  && locale-gen en_US.UTF-8

ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

RUN set -ex \
  && cd /work \
  && bundle install \
  && rm -rf /root/.bundle/cache

上記では、ベースイメージに Docker official の Ruby イメージ ruby:2.6.3-stretch (Debian ベース) を利用していますが、ここは slim イメージでも (build-essential を apt-get install する必要がありますが) 問題ありません。

Docker コンテナでの jekyll の実行

Jekyll / Minimal Mistakes の Docker イメージが構築できたところで、次はそのイメージを使って Jekyll の各種サブコマンドを実行してみましょう。

例えば、手元の環境において執筆中の記事を Web ブラウザ上で確認したいのであれば、以下のように jekyll serve を Docker コンテナ上で実行します。

# カレントディレクトリに _config.yml などがあることを想定している
docker run --rm -it --name <コンテナ名> \
    -v $PWD/_config.yml:/work/_config.yml \
    -v $PWD/index.html:/work/index.html \
    -v $PWD/_data/:/work/_data/ \
    -v $PWD/_posts/:/work/_posts/ \
    -v $PWD/_site/:/work/_site/ \
    -v $PWD/images/:/work/images/ \
    -p 4000:4000 \
    -w /work \
    <イメージ名> \
    bundle exec jekyll serve -H 0.0.0.0

実際に GitHub Pages などで公開するための HTML その他を出力したいのであれば、以下のように jekyll build を実行します。docker run コマンドの -e (--env) オプションで JEKYLL_ENV=production の環境変数を設定しているのがポイントですね。

docker run --rm -it --name <コンテナ名> \
    -v $PWD/_config.yml:/work/_config.yml \
    -v $PWD/index.html:/work/index.html \
    -v $PWD/_data/:/work/_data/ \
    -v $PWD/_posts/:/work/_posts/ \
    -v $PWD/_site/:/work/_site/ \
    -v $PWD/images/:/work/images/ \
    -w /work \
    -e JEKYLL_ENV=production \
    <イメージ名> \
    bundle exec jekyll build

なお、これらのコマンドを毎回手で手で打つのは辛いので、以下のような Makefile を用意しておけば、 make jekyll-serve, make jekyll-build といったコマンドをを打つだけで事を済ませられるようになります。

DOCKER = docker

DOCKER_IMAGE = minimal-mistakes-jekyll
DOCKER_CONTAINER = minimal-mistakes-jekyll

.PHONY: docker-build jekyll-build jekyll-serve

docker-build:
	mkdir -p tmp
	cp Gemfile Dockerfile tmp/
	docker build tmp/ -t $(DOCKER_IMAGE)

jekyll-serve:
	docker run --rm -it --name $(DOCKER_CONTAINER) \
		-v $$PWD/_config.yml:/work/_config.yml \
		-v $$PWD/index.html:/work/index.html \
		-v $$PWD/_data/:/work/_data/ \
		-v $$PWD/_posts/:/work/_posts/ \
		-v $$PWD/_site/:/work/_site/ \
		-v $$PWD/images/:/work/images/ \
		-p 4000:4000 \
		-w /work \
		$(DOCKER_IMAGE) \
		bundle exec jekyll serve -H 0.0.0.0

jekyll-build:
	docker run --rm -it --name $(DOCKER_CONTAINER) \
		-v $$PWD/_config.yml:/work/_config.yml \
		-v $$PWD/index.html:/work/index.html \
		-v $$PWD/_data/:/work/_data/ \
		-v $$PWD/_posts/:/work/_posts/ \
		-v $$PWD/_site/:/work/_site/ \
		-v $$PWD/images/:/work/images/ \
		-w /work \
		-e JEKYLL_ENV=production \
		$(DOCKER_IMAGE) \
		bundle exec jekyll build

Minimal Mistakes のアップグレード

直近まで利用していた Minimal Mistakes のバージョンは 4.9.1 で、そこから最新の 4.16.4 まではかなりのリリースが積み重なっており、_config.yml その他のファイルのマイグレーションが必要でした。

Quick-Start Guide を消す

Minimal Mistakes において、ページ上部 (右上) のメニュー表示は _data/navigation.yml の内容に基づいて作られるのですが、このファイルが存在しないと、Quick-Start Guide へのリンクが表示されてしまいます。

以前は main: とだけ書かれた内容のファイルを _data/navigation.yml として置いておけば十分でした。しかし、いつのバージョンからか main: と書くだけでは不十分で、main: [] と明示的に空配列まで記述しなければならなくなりました (空配列がないと Quick-Start Guide が表示されてしまう)。

Author リンクの記述

著者情報のエリアに表示される各種 Web サービスへのリンクの設定方法が、#1581 の変更によって変わりました 。具体的には、_config.yml に以下のような書式で記述します。関連するドキュメントは こちら

author:
  links:
    - label: "Email"
      icon: "fas fa-fw fa-envelope-square"
      url: mailto:your.name@email.com
    - label: "Website"
      icon: "fas fa-fw fa-link"
      url: "https://your-website.com"
    - label: "Twitter"
      icon: "fab fa-fw fa-twitter-square"
      url: "https://twitter.com/username"
    - label: "Facebook"
      icon: "fab fa-fw fa-facebook-square"
      url: "https://facebook.com/username"
    - label: "GitHub"
      icon: "fab fa-fw fa-github"
      url: "https://github.com/username"
    - label: "Instagram"
      icon: "fab fa-fw fa-instagram"
      url: "https://instagram.com/username"

これにより、Speaker Deck や Slideshare といったこれまでサポートされていなかったサービスのリンクも (Font Awesome で目的のアイコンを探す必要はありますが) 自由に追加できるようになりました。

フッターリンクの記述

著者情報のリンクと同様に、フッターのリンクも _config.yml で自由に制御できるようになりました。記述方法もほぼ同じで、以下のようになります。

footer:
  links:
    - label: "Twitter"
      icon: "fab fa-fw fa-twitter-square"
      url: "https://twitter.com/username"
    - label: "Facebook"
      icon: "fab fa-fw fa-facebook-square"
      url: "https://facebook.com/username"
    - label: "GitHub"
      icon: "fab fa-fw fa-github"
      url: "https://github.com/username"

base_path の削除

以前存在していた base_path のヘルパーが 削除された ことによって、{% include base_path %} の Liquid タグが含まれたファイルが存在すると以下の類のエラーが出力されるようになりました。

       Jekyll Feed: Generating feed for posts
  Liquid Exception: Could not locate the included file 'base_path' in any of ["/work/_includes", "/usr/local/bundle/gems/minimal-mistakes-jekyll-4.16.4/_includes"]. Ensure it exists in one of those directories and, if it is a symlink, does not point outside your site source. in index.html
             Error: Could not locate the included file 'base_path' in any of ["/work/_includes", "/usr/local/bundle/gems/minimal-mistakes-jekyll-4.16.4/_includes"]. Ensure it exists in one of those directories and, if it is a symlink, does not point outside your site source.
             Error: Run jekyll build --trace for more information.

そもそも、このブログではもはや base_path は使っていなかったので、削除して対処しました。

Docker 化のハマりどころ

以降は Jekyll + Minimal Mistakes の環境を Docker 化するにあたって、ハマったポイントになります。

ロケールの設定

前述した Dockerfile には、以下のようにロケール設定の記述がありました。

# (ロケール設定部分を抜粋)
RUN set -ex \
  && apt-get update \
  && apt-get install -y \
    locales \
    locales-all \
  && locale-gen en_US.UTF-8

ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

仮にこのロケールを 設定することなく ビルドした Docker イメージを使って jekyll build もしくは jekyll serve した場合、以下のように scss ファイルのコンパイルで Invalid US-ASCII character が発生してしまいます。

make jekyll-serve 
# (省略)
Configuration file: _config.yml
            Source: /work
       Destination: /work/_site
 Incremental build: enabled
      Generating... 
       Jekyll Feed: Generating feed for posts
  Conversion error: Jekyll::Converters::Scss encountered an error while converting 'assets/css/main.scss':
                    Invalid US-ASCII character "\xE2" on line 54
jekyll 3.8.5 | Error:  Invalid US-ASCII character "\xE2" on line 54
make: *** [jekyll-serve] Error 1

コンテナ外からの WEBrick サーバへのアクセス

Docker コンテナ上に jekyll serve で立ち上げた HTTP サーバ (WEBrick) に コンテナ外 からアクセスする場合、-h, --host オプションなどで 0.0.0.0 にバインドする必要があります。これを怠ると、コンテナ内からは curl http://localhost:4000/ でレスポンスが得られるけどコンテナ外からだと疎通できない… みたいな状況に陥ります。

まとめ

Gem 化によって Minimal Mistakes のテーマを使った Jekyll 環境の構築は随分と楽になりましたが、さらに Docker 化することで、環境を新しい PC に移行することも楽にできるようになりました。

なお Docker 化した Minimal Mistakes + Jekyll の環境は komiya-atsushi/dockerized-minimal-mistakes-jekyll-example にてそのサンプルを公開しています。