🚀

WordPressテーマのCI/CDをGitHub Actionsで構築する

に公開

はじめに

この記事では、GitHub Actionsを活用したWordPressテーマのCI/CD構築について解説する。安全かつ効率的な運用を実現するための方法を紹介する。

背景:WordPress運用における課題

WordPressは手軽にブログやWebサイトを始められる便利なCMSだが、DevOpsの観点からはいくつかの課題がある。

  • 開発環境、ステージング環境、本番環境の運用が煩雑になりがち。
  • テーマファイルの管理が難しい。
    • ファイルを直接編集するとバージョン管理ができない。
    • etckeeperを使っても、ステージング環境と本番環境のファイルを同期するきれいな方法がない。
  • バージョン管理ができない。
    • 更新するたびにzipファイルを作成してアップロードするのは手間がかかる。
  • DB内のデータ(記事、ページ)とファイル(プラグイン、テーマ、アセット)が密接に連携しているため、コードレベルでのスナップショットが取りづらい。

解決策:GitHub ActionsによるCI/CD

これらの課題を解決するために、GitHub Actionsを活用してWordPressテーマのCI/CDを構築する。

  • テーマファイルをGitHubリポジトリで管理する
  • GitHub Actionsで、developブランチへのpushをトリガーにステージング環境へデプロイする
  • GitHub Actionsで、mainブランチへのpushをトリガーに本番環境へデプロイする
  • CIでPHPの構文チェックを行い、本番環境でのエラーを未然に防ぐ

システム設計

このシステムでは、以下の要素を組み合わせてWordPressテーマのCI/CDを実現します。

  • GitHubリポジトリ:テーマファイルのソースコードを管理する。
  • GitHub Actions:CI/CDのワークフローを定義し、実行する。
  • SSH:GitHub ActionsからWordPressサーバーへ安全にファイルを転送する。
  • rsync:効率的にファイルを同期する。

設定手順

1. GitHubリポジトリの準備

まず、WordPressテーマのファイルをGitHubリポジトリに登録する。

2. GitHub Actionsのワークフロー設定

次に、GitHub Actionsのワークフローを設定する。

ステージング環境へのデプロイ

.github/workflows/deploy-staging.yml

name: Deploy to Staging

on:
  push:
    branches: [ develop ]
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    - name: PHP Syntax Check
      uses: ./.github/actions/php-syntax-check
  deploy:
    needs: test
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Set up SSH
      uses: webfactory/ssh-agent@v0.9.0
      with:
        ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY_STAGING }}
        # known_hosts: ${{ secrets.KNOWN_HOSTS_STAGING }} # よりセキュアにする場合は有効化

    - name: Ensure target theme directory exists on remote
      run: |
        SSH_HOST="${{ secrets.STAGING_SERVER_HOST }}"
        SSH_USER="${{ secrets.STAGING_SERVER_USER }}"
        THEME_PATH="${{ secrets.STAGING_THEME_PATH }}"
        ssh -o StrictHostKeyChecking=no "${SSH_USER}"@"${SSH_HOST}" "mkdir -p \"${THEME_PATH}\""

    - name: Rsync theme files to Staging
      run: |
        SSH_HOST="${{ secrets.STAGING_SERVER_HOST }}"
        SSH_USER="${{ secrets.STAGING_SERVER_USER }}"
        THEME_PATH="${{ secrets.STAGING_THEME_PATH }}"
        rsync -avzc --delete --exclude='.*' --exclude README.md -e "ssh -o StrictHostKeyChecking=no" ./ "${SSH_USER}"@"${SSH_HOST}":"${THEME_PATH}"

このワークフローは、develop ブランチへのpushをトリガーに、以下の処理を行う。

  1. コードをチェックアウトする
  2. PHPの構文チェックを行う
  3. SSHでWordPressサーバーに接続し、テーマファイルをrsyncで同期する

このrsyncを実行する際のオプションは重要である。特に重要なオプションを以下に示す。

-c オプション:ファイルのチェックサムで比較を行い、同一ファイルであれば変更しない。GitHub Actionsでコピー元のファイルが準備される際、タイムスタンプがcheckout時のものになるため、更新日時がサーバと異なることを避けるために使用する。

-u オプション:サーバに新しいファイルが存在する場合、上書きしない。今回はすべてのファイルを上書きするため、このオプションは使用しない。

--exclude:機密情報を含まないように、ドキュメントやgit関連ファイルを除外する。

本番環境へのデプロイ

.github/workflows/deploy-production.yml

name: Deploy to Production

on:
  push:
    branches: [ main ]
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    - name: PHP Syntax Check
      uses: ./.github/actions/php-syntax-check
  deploy:
    needs: test
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Set up SSH
      uses: webfactory/ssh-agent@v0.9.0
      with:
        ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY_PRODUCTION }}
        # known_hosts: ${{ secrets.KNOWN_HOSTS_PRODUCTION }} # よりセキュアにする場合は有効化

    - name: Ensure target theme directory exists on remote
      run: |
        SSH_HOST="${{ secrets.PRODUCTION_SERVER_HOST }}"
        SSH_USER="${{ secrets.PRODUCTION_SERVER_USER }}"
        THEME_PATH="${{ secrets.PRODUCTION_THEME_PATH }}"
        ssh -o StrictHostKeyChecking=no "${SSH_USER}"@"${SSH_HOST}" "mkdir -p \"${THEME_PATH}\""

    - name: Rsync theme files to PRODUCTION
      run: |
        SSH_HOST="${{ secrets.PRODUCTION_SERVER_HOST }}"
        SSH_USER="${{ secrets.PRODUCTION_SERVER_USER }}"
        THEME_PATH="${{ secrets.PRODUCTION_THEME_PATH }}"
        rsync -avzc --delete --exclude='.*' --exclude README.md -e "ssh -o StrictHostKeyChecking=no" ./ "${SSH_USER}"@"${SSH_HOST}":"${THEME_PATH}"

    - name: Clear WordPress Cache
      run: |
        SSH_HOST="${{ secrets.PRODUCTION_SERVER_HOST }}"
        SSH_USER="${{ secrets.PRODUCTION_SERVER_USER }}"
        ssh -o StrictHostKeyChecking=no "${SSH_USER}"@"${SSH_HOST}" "wp w3-total-cache flush all"

  release:
    needs: deploy
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    - name: Release Drafter
      uses: release-drafter/release-drafter@v6
      with:
        publish: true
        version: ${{ steps.version.outputs.version-without-v }}
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

このワークフローは、main ブランチへのpushをトリガーに、以下の処理を行う。

  1. コードをチェックアウトする
  2. PHPの構文チェックを行う
  3. SSHでWordPressサーバーに接続し、テーマファイルをrsyncで同期する
  4. WordPressのキャッシュをクリアする
  5. リリースノートを自動生成する

PHP構文チェック

.github/actions/php-syntax-check/action.yml

name: PHP Syntax Check
description: Checks PHP syntax for errors.
runs:
  using: "composite"
  steps:
    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: '7.4'
    - name: Run PHP Syntax Check
      shell: bash
      run: |
        find . -name "*.php" -print0 | xargs -0 -n1 php -l

このアクションは、PHPの構文チェックを行います。

リリースノート自動生成

.github/release-drafter.yml

name-template: 'v$RESOLVED_VERSION 🌈'
tag-template: 'v$RESOLVED_VERSION'
categories:
  - title: '🚀 Features'
    labels:
      - 'feature'
      - 'enhancement'
  - title: '🐛 Bug Fixes'
    labels:
      - 'fix'
      - 'bugfix'
  - title: '🧰 Maintenance'
    label: 'chore'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
version-resolver:
  major:
    labels:
      - 'major'
  minor:
    labels:
      - 'minor'
  patch:
    labels:
      - 'patch'
  default: patch
template: |
  ## Changes

  $CHANGES

このファイルは、リリースノートの自動生成に関する設定を記述します。

3. GitHub Secretsの設定

GitHub ActionsからWordPressサーバーへSSH接続するために、GitHub Secretsを設定します。

  • SSH_PRIVATE_KEY_STAGING: ステージング環境へのSSH接続に使用する秘密鍵
  • SSH_PRIVATE_KEY_PRODUCTION: 本番環境へのSSH接続に使用する秘密鍵
  • STAGING_SERVER_HOST: ステージング環境のホスト名
  • STAGING_SERVER_USER: ステージング環境のユーザー名
  • STAGING_THEME_PATH: ステージング環境のテーマファイルのパス
  • PRODUCTION_SERVER_HOST: 本番環境のホスト名
  • PRODUCTION_SERVER_USER: 本番環境のユーザー名
  • PRODUCTION_THEME_PATH: 本番環境のテーマファイルのパス

4. WordPressサーバーの設定

WordPressサーバーに、GitHub ActionsからWordPressサーバーへSSH接続できるように設定します。

  • Wordpressを運用しているホストにはGithub Actionsからsshで接続できるようにしておく必要があります。
    • Github actionsのIPアドレスの空間が膨大なのでligthsailだと制限をかけるのが不可能です。
    • Github actionsのsource IP addressはAPIで公開されています。

sshキーペアの作り方はこんな感じです。生成された秘密鍵をGithub Actionsのsecretsに登録し、公開鍵をwordpressの.ssh/authorized_keysに追加します。

% ssh-keygen -t ed25519 -C "github-actions-staging@example.com" -f ~/.ssh/github_actions_deploy_key_staging
% ssh-keygen -t ed25519 -C "github-actions-production@example.com" -f ~/.ssh/github_actions_deploy_key_production

実行結果

GitHub Actionsのワークフローを実行すると、ステージング環境と本番環境へテーマファイルが自動的にデプロイされます。

ステージングは1分程度で完了します。

本番も1分程度で完了します。

今後の展望

  • WordPressをSSG(Static Site Generator)に移行することで、より高速かつ安全なWebサイトを構築できる可能性があります。
  • カオスになりやすいWordPressの運用に少しでも秩序を導入できたのでこれでしばらくは延命できます。

まとめ

GitHub Actionsを活用することで、WordPressテーマのCI/CDを簡単に構築できます。
これにより、開発効率が向上し、安全な運用を実現できます。

Discussion