【その弐】Apache/PandocでMarkdownをHTMLにして配信するDockerコンテナの作成 - リモート版

## はじめに

先日ApacheとPandocを組み込んだDockerコンテナをご紹介しました → [ローカル版](https://qiita.com/abun-kobu/items/f390846cdb474777ca84)

コンテナ内あるいはコンテナが動作するホストのディレクトリにソースファイルを置く方式でした。
そうではなく、提供したいMarkdownソースを含むWebリソースがコンテナホストの外部、つまりリモートにある場合に使えるコンテナ（リモート版）を作成したので公開します。

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

以下、前回のローカル版と共通の事柄は割愛します。

## Apache

ローカル版の場合、Apache配下のディレクトリに実在するMarkdownソース（拡張子`md`）の内容がフィルタの標準入力に渡されます。
しかしMarkdownファイルがApache配下のローカルディレクトリに存在しない場合、この方式は使えません。

Apacheには、アクションハンドラという、特定の拡張子を持つURLパスの要求があると、あらかじめ指定しておいたCGIスクリプトを呼び出してくれる、というしくみがあります。
要求されたパスがローカルディレクトリになくてもかまいません。

このしくみを使って、コンテナとは別のWebサーバからMarkdownソースを読み込んで、HTML変換するハンドラを作成しました。

次のApache設定で`pandoc-handler`という名前のアクションハンドラを指定します。

[local.conf]

```
LoadModule cgid_module modules/mod_cgid.so
LoadModule actions_module modules/mod_actions.so

AddHandler markdown-text .md
Action markdown-text /cgi-bin/pandoc-handler virtual

SetEnv REMOTE_DIR https://elsewhere.com/docker
```

説明します。

- `LoadModule`でアクションハンドラを利用可能とする`mod_actions`と、CGIスクリプトを利用可能とする`mod_cgid`をロード。
- `AddHandler`と`Action`ディレクティブで、URLパスで指定されたファイルが拡張子`md`を持つ場合にCGIスクリプトの`pandoc-handler`を呼び出してもらうよう設定
- SetEnvは次項で説明するリモートディレクトリの指定です。

>ベースイメージの`httpd:2.4`ではあらかじめURLの'/cgi-bin'がスクリプト実行可能ディレクトリの'/usr/local/apache2/cgi-bin'に対応づけられているのでこれを利用する。

## Apacheハンドラ

Pandocを呼び出すApacheハンドラを作成しました。
ApacheからPATH_INFO環境変数で渡されるURLパスに応じて取得したMarkdownソースをPandocで変換、標準出力にHTMLを出力するBashシェルスクリプトです。

要求されたURLパスからMarkdownソースを読み込む（あるいは生成することも可）方法はアプリケーションによって様々考えられます。
クラウドのファイルサービスから読む、どこかのデータベースから読む、リモートのgitレポジトリから取得、sftpで取得、などです。

このサンプルは固定のURLが指すリモートディレクトリからMarkdownソースファイルを読み込みます。
前項で設定済みの`REMOTE_DIR`環境変数から`curl`コマンドでMarkdownファイルを読み込みます。

[pandoc-handler]

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

説明します。

- 参照されたMarkdownソースのURLパスが`PATH_INFO`環境変数で渡される。
- 前項の`REMOTE_DIR`環境変数で指定しておいたリモートのWebサーバから`curl`で指定ファイルを取得。
- `pandoc`でHTMLに変換して標準出力へ出力

取得例:

- PATH_INFO = /test.md
- REMOTE_DIR = https://elsewhere.com/docker
- 取得ファイル = https://elsewhere.com/docker/test.md

## Docker作成

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

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

前回同様、FROMで公式DockerハブからLinuxとApacheを含むベースイメージ`httpd`を取得します。
前回とは異なり、RUNで`pandoc`に加えて`curl`を取得します。
`ca-certificate`はcurlでSSLを使うために必要だった。
前回同様、COPYでApache設定ファイルとアクションハンドラ（CGIスクリプト）をコンテナのしかるべき場所にコピーし、Dockerのビルドコマンドを実行します。

## Dockerコンテナ実行

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

```
$ docker run --detach -publish 8080:80 pandoc:remote
```

前回のフィルタの場合と異なりローカルディレクトリは使わないので`--mount`オプションはありません。
前回同様`--public`オプションでポートの割り当てを行います。

## テスト

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

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

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

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

これで 'https://elsewhere.com/docker/test.md' に置いたはずのMarkdownファイルがHTMLになって表示されれば成功です。

続いてこのDockerコンテナをAmazon AWSのコンテナサービスのひとつECS（Elastic Container Service）で動かしてみました。
次回はその顛末を書こうと思います。

---

### 使用環境

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

### 参考リンク

- [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-remote) 

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

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

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

- [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/22