WordPressをDockerへ移行した話

概要

本ブログを構築しているWordPressですが、コンテナ環境に移行しました。 それによりDB専用サーバを用意してコンテナからDBサーバを参照しています。 また、合わせてLet's Encryptをワイルドカード証明書にしました。

移行した理由は?

以下の2つを目的としています。

  • サーバー台数を減らすことによるコスト削減
  • コンテナ運用の学習

証明書をワイルドカードにした理由は?

サブドメインごとの証明書管理が面倒だった。

DB専用サーバを用意した理由は?

MastodonサーバでPostgreSQLを運用している関係上、RDSではなくEC2にDB専用サーバーを用意した方が拡張性を考慮しつつコストを抑えられた。 PostgreSQLはDockerサーバ内で動作しているため、今後移行を考えています。

今後の懸念は?

Dockerエンジンで複数のコンテナ上で動作しているため、Masotodnコンテナの負荷が上がった際にWordPressコンテナも影響を受ける可能性があります。 なので今後は状況に応じてスケールアップすることで対応を考えています。

移行の段取り

  • DBサーバーの構築
  • 既存WordPressのエクスポート
  • 既存WordPressサーバの停止
  • ワイルドカード証明書の新規取得
  • Nginxのバーチャルホストの設定
  • WordPressコンテナの作成・稼働
  • WordPressデータのインポート

DBサーバーの構築

[aside type="warning"]新規のDBサーバーの作業です。[/aside] OSインストールは割愛します。

OS周辺の設定

date
Tue Aug 28 06:19:14 UTC 2018

timedatectl set-timezone Asia/Tokyo

date
Tue Aug 28 15:19:57 JST 2018

vi /etc/hostname
database.loner.jp

reboot

MariaDBのインストール

vi /etc/yum.repos.d/MariaDB.repo
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.3.9/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

[aside type="normal"]baseurlは以下のURLを参考にバージョン指定できます。 http://yum.mariadb.org/[/aside]

yumをアップデートしてMariaDBをインストールします。

yum -y update
yum install -y mariadb-server mariadb-devel

MariaDBの起動・自動起動設定をします。

systemctl start mariadb
systemctl enable mariadb

MariaDBのセットアップ

vi /etc/my.cnf.d/server.cnf
[mysqld]
character-set-server = utf8
skip-character-set-client-handshake

[mysql]
default-character-set = utf8
mysql_secure_installation
Set root password? [Y/n]   # rootのパスワードを設定します。(Y)
パスワードを設定
Remove anonymous users? [Y/n]   # 匿名ユーザでのログインをできないようにします。(Y)
Disallow root login remotely? [Y/n]   # リモートからrootでのログインを禁止します。(Y)
Remove test database and access to it? [Y/n]   # testデータベースを削除します。(Y)
Reload privilege tables now? [Y/n]   # 設定反映のため、ユーザ権限テーブルをすぐにリロードします。(Y)

WordPress専用のDBとユーザを作成します。

要素
DB名 wordpress
DBユーザ名 wpadmin
DBユーザのパスワード wppassword
mysql -u root -p
CREATE DATABASE `wordpress` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
MariaDB [(none)]> CREATE USER `wpadmin`@`%` IDENTIFIED BY `wppassword`;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON `wordpress`.* TO `wpadmin`@`%`;

[aside type="normal"]%は接続許可するホストになりますが、%は全て許可となります。セキュリティ上接続元ホストを指定してください。[/aside]

これで構築完了です。最後に再起動しておきます。

reboot

既存WordPressのエクスポート

[aside type="warning"]既存のWordPressサーバーの作業です。[/aside]

「All-in-One WP Migration」というアドオンを使いました。

フリーの範囲では500MBまでの移行データをダウンロードできます。 私が実施した時は170MBでした。

エクスポートからファイルを指定します。

少し待つとダウンロードできるようになるので、エクスポートデータをダウンロードします。 拡張子は「wpress」になります。

[aside type="normal"]ツール使わずにdumpとったり、ファイルをコピーしたりと試しましたが、Docker環境への移行ということもあり、ツールでデータを入れ直す方が早く綺麗に移行ができました。[/aside]

既存WordPressサーバの停止

Let's Encryptを使っており証明書の申請時にサーバのIPアドレス(Aレコード)のチェックが行われます。 なのでこのタイミングでブログのAレコードを変更する必要があり既存WordPressへアクセスすることができなくなります。 なお、Let'sEncryptの証明書はNginxに記載する証明書ファイルとそのシンボリックリンクファイルがあればサーバ間でコピーして正常に動くようです。 証明書をサーバ間でコピーすれば停止時間は0にすることも可能です。

ワイルドカード証明書の新規取得

[aside type="warning"]Dockerサーバーの作業です。[/aside]

適当なディレクトリにGitHubからcertbotをcloneしてきます。

git clone https://github.com/certbot/certbot
cd certbot
./certbot-auto certonly --manual --domain loner.jp --domain *.loner.jp --agree-tos --manual-public-ip-logging-ok --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory

ワイルドカード証明書なので、いろいろサーバなど指定したオプションで実行する必要があります。 サブドメインなしのドメインも含めたい場合は明示的に指定しないといけません。「--domain loner.jp」

[aside type="normal"]前提 証明書を取得するサーバのIPアドレスとドメインのAレコードは一致させておかないとエラーになります。[/aside]

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.loner.jp with the following value:

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

まず1回目のTXTレコード登録です。 「_acme-challenge.loner.jp」に「XXXXXX....」のTXTレコードを登録します。 TTLによりますが、しばらく時間を開けないとTXTレコードが引くことができずエラーになります。

digコマンドで確認することができます。

dig -t txt _acme-challenge.loner.jp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.loner.jp with the following value:

YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Waiting for verification...
Cleaning up challenges

なぜか2回確認が出るようです。 先ほど登録した「XXXX...」を「YYYYY...」に変更します。しばらく時間を置いてEnterを押します。

以下の場所に証明書が配置されます。

ls -l /etc/letsencrypt/live/
drwxr-xr-x 2 root root 4096 Sep  2 04:40 loner.jp-0001

ls -l /etc/letsencrypt/live/loner.jp-0001/
lrwxrwxrwx 1 root root  37 Sep  2 04:40 cert.pem -> ../../archive/loner.jp-0001/cert1.pem
lrwxrwxrwx 1 root root  38 Sep  2 04:40 chain.pem -> ../../archive/loner.jp-0001/chain1.pem
lrwxrwxrwx 1 root root  42 Sep  2 04:40 fullchain.pem -> ../../archive/loner.jp-0001/fullchain1.pem
lrwxrwxrwx 1 root root  40 Sep  2 04:40 privkey.pem -> ../../archive/loner.jp-0001/privkey1.pem
-rw-r--r-- 1 root root 682 Sep  2 04:40 README

Nginxのバーチャルホストの設定

[aside type="warning"]Dockerサーバーの作業です。[/aside]

Nginxはすでに導入済みのため今回はインストール手順は別記事を参考にしてください。 ログなどの設定は一旦省略しています。

  • 80ポートはhttpsにリダイレクト
  • 443ポートはローカルホストのWordPressコンテナのポートに通信
vi /etc/nginx/conf.d/wordpress.conf

server {
  listen 80;
  server_name loner.jp;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  server_name loner.jp; # 取得したドメインを指定してください
  root /var/www/html; # コンテナ内のWordPressのディレクトリを指定します。
  index index.php;

  ssl on;
  ssl_certificate      /etc/letsencrypt/live/loner.jp-0001/fullchain.pem;
  ssl_certificate_key  /etc/letsencrypt/live/loner.jp-0001/privkey.pem;

  # TLS1.0 1.1 1.2のみ有効
  ssl_protocols        TLSv1 TLSv1.1 TLSv1.2;
  # サーバが提示した暗号スイートを優先
  ssl_prefer_server_ciphers on;

  # 安全でない暗号化スイートはサポートしない
  ssl_ciphers 'kEECDH+ECDSA+AES128 kEECDH+ECDSA+AES256 kEECDH+AES128 kEECDH+AES256 kEDH+AES128 kEDH+AES256 +SHA !aNULL !eNULL !LOW !kECDH !DSS !MD5 !EXP !PSK !SRP !CAMELLIA !SEED';
  # SSLセッションキャッシュとサイズを指定
  ssl_session_cache    builtin:1000 shared:SSL:10m;
  # SSLセッションキャッシュのタイムアウトまでの時間
  ssl_session_timeout  10m;
  # OCSP応答をサーバー側にキャッシュ
  ssl_stapling on;
  #DH鍵交換パラメータファイル
  ssl_dhparam /etc/nginx/ssl/dhparam.pem;

  #HTTP Strict Transport Security
  add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';

  location / {
    proxy_set_header Host $http_host;
    proxy_pass http://127.0.0.1:8000; # コンテナのポートを指定します。
  }
}

WordPressコンテナの作成・稼働

[aside type="warning"]Dockerサーバーの作業です。[/aside]

/opt/wordpress配下にWordPressのファイルを永続化します。 environmentは.envファイルなど別ファイルを読み込ませることも可能です。

vi /opt/wordpress/docker-compose.yml

version: '3'

services:
  wordpress:
    image: wordpress:latest
    ports:
      - "8000:80"
    restart: always
    volumes:
      - /opt/wordpress:/var/www/html/:z
    environment:
      WORDPRESS_DB_HOST: <DBのIP>:3306
      WORDPRESS_DB_USER: <DBのユーザ>
      WORDPRESS_DB_PASSWORD: <DBのパスワード>

docker-composeから起動します。

cd /opt/wordpress
docker-compose up -d

WordPressの初期設定

https://loner.jp<自分のサイト>にアクセスします。 CSSがmix-content(http,https混在)によりブロックされます。 そのままやりづらいですが、サイト名やユーザを設定します。 [aside type="normal"]後ほどデータをインポートするので上書きされます。[/aside]

管理画面にログインしたら、「設定」の「一般」でWordPressアドレスとサイトアドレスをhttpsに修正します。

  • WordPress アドレス (URL)
  • サイトアドレス (URL)

画面を更新すると、以下の画面が表示されます。

このページは動作していません loner.jp でリダイレクトが繰り返し行われました。

WordPressのコンフィグファイルを編集し「$_SERVER['HTTPS'] = 'on';」を追加ます。

vi /opt/wordpress/wp-config.php

//add config
$_SERVER['HTTPS'] = 'on';

require_once(ABSPATH . 'wp-settings.php');

これで管理画面にアクセスできるようになりました。

WordPressデータのインポート

新しいWordPressにデータをインポートするため「All-in-One WP Migration」のプラグインをインストールします。

インポート>ファイルから先ほどダウンロードした「.wpress」拡張子のファイルを選択してインポートして完了です。 全てのデータが復旧されており、優秀なプラグインでした。

苦労した点

停止時間を発生させるか悩みましたが、まとめて作業をしたかったこともあり、サーバ停止させました。 データ移行でdumpを取得したりファイル移行を試しましたが、WordPressに限ってはプラグインが優秀なので、そちらを利用する方が結果的によかったです。 Docker化することで、ファイルをコピーしてくるとファイルのパーミッションやhtaccessなどいろいろ変更点があり、その整理から解放されました。

今後は他のコンテナと共有のホストになるので、パフォーマンスや停止時間などいろいろ考慮して構成を変更していきたいと思います。