phpMyFAQ on Docker on CentOS7

# はじめに

[phpMyFAQ](https://www.phpmyfaq.de/) を使う機会があったので、公式の Compose ファイル、Dockerfile を利用し、CentOS7 上で稼働させました。

すんなりいくと考えていたら、案外と紆余曲折ありましたので、備忘として残しておきます。

# 環境

- CentOS7 (3.10.0-957.12.2.el7.x86_64)
- Docker CE (version 19.03.2)
- Docker Compose (docker-compose version 1.24.0)

# ダウンロード、ビルド

まず公式の [GitHub リポジトリ](https://github.com/thorsten/phpMyFAQ)を確認すると、**Installation** の項に次の記載があります。

> To build a production release please use the docker-hub repository or use images provided on docker.io.

「本番リリースをビルドするには docker-hub リポジトリか、docker.io で提供しているイメージ使えや」と書かれており、それぞれリンクが張られているのが分かります。

更に [docker-hub](https://github.com/phpMyFAQ/docker-hub) をクリックすると、別のリポジトリが開き、そこにもインストール方法が書かれています。

どうやらこのリポジトリから clone してビルドすると良さそうなので、書かれている方法を試してみます。

```
$ git clone https://github.com/phpMyFAQ/docker-hub.git && cd docker-hub
$ git checkout 3.0
$ docker build -t phpmyfaq .

（途中省略）

  Problem 1
    - The requested PHP extension ext-gd * is missing from your system. Install or enable PHP's gd extension.

```

「**PHP エクステンションに ext-gd がねえよ**」と怒られました･･･。

色々調べたところ、Dockerfile の最初の方で `composer:latest` をベースイメージとして composer をインストールしている箇所があるのですが、そこで怒られたようです。

Dockerfile の26 行目辺りに ext-gd と依存パッケージをインストールする処理を追加します。

```dockerfile:Dokerfile
･･･

#=== Get PMF source code ===
ARG PMF_BRANCH="3.0"
RUN set -x \
 && git clone \
        --depth 1 \
        -b $PMF_BRANCH \
        https://github.com/thorsten/phpMyFAQ.git \
        /app

### ここから追加 ###
RUN set -x \
 && apk --no-cache add zlib-dev libpng-dev \
 && docker-php-ext-install gd
### ここまで追加 ###

#=== Call composer ===
RUN set -x \
  && composer install --no-dev

･･･
```

そして再びビルドします。

```
$ docker build -t phpmyfaq .

･･･

checking for libzip... configure: error: Please reinstall the libzip distribution
not found
```

今度は「**libzip がねえよ**」と怒られました。

ログを遡ってエラーの出てる箇所を調べてみると、Dockerfile内 `Install intl, opcache, and zip php dependencie` のところにある `buildDeps` に `libzip-dev` を追加すると良さそうです。

```dockerfile:Dockerfile
#=== Install intl, opcache, and zip php dependencie ===
RUN set -x \
 && buildDeps="libicu-dev zlib1g-dev libxml2-dev" \
 ↓↓↓↓↓ libzip-dev 追加
 && buildDeps="libzip-dev libicu-dev zlib1g-dev libxml2-dev" \
```

再々度ビルドを実行します。

```
$ docker build -t phpmyfaq .

･･･

Successfully tagged phpmyfaq:latest
```

これでようやくビルドできました。

# コンテナ起動

イメージのビルドもうまくいったので、`docker-compose` すれば諸々のコンテナが起動してくれるはずです。

```
$ docker-compose up -d
```

コンテナが起動したか確認してみましょう。

```
$ docker-compose ps
         Name                        Command                 State             Ports        
--------------------------------------------------------------------------------------------
docker-hub_mariadb_1      docker-entrypoint.sh mysqld      Up           3306/tcp            
docker-hub_phpmyadmin_1   /docker-entrypoint.sh apac ...   Up           0.0.0.0:8000->80/tcp
docker-hub_phpmyfaq_1     /entrypoint apache2-foreground   Up           0.0.0.0:8080->80/tcp
elasticsearch             /bin/bash bin/es-docker          Restarting 
```

どうやら ElasticSearch コンテナに問題が発生しているようなので、ログを確認します。

```
$ docker-compose logs elasticsearch

･･･
[2020-03-23T06:06:57,728][WARN ][o.e.b.ElasticsearchUncaughtExceptionHandler] [] uncaught exception in thread [main]
org.elasticsearch.bootstrap.StartupException: java.lang.IllegalStateException: Failed to create node environment
        at org.elasticsearch.bootstrap.Elasticsearch.init(Elasticsearch.java:136) ~[elasticsearch-5.6.9.jar:5.6.9]
        at org.elasticsearch.bootstrap.Elasticsearch.execute(Elasticsearch.java:123) ~[elasticsearch-5.6.9.jar:5.6.9]
        at org.elasticsearch.cli.EnvironmentAwareCommand.execute(EnvironmentAwareCommand.java:70) ~[elasticsearch-5.6.9.jar:5.6.9]
        at org.elasticsearch.cli.Command.mainWithoutErrorHandling(Command.java:134) ~[elasticsearch-5.6.9.jar:5.6.9]
        at org.elasticsearch.cli.Command.main(Command.java:90) ~[elasticsearch-5.6.9.jar:5.6.9]
        at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:91) ~[elasticsearch-5.6.9.jar:5.6.9]
        at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:84) ~[elasticsearch-5.6.9.jar:5.6.9]
･･･
```

`Failed to create node environment` というエラーが発生しています。
調べてみたところ、elasticsearch の永続データを保存するホスト側ディレクトリ `./volumes/esdata` のアクセス権に問題があるようです。

このディレクトリの所有者を、ホスト側カレントユーザーに変更して再度コンテナを起動してみます。

```
$ docker-compose down
$ sudo chown -R $USER. volumes/esdata
$ docker-compose up -d
```

再びコンテナの状態を確認してみます。

```
$ docker-compose ps
         Name                        Command                 State             Ports        
--------------------------------------------------------------------------------------------
docker-hub_mariadb_1      docker-entrypoint.sh mysqld      Up           3306/tcp            
docker-hub_phpmyadmin_1   /docker-entrypoint.sh apac ...   Up           0.0.0.0:8000->80/tcp
docker-hub_phpmyfaq_1     /entrypoint apache2-foreground   Up           0.0.0.0:8080->80/tcp
elasticsearch             /bin/bash bin/es-docker          Restarting 

```

まだ ElasticSearch コンテナで問題が起こってるようなのでログを確認します。

```

$ docker-compose logs elasticsearch
･･･
ERROR: [1] bootstrap checks failed
[1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
```

「**メモリマップの最大数が少ねえよ、増やしな**」とのことです。

ホスト側カーネルパラメータ `vm.max_map_count` の値を確認します。

```
$ sudo sh -c "sysctl -a | grep max_map"
vm.max_map_count = 65530
```

指摘された通り `65530` となってるので、`262144` まで増やします。（`65530` は CentOS7 でのデフォルト値）

```
$ docker-compose down
$ sudo sysctl -w vm.max_map_count=262144
$ sudo sh -c "echo 'vm.max_map_count = 262144' >> /etc/sysctl.conf"
```

念のため変更されたか確認してみます。

```
$ sudo sh -c "sysctl -a | grep max_map"
vm.max_map_count = 262144
```

これで再度コンテナを起動、状態を確認します。

```
$ docker-compose up -d
$ docker-compose ps
         Name                        Command               State                Ports              
---------------------------------------------------------------------------------------------------
docker-hub_mariadb_1      docker-entrypoint.sh mysqld      Up      3306/tcp                        
docker-hub_phpmyadmin_1   /docker-entrypoint.sh apac ...   Up      0.0.0.0:8000->80/tcp            
docker-hub_phpmyfaq_1     /entrypoint apache2-foreground   Up      0.0.0.0:8080->80/tcp            
elasticsearch             /bin/bash bin/es-docker          Up      0.0.0.0:9200->9200/tcp, 9300/tcp
```

うまく起動してくれたようです。

# phpMyFAQ へアクセス

ブラウザから `http://<ホストのIPアドレス>:8080` へアクセスします。

スクリーンショットのように phpMyFAQ のセットアップページが表示されるので、あとは良しなに各項目を設定します。

![phpmyfaq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/284c535e-f43a-8a3a-b374-cee412aed67a.png)

ちなみにこちらの環境では、次のように項目を埋めました。

![phpmyfaq-setup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/66c73a7f-30ed-20cd-2e18-681d789419ea.png)


# Tips

## SMTP に Gmail を利用する

管理ダッシュボードの「設定」>「環境設定」>「Mail setup」で次のように設定します。

- SSL 接続の場合
    ![phpmyfaq-smtp-ssl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/20c4a002-08cc-ffea-971c-e8668b2ff0b9.png)


- TLS 接続の場合
    ![phpmyfaq-smtp-tls.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/9c556612-2653-e05d-725a-7027291756a4.png)

## WYSIWYG エディタを使いたい

フロントエンド側で「内容の追加」等の投稿ページで WYSIWYG が使えません。

![phpmyfaq-wysiwyg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/508d0e0d-74ce-b5ce-24d6-aea27dc3a780.png)

管理ダッシュボードの設定（「設定」>「環境設定」>「メイン設定」）を確認するも、デフォルトで「同梱の WYSIWYG エディターを有効にする」が有効化されています。

![phpmyfaq-config-wysiwyg-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/2f6198bf-694c-3edc-ac7b-c18bb1d88adb.png)

どうやら v3.0 になってから、フロントエンド側で WYSIWYG を有効／無効にする項目が追加されたようですので、この項目を有効にすれば WYSIWYG が使えるようになります。

![phpmyfaq-config-wysiwyg-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/31c19ab8-97bc-e7bf-f16f-4c88b0a6740b.png)

![phpmyfaq-wysiwyg-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94476/63afefbf-a67d-4b23-3b97-8d06ee4fb4aa.png)


また WYSIWIG を使えるのは**回答欄**のみのようで、**質問欄**はテキストしか入力できないようです。