WordPressを改造してデプロイして、という作業をきちんと管理しようとすると、ごちゃごちゃと考えることが多くなります。
個人サーバレベルですがある程度方法が固まってきたので、連載形式でそのあたりを書いてみたいと思います。

前提条件

次のような管理体制とします。

  • サーバはVPS(sshで操作できるサーバ)
  • WordPressのソースはgitで管理している
  • ansibleでサーバ管理をしている

デプロイ方式はcapistranoのモデルにしたがう

ansibleでのデプロイ方法については、r_rudiさんにより良記事が日本語訳されています。

http://tdoc.info/blog/2015/01/14/deploying_with_ansible.html

この方式をWordPressに適用していくと、ディレクトリ構造は次のようになります。

.
├── releases
|   ├── 20151002210144
|   └── 20151002210406
├── shared
|   └── uploads
└── current -> releases/20151002220433

デプロイ手順をおおざっぱにいうと次のようになります。

  1. releaseディレクトリにgitからcloneする
  2. cloneしたディレクトリ上にwp-config.phpを作成する
  3. currentシンボリックリンクをcloneしたディレクトリに強制置換で振り向ける

このとき、アップロードした画像ファイルなどは維持されている必要があります。

wp-content/uploadsの維持

wp-contentディレクトリにはプラグインやテーマなどが入りますが、このうちデプロイ時に維持すべきはwp-content/uploadsディレクトリです。画像ファイルが入っています。
wp-content/uploadsshared/uploadsに実体を置き、wp-content/uploadsはシンボリックリンクでshared/uploadsを見るようにします。

wp-content/pluginswp-content/themesは修正・追加する場合があるため、管理画面でのインストールではなく、gitにコミットしての手動インストールにします。
wp-content/cachewp-content/ewwwなどキャッシュファイルは、デプロイ時には維持せず消してしまいたいものです。これらはgit上に置かないようにすることで、git clone時に生成されないようにします。

wp-config.phpはansibleで作成する

wp-config.phpにはDBパスワードなどを書かないといけないため、gitにそのままコミットするのは避けたいです。かといって管理対象外とするのもまずいです。
そこで、ansible-vaultで暗号化して、playbookとしてgit管理することにします。

$ ansible-vault --vault-password-file ~/.vault_pass.txt edit roles/site_wordpress/vars/main.yml

host_vars/prod.ymlではなくroles/site_wordpress/vars/main.ymlにしているのは、host_vars/prod.ymlにはIPアドレスなども書いており、暗号化でdiffが見えなくなるのを嫌ったためです。このあたりはincludeなどでうまく避ける方法もありそうですが、いまのところこうしています。stage環境と本番環境でDB名を変えるなどの必要が出てくる場合はhost_varsに移動させたほうが良いでしょう。

変数を定義できたら、あとはtempleteモジュールで作成するだけです。元となるwp-config.phpはバージョン依存なのでWordPressのgitに入れたいところですが、変数が増えた時に対応できないためroles/site_wordpress/templates/wp-config.php.j2のようにplaybookの一部としています。WordPressのバージョンアップをするときには要注意事項になります

playbookソースコード

以上を踏まえて、roles/site_wordpress/tasks/main.ymlは次のようになります。

---
- name: '各種デプロイディレクトリ作成'
  file: path=/app/{{vhost}}/{{item}} owner=appdept group=appdept recurse=yes state=directory
  with_items:
    - 'releases'
    - 'shared'

- name: '各種データディレクトリ作成'
  file: path=/app/{{vhost}}/{{item}} owner=appdept group=appdept mode=0777 state=directory
  with_items:
    - 'shared/uploads'

- name: 'リリースタイムスタンプ作成'
  command: date '+%Y%m%d%H%M%S'
  register: release_date
  changed_when: false

- name: 'gitリポジトリclone'
  git:
    repo: git@gitlab.com:username/{{vhost}}.git
    dest: /app/{{vhost}}/releases/{{release_date.stdout}}
    version: '{{project_version}}'
    depth: 1
    accept_hostkey: yes
  become_user: appdept

- name: 'wp-contentパーミッション設定'
  file: path=/app/{{vhost}}/releases/{{release_date.stdout}}/wp-content mode='g+w,o+w' recurse=yes state=directory

- name: 'sharedシンボリックリンク作成'
  file:
    path: '/app/{{vhost}}/releases/{{release_date.stdout}}/{{item.target}}'
    src:  '/app/{{vhost}}/shared/{{item.src}}'
    state: link
  with_items:
    - { target: 'wp-content/uploads', src: 'uploads' }

- name: 'wp-config.php作成'
  template: src={{item}}.j2 dest=/app/{{vhost}}/releases/{{release_date.stdout}}/{{item}} owner=appdept group=appdept
  with_items:
    - 'wp-config.php'

- name: 'currentシンボリックリンク置換'
  file:
    path: '/app/{{vhost}}/current'
    src:  'releases/{{release_date.stdout}}'
    state: link

- name: 'cron設定'
  cron:
    name: 'wp_cron'
    cron_file: 'wp_{{vhost}}'
    job: '/usr/bin/php -q /app/{{vhost}}/current/wp-cron.php 2>&1'
    user: apache
    minute: '*/5'

appdeptユーザはソースコード配備用ユーザです。apacheユーザはhttpdサービス(apacheかnginxかその他)の実行ユーザです。
「gitリポジトリclone」のrepoパラメータは適時変えてください。vhost変数はバーチャルホスト名で、httpdサービスの設定にも用いているものです。

playbook実行時にproject_version変数を設定するようにします。

ansible-playbook --vault-password-file ~/.vault_pass.txt -i hosts --extra-vars "project_version=master" prod.yml --tags blog

前のバージョンに戻したい場合は「project_version=master」を「project_version=v4.0.0」などにします。あらかじめgitにタグを打っておく必要があります。

このplaybookのまずい点として、--checkでエラーになります。release_date.stdout変数が定義されないためで、もっとうまいやり方がありそうです。

参考サイト

http://tdoc.info/blog/2015/01/14/deploying_with_ansible.html