WordPressをDockerizedしました
概要
クイックにWordPressを動かせる環境が欲しかったのでDocker composeで立ち上げられるようにしました。本番運用にも使えるように、動的に追加されるデータはファイルシステム上に保管されて永続化されるようにしています。
テンプレートリポジトリを用意したので、forkして使うのが手っ取り早いです。
https://github.com/matsubo/wordpress-docker-templateサーバ運用
まず、Lightsail (月にで個人開発のサービスを一部運用していたのですが、データ量が多くなってきたのでストレージが足りなくなってきたことと、物理RAMが足りなくなってきたので自宅サーバへ移動しました。
Lightsailは以下のインスタンスを使っていました。

自宅サーバ自体もオーバースペック過ぎて、電気消費が大きいので新規に調達しました。
調達したPCはこちら。
自宅サーバー用にGMKtec Nucbox M2(Intel Core i7)を買ったのでレビュー
自宅サーバ用にGMKtec Nucbox M2(Core i7/32GB/1TB SSD)を53,000円で購入。CINEBENCHベンチマーク結果やUbuntu 22でのWiFiドライバ問題など実使用レポートを公開。
2024/04/02安くて良いです
サービス運用
物理RAMが32GBあり、しばらく運用している現状で20GBぐらい使っています。

すべてのサービスをDockerizedしました。
DockerのRAMの利用常用はこんな感じです。

コンテナ数は30個ぐらいです。
RAMをたくさん使っているのは、MySQLとRailsのアプリケーションサーバです。RSS領域で使っています。あとは、disk cacheとしてちょこちょこ使われています。
WordPressサイトは10個ぐらいあります。1サイトごとにMySQLを立てているとメモリのMySQLサーバを立ち上げた直後の初期メモリ分が無駄になってしまうのでMySQLサーバは共有にしてアプリケーションサーバだけコンテナを個別にしました。MySQLは起動直後でも200MBぐらい消費するので、サイトごとに立てると馬鹿にならないです。128MBに制限したらメモリ不足で立ち上がりませんでした。
1.5ヶ月ほど運用していますが問題は起きていないし速度もLightsailに比べるとだいぶ速いです。
Docker Composeの設定
設定を作るときにこだわったポイントは以下です。
- 動的に生成されるMySQLのデータや、WordPressでアップロードしたメディアやプラグイン、テーマはファイルシステム上に保存される
- 必要最低限のパーミッションなので万が一クラックされても汚染されるスコープが狭い
- WordPress本体のバージョンの更新はイメージで行い、プラグインやテーマの更新はWeb上から動的に行える
単一サイト構成
以下が docker-compose.yml です。
services: mysql: user: "${UID:-1000}:${GID:-1000}" image: mysql:latest restart: always volumes: - ./mysql/data:/var/lib/mysql - ./mysql/conf/custom.cnf:/etc/mysql/conf.d/custom.cnf environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: ${MYSQL_DATABASE:-wordpress} MYSQL_USER: ${MYSQL_USER:-root} MYSQL_PASSWORD: ${MYSQL_PASSWORD}
wordpress: image: wordpress:latest user: "${UID:-1000}:${GID:-1000}" restart: always volumes: - ./wordpress/themes:/var/www/html/wp-content/themes - ./wordpress/plugins:/var/www/html/wp-content/plugins - ./wordpress/uploads:/var/www/html/wp-content/uploads links: - mysql depends_on: - mysql ports: - "${EXPOSE_PORT:-8080}:80" environment: WORDPRESS_DB_HOST: mysql WORDPRESS_DB_NAME: ${MYSQL_DATABASE:-wordpress} WORDPRESS_DB_USER: ${MYSQL_USER:-root} WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}複数サイト構成(MySQL共有)
MySQLコンテナをWordPressごとに立ち上げるとメモリを消費してしまうので、MySQLを1つ立ち上げて複数のWordPressサイトから接続して使うほうが効率的です。
WordPressのコンテナの定義をコピー&ペーストして一部ハードコードして使います。複数のDBを扱うのでMySQLではrootで作業する必要が出てきます。
services: mysql: user: "${UID:-1000}:${GID:-1000}" image: mysql:latest restart: always volumes: - ./mysql/data:/var/lib/mysql - ./mysql/conf/custom.cnf:/etc/mysql/conf.d/custom.cnf environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} MYSQL_ROOT_HOST: '%'
production: image: wordpress:latest user: "${UID:-1000}:${GID:-1000}" restart: always volumes: - ./production/themes:/var/www/html/wp-content/themes - ./production/plugins:/var/www/html/wp-content/plugins - ./production/uploads:/var/www/html/wp-content/uploads links: - mysql depends_on: - mysql ports: - "8080:80" environment: WORDPRESS_DB_HOST: mysql WORDPRESS_DB_NAME: production WORDPRESS_DB_USER: root WORDPRESS_DB_PASSWORD: ${MYSQL_ROOT_PASSWORD}
staging: image: wordpress:latest user: "${UID:-1000}:${GID:-1000}" restart: always volumes: - ./staging/themes:/var/www/html/wp-content/themes - ./staging/plugins:/var/www/html/wp-content/plugins - ./staging/uploads:/var/www/html/wp-content/uploads links: - mysql depends_on: - mysql ports: - "8081:80" environment: WORDPRESS_DB_HOST: mysql WORDPRESS_DB_NAME: staging WORDPRESS_DB_USER: root WORDPRESS_DB_PASSWORD: ${MYSQL_ROOT_PASSWORD}自分の環境ではこの複数サイト構成を使っています。
WordPressの大まかなインフラ設定
- DBは1コンテナ
- WordPressのコンテナはオフィシャルのイメージを使っています。latestタグ。
- theme, uploads, pluginsの3つのディレクトリはローカルのファイルシステムに保存してコンテナ側からマウントしています。
1つのdocker-compose.ymlに上記の設定を入れています。
1点、運用上ちょっと微妙なところはdocker compose経由でサービスを立ち上げると一気にコンテナを立ち上げてしまうので起動直後はCPU、Diskの負荷が増大します。
依存関係をつけて順番に起動していくように書いても良いですが、実際には依存関係がないし順番の管理が面倒なので割愛します。
セットアップ
テンプレートとなるリポジトリをcloneしてきます。
% git clone [email protected]:matsubo/wordpress-docker-template.git% cd wordpress-docker-template以下のコマンドを打って動作に必要な環境変数を一通り自動で作成します。
echo -n > .envecho "MYSQL_DATABASE=wordpress" >> .envecho "MYSQL_USER=wordpress" >> .envecho "MYSQL_ROOT_PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 15)" >> .envecho "MYSQL_PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 15)" >> .envecho "EXPOSE_PORT=8080" >> .envecho "UID=$(id -u)" >> .envecho "GID=$(id -g)" >> .envそのあと、docker compose up すれば初期設定が行われて、サーバ環境が立ち上がります。
% docker compose upブラウザでアクセスすれば初期設定画面が出るので、そのまま進めればOKです。
既存のWordPressからDockerに移行する方法
オンプレで運用しているWordPressから移行する場合は以下の手順でいけます。
% cp -ra /old/wordpress/wp-content/{plugins,themes,uploads} wordpress/% mysqldump -u ${OLD_MYSQL_USER} --password=${OLD_MYSQL_PASSWORD} ${OLD_MYSQL_DB_NAME} | bzip2 > dump.sql.bz2% docker compose cp dump.sql.bz2 mysql:/dump.sql.bz2% docker compose exec mysql bash -c 'bzcat /dump.sql.bz2 | mysql -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE'% docker compose exec mysql bash rm /dump.sql.bz2wp-contentの中身をコピーして、DBをdumpしてコンテナに流し込むだけなので簡単です。
PHPの設定変更
Dockerhubから提供されているデフォルトのWordPressイメージでは、HTTP経由でアップロードできるファイルサイズの最大容量がたった2MBしかないです。
増やすためにはphp.iniによって設定をoverrideする必要があります。
wordpress/custom.ini にファイルを作って中身を以下のように追加します。
post_max_size = 50Mupload_max_filesize = 50MあとはWordPressのイメージを起動する際に上記のファイルをマウントしてしまえばよいだけです。
volumes: - ./wordpress/custom.ini:/usr/local/etc/php/conf.d/custom.iniWordPressのバージョン更新
% docker pull wordpress:latest% docker compose down && docker compose up -dバックアップとリストア
クラウドじゃなくなったのでバックアップをしっかり取っていく必要があります。
ホストOS側でバックアップが取りやすいのがこの構成の良いところです。一時停止が許容できるなら以下のtarで丸ごとバックアップするのが一番簡単です。
フルバックアップ
% docker compose down% tar jcf /path/to/backup.tar.bz2 .フルバックアップからのリストア
% tar xf /path/to/backup.tar.bz2環境の削除
環境を潰して元どおりにする場合。
% docker compose down% rm -rf mysql/data/*% rm -rf wordpress/*/*今後
ハードウェア故障に対してのBCPを考えていきます。