gollumをAlpine LinuxでDocker化

最近勉強したことをメモするのに[gollum](https://github.com/gollum/gollum)を使っていたのだけど、いまどきCentOS7に何も考えずこれを動かしておくのも勿体無いなと思い、Alpine LinuxでDockerコンテナ化してCoreOSで動かすことにした。Alpine Linuxは当方初挑戦である。今回の成果はGitHubにも上げました。

[chroju/docker_gollum: gollum on docker (Alpine Linux)](https://github.com/chroju/docker_gollum)

gollum ?
========

Github Wikiだけを切り出して汎用的に使えるようにしたもの、といった位置づけらしい。特徴としてはMarkdownやReSTといった複数の書式が使えるという点、出力がGithub Wikiを元としているのでかなり見慣れたスッキリした見た目になる点など。Gemで提供しているので取り回しがしやすい点も重宝する。

インフラ環境の選択
========

ホスト
----

Dockerコンテナを置く環境としては、さくらクラウドのCoreOSを使うことにした。理由は単純にクーポンを持ってるからなのだけど、1台自由に使えるDockerホストは欲しいと思ってた。検証環境としては大変便利だと思うので。

クラウドなので何も考えずに使えるのは使えるんだけど、一点だけ注意点としてはCoreOSのバージョンが最新とは限らないようなので、起動後に一度以下コマンドを実行して手動でバージョンを上げておく必要がある。自分の場合は`docker pull`が正しく動かなかった。

```bash
$ sudo update_engine_client -update
```

コンテナ
----

時代の潮流に乗ってAlpine Linux。 **正直言って必要な部分だけしか学べてないので、これ以降書いていることと異なるベストプラクティスがあるかもしれない。** Docker用軽量OSということで簡単に使おうと思ってたけど、OSはOSなので時間作ってもうちょい掘り下げたいところ。

※2016-05-02 `CMD`を修正。`crond`が後ろだと動かないことに気付いた。

Dockerfile
========

取りあえず完成版を貼る。

```docker
FROM ruby:alpine
MAINTAINER chroju

WORKDIR /root

ADD files/id_rsa /root/.ssh/id_rsa
RUN apk --update --no-cache add git g++ ruby-dev linux-headers icu-dev libxml2-dev libxslt-dev build-base openssh && \
ssh-keyscan -t rsa github.com > ~/.ssh/known_hosts && \
gem install gollum github-markdown redcarpet org-ruby --no-ri --no-doc -- --use-system-libraries && \
git config --global user.email "chor.chroju@gmail.com" && git config --global user.name "chroju" && \
git clone git@github.com:chroju/gollum_articles /root/gollum && \
touch /etc/periodic/hourly/gitpush && \
echo -e "#!/bin/sh\ncd /root/gollum && git push origin master" >> /etc/periodic/hourly/gitpush && \
chmod a+x /etc/periodic/hourly/gitpush

ADD files/auth.rb /root/gollum/auth.rb

CMD crond && /usr/local/bundle/bin/gollum /root/gollum --config /root/gollum/auth.rb

EXPOSE 4567
```

Dockerfile、現状`RUN`に`&&`で複数コマンド書き連ねるみたいのがベストプラクティスになってて、仕様がなんだかイケてない気がする……ってのはここでは置いておいて。やっていることはそれほど多くないとは思う。Alpine LinuxのイメージはRubyが入ったものがあったので、Gemであるgollum動かす上で選定した。

apk add
----

Alpine Linuxのパッケージ管理はapkを使う。`--update`でパッケージリストをアップデートし、`--no-cache`でキャッシュを捨ててイメージを小さく保つ。入れているのはgollumで必要なものと`git`コマンドを使うための`openssh`だが、不要なものもちょっと入ってるかも。

ssh-keyscan
----

gollumで書いた記事のバックアップとして、コンテナからGitHubへやり取りさせようとしていたのだが、これが何故か`Host key verification failed.`になってしまった。ググったらちょうどいいstack overflowが出たのでそのまま解消策として採用してるけど、具体的になぜこれが対策になるかはまだ調べてない。

[docker - Dockerfile Cannot access GIT repo with my private key - Stack Overflow](http://stackoverflow.com/questions/27482504/dockerfile-cannot-access-git-repo-with-my-private-key)

GitHubでの記事保存
----

gollumで書いた記事はそのままだとコンテナの停止と共に消えてしまうので、先述の通りGitHub上に保存している。本来であればCoreOS上でレポジトリを持っておき、Dockerにマウントさせる形を取りたかったのだが、どうもそれだとgollumが正常に動作しないので諦めた。現状はgollumの記事を保存しているGitHubレポジトリを`RUN`の段階で`git clone`し、コンテナの起動後はcronで定期的に`git push`させるようにしている。

### Alpine Linuxにおけるcron

Alpine Linuxのcronについては、OfficialｎのWikiを探したら次の場所に記載があった。

[Alpine Linux:FAQ - Alpine Linux](https://wiki.alpinelinux.org/wiki/Alpine_Linux:FAQ#My_cron_jobs_don.27t_run.3F)

`/etc/periodic`配下に`15min`、`hourly`、`daily`といったフォルダがあるので、必要とする間隔のフォルダ内に実行可能ファイルを置けばよい。なお、ファイルは拡張子を省く必要があるので、`.sh`は不要。

また上記FAQ内にはcrondが自動起動されるかのような記述があるが、自分の環境では起動しなかった（Dockerコンテナ上のAlpineだとダメなのかも？）ので、明示的に`CMD`で起動する必要がある。

gollumの認証
----

gollumはデフォルトだと認証機構を持たないので、簡単な認証を設ける。

```rb:auth.rb
module Precious
  class App < Sinatra::Base
    use Rack::Auth::Basic, "Restricted Area" do |username, password|
      [username, password] == ["chroju", "xxxx"]
    end
  end
end
```

このファイルをgollumのディレクトリに置き、gollum実行時に`--config`オプションで渡すと認証が有効になる。この構成ではgollumディレクトリは`git push`することにしているので、`.gitignore`でauth.rbを無視させることを忘れずに。

docker run
========

必要なコマンドはすべてDockerfileの`CMD`に入れ込んだので、実行時はシンプルにポートフォワーディングだけ設定すればOK。

```bash
$ docker run -d -p 4567:4567 gollum:latest
```