【その壱】Apache/PandocでMarkdownをHTMLで配信するDockerコンテナの作成

## はじめに

ApacheとPandocを組み込んだDockerコンテナを作成してみたので体験を共有します。

Pandocを使用するとMarkdownをHTMLやPDFに変換できます。
これをApacheに組み込むとMarkdownをダイナミックにHTMLに変換できます。
こうして作ったWebサイトをDockerコンテナに入れると構築や配布が楽になります。
たとえばAmazon AWSのコンテナサービスに登録するなど利用範囲が広がります。

>Dockerファイルほかソースはgithubで、作成済みのDockerイメージはDocker Hubで公開済みです（末尾参照）。

## Pandoc

ローカルPCで（たとえばWindows WSLを用いて）Pandocコンバータを使ってMarkdownをHTMLに変換するには:

```
$ ls
 test.md
$ cat test.md
 # test.md
 Hello **Wonderful** World.
$ pandoc test.md > test.html
$ ls
 test.md
 test.html
$ cat test.html
 <h1 id="test.md">test.md</h1>
 <p>Hello <strong>Wonderful</strong> World.</p>
$
```

## Apache

ApacheでMarkdownファイルの拡張子`md`が参照された場合にPandocが実行されるようにすればHTMLへの自動変換が実現できます。
それにはApacheの外部フィルタというしくみを使うのが簡単です。
Apacheで次のような設定をすれば、Markdownファイルが参照された場合に指定のフィルタが実行されます。
ここでは`pandoc-filter`という名前です。

[local.conf]

```
LoadModule ext_filter_module modules/mod_ext_filter.so

ExtFilterDefine pandoc-filter \
        mode=output intype=text/markdown outtype=text/html \
        cmd="/usr/local/apache2/pandoc-filter"

<Directory /usr/local/apache2/htdocs>
        SetOutputFilter pandoc-filter
        AddType text/markdown .md
</Directory>
```

説明します。

- `LoadModule`で外部フィルタを利用可能とする`ext_filter_module`をロード。
- `ExtFilterDefine`でフィルタが対象とするMIMEタイプとコマンドのパスを指定。
- `Directory`内は、指定ディレクトリ内で拡張子`md`を持つファイルが参照された場合にフィルタを実行してもらう設定。

## Apacheフィルタ

Pandocを呼び出すApacheフィルタを作成しました。
標準入力で渡されるMarkdownソースをPandocを呼び出して標準出力に変換結果のHTMLを出力するBashシェルスクリプトです。

[pandoc-filter]

```
 #!/bin/bash
 BASENAME=$(basename -s .md $DOCUMENT_URI)
 /usr/bin/pandoc -f gfm -t html5 -c "/pandoc-gfm.css" \
	-T "Converted" -M title=${BASENAME}
```

補足します。

- 参照されたMarkdownファイルのパスがDOCUMENT_URI環境変数で渡される。
　たとえば「/test.md」など。ここからPandocに渡すタイトルを取る。
- `-f`は変換元の形式、`-t`は変換先の形式、`-c`はスタイルシートの場所、
  `-T`と`-M title=`で出力されるHTMLのタイトルを指定。
- Pandocは何も指定しないと標準入力から読み込み標準出力へ出力する。

## Docker作成

上記のApache設定ファイルとフィルタスクリプトを組み込んだDockerコンテナを作成します。

```
$ ls
 Dockerfile
 usr-local-apache2/
$ ls usr-local-apache2
 local.conf
 pandoc-filter
$ cat Dockerfile
 FROM httpd:2.4
 RUN apt-get update && apt-get install -y pandoc
 COPY ./usr-local-apache2 /usr/local/apache2/
 RUN echo 'Include local.conf' >> /usr/local/apache2/conf/httpd.conf
$ docker build -t pandoc:test .
```

順に説明します。

- Dockerコンテナを作る場合にはビルド手順を書いたDockerfileを作成する。
- FROMで元になるDockerイメージを指定。
  公式DockerハブからLinuxとApacheを備えたhttpdというイメージを取得。
- RUNでPandocをインストール。
- COPYで先に用意したApache設定ファイルとフィルタをコンテナにコピー。
  コピー先は/usr/local/apachce配下。
- これに続くRUNコマンドで設定ファイルをIncludeする指定をApacheのメインの設定ファイルの末尾に追加。
- Dockerのビルドコマンドを実行。

## Dockerコンテナ実行

Dockerコンテナができたら作成したホスト上で実行してみます。

```
$ docker run --detach -publish 8080:80 \
	--mount type=bind,src=/var/docker/pandoc/htdocs,dst=/usr/local/apache2/htdocs,ro \
	pandoc:test
```

順に説明します。

- `--detach`はコンテナをバックグラウンド（デーモンとして）実行する指定。
- `--publish`で外部からもアクセスできるようホストマシンのポートとコンテナ内で使用するポートを結びつける。
- `--mount`はコンテナ内のドキュメントディレクトリの/usr/local/apache2/htdocsをホスト側のディレクトリに結びつける。
そうしないといちいちコンテナにファイルを追加しなくてはなりません。

## テスト

まずコンテナを実行しているホストマシン内から:

```
$ curl localhost:8080/test.md
```

続いてホストマシンの外部からブラウザでアクセスします。

```
http://example.com:8080/test.md
````

---

### 使用環境

- Docker CE 19.03.12
- ベースイメージ: 公式 [httpd:2.4](https://hub.docker.com/_/httpd)
- テスト環境: Raspberry Pi 3B (raspiban/debian10-buster)、クラウド上のVPS（同じくDebian10-Buster）

### 参考リンク

- [Apache](https://httpd.apache.org/)
- [Pandoc](https://pandoc.org/)
- [Docker](https://www.docker.com/)

DockerfileやApache設定ファイル、Apacheフィルタのソースはgithubで公開しました。
git cloneしてdocker buildすればコンテナが作成できます。

- [github](https://github.com/kobucom/docker-pandoc) 

作成したイメージはDocker Hubからも取得できます。

- [docker-hub](https://hub.docker.com/r/kobucom/pandoc) 

### 横浜工文社の関連ページ

- [Markdown変換Docker](https://kobu.com/docker/index.html) 
- [Markdownダイナミック変換](https://kobu.com/markdown/dynamic.html)
- [Markdown解説](https://kobu.com/markdown/index.html)
 
Written 2020/09/21