緊急の問い合わせが届くと、早急に問題を解決しようとするものですが、本番環境のWordPressサイトでは、そのスピードがかえって裏目に出ることもあります。

プラグインの更新失敗や設定変更、急いだデータベース操作など、ちょっとした作業が原因でサイトが部分的に壊れたり、完全に停止してしまうことはよくあります。そして直前のバックアップがなければ、安全に元の状態へ戻すのは困難です。

今回は、そうしたリスクを未然に防ぐ、バックアップの自動化を掘り下げます。ZendeskとKinsta APIを連携させることで、緊急度の高いWordPress関連の問い合わせが届いた際、エンジニアが対応を始める前に自動でバックアップが作成されます。その結果、復元ポイントを確保した状態で対応を開始できるため、より安全で一貫性のあるインシデント対応プロセスを実現できます。

何かを修正する前にバックアップを取るべき理由

プラグインの競合、データベースクエリの失敗、またはバックアップのない本番サイトでの不完全なアップデートは、復旧が困難です。バックアップが作成される前に行った変更は、何か問題が発生した場合、クリーンポイントがないことを意味します。

複数のクライアントサイトを管理していると、作業担当者が作業開始前に毎回バックアップを作成する運用になりがちです。課題となるのは、この手動プロセスへの依存です。

Kinstaへ移行したPixeled Eggsは、危機的状況にある人々を支援する団体やサービスをクライアントに抱えているため、その責任は非常に大きくなります。心のケアや緊急支援を必要としている人々にとって、サイトへ確実にアクセスできることは不可欠であり、障害対応に失敗すれば深刻な影響につながりかねません。

運用負荷の少ないソリューションにより、開発チームの作業時間を大幅に削減できたのは非常に大きいです。おかげで、高性能なWordPressサイトの設計・開発に集中することができています

バックアップ自動化に必要なもの

これからご紹介する自動化には、以下が必要になります。

  • Kinstaアカウントおよび本番環境で稼働しているWordPressサイト(最低1件)
  • ZendeskのSuite Teamプラン以上のアカウント(またはSupport Team/Professional/Enterpriseプラン)※Webhookとトリガー機能は、これらすべてのプランで利用可能
  • Webhookとトリガーを作成するためのZendesk管理者権限
  • ローカル環境にインストールされたNode.js

Kinsta APIを利用するには、MyKinstaにログイン後、ダッシュボードから「企業の設定」>「APIキー」に移動して、「APIキーを作成」をクリックします。

MyKinstaの「APIキー」画面
MyKinstaの「APIキー」画面

キー名を設定し、有効期限を選択して「生成」をクリックします。APIキーはこのタイミングで一度しか表示されないため、画面を閉じる前に必ずコピーして保存してください。

また、サイトIDも必要になります。サイトIDは、MyKinstaで対象サイトを開いた際のURLから確認できます。あるいは、APIキーを設定後に GET /sitesエンドポイントを実行して取得することも可能です。

準備ができたら、プロジェクトルートにある.envファイルへAPIキーを追加します。

KINSTA_API_KEY=your_api_key_here

なお、サイトIDと環境IDは別のものです。サポート担当者が入力するのはサイトIDで、ミドルウェア側がGET /sites/{siteId}/environmentsを実行して環境IDを取得します。

また、APIキーのアクセス権限は、キーを作成したユーザーの権限レベルに応じて決まります。たとえば、開発者権限のAPIキーは、所有者権限や管理者権限のキーよりも利用できる範囲が制限されています。リクエスト時に権限エラーが発生した場合は、まずAPIキーの権限設定を確認してください。

その他の開発前提条件

ローカル環境で開発を行う場合、ミドルウェアはZendeskから直接アクセスできない localhost上で動作します。そのため、ngrokのようなトンネリングツールを使用してローカルポートをインターネットへ公開し、一時的な公開URLを作成する必要があります。ローカル環境で統合が正常に動作することを確認した後、そのURLをデプロイ済みミドルウェアのURLへ置き換えます。

また、チケットからKinstaサイトIDをWebhookペイロードへ渡すために、Zendesk側でカスタムチケットフィールドを作成する必要があります。Zendesk管理画面右側のメニューから「Objects and rules(オブジェクトとルール)」>「Tickets(チケット)」>「Fields(フィールド)」へ移動し、新しいテキストフィールドを作成してください。

KinstaサイトID入力用のカスタムテキストフィールドを作成するZendeskの「Fields」画面
KinstaサイトID入力用のカスタムテキストフィールドを作成するZendeskの「Fields」画面

次に、わかりやすい名前を設定し、Zendeskによって割り当てられる数値のフィールドIDを控えておきます。WordPress関連の障害チケットを担当者が開く際、このフィールドに対象サイトのサイトIDを入力します。

ZendeskとKinsta APIを連携する方法

該当するサポートチケットの受信をきっかけにバックアップを作成するため、Node.jsミドルウェアでZendeskのWebhook呼び出しを受信します。そこからKinstaのサイトIDを環境IDに紐づけ、タグ付きの手動バックアップを実行します。

Zendesk側で設定するのは、ミドルウェアのエンドポイントを指定するWebhookと、条件に一致するチケットを受信した際に発火するトリガーの2つです。

1. Zendesk Webhookを作成する

Zendeskでは、Webhookとトリガーは別々のオブジェクトとして扱われます。まずはWebhookを作成し、その後でトリガーのアクションとして関連付けます。逆の順序では設定できません。また、Webhookは作成後に接続方式を変更できないため、設定順序が重要です。

Webhookを作成するには、Zendesk管理画面で「Apps and integrations(アプリと統合)」>「Webhook」>「Webhook」へ移動し、「Create webhook(Webhookを作成)」をクリックします。

Zendeskの「Webhook」画面
Zendeskの「Webhook」画面

接続方法には「Trigger or automation(トリガーまたは自動化)」を選択します。「Next」をクリックして名前を入力してください。エンドポイントURLには、いったん仮のURLを入力します。これはミドルウェアのデプロイ後に更新します。そのURLの末尾に/backupを追加し、リクエストメソッドをPOST、リクエスト形式をJSONに設定します。

認証方法には、Bearerトークンを使用するのが実用的です。後ほどミドルウェア側で、受信リクエストを検証する処理を追加できます。また、Zendeskにはリクエスト検証に使える署名ヘッダー(x-zendesk-webhook-signature)も含まれています。Webhookを作成すると、トリガに接続するまでZendeskのWebhookパネルに表示されます。

2. Zendeskトリガーを設定する

Webhookの設定が完了したら、「Objects and rules(オブジェクトとルール)」>「Business rules(ビジネスルール)」>「Triggers(トリガ)」へ移動し、「Create trigger(トリガを作成)」をクリックします。

空のトリガー作成画面を表示したZendeskの「Triggers」画面
空のトリガー作成画面を表示したZendeskの「Triggers」画面

トリガーに名前を付けたら、「Conditions(条件)」セクションで、チケットが新規作成されたとき、優先度が「Urgent(重要)」であること、カスタムフィールドが入力されていること、そしてタグに wordpress-emergencyが含まれていることを条件として設定します。この組み合わせにより、サポート担当者がWordPressの緊急障害として明示的にマークした新規チケットに対してのみ、トリガーが実行されます。

チケット作成時の条件が設定されたZendeskの「Trigger」編集画面
チケット作成時の条件が設定されたZendeskの「Trigger」編集画面

次に、「Actions(アクション)」>「Add action(アクションを追加)」をクリックし、「Notify by(通知方法)」>「Active webhook(アクティブWebhook)」を選択して、作成したWebhookを指定します。

すると、リクエストペイロード編集画面が開き、Zendeskからミドルウェアへ送信するデータを定義できます。ペイロードは標準的なJSON形式で、Webhook実行時にチケット情報を埋め込むためのプレースホルダー構文も利用できます。

カスタムフィールドの書式は{{ticket.custom_fields.FIELD_ID}}です。FIELD_IDには、事前準備で作成したカスタムフィールドの数値IDを指定します。

{
  "ticket_id": "{{ticket.id}}",
  "site_id": "{{ticket.custom_fields.12345678}}" // Replace the numeric placeholder with the Zendesk field ID value.
}

これを定義することで、Zendeskはチケット内のKinstaサイトIDを自動的にミドルウェアへ渡せるようになります。

3. ミドルウェアエンドポイントの構築

ミドルウェアは、ZendeskとKinsta APIを連携させる役割を担います。Express.jsは、ルーティングやリクエストボディの解析を行える軽量なNode.js向けWebフレームワークで、Zendeskから呼び出されるPOST /backupエンドポイントを定義できます。

新規プロジェクトディレクトリを初期化したら、必要な依存関係をインストールします。

npm init -y
npm install express dotenv

ここで、expressはサーバーとルーティングを担当し、dotenv.envファイルを読み込む役割を果たします。これにより、APIキーをソースコードへ直接記述することなく、実行時に利用できるようになります。

app.jsファイルを作成すると、Expressサーバーが起動し、受信したJSONを解析して、Zendeskのペイロードを受け取るPOST /backupルートを定義できます。

// app.js
const express = require('express');
require('dotenv').config();
const app = express();
app.use(express.json());
const KinstaAPIUrl = 'https://api.kinsta.com/v2';
const headers = {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${process.env.KINSTA_API_KEY}`
};

app.post('/backup', async (req, res) => {
    const { ticket_id, site_id } = req.body;
    if (!site_id) {
        return res.status(400).json({ message: 'Missing site ID' });
    }

    // Kinsta API calls placeholder
    res.status(200).json({ message: 'Received' });
});

app.listen(3000, () => console.log('Server running on port 3000'));

本番環境では、リクエストがZendeskから送信されたものであることを検証する処理も追加してください。ZendeskはWebhook実行時に x-zendesk-webhook-signaturex-zendesk-webhook-signature-timestampヘッダーを含めるため、これらを利用してWebhookペイロードの正当性を検証できます。

 

4. Kinsta APIで認証

Kinsta APIへのすべてのリクエストでは、Bearerトークン認証を使用します。AuthorizationヘッダーにAPIキーを含め、app.js内で定義した headers定数によって、アプリケーション内のすべてのリクエストへ自動的に適用されます。

また、ファイル冒頭のrequire('dotenv').config() により、他の処理が実行される前に.envファイルが読み込まれます。そのため、process.env.KINSTA_API_KEYは実行時に実際のAPIキーへ解決され、キー自体をソースコードへ記述する必要がありません。

次に必要になるのが、対象サイトの環境IDです。これはKinstaのbackupエンドポイントを利用するために必要となります。headers定数の下に、以下の関数を追加してください。

const getEnvironmentId = async (siteId) => {
    const resp = await fetch(
        `${KinstaAPIUrl}/sites/${siteId}/environments`,
        { method: 'GET', headers }
    );
    const data = await resp.json();
    return data.site.environments[0].id;
};

この関数はGET /sites/{siteId}/environmentsを実行し、レスポンス内の最初の環境IDを返します。これは本番環境に対応しています。

複数の環境を利用していて特定の環境を対象にしたい場合は、単純に最初の結果を使用するのではなく、環境名をもとに対象環境を判別することも可能です。

5. Kinsta APIを通してバックアップをトリガー

バックアップを作成するには、ミドルウェア側でPOST /sites/environments/{envId}/manual-backupsを実行します。そのために、getEnvironmentId関数の下へ、以下の追加関数を定義します。

const triggerBackup = async (envId, tag) => {
    const resp = await fetch(
        `${KinstaAPIUrl}/sites/environments/${envId}/manual-backups`,
        {
            method: 'POST',
            headers,
            body: JSON.stringify({ tag })
        }
    );
    const data = await resp.json();
    return data;
};

tagパラメータはバックアップにラベルを付与するためのもので、MyKinsta上で識別しやすくなります。タグにZendeskのチケットIDを含めることで、バックアップ一覧を確認した際に、どの障害対応をきっかけに作成されたバックアップなのかを追跡できます。

最後に、POST /backupルートを更新し、これら2つの関数を順番に実行するようにします。

app.post('/backup', async (req, res) => {
    const { ticket_id, site_id } = req.body;
    if (!site_id) {
        return res.status(400).json({ message: 'Missing site ID' });
    }
    try {
        const envId = await getEnvironmentId(site_id);
        const tag = `pre-remediation-${ticket_id || 'manual'}`;
        const result = await triggerBackup(envId, tag);
        res.status(200).json(result);
    } catch (err) {
        console.error(err);
        res.status(500).json({ message: 'Backup failed' });
    }
});

バックアップエンドポイントへのリクエストが成功すると、処理が進行中であることを示すレスポンス本文とともに、202ステータスが返されます。

{
    "operation_id": "backups:add-manual-abc123",
    "message": "Adding a manual backup to environment in progress.",
    "status": 202
}

ただし、202レスポンスはバックアップ完了を意味するものではありません。手動バックアップは非同期で実行されるため、ステータスがcompletedになるまでGET /operations/{operation_id} エンドポイントをポーリングして確認する必要があります。

とはいえ、多くのワークフローでは、チケットをオープンする段階では202レスポンスが返ってくれば十分です。

Zendeskチケットから作成されたバックアップがMyKinstaの「バックアップ」画面に表示される
Zendeskチケットから作成されたバックアップがMyKinstaの「バックアップ」画面に表示される

node app.jsを実行し、有効なサイトIDとチケットIDを本文に含めたテストリクエストを送信したら、MyKinstaでバックアップが正しいタグ付きで作成されていることを確認します。

Kinstaなら、問題発生時にクライアントサイトをすぐに保護

この連携により、Zendeskで緊急のWordPressサポートチケットが作成されると、即座にバックアップを実行されるようになります。ミドルウェアがKinsta APIを呼び出し、エンジニアがチケットを確認する前に、タグ付きのスナップショットを自動作成します。

ローカル開発では、ngrokを使ってZendeskとlocalhostを接続します。ミドルウェアを恒久的なエンドポイントへ移行する段階では、Sevallaの使用がおすすめです。プロジェクトをGitサービスへプッシュし、リポジトリを接続した上で、デプロイ設定に環境変数を追加します。その後、Zendesk側のWebhookエンドポイントURLを本番環境のURLへ更新してください。

多数のクライアントサイトを運用している場合は、Kinsta自動アップデートアドオンとの組み合わせも効果的です。プラグインやテーマを常に最新状態に保ちながら、更新後に自動ビジュアルテストを実行し、問題が発生した場合は変更を自動的にロールバックできます。さらに、サイトごとに更新スケジュールを柔軟に設定することも可能です。

本記事に関するご質問は、Kinstaのカスタマーサポートまでお問い合わせください。

Joel Olawanle Kinsta

Kinstaでテクニカルエディターとして働くフロントエンド開発者。オープンソースをこよなく愛する講師でもあり、JavaScriptとそのフレームワークを中心に200件以上の技術記事を執筆している。