ホストディレクトリに入れたwordPressをdockerで構築したApache+PHP+MySQLで動かす

# はじめに
DockerにはDockerHubという便利なイメージのレポジトリなんていうのがあります。
必要なイメージは大概ここに落ちていて、PHPやMySQLの公式イメージもあったりします。
**しかし!** ……　公式イメージのみで今までと同じようなWordPressの環境を作ろうとするとハマります。
具体的には**ホストディレクトリにWordPressのフォルダごと入れた環境をDocker内から参照し、Apacheで実行する**
というものです。
ネットを漁ってみても、特に**ホストディレクトリへの書き込み権限**まで踏み込んだリファレンスは少ないように感じます。（コンテナ内にWordPressを入れる例は多々あり）

下記に構築の要件をまとめてみたいと思います。同じことをしたいなと思っている方は参考にしてみてください・

### 要件
* Dockerコンテナにて公式イメージ PHP 5.6 (Apache)を実装
* Dockerコンテナにて公式イメージ MySQL 5.7を実装
* データの永続化、メンテナンスの容易さから Apacheはホストディレクトリの /docker/www をwebrootとして参照する
* MySQLも同様にホストディレクトリの/docker/lib/mysql にデータベース(/var/lib/mysql 以下)を書き込むことにする
* ホストにはApacheとか入れてません(CoreOS使用)
* phpMyAdminとかはセキュリティ的に使わず、[HeidiSQL](http://www.heidisql.com/)などでデータベースにアクセスする方法を考えます。

要はホストディレクトリにデータをぶち込みデータを永続化にする設定にします

# MySQL編
##公式イメージをpullする
まず、公式イメージをレポジトリからpullします。
https://hub.docker.com/_/mysql/

```bash:pull作業
docker pull mysql:5.7
```

これでイメージは準備できました。

## 設定（my.cnf）を少し書き換える
MySQLのデータを永続化させるためにはホストディレクトリに/var/lib/mysql 以下のデータを
書き込ませる必要がありますが、デフォルトの設定だとうまくいきません。そこで追加のcnfデータをかきます。


まずホスト側でDocker作業用ディレクトリ /docker/ を作り、
その中にmysqlディレクトリを作成し、（ここら辺は任意のディレクトリでよいです）
起動時に追加した設定ファイル（cnf）を読み込ませることにします。
追加cnfデータadd.cnfは以下のように書きます。（名前も任意です。）


```bash:add.cnf
[mysqld]
user = root
character-set-server=utf8
```

userはmysqlの実行ユーザに関する項目でデフォルトはmysqlとなっています。
しかし、ホストディレクトリにデータを書き込む際は実行ユーザがそのままだと書き込めないので（実行ユーザーをmysqlにしたまま書き込む方法もあり 後述で検証）rootの方がよいです。
character-set-server=utf8 もついでに設定しておきます。　（デフォルトではlatin)

## コンテナ起動
ではコンテナを起動します。
あらかじめ、作ったadd.cnfを読み込ませ、さらにコンテナ側の/var/lib/mysql と 新たに作成した /docker/lib/mysql とファイル共有させます。mkdirであらかじめ作っておいて下さい。こうすることで、コンテナを消してもデータベースの内容とかが永続化します。

```bash:run作業
docker run --name mysql -v /docker/mysql:/etc/mysql/conf.d -v /docker/lib/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD='password' -d mysql:5.7
```

ファイル共有の設定は -vオプションで コンテナ側のディレクトリ**:（コロン）**ホスト側のディレクトリ で実現できます。
-eオプションで環境変数を流し込むことができるのでついでにmysqlのルートパスワードを設定しておきます。
'password'に任意のパスワードを入れて下さい。　&などがパスワードに入っている時はクオーテーションマークで囲ってあげれば大丈夫
のちのち、PHPとMySQLを連携させたり、外からコンテナ内のMySQLにアクセスするためにも--name はつけておいた方が便利です。

## 確認
起動したか確認します。

```bash:ps
coreos@coreos ~ $ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
7b55a5759557        mysql:5.7           "/entrypoint.sh mysql"   4 minutes ago       Up 4 minutes        3306/tcp            mysql
```

mysqlが起動していることが確認できました。
ちなみにホスト側に3306ポートがバインドしていないのでまだ、外からSQLを流し込むことはできません。


# PHP-Apache 5.6 編
## 一筋縄ではいかないPHP編です
MySQLのコンテナでは公式イメージを使い、MySQLの実行ユーザを簡単にrootへ変更できました。
しかし**公式イメージのPHP-Apacheでは実行ユーザwww-dataからrootに変えるのが難しいのです！**
これでは、ホストディレクトリにApacheがファイルを書き込むことができません。WordPressではプラグインやテーマの更新の際、
Apacheが自らWordPressのデータを書き換えにいきます。　書き換え権限がないディレクトリの場合は更新がうまくできません。

そこで、ホストディレクトリをApacheが書き込み可能な状態で運用する方法をいくつか考えていきたいと思います。

* その一 DockerfileでUbuntuから作り上げる　（真のインフラエンジニアコース）
* その二　ホストディレクトリをどんなユーザーでも書き込めるようにしてしまう。（パーミッションガバガバコース）
* その三　ホスト側にユーザーwww-dataを作成してしまう　（変則コース）

それぞれ見ていきましょう

### その一 DockerfileでUbuntuから作り上げる　（真のインフラエンジニアコース）
DockerにはDockerfileというとても便利な機能があります。
公式PHP-ApacheイメージではすでにApacheの実行ユーザがwww-dataで作りこまれているので、なかなかこの牙城を突き破る（rootにする）のはめんどくさいです。いっそ、UbuntuなどのイメージにApacheやPHPなどをぶち込む設定をDockerfileに書くのも手かと。
その際、Dockerfileに

```bash:Dockefile
ENV APACHE_RUN_USER root
ENV APACHE_RUN_GROUP root
```
の項目を入れる か apache2.confを書き直したものをCOPYコマンドで書き換えるという作戦ができそうです。
UbuntuからPHPが動く環境を作る方法はネットにリファレンスが転がっているのでググってください。

### その二　ホストディレクトリをどんなユーザーでも書き込めるようにしてしまう。（パーミッションガバガバコース）
セキュリティ的にもガバガバですし、なんかもう全てをあきらめた感がすごいのですが、
ホストディレクトリのパーミッションを777にして全ユーザが読み書きできるようにするのも作戦です。
男ならこの方法も潔いでしょう…　上司に怒られそうですが。

```bash:chmod
chmod 777 -R /docker/www
```

### その三　ホスト側にユーザーwww-dataを作成してしまう　（変則コース）
今回の実装ではほかにApacheが動く環境がないことが確認できています。
そこでコンテナ側の実行ユーザ www-dataをホスト側に作ってしまって、ディレクトリのownerもwww-dataにしてしまいましょう。
ポイントはwww-dataのuidをコンテナ側とそろえておくことです。

今回はこの方法を採用したいとおもいます。

## MySQL用イメージ作成
### 公式イメージのpull
まずはphp-apache5.6公式のイメージをpullします。
https://hub.docker.com/_/php/ 　←こ↑こ↓

```bash:pull
docker pull php:5.6-apache 
```

### MySQLが動くように新規イメージを作る(Dockerfile編)
公式PHPイメージではphp-extがありますのでそれを使ってMySQL関係をインストールしてしまいます。
vimはログを確認するために入れたけどいれなくてもいいです。

```bash:Dockerfile
FROM php:5.6-apache
RUN apt-get update && \
    apt-get install -y vim && \
  docker-php-ext-install pdo_mysql mysqli mbstring
```

今回はこのDockerfileを /docker/php に入れましたのでビルドしていきたいと思います。

```bash:build
docker build -t  php:usingmysql /docker/php
```

タグはusingmysqlにしました。

## PHPのコンテナを起動する
作ったイメージを利用してphp-apacheのコンテナを起動します。
要件通り、ホストディレクトリ /docker/www と コンテナの /var/www/html を結びつけています。
またすでに起動しているmysqlコンテナとリンクを組んでます。これでMySQLのコンテナはホスト名 mysqlとしてアクセスできます。

```bash:build
docker run -p 80:80 -p 443:443 -v /docker/www:/var/www/html --link mysql:mysql --name php -d php:usingmysql
```

## 確認

```bash:ps
coreos@coreos / $ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                      NAMES
af7bcbd2b8d6        php:usingmysql      "apache2-foreground"     4 seconds ago       Up 3 seconds        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   php
7b55a5759557        mysql:5.7           "/entrypoint.sh mysql"   2 hours ago         Up 2 hours          3306/tcp                                   mysql
```

無事起動しました。

## phpコンテナ内のwww-dataのuidとか確認する
PHPの公式イメージはDebianが元になっているのでおそらく（確実に）www-dataがapacheの実行ユーザだと考えられますが、一応確認してみたいと思います。
起動しているコンテナのbashを起動してコンテナ内に入ることにします。

```bash:build
docker exec -ti php bash
```

-ti オプションをつけると標準出力にダイレクトします。

コンテナ内でwww-dataの詳細を確認します。

```bash:build
root@af7bcbd2b8d6:/var/www/html# id www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)
```

やっぱりwww-dataがApacheの実行ユーザーで間違いないと思いますし、uidは33でした。

## phpコンテナ内での作業

### MySQLコンテナのlinkが上手くいっているか確認

phpコンテナに入っているついでにMySQLへのlinkが上手くいっているか確認しておきましょう。

リンクがうまくいっているなら/etc/hostsにコンテナのIPが入ります。

```bash:/etc/hosts
root@af7bcbd2b8d6:/var/www/html# cat /etc/hosts
172.17.0.68     af7bcbd2b8d6
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.31     mysql 7b55a5759557
172.17.0.31     mysql
172.17.0.31     mysql.bridge
172.17.0.68     php
172.17.0.68     php.bridge
```

MySQLのコンテナに172.17.0.31 がふられていました。（172.17～　はDockerのIPみたいです）
環境によってIPアドレスは変化するので毎度確認しておいて下さい。

###外からMySQLにアクセスする方法を考える
先ほど確認したIPアドレスをつかって外からMySQLにアクセスする方法を考えます。
方法は２通りです。

* phpMyAdminをつかう
* SSHトンネルを使う ←今回はこっち

####SSHトンネルを使ったデータベースアクセス(Docker編)
Windowsの方であれば[HeidiSQL](http://www.heidisql.com/) が便利です。
冗長な内容なので飛ばして構いません

![無題4.png](https://qiita-image-store.s3.amazonaws.com/0/97408/4d74b6e4-08f0-8c65-8fa7-e053789270d3.png)

ネットワーク種別をMySQL (SSH tunnel)にして
ホスト名は先ほど調べたMySQLに振られたDockerのIPを
ユーザー名は root
パスワードは 先ほど設定したMySQLのルートパスワードを入れます

![無題5.png](https://qiita-image-store.s3.amazonaws.com/0/97408/fad3518e-4b7a-c728-c5fa-c5d7110a17ee.png)

SSHトンネルを使うにはplinkが必要です。PuTTYが入っている人は再度インストールする必要はないです。
SSHホストとポートはDockerの動いているサーバのものを指定
ユーザー名、パスワードもホストサーバのものを利用します。
鍵方式のログインも可能です(OpenSSH形式のものはPuTTY形式への変換が必要です)
ローカルポートには利用していないポートを指定しておけばいいです。

これでアクセスできます。SSHトンネルでMySQLにアクセスする方法は便利なのです！

## ホストに www-data を設定する
### ユーザー www-data を作る 
もう少しで終わるのでがんばっていきましょう。
コンテナからexitで抜けた後ホスト側でユーザー www-data を作ります。 

```bash:useradd
sudo useradd -M -u 33 -g docker www-data
```

-Mオプションはホームディレクトリを作成しないオプションです。
-u でuidを設定します。 先ほど確認したら33だったので33にしました。

確認します

```bash:id
coreos@coreos / $ id www-data
uid=33(www-data) gid=233(docker) groups=233(docker)
```

### /docker/www の所有ユーザーをwww-dataにする

```bash:id
sudo chown -R  www-data /docker/www
```

これで終わりです。

# おわりに
あとは/docker/www に WordPressを入れれば完成です。

WordPressのデータベースアドレスはmysqlにしておけば大丈夫です。

![無題3.png](https://qiita-image-store.s3.amazonaws.com/0/97408/e3716a7b-dd0d-efd7-7436-8583f7af0a9f.png)


これだけです！？ふざけるな！大変だったぞ！

以上です。 :neckbeard: