docker-compose を使って WordPress テーマ開発環境を構築しよう

2017年10月10日 nginx + PHP-FPM7 + HTTP/2 版の解説エントリを公開しましたので、そちらをご覧ください。

はじめに

久々に WordPress を使って web サイトを作成する機会があったので、これを期に Docker を使った WordPress 環境を構築する手順を学んでみることにしました。単に WordPress を動作させるだけの手順であればググればいくらでも出てきますが、テーマ開発に適した構成や WP プラグインインストールの自動化などがまとまった情報がイマイチ見当たらなかったので、備忘録として残しておくとします。今回は docker-compose を使って複数のコンテナによる構成を組んでみましょう。

docker compose って?

docker compose とは、複数の Docker コンテナからなるサービスを構築・実行する手順をひとまとめに定義して自動化するという機能です。例えば WordPress の場合ですと、WordPress 本体が置かれているアプリケーション・サーバと MySQL サーバという大まかに二つのコンテナで構成されることになります 1)もちろん組み方によってはもっと細かくコンテナを切ることも出来ますが、あくまで一例として大雑把な構成を紹介しています。。普通であればそれらコンテナごとに個別に起動させ、さらにそれぞれを関連付ける ( linkオプション ) 必要があります。起動する順序にも気を使わなくてはなりません。コンテナの数が増えてくるとなかなかどうして面倒になってしまいます。

docker compose は docker-compose.ymlというファイルで構成を定義します。YAML で体系的に構成を定義出来るので全体像の見通しが良いのが特徴です。docker run時のオプションも殆ど定義することができ、コマンド1回実行するだけで複数のコンテナサービスを全て起動させることが可能です。

構築までのステップ

  1. Docker および docker-compose をインストール
  2. まっさらな WordPress × MySQL 環境を構築
  3. WordPress テーマ開発ディレクトリを volume としてマウントする
  4. MySQL から dump したデータを起動と同時に初期データとして突っ込む
  5. 任意の WP プラグインを起動と同時にインストールする

このようなチュートリアル形式で進めていきます。サンプルコードは GitHub にて公開しておりますので、必要に応じてご参照ください。

Step.1 ) Docker および docker-compose をインストール

公式サイトからバイナリファイルをダウンロードして Docker をインストールします。なお、2016年12月時点での最新版は 1.12.3 です。

続いて docker compose をインストールします。公式サイトから Docker Toolbox という様々なコンポーネントの詰め合わせをインストールするか、ターミナルから curl コマンドを実行してインストールします。

コマンドラインからインストールするには、ターミナルから以下のコマンドを実行するだけで OK。公式リポジトリからダウンロードされます。

$ curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose

続いてダウンロードしたバイナリに対して実行権限を追加します。以下のコマンドをそのまま実行すれば OK です。

$ chmod +x /usr/local/bin/docker-compose

無事にインストールできたか確認してみましょう。ターミナルを起動して以下のコマンドを実行してみます。

$ docker-compose -v
docker-compose version 1.9.0, build 2585387

このようにバージョン情報が表示されたらインストールは成功です。

Step.2 ) まっさらな WordPress × MySQL 環境を構築

基本となる WordPress と MySQL の環境を構築してみましょう。任意のディレクトリを作成し、docker-compose.yml ファイルを作成してそれぞれのコンテナ情報を記述します。

version: "2"
services:
    wordpress:
        image: wordpress:latest
        ports:
            - "9000:80"
        depends_on:
            - db
        environment:
            WORDPRESS_DB_HOST: "db:3306"
        env_file: .env
    db:
        image: mysql:latest
        env_file: .env
        volumes:
            - db-data:/var/lib/mysql
# databaseのように永続的なストレージが欲しい場合に必要な設定
# https://docs.docker.com/compose/compose-file/#volume-configuration-reference
volumes:
    db-data:

WordPress と MySQL はそれぞれ docker 公式のイメージを使用します。このように記述しておくだけでコマンド実行時にDocker 公式レジストリから自動でダウンロードしてくれます。イメージのサイズはそれぞれ約 400MB とそれなりにありますが、一度ダウンロードしたイメージはローカルにキャッシュされるので、二回目以降はダウンロードに待たされることはありません。

ports は 9000 番でアクセスを受け付けて ( 8080 でも OK ) wordpress コンテナの 80 番ポートにフォワードするようにしました。これにより、起動後はブラウザから http://localhost:9000 でWordPress トップページにアクセス可能となります。

env_file は様々な環境変数を定義したテキストファイルです。今回は主にDB_USERDB_PASSWORD などの値を別ファイルに定義しています。このようにファイルを分けなくとも docker-compose ファイル内に直接記述することも可能ですが、よりセキュアな状態を保つという目的で別ファイル化して Git などのバージョン管理下に含めないようにしています。

WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wp_user
WORDPRESS_DB_PASSWORD=hogehoge
MYSQL_RANDOM_ROOT_PASSWORD=yes
MYSQL_DATABASE=wordpress
MYSQL_USER=wp_user
MYSQL_PASSWORD=hogehoge

では実行してみます。docker-compose.yml のあるディレクトリから以下のコマンドを実行します。

$ docker-compose up -d
Creating network "step1_default" with the default driver
Creating volume "step1_db-data" with local driver
Creating step1_db_1
Creating step1_wordpress_1

起動コマンドに -d オプションを付けることでコンテナをバックグラウンドで起動させておくことが出来ます。これをしないとそのウィンドウ ( タブ ) 上で別の操作をすることが出来ないので、特別な理由がない限り付けておくと良いでしょう。

これで WordPress 環境が起動しました。Webブラウザから http://localhost:9000 にアクセスしてみます。

WordPress 初期設定画面が表示されました。無事に構築できてますね。

コンテナを停止するには docker-compose stopコマンドを実行します。再びコンテナを起動するにはdocker-compose startもしくはdocker-compose upを実行します。stop コマンドであればコンテナは削除されずに残るので、再起動してもGUI から設定した内容や DB のデータはそのまま保持されています。コンテナを削除するには docker-compose downを実行します。これで関連する全てのコンテナが停止と同時に削除されます。当然そこから再起動してもデータは何も残っていません。

ここまででベーシックな WordPress 環境の構築が出来ました。次にこれに手を加えて WordPress テーマの開発をするための環境にしていくとします。

Step.3 ) テーマ開発ディレクトリを volume としてマウントする

Docker には起動元 ( docker を実行したホストマシン ) の任意のディレクトリをコンテナ内のディレクトリとしてマウントする機能があります。このマウントされた領域を volume といいます。WordPress のテーマは {WordPress ルート}/wp-content/themes/ ディレクトリ配下に置く決まりですが、Docker コンテナの中に入って直接そこでテーマ開発のためのコーディングをするというのは現実的ではありません。あくまでもコーディングはホストマシン側で行い、その内容を Docker コンテナ内に同期させるのがスマートです。

volume のマウント自体はとても簡単です。まずマウントしたいディレクトリを用意し、そのパスを Docker コンテナ内の任意のパスに紐付けるだけで OK です。先程の docker-compose.yml を以下のように修正します。

version: "2"
services:
    wordpress:
        image: wordpress:latest
        ports:
            - "9000:80"
        depends_on:
            - db
        environment:
            WORDPRESS_DB_HOST: "db:3306"
        env_file: .env
        volumes:
            - ./themes/bones:/var/www/html/wp-content/themes/bones
    db:
        image: mysql:latest
        env_file: .env
        volumes:
            - db-data:/var/lib/mysql
# databaseのように永続的なストレージが欲しい場合に必要な設定
volumes:
    db-data:
        driver: local

{ホスト側の相対パス}:{コンテナ側の絶対パス} と指定すればマウントされます。ここでは例としてBonesというカスタマイズ用テーマをマウントしています。

.
├── docker-compose.yml
└── themes/
    └── bones/

用意が出来たら先ほどと同じくコマンドを実行してコンテナを起動してみましょう。無事に起動できたらブラウザからテーマ一覧ページ ( http://localhost:9000/wp-admin/themes.php ) にアクセスしてみます。

マウントしたテーマが初回から含まれているのがわかります。マウントは単なるディレクトリの参照なので、ホスト側でコーディングすればその内容がコンテナ側にもそのまま反映されます。

Step.4 ) MySQL から dump したデータを起動と同時に初期データとして流し込む

投稿記事、ユーザー、カテゴリなどテーマ開発をする上である程度揃っていないと困るようなデータがあります。コンテナ作成の度に毎回手入力するのは非効率です。あらかじめ入力しておいたそれらのデータを保存しておき、コンテナ起動と同時に初期データとして流し込んでしまえば最初からデータありきの状態でテーマ開発をはじめることが出来ます。

とりあえず適当なユーザーと投稿記事を作成します。

- admin
- Lennon
- McCartney
- Let It Be ( Paul McCartney )
- Revolution ( John Lennon )
- 坊っちゃん ( admin )
- Hello world! ( admin )

mysqldump でバックアップ

mysqldump コマンドを使えば DB に保存されたデータを.sqlファイルとしてバックアップすることが出来ます。MySQL の Docker コンテナが起動している状態で以下のコマンドを実行します。

$ docker exec -it dbコンテナ名 sh -c 'mysqldump データベース名 -u データベースユーザ名 -pデータベースパスワード 2> /dev/null' > db-data/mysql.dump.sql

成功するとホスト側のdb-data/ディレクトリにmysql.dump.sqlというファイルが生成されます。このファイルを先ほどの WordPress テーマと同じ要領で Volume マウントすれば初期データとして流し込まれます。

version: "2"
services:
    wordpress:
        image: wordpress:latest
        ports:
            - "9000:80"
        depends_on:
            - db
        environment:
            WORDPRESS_DB_HOST: "db:3306"
        env_file: .env
        volumes:
            - ./themes/bones:/var/www/html/wp-content/themes/bones
    db:
        image: mysql:latest
        env_file: .env
        volumes:
            - db-data:/var/lib/mysql
            - ./db-data/mysql.dump.sql:/docker-entrypoint-initdb.d/install_wordpress.sql
volumes:
    db-data:
        driver: local

docker-compose.yml に追記してコマンド実行してみましょう。起動に成功したら web ブラウザからアクセスしてみます。今回は起動と同時に初期設定の情報も反映されているので、これまでと違っていきなりトップページが表示されるはずです。

投稿記事及びユーザーも先ほど入力したものが初期データとして入っています。これでダミー記事の投稿やユーザー作成といった煩わしい手作業が自動化されました。

Step.5 ) 任意のWPプラグインを起動と同時にインストールする

当ブログもそうなのですが、テーマ開発をしていくうちに特定の WordPress プラグインに依存してしまうことがあります。一つや二つ程度ならまだしも数が多くなるとコンテナ作成の度に手作業でインストールするのは非常に大変です。やはりこれもコードで管理し、コンテナ時に必要なプラグインを自動でインストール出来るようにするのが良いでしょう。

公式の WordPress イメージを拡張したオリジナルのイメージを定義する

これまでは公式の WordPress イメージをそのまま使用してきましたが、プラグインのインストールとなると流石にそれだけでは難しいので、ここは公式イメージをベースにしつつプラグインのインストール処理を追加したオリジナルのイメージを定義するとします。イメージはDockerfileを記述することで定義します。

FROM wordpress:latest
# 必要なツール郡をインストール
RUN apt-get update
RUN apt-get -y install wget unzip
# WP プラグイン (zip) ダウンロード
WORKDIR /tmp/wp-plugins
RUN wget https://downloads.wordpress.org/plugin/contact-form-7.4.6.zip
RUN wget https://downloads.wordpress.org/plugin/syntaxhighlighter.zip
RUN wget https://downloads.wordpress.org/plugin/wp-emmet.zip
# Zip ファイルを解凍してインストール
RUN unzip './*.zip' -d /usr/src/wordpress/wp-content/plugins
# 不要になった一時ファイルを削除
RUN apt-get clean
RUN rm -rf /tmp/*
# サーバが読めるように wp-content 以下の所有者を変更
RUN chown -R www-data:www-data /usr/src/wordpress/wp-content
WORKDIR /var/www/html

インストール方法ですが、何てことはありません。欲しいプラグインの Zip ファイルをwgetコマンドで直接ダウンロードし、所定のディレクトリに解凍するだけです。サンプルではContact Form 7SyntaxHighlighter EvolvedWP Emmetをインストールしています。他にインストールしたいプラグインがあれば上記に倣って追記していけば OK です。

Dockerfile が出来たら、これをビルドする処理を docker-compose.yml に記述します。

version: "2"
services:
    wordpress:
        build: ./my-wordpress
        ports:
            - "9000:80"
        depends_on:
            - db
        environment:
            WORDPRESS_DB_HOST: "db:3306"
        env_file: .env
        volumes:
            - ./themes/bones:/var/www/html/wp-content/themes/bones
    db:
        image: mysql:latest
        env_file: .env
        volumes:
            - db-data:/var/lib/mysql
            - ./db-data/mysql.dump.sql:/docker-entrypoint-initdb.d/install_wordpress.sql
volumes:
    db-data:
        driver: local

これまで image: wordpress:latestと公式イメージを指定していたのをbuild: ./my-wordpressとビルドする Dockerfile のあるディレクトリを指定するようにしました。これによりコマンド実行時に指定した Dockerfile から新たな WordPress イメージがビルドされ、そこから更にコンテナが生成されるようになります。

ターミナルから docker-compose run -d を実行して web ブラウザからhttp://localhost:9000/wp-admin/plugins.phpへアクセスしてみましょう。

Dockerfile に定義したプラグインが最初からインストールされているのが分かります。これで一通りテーマ開発するための WordPress 環境構築手順が定義されました。

締め - 動作が軽いので気軽にスクラップ & ビルドが出来る

これまで WordPress を使ったサイト制作には VCCW を使っていました。Vagrant が基盤になっており、VirtualBox に仮想マシンを立てて構築するというものです。製作者が日本の方ということもあり比較的導入コストは低くて良いのですが、いかんせん起動に時間がかかるのとそれなりに負荷が高いという側面もあります。仮想マシンという巨大なバイナリ形式で状態を持っているので、開発者間での受け渡しやバージョン管理を容易にすることが出来ません。

Docker は学習コストが少々高めですが2)そもそも僕自身インフラの知識が浅いというのもあります。、ローカルとサーバーとで文字通り全く同じ構成を組めるのが強みです。また、全ての構成や状態を『プログラミングコード』という形で定義することが出来るので、その全てを容易にバージョン管理することも可能です。何より動作が軽いので、手軽に試して失敗したら即やり直すというのがスピーディに出来るので学習が捗ります。

脚注

脚注
1 もちろん組み方によってはもっと細かくコンテナを切ることも出来ますが、あくまで一例として大雑把な構成を紹介しています。
2 そもそも僕自身インフラの知識が浅いというのもあります。