「DockerでWordPressサイトを開発してみよう」を読んでみよう

# はじめに
[DockerでWordPressサイトを開発してみよう](http://www.slideshare.net/mookjp/dockerword-press)がとてもいいスライドでした。
せっかくならこの内容を「操作できる」だけでなく、「理解できる」ようにしたいと思い、スライドの中身をちゃんと調べたのが、このエントリです。

具体的には、各コマンドやDockerfileのソースの調査履歴になります。
各インフラの知識やLinuxコマンドを学ぶことになるため、人によっては一挙に覚えることが増えて混乱するかもしれません。
とはいえ裏を返せば、サーバ周りの知識が一気に身につく感じがしました。

ちなみに筆者のレベルは、Docker覚えたて。下のような内容をこの前知りました。それでもDocker使えるんだから楽しい。
[はじめてのDocker for Mac](http://qiita.com/kobori_akira/items/0cc993caeb20d77cd367)


## 前提
`$ docker --version`が使えるところまでを前提とします。
よって、**スライド15枚目までは省略。**

# WordPressをDockerで使えるようにする
**スライド16〜22**
まずは、Dockerの基本である「ダウンロードしたイメージからコンテナを起動」を実施する。


```
$ docker pull tutum/WordPress
$ docker run -d -p 80:80 --name=WordPress tutum/WordPress
```

pullコマンドで、Dockerイメージをダウンロードする。
今回は"tutum/WordPress"と名付けられたDockerイメージをダウンロードしている。

runコマンドで、ダウンロードしたDockerイメージからコンテナを作成する。
最後に書かれた"tutum/WordPress"が、指定したDockerイメージ。

## runコマンドのオプション
`-d`オプションで、デタッチド・モードで実行を指定する。
「デタッチド・モード」とは、バックグラウンドで実行すること。つまりは、コンソールに入出力が表示されないことを指す。

`-pオプション`で、コンテナにポートフォワーディングでアクセスできるようにさせる。
ポートフォワーディングとは、ローカルの特定のポートへの通信を、別のIPアドレスの特定のポートに飛ばすこと。
この場合だと、localhostのポート番号80にアクセスすると、それはコンテナ（が管理するWebサーバApache）のポート番号80に飛ぶ。

`--name`オプションで、コンテナの名前を決める。このオプションをつけない場合は、コンテナ名はランダムな英単語がつけられる。

## 作成されたコンテナ（WordPress）について
コンテナが作成されたので、実際にブラウザで http://localhost:80/ にアクセスできるようになった。
（※スライドではIPアドレスでアクセスしているが、IPアドレスの取得は割愛。）

また、スライドでは紹介されていないが、`$ docker ps`で起動中のコンテナを確認することができる。

```
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                          NAMES
529c95595d2a        tutum/WordPress     "/run.sh"                13 hours ago        Up About an hour    0.0.0.0:80->80/tcp, 3306/tcp   WordPress
56676d358595        mysql:5.7           "docker-entrypoint.sh"   39 hours ago        Up About an hour    3306/tcp                       db
```

CONTAINER ID（コンテナID）とは、イメージから作成したコンテナ特有のID。
コンテナは、1つのイメージから複数つくることができ、それぞれ異なるコンテナIDとコンテナ名を持つ。
後述するが、コンテナの停止・再開・削除などは、コンテナ名またはコンテナIDを指定する。

IMAGEは、そのコンテナがつくられるもとになったDockerイメージのこと。

COMMANDは、起動時に与えられたコマンド。
つまり、`$ docker run`というのは、ただコンテナを作成するだけでなく、作成したあとに早速なにかしらのコマンド（操作）がされていることになる。

**（PORTSは、まだ自分の理解が追いついていません。以下は下書きレベルです。）**
PORTSは、バインドしているポートを指す。「バインド」とは、ローカル（今操作してるPC）とリモート（コンテナの中身）の接続のこと。
IPアドレス0.0.0.0は、localhostのこと。ちなみに、127.0.0.1もlocalhostにつながる。（ループバックアドレスと呼ばれている）
ポート80は、HTTP用に予約されたポート番号。3306は、一般的にはMySQLを使うときのポート番号とされている。
つまり、localhostのポート番号80と、コンテナのポート番号80, 3306がバインドされていることが、COMMANDからわかる。

NAMEは、コンテナ名。

# オリジナルのDockerイメージ作成とDockerfile
**スライド23〜25**
次は、ダウンロードしたDockerイメージ"tutum/WordPress"がどのように生まれたかを見ていく。

自分の理解としては、あるDockerイメージは必ず他のDockerイメージをもとに作成されている。
つまり、いま利用した"tutum/WordPress"も別のDockerイメージを土台にしている。

この「何を土台にして、どんな操作を加えるか」を決めるのが**Dockerfile**だ。
そして`$ docker build`（詳細は後述）で、「新しいイメージ名をつけてDockerイメージを作成する」ことができる。

たとえば、"tutum/WordPress"のDockerfileは、以下のようになっている。

```
FROM tutum/lamp:latest
MAINTAINER Fernando Mayo <fernando@tutum.co>, Feng Honglin <hfeng@tutum.co>

# Install plugins
RUN apt-get update && \
  apt-get -y install php5-gd && \
  rm -rf /var/lib/apt/lists/*

# Download latest version of WordPress into /app
RUN rm -fr /app && git clone --depth=1 https://github.com/WordPress/WordPress.git /app

# Configure WordPress to connect to local DB
ADD wp-config.php /app/wp-config.php

# Modify permissions to allow plugin upload
RUN chown -R www-data:www-data /app/wp-content /var/www/html

# Add database setup script
ADD create_mysql_admin_user.sh /create_mysql_admin_user.sh
ADD create_db.sh /create_db.sh
RUN chmod +x /*.sh

EXPOSE 80 3306
CMD ["/run.sh"]
```

## FROM
1行目の「FROM」は、土台とするDockerイメージを指定する。
`FROM tutum/lamp:latest`とあるので、おそらくLAMP環境（Linux, Apache, MySQL, PHP）が入ったイメージが土台になっている。

2行目のMAINTAINERは、このファイルを作成した責任者。操作には直接影響ないはず。

## RUN（丁寧に解説）
「RUN」は、以降のコマンドを実行するコマンド。

```
# Install plugins
RUN apt-get update && \
  apt-get -y install php5-gd && \
  rm -rf /var/lib/apt/lists/*
```

たとえば上のコマンドは、"php5-gd"というパッケージをインストールしている。
とはいえ、急に見ても自分はわからなかったので、ひとつずつ分解する。

まず、このコマンドは3行あるように見えるが、実際は&&とバックスラッシュがあるように、~~1つの
命令文になっている~~1つ目の命令が正しく実行されると続いて2つ目の命令が実行されるようになっている。
（あまりに低いレベルの解説ですが、自分はそもそも2,3行目がRUNに含まれてるとすら分かりませんでした・苦笑）

`apt-get`は、Linuxコマンドのひとつで、パッケージを取得するもの。
そのうち、`update`コマンドで、取得できるパッケージのリストを更新する。
そして、`-y install`コマンドで、インストールを実行する。
（`-y`は、問い合わせに対してすべてyesと答えるオプション。Dockerfileは当然応答ができないので、このオプションは頻繁に使われそう。）
`rm -rf`は、指定したフォルダ以下をすべて強制的に削除するコマンド。
"/var/lib/apt/lists/*ディレクトリは、前のコマンドで取得したパッケージのリストを指している。

まとめると、このRUNコマンドでは、最新化したパッケージリストからphp5-gdパッケージを取得・インストールし、パッケージリストを削除している。
このコマンドによって、無駄なファイル（パッケージリスト）を残すことなく、php5-gdパッケージをインストールしたことになる。

## その他のコマンド
上の内容がわかれば、あとは割と簡単に読めるはず。

```
RUN rm -fr /app && git clone --depth=1 https://github.com/WordPress/WordPress.git /app
```

上のRUNコマンドでは、appフォルダを削除して、WordPressをappフォルダにダウンロードする。
（depthは、WordPressの履歴をどれくらい取得するか。今回の場合は必要ないので、1を指定して最新だけ取得している。）


もうひとつ、ADDコマンドも出現する。これは、ローカルのファイルをコンテナの中に追加（更新）するコマンド。

```
ADD wp-config.php /app/wp-config.php
```

上のADDコマンドでは、ローカルに存在するwp-config.phpを、コンテナ内の/app/wp-config.phpに上書きしている。
こうすることで、土台となるイメージの設定ファイルを書き換えることが可能になる。


```
RUN chown -R www-data:www-data /app/wp-content /var/www/html
```
`chown -R`コマンドは、ファイルやディレクトリ（の中身も含め）の所有者を変更する。所有者は、「（所有者）:（グループ）」で指定する。
この場合は、/app/wp-contentディレクトリと、/var/www/htmlディレクトリの所有者をwww-data（www-dataグループ）に設定する。

```
ADD create_mysql_admin_user.sh /create_mysql_admin_user.sh
ADD create_db.sh /create_db.sh
RUN chmod +x /*.sh
```

2つのADDコマンドは省略。
つぎのRUNコマンドで出てくる`chmod`は、アクセス権を変更するLinuxコマンド。
アクセス権にも色々あり、`+x`は実行権限を追加する記述。つまり、拡張子shのファイル（ADDしたファイル）の実行権限を追加する命令。

```
EXPOSE 80 3306
```

EXPOSEコマンドは、コンテナ内の開放するポート番号を指定する。
HTTPとmysqlが利用できないといけないので、80と3306を開放している。

```
CMD ["/run.sh"]
```

CMDコマンドは、コンテナの実行コマンドを指定。
つまり、前述した`$ docker run`が実行されたときの、コンテナ作成後のコマンドを指定できる。

# オリジナルのDockerイメージ（カスタマイズしたWordPress）の作成
**スライド26〜35**

スライドの通り、WordPressは、wp-config.phpとMySQLのwordpressデータベースに設定を持っている。
よって、さきほど見たDockerfileにこれらをあらかじめ追加するよう命令を書けば、設定済のイメージをつくることができる。

ここで重要なのは、これから作るイメージはDockerfileで見た「tutum/lampを土台にしてDockerfileに定義した操作を行った、オリジナルのDockerイメージ」だということ。
このイメージから作成されるコンテナは設定済なので、さまざまな人に共有することが可能になる。

## コンテナとローカルとのファイル共有

まず、これまでにコンテナ名「wordpress」を作成しているはずなので、これを削除してしまう。
`rm -f`コマンドで、強制的にコンテナを削除する。注意点として、Dockerイメージはローカルに残ったままである。
イメージから作成されたコンテナを削除しているだけ。
```
$ docker rm -f wordpress
```

つぎに、下記サイトをローカルにダウンロードしておく。
https://github.com/mookjp/tutum-docker-wordpress

ダウンロードしたフォルダに移動して、あらためてwordpressコンテナを作成する。
ただし、`-v`オプションを追加する。

```
$ docker run -d -p 80:80 -v $(pwd):/data-share --name=wordpress tutum/wordpress
```
`-v`オプションで、ローカルとコンテナ内のファイルを共有できる。
"$(pwd)"は、いまいるローカルのディレクトリ（正しく操作していれば、ダウンロードしたフォルダになるはず）。
"/data-share"は、コンテナ側のディレクトリ。存在しない場合は作成される。

実際に、ファイルが共有されているか確認してみたい。
**（次の一文、ちょっと不安です）**そのためには、コンテナにログインして、「コンソールを開く」を実行するプロセスを実行する。

```
$ docker exec -it wordpress /bin/bash
```

`$ docker exec`は、「コンテナの中でプロセスを実行する」ためのコマンド。~~`-it`オプションで、コンテナにログインすることができる。~~（現在コメント欄にて教えてもらってます。のちほど更新）
最後の"/bin/bash"はコマンドで、bashシェルを起動する（「コンソールを開く」と同義と理解してます。）

ログインすると、コンソールが`root@1593df29e49d:/# `のようになるはず。
このコンソールはコンテナの中を表示している。
この中で、`ls`コマンドを叩くと、"data-share"ディレクトリとファイル共有が確認できる。

```
root@1593df29e49d:/# ls
app  boot          create_mysql_admin_user.sh  dev  home  lib64  mnt  proc  run     sbin  start-apache2.sh  sys  usr
bin  create_db.sh  data-share                  etc  lib   media  opt  root  run.sh  srv   start-mysqld.sh   tmp  var
root@1593df29e49d:/# ls data-share
Dockerfile			create_mysql_admin_user.sh	LICENSE		mysql.dump.sql
README.md			wp-config.php	circle.yml			wp-content	create_db.sh
```

#設定後のデータをDockerfileに入れる
このあとは、実際に設定を終えてから、そのデータをdata-shareにコピーする。

設定後、以下のコマンドを実行する。`mysqldump`は、データベースのバックアップを取るコマンド。
ユーザ名rootでwordpressデータベースに入り、このバックアップをdata-shareディレクトリ内のmysql.dump.sqlとして保存している。

```
mysqldump -u root wordpress > /data-share/mysql.dump.sql
```

つぎに、このmysql.dump.sqlを初期データとして挿入するよう、create_db.shを編集する。
スライドでは、ダウンロードファイルに含まれているcreate_db.shを編集することを想定していると思うが、当然コンテナ内のファイルをviなどで編集して、data-shareで共有することも可能のはず。
なお、シェルスクリプトの調査まで始めると大変なので、いったん逃げる。

```
#!/bin/bash

if [[ $# -eq 0 ]]; then
	echo "Usage: $0 <db_name>"
	exit 1
fi

/usr/bin/mysqld_safe > /dev/null 2>&1 &

echo "=> Creating database $1"
RET=1
while [[ RET -ne 0 ]]; do
	sleep 5
	mysql -uroot -e "CREATE DATABASE $1"
	mysql -uroot $1 < /mysql.dump.sql #ここを追加
	RET=$?
done

mysqladmin -uroot shutdown

echo "=> Done!"
```

最後に、Dockerfileを修正する。
いまローカルにあるmysql.dump.sqlは、さきほど取得したものだ。これを、新しくつくるオリジナルのDockerイメージに含めてしまう。
以下はDockerfileの修正後。

```
FROM tutum/lamp:latest
MAINTAINER Fernando Mayo <fernando@tutum.co>, Feng Honglin <hfeng@tutum.co>

# Install plugins
RUN apt-get update && \
  apt-get -y install php5-gd && \
  rm -rf /var/lib/apt/lists/*

# Download latest version of Wordpress into /app
RUN rm -fr /app && git clone --depth=1 https://github.com/WordPress/WordPress.git /app

# Configure Wordpress to connect to local DB
ADD wp-config.php /app/wp-config.php

# Modify permissions to allow plugin upload
RUN chown -R www-data:www-data /app/wp-content /var/www/html

# Add database setup script
ADD create_mysql_admin_user.sh /create_mysql_admin_user.sh
ADD mysql.dump.sql /mysql.dump.sql #ここを追加
ADD create_db.sh /create_db.sh
RUN chmod +x /*.sh


EXPOSE 80 3306
CMD ["/run.sh"]
```

たった1行の追記だが、これによって新しいイメージができることになる。
`$ docker build`でDockerイメージを作成してみる。イメージ名はtutum/wordpressではなく、my-wordpressとする。最後のドットを忘れずに。
Dockerに割り振ったCPUとメモリも寄ると思うが、パッケージを取得などもあるので時間が多少かかる。

```
$ docker build -t my-wordpress .
```

`-t`オプションは、ビルド成功後に作成されたイメージにリポジトリとタグを付与する。
最後のドットは、Dockerfileのあるディレクトリを指定するもの。

ビルドが完了したら、さきほどのwordpressコンテナを終了して、my-wordpressイメージからコンテナを新規作成する。
すると、設定済みのコンテナができあがる。

```
$ docker rm -f wordpress
$ docker run -d -p 80:80 --name=my-wordpress my-wordpress
```

# さいごに
**スライド37〜50**

ここまでが理解できると、自身でDockerを管理しながら開発することができるようになると思います。
もちろん、Dockerfileを作成するにはLinuxコマンドの知識などが必要ですが、なんとなく自力でこのあとは進めるような気がしてきました。

残りのスライドは、ここまでに覚えたことを利用して開発環境をさらに効率よくする手順を紹介しています。
それほど難しい話ではないので、このエントリはここで締めます。