WordPressをコンテナで
CMSといったらやっぱりWordPress。ブログ構築・サイト構築はもちろん、簡易会員管理システムや予約システムなどいろいろ汎用的につかえるので、@MINOはフレームワーク的に活用させてもらっています。
今回はDockerにてWordPressを稼働させようと思います。
- 環境
- 作業マシン GNU/Linux debian8
- サーバ conohaクラウド
- CPUコア 2Core
- メモリ 1GB
- ストレージ50GB
- OS CentOS7.2
- チャレンジ内容
- CentOSにDockerの導入
- Docker経由でWordPressの導入
- テーマのデータコンテナ化
テーマのデータコンテナ化
今回のチャレンジでは開発のしやすさを意識した構成を考えています。WordPressでカスタマイズするというのはテーマをいじることがほとんどかと思います。
テーマの開発とデプロイ(サーバへの配置)がやりやすいと開発効率も上がるはず。
具体的に言うと
/var/www/html/wp-content/themes/my-thema
をデータコンテナ化します。このディレクトリはテーマディレクトリのデフォルト位置なので、
こうしてmy-theme
ディレクトリを分離することで、テーマを管理しやすくします。
このデータコンテナは別途、サーバ(Dockerホスト)上の別なディレクトリにバインドしています。このディレクトリにGitHub経由で開発したファイルをclone
で持ってくるなりpull
なりすることにより自動的にデプロイが可能になります。
公式のWordPressのDockerfileではVOLUM
コマンドで/var/www/html
が作られています。
これはドキュメントルート(サイトの公開用のディレクトリ)として使われるディレクトリで、Dockerfileの記述上、ここにWordPressのファイルがコピーされるように設定されています。
なので、WordPressコンテナをrun
した段階で/var/www/html
がつくられ、それ以下のwp-content/themes
が存在していることなります。
CentOS7にDockerを導入する。
Dockerのインストールに関しては別記事にまとめましたので参照してください。
WordPressをコンテナとして起動する
デプロイ用ディレクトリを作る
サーバ(Dockerホスト)にテーマをデプロイするディレクトリを作ります(ディレクトリは任意でOKです)。
$ mkdir /home/hoge/deploy/
データコンテナを作る
データコンテナを作ります。先ほど作ったデプロイ用ディレクトリをバインドしたボリュームを持ったデータコンテナです(ややこしい)。
docker create --name thema -v /home/hoge/deploy:/var/www/html/wp-content/themes/my-thema busybox
データコンテナは起動している必要がないので、run
ではなくcreate
でOKです。
このデータコンテナには/var/www/html/wp-content/themes/my-them
がボリュームとして作られているわけです。
データベースコンテナを作る
WordPressコンテナに必要不可欠になるデータベースコンテナ(MySQLコンテナ)を作ります。
$ docker run -d --name db -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=db mysql
WordPressコンテナを作る
最後に、データコンテナをバインドし、データベースコンテナをリンクしたWordPressコンテナを作ります。
データコンテナを--volumes-from
オプションでバインドして、--link
オプションでMySQLコンテナをリンクし、必要な情報をe
オプションで指定します。例ではコンテナの名前をwpにしています。
データベース関連の指定を行わないと(-e
オプションで指定しているもの)エラーになってrun
は失敗します。
$ docker run -d -p 80:80 --volumes-from thema -e WORDPRESS_DB_HOST=172.17.0.2:3306 -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=password --name wp --link wpdb:mysql wordpress
上記の例だとipなどがハードコードになっていますので、コマンドに汎用性がありません。なのでもう少しスマートに書く方法として環境変数を使ったほうが良いかもしれません。今回の例では以下の様になります。
$ docker run -p 80:80 --volumes-from thema -e WORDPRESS_DB_HOST=$TESTDB_ENV_MYSQL_ROOT_PASSWORD -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=$TESTDB_ENV_MYSQL_ROOT_PASSWORD --name wp --link wpdb:mysql wordpress
$TESTDB_ENV_MYSQL_ROOT_PASSWORD
や$TESTDB_ENV_MYSQL_ROOT_PASSWORD
はMySQLコンテナからWordPressコンテナに出力された環境変数です。こっちのほうがスマートです。
-p
オプションでポートのバインドを行っています。コンテナのport80
をホストのport80
につないでいるような感じです。ホストのport80
にリクエストがあったらコンテナのport80
が応答するようになります。
--volumes-from thema
を指定することで、WordPressコンテナの/var/www/html/themes
に先ほど作ったデータコンテナがバインドされます。
かつ/var/www/html/themes
はサーバ(Dockerホスト)の/home/hoge/deploy
にバインドされているので、このディレクトリにテーマファイル(ディレクトリ)をpull
してくるなりすることで、コンテナの中にテーマが追加することができます。
これでサーバに直接wordpressをインストールした時の感覚と同じように扱うことができます。
補足・ハマったところ
docker: Error response from daemon: failed to create endpoint wp on network bridge: iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --d
port 80 -j DNAT --to-destination 172.17.0.3:80 ! -i docker0: iptables: No chain/target/match by that name.
ポートにバインディングしようとたらできない…。ずっとこんなエラーがでてしまう。
dockerのポートマッピングはポートフォワーディングを使っていると理解しているので、それほど難しいものではないと思っていました。
どうやってもできず、いろいろ検索しましたがクリティカルな情報をえられず息も絶え絶えに。
結局解決したのが
- DockerEnginの再起動
というオチ。
なんだそりゃ。
再起動した後は今のところ上記のエラーはでていません。
データボリューム・データコンテナとホストのディレクトリやファイルの所有者について
コンテナが展開したディレクトリはあくまでもコンテナの持ち物になるようで、ホスト側からはroot
権限でしか触ることができないようです。
しかしコンテナには存在せず、データコンテナを介してかデータボリュームを介してホストから作られたディレクトリはrun
を実行したユーザの所有になっていました。
今回の例で言うと
/var/www/html/wp-content/themes/my-thema
はもともとコンテナに存在しないので、run
時に作られるディレクトリとなります。このディレクトリはrun
を実行したホストのユーザが所有権を持つことになります。
しかし
/var/www/html/wp-content/themes
はもともとコンテナに存在する(WordPressのDockerfileの処理上で作られるディレクトリで所有者はwww-data
になるよう記述されている)ので所有者はあくまでもコンテナに存在するユーザ(今回の場合はwww-data
)になるようです。
/var/www/html/wp-content/themes
とバインドされたホストディレクトリを覗くとWordPressコンテナ側で作られたファイルやディレクトリは所有者が数字になっているかと思います。
@MINOの環境では33
になっていました。これはWordPressコンテナ内のwww-data
ユーザのuid
と一致します。
drwxr-xr-x 6 33 33 99 2月 3 02:12 .
drwxrwxr-x 3 hoge hoge 17 2月 25 12:41 ..
-rw-r--r-- 1 33 33 28 6月 6 2014 index.php
drwxr-xr-x 7 33 33 4096 2月 3 02:11 twentyfifteen
drwxr-xr-x 9 33 33 4096 2月 3 02:11 twentyfourteen
drwxr-xr-x 8 33 33 4096 2月 3 02:12 twentysixteen
そのため/var/www/html/wp-content/themes
をバインドした場合、ホストディレクトリにroot
以外のユーザ権限でgit clone
を行っても失敗します。
例えばこう。
git clone https://github.com/hoge/my-thema.git
fatal: could not create work tree dir 'thema'.: ????????
??????という気味の悪いものが出力されていますが、おそらくこれはpermission denied
のことだと思います。文字化けなのかな。
さらにはコンテナを止めた後にもバインドしていたホストのディレクトリの所有者はコンテナ側のユーザのままになっています(ボリュームの書き込み権限を与えた場合)
ro
オプションでボリュームを読み込み専用にした場合
/var/www/html/wp-content/themes
docker run -i -t -d -p 80:80 --volumes-from dc01:ro -e WORDPRESS_DB_HOST=172.17.0.2:3306 -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=pass --name wp --link db:mysql wordpress
上記のようにro
オプションを付けてボリュームコンテナを読み込み専用としてバインドした場合、/var/www/html/wp-content/themesにバインドしたホストのディレクトリの所有者はホストのユーザとなりました。
読み込み専用にしたことで所有者の書き換えが行われなかったためかと思います。
しかし困ったことに、/var/www/html/wp-content/themes
に展開されているべき公式テーマも無い状態になります。
読み込み専用にしてしまったため、/var/www/html/wp-content/themes
にはファイルを書き込むことができなかったということなのだと思います。
所有者のテスト
以下のようにしてデータコンテナを作り、CentOSコンテナの/var
ディレクトリにバインドするようにしてみました。
docker create -v /home/hoge/var/:/var --name data busybox
docker run -it --volumes-from data --name os centos /bin/bash
[root@0fa622460197 /]# ls -al
total 32
drwxr-xr-x 17 root root 4096 Feb 25 07:11 .
drwxr-xr-x 17 root root 4096 Feb 25 07:11 ..
-rwxr-xr-x 1 root root 0 Feb 25 07:11 .dockerenv
-rwxr-xr-x 1 root root 0 Feb 25 07:11 .dockerinit
... 〜中略〜
drwxr-xr-x 13 root root 143 Feb 17 16:51 usr
drwxrwxr-x 2 1000 1000 6 Feb 25 07:09 var
この場合、CentOSコンテナの内部から確認すると/var
ディレクトリのみ1000
というユーザが所有者になっています。これはホスト側のrun
を実行したユーザのuid
に一致します。
このようにイメージ側で所有権の変更がされない場合、バインドしたディレクトリの所有者はホスト側のユーザとなるようです。
root
になるかsudo
を付けてclone
なりpull
なりをすればいいのですが、果たしてそれで良いのかは@MINOにはわかっていません。
jenkinsさんらCIツールと連携するとなるとホストマシンへのroot
でのログインはセキュリティ上避けたいですし、sudo
付きのコマンド実行って@MINOにはまだ難しく思える点も多々あります(自動的にパスワードを入れる処理が難しい)。
本来であればWordPress以下のファイルはすべて、WordPressコンテナに存在するwww-data
(apacheの実行ユーザ)というユーザの所有になっているべきかと思います。
所有者がwww-data
以外でもテーマ自体は動くので問題ないといえばそれまでですが、動いているからよしとすべきなのか、ちょっと不整備な感じがして気になる部分です。
これはおそらくDockerfileにて所有者ないしは所有グループについての処理をカスタマイズする必要があるのではないかと思います。
この辺の処理はまだ@MINOの経験値だと解決できそうにないのでもっと勉強してみたいと思います。
後記
後からテーマを追加した場合どうするかの解決方法が思いついていません。wordpressコンテナに後付でデータコンテナをバインドできのかな。
もしできない場合はcontentディレクトリ自体をデータコンテナにして、入れ子状態に方法もあるかも。それであれば一度作ったwordpressコンテナを解体せずにデータだけ入れ替えができるかも。