Recovery
========

PostgreSQLの用語では、リカバリとは、既存のバックアップを使用してPostgreSQLインスタンスを起動するプロセスです。
PostgreSQLのリカバリメカニズムは非常に堅牢で豊富です。また、ポイントインタイムリカバリーPITRもサポートしており、カタログ内の最初に使用可能なバックアップから最後にアーカイブされたWALまで、特定のクラスターを任意の時点に復元できます。
(この場合、WALアーカイブは必須です。)

KubernetesのEDB
Postgresでは、既存のクラスターでリカバリインプレースを実行できません。リカバリーは、代わりに、使用可能な物理的バックアップから新しいPostgresクラスターをブートストラップする方法です。

..  Note::
   `bootstrap` スタンザの詳細については、 :ref:`BootstrapConfiguration <BootstrapConfiguration>` を参照してください。

``recovery``
ブートストラップモードでは、既存の物理ベースバックアップからクラスターを作成できます。次に、アーカイブからREDOログを含むWALファイルを再適用します。

WALファイルは、定義された_recovery object store_からプルされます。

ベースバックアップは、オブジェクトストアまたはボリュームスナップショットを使用して取得できます。

..  Note::
   バージョン1.25以降、KubernetesのEDB Postgresには、 `Barman Cloud plugin <https://github.com/cloudnative-pg/plugin-barman-cloud>`_ などのプラグインを使用したバックアップとリカバリーの実験的なサポートが含まれています。

\_recovery object store_からのリカバリは2つの方法で実現できます。

- リカバリオブジェクトストア、つまりBarman
  Cloudによって作成され、\ ``externalClusters``
  セクションの\ ``barmanObjectStore``
  オプションを介して定義された別のクラスターのバックアップを使用することをお勧めします。

- または、同じ名前空間内の既存の\ ``Backup``
  オブジェクトを使用できます。

どちらの復旧方法も、完全な復旧最後に使用可能なWALまでまたは最大
:ref:`ポイント インタイム リカバリーPITR <ポイント インタイム リカバリーPITR>` 
までのいずれかが有効になります。完全なリカバリーを実行するときに、クラスターをレプリカモードで起動することもできます。 :ref:`レプリカクラスター <レプリカクラスター>` を参照してください。

..  Important::
   レプリカモードを使用する場合、復旧したクラスターのPostgreSQL構成`.spec.postgresql.parameters` が、物理レプリケーションの観点から元の構成と互換性があることを確認します。

\_volume snapshots_を使用したリカバリの場合

- すべてが同じバックアップに属し、同じ\ ``k8s.enterprisedb.io/cluster``
  および\ ``k8s.enterprisedb.io/backupName``
  ラベルで識別される\ ``VolumeSnapshot``
  オブジェクトの一貫したセットを使用します。次に、
  :ref:``VolumeSnapshot` オブジェクトからのリカバリー <`VolumeSnapshot` オブジェクトからのリカバリー>` の説明に従って、 ``.spec.bootstrap.recovery``
  スタンザの\ ``volumeSnapshots`` オプションを使用してリカバリします。

オブジェクトストアからのリカバリー
----------------------------------

Barman
Cloudによって作成され、サポートされているオブジェクトストアに保存されているバックアップから復元できます。
``barmanObjectStore``
セクションで必要な構成をすべて含む外部クラスターを定義した後、
``.spec.recovery.source`` オプションで参照する必要があります。

この例では、AzureのBLOBコンテナにリカバリオブジェクトストアを定義します。

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-restore
   spec:
     [...]

     superuserSecret:
       name: superuser-secret

     bootstrap:
       recovery:
         source: clusterBackup

     externalClusters:
       - name: clusterBackup
         barmanObjectStore:
           destinationPath: https://STORAGEACCOUNTNAME.blob.core.windows.net/CONTAINERNAME/
           azureCredentials:
             storageAccount:
               name: recovery-object-store-secret
               key: storage_account_name
             storageKey:
               name: recovery-object-store-secret
               key: storage_account_key
           wal:
             maxParallel: 8

前の例では、アプリケーションデータベースとその所有ユーザーの名前がデフォルトで\ ``app``
であることを前提としています。リストアするPostgreSQLクラスターが別の名前を使用している場合、
:ref:`アプリケーションデータベースの構成 <アプリケーションデータベースの構成>` に記載されているように、リカバリフェーズを終了する前にこれらの名前を指定する必要があります。

..  Important::
   デフォルトでは、 `recovery` メソッドは、オブジェクトストア内のバックアップデータのメインフォルダーの名前として、 `externalClusters` セクションのクラスターの`name` を厳密に使用します。この名前は、通常、サーバーの名前用に予約されています。 `barmanObjectStore.serverName` プロパティを使用して、別のフォルダー名を指定できます。

..  Note::
   この例では、並列WALリストア機能を利用し、最大8つのジョブを専用にして、アーカイブから必要なWALファイルを同時に取得します。この機能により、復旧時間を大幅に短縮できます。このシナリオを事前に計画し、ご使用の環境に合わせてこのパラメーターの値を正しく調整してください。必要なときに違いを生みますし、そうします。

``VolumeSnapshot`` オブジェクトからのリカバリー
-----------------------------------------------

..  Warning::
   ボリュームスナップショットからプライマリインスタンスをリカバリした後にレプリカを作成する場合、オペレーターは`pg_basebackup` を使用して同期することになる場合があります。この動作により、データベースのサイズによっては、プロセスが遅くなります。この制限は、将来的にオンラインバックアップとPVCクローン作成のサポートが導入されると解除されます。

KubernetesのEDB Postgresは、
:ref:`volumesnapshot backups <Backup>` の宣言APIを使用して取得された既存の\ ``Cluster``
のPVCの\ ``VolumeSnapshot``
から新しいクラスターを作成できます。次の例のように、スナップショットの名前を指定する必要があります。

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-restore
   spec:
     [...]

     bootstrap:
       recovery:
         volumeSnapshots:
           storage:
             name: <snapshot name>
             kind: VolumeSnapshot
             apiGroup: snapshot.storage.k8s.io

バックアップされたクラスターが別のPVCを使用してWALファイルを保存していた場合、リカバリーにはそれも含める必要があります。

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-restore
   spec:
     [...]

     bootstrap:
       recovery:
         volumeSnapshots:
           storage:
             name: <snapshot name>
             kind: VolumeSnapshot
             apiGroup: snapshot.storage.k8s.io

           walStorage:
             name: <snapshot name>
             kind: VolumeSnapshot
             apiGroup: snapshot.storage.k8s.io

前の例では、アプリケーションデータベースとその所有ユーザーの名前がデフォルトで\ ``app``
であることを前提としています。リストアするPostgreSQLクラスターが別の名前を使用している場合、
:ref:`アプリケーションデータベースの構成 <アプリケーションデータベースの構成>` に記載されているように、リカバリフェーズを終了する前にこれらの名前を指定する必要があります。

..  Warning::
   スナップショットからレプリカモードクラスターをブートストラップして、プライマリだけでなくスタンバイインスタンスのスナップショットを活用する場合、次のことをお勧めします。

1. 単一インスタンスのレプリカクラスターから開始します。プライマリインスタンスは、スナップショットとソースクラスタからの使用可能なWALを使用して復旧されます。
   2. レプリカクラスター内のプライマリのスナップショットを取得します。
   3. 必要に応じて、レプリカクラスター内のインスタンスの数を増やします。

``Backup`` オブジェクトからのリカバリー
---------------------------------------

クラスターを作成する必要がある名前空間で\ ``Backup``
リソースが既に利用可能な場合、次の例のように\ ``.spec.bootstrap.recovery.backup.name``
を使用して名前を指定できます。

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-example-initdb
   spec:
     instances: 3

     bootstrap:
       recovery:
         backup:
           name: backup-example

     storage:
       size: 1Gi

このブートストラップ方法では、復元する必要があるバックアップへの参照のみを指定できます。

前の例では、アプリケーションデータベースとその所有ユーザーの名前がデフォルトで\ ``app``
であることを前提としています。リストアするPostgreSQLクラスターが別の名前を使用している場合、
:ref:`アプリケーションデータベースの構成 <アプリケーションデータベースの構成>` に記載されているように、リカバリフェーズを終了する前にこれらの名前を指定する必要があります。

追加の考慮事項
--------------

オブジェクトストア、ボリュームスナップショット、または既存の\ ``Backup``
リソースからリカバリーするかどうかにかかわらず、\ ``Cluster``
が完全にプライマリに昇格し、書き込み操作を受け入れるまで、カタログを含むデータベースを変更することはできません。この制限には、\ ``Cluster``
がプライマリに移行するまで遅延されるロールオーバーライドが含まれます。その結果、次の考慮事項が適用されます。

- アプリケーションデータベース名とユーザーは、復元されるバックアップからコピーされます。これは、Kubernetesクラスターの通常のメンテナンスアクティビティの一部であるため、現在基になるシークレットのバックアップは行っていません。

- 元のpostgresユーザーパスワードを保持するには、\ ``enableSuperuserAccess``
  を構成し、\ ``superuserSecret`` を提供します。

デフォルトでは、リカバリはデフォルトのターゲットタイムライン ``latest``
で使用可能な最新のWALまで続行されます。オプションで\ ``recoveryTarget``
を指定して、ポイントインタイムリカバリーを実行できます
:ref:`ポイント インタイム リカバリーPITR <ポイント インタイム リカバリーPITR>` を参照してください。

..  Important::
   `barmanObjectStore.wal.maxParallel` オプションを使用して、リカバリオブジェクトストアからトランザクションログを同時にダウンロードすることにより、アーカイブからのWAL取得を高速化することを検討します。

ポイント インタイム リカバリーPITR
----------------------------------

ベースバックアップを抽出した後、最新のWALまでのすべてのWALを再生する代わりに、任意の時点でWALの再生を停止するようにPostgreSQLに依頼できます。
PostgreSQLは、この技術を使用してPITRを達成します。
WALアーカイブの存在は必須です。

..  Important::
   PITRでは、 :ref:`リカバリーターゲット <リカバリーターゲット>` で説明したオプションを使用してリカバリターゲットを指定する必要があります。

リカバリターゲットが指定された場合、オペレーターは、この機能が動作するために必要な構成パラメーターを生成します。

オブジェクトストアからのPITR
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

この例では、ベースバックアップとWALアーカイブの両方を含むAzureのリカバリオブジェクトストアを使用します。リカバリターゲットは、要求されたタイムスタンプに基づいています。

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-restore-pitr
   spec:
     instances: 3

     storage:
       size: 5Gi

     bootstrap:
       recovery:
         # Recovery object store containing WAL archive and base backups
         source: clusterBackup
         recoveryTarget:
           # Time base target for the recovery
           targetTime: "2023-08-11 11:14:21.00000+02"

     externalClusters:
       - name: clusterBackup
         barmanObjectStore:
           destinationPath: https://STORAGEACCOUNTNAME.blob.core.windows.net/CONTAINERNAME/
           azureCredentials:
             storageAccount:
               name: recovery-object-store-secret
               key: storage_account_name
             storageKey:
               name: recovery-object-store-secret
               key: storage_account_key
           wal:
             maxParallel: 8

この例では、タイムスタンプの形式で\ ``targetTime``
のみを指定する必要がありました。リカバリーを開始するベースバックアップを指定する必要はありません。

``backupID``
オプションは、リカバリプロセスを開始するベースバックアップを指定できるオプションです。デフォルトでは、この値は空です。

BarmanバックアップIDの形式で値を割り当てると、オペレーターはそのバックアップをリカバリのベースとして使用します。

..  Important::
   このようなバックアップが存在し、アクセス可能であることを確認する必要があります。

バックアップIDを指定しない場合、オペレーターは次のようにリカバリのベースバックアップを検出します。

- ``targetTime`` または\ ``targetLSN``
  を使用する場合、オペレーターは、そのターゲットより前に完了した最も近いバックアップを選択します。

- それ以外の場合、オペレーターは最後の利用可能なバックアップを時系列で選択します。

``VolumeSnapshot`` オブジェクトからのPITR
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

次の例では、以下を使用します。

- リカバリプロセスを開始するベースバックアップを含む\ ``PGDATA``
  のKubernetesボリュームスナップショット。このスナップショットは\ ``recovery.volumeSnapshots``
  セクションで指定され、 ``test-snapshot-1`` と呼ばれます。

- WALアーカイブを含むMinIOのリカバリオブジェクトストア。オブジェクトストアは、外部クラスター定義の形式で\ ``recovery.source``
  オプションで指定されます。

リカバリターゲットは、要求されたタイムスタンプに基づいています。

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-example-snapshot
   spec:
     # ...
     bootstrap:
       recovery:
         source: cluster-example-with-backup
         volumeSnapshots:
           storage:
             name: test-snapshot-1
             kind: VolumeSnapshot
             apiGroup: snapshot.storage.k8s.io
         recoveryTarget:
           targetTime: "2023-07-06T08:00:39"
     externalClusters:
       - name: cluster-example-with-backup
         barmanObjectStore:
           destinationPath: s3://backups/
           endpointURL: http://minio:9000
           s3Credentials:
             accessKeyId:
               name: minio
               key: ACCESS_KEY_ID
             secretAccessKey:
               name: minio
               key: ACCESS_SECRET_KEY

..  Note::
   バックアップクラスターで`walStorage` が有効になっていた場合、 :ref:`Recovery from VolumeSnapshot objects <Recovery>` で述べたように、 `PGWAL` ディレクトリを含むボリュームスナップショットも指定する必要があります。

..  Warning::
   ボリュームスナップショットのベースバックアップの終了時刻がリカバリターゲットのタイムスタンプより前であることを確認するのは自分の責任です。

リカバリーターゲット
^^^^^^^^^^^^^^^^^^^^

次に、使用可能なリカバリターゲット基準を示します。

targetTime
`RFC 3339 <https://datatracker.ietf.org/doc/html/rfc3339>`_ 形式で表現される、リカバリーが進行するタイムスタンプ。正確な停止ポイントは、
``exclusive`` オプションの影響も受けます。

targetXID
リカバリーが続行されるトランザクションID。正確な停止ポイントは、
``exclusive``
オプションの影響も受けます。回復されるトランザクションは、指定されたトランザクションより前にコミットされたトランザクション、およびオプションで含まれるトランザクションです。

targetName リカバリが続行する名前付けのリストアポイント
``pg_create_restore_point()`` で作成されます。

targetLSN
リカバリを続行するログ先行書き込みの場所のLSN。正確な停止ポイントは、
``exclusive`` オプションの影響も受けます。

targetImmediate
リカバリーは、一貫した状態に到達するとすぐに、つまりできるだけ早く終了します。オンラインバックアップから復元する場合、これはバックアップの取得が終了したポイントを意味します。

..  Important::
   `targetTime` または`targetLSN` のいずれかを指定すると、オペレーターは最も近いバックアップを取得できます。ただし、これは残りのターゲット`targetName` 、`targetXID` 、および`targetImmediate` では不可能です。このような場合、`backupID` の指定は必須です。

この例では、\ ``targetName`` ベースのリカバリターゲットを使用します。

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   [...]
     bootstrap:
       recovery:
         source: clusterBackup
         recoveryTarget:
           backupID: 20220616T142236
           targetName: restore_point_1
   [...]

各\ ``recoveryTarget`` 構成のターゲットから1つだけを選択できます。

さらに、 ``targetTLI``
を指定して、特定のタイムラインに強制的にリカバリーできます。

デフォルトでは、以前のパラメーターは包括的であるとみなされ、リカバリターゲットの直後で停止し、
`the behavior in PostgreSQL <https://www.postgresql.org/docs/current/runtime-config-wal.html#GUC-RECOVERY-TARGET-INCLUSIVE>`_  と一致します。

``exclusive`` パラメーターを\ ``true``
に設定することにより、リカバリターゲットの直前で停止する排他的動作を要求できます。次の例は、この動作を示しており、ベースバックアップとWALアーカイブの両方にAzureのBLOBコンテナーに依存します。

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   metadata:
     name: cluster-restore-pitr
   spec:
     instances: 3

     storage:
       size: 5Gi

     bootstrap:
       recovery:
         source: clusterBackup
         recoveryTarget:
           backupID: 20220616T142236
           targetName: "maintenance-activity"
           exclusive: true

     externalClusters:
       - name: clusterBackup
         barmanObjectStore:
           destinationPath: https://STORAGEACCOUNTNAME.blob.core.windows.net/CONTAINERNAME/
           azureCredentials:
             storageAccount:
               name: recovery-object-store-secret
               key: storage_account_name
             storageKey:
               name: recovery-object-store-secret
               key: storage_account_key
           wal:
             maxParallel: 8

アプリケーションデータベースの構成
----------------------------------

復旧したクラスターの場合、追加の構成でアプリケーションデータベース名と資格情報を構成できます。アプリケーションデータベースの資格情報を更新するには、独自のパスワードを生成、シークレットとして保存し、シークレットを使用するようにデータベースを更新できます。または、オペレーターにランダムで安全なパスワードを使用してシークレットを生成させて使用することもできます。
:ref:`空のクラスターをブートストラップする `initdb` <空のクラスターをブートストラップする `initdb`>` を参照

シークレットの詳細については、

..  Important::
   `Cluster` がリカバリモードである間、カタログを含むデータベースへの変更は許可されません。この制限には、`Cluster` がプライマリに移行するまで遅延されるロールオーバーライドが含まれます。このフェーズでは、ユーザーはソースクラスターで定義されたままになります。

次の例では、ライブクラスターからブートストラップに従って、所有者\ ``app``
と提供されたシークレット\ ``app-secret``
に保存されたパスワードを使用して\ ``app`` データベースを構成します。

.. code:: yaml

   apiVersion: postgresql.k8s.enterprisedb.io/v1
   kind: Cluster
   [...]
   spec:
     bootstrap:
       recovery:
         database: app
         owner: app
         secret:
           name: app-secret
         [...]

上記の構成では、次は **復旧が完了した後** にのみ発生します。

1. ``app`` データベースが存在しない場合、作成されます。

2. ``app`` ユーザーが存在しない場合、作成されます。

3. ``app`` ユーザーが\ ``app``
   データベースの所有者でない場合、所有権は\ ``app``
   ユーザーに付与されます。

4. ``username`` 値がシークレットの\ ``owner``
   値と一致する場合、アプリケーションユーザーこの場合は\ ``app``
   ユーザーのパスワードはシークレットの\ ``password`` 値に更新されます。

リカバリーの内部的な仕組み
--------------------------

オブジェクトストレージにアップロードされたデータを使用して、既存のバックアップから新しいクラスターを_bootstrap_できます。オペレーターは、
``barman-cloud-restore``
ツールベースバックアップ用と\ ``barman-cloud-wal-restore``
ツールWALファイル用、要求に応じて並列サポートを含むを使用して、リカバリプロセスをオーケストレーションします。

``recovery`` ブートストラップ方法の詳細と手順については、
:ref:`バックアップからのブートストラップ `recovery` <バックアップからのブートストラップ `recovery`>` を参照してください。

..  Important::
   `PostgreSQL PITR <https://www.postgresql.org/docs/current/continuous-archiving.html#BACKUP-PITR-RECOVERY>`_ の方法がよくわからない場合

は動作しますが、 ``.spec.postgresql.parameters``
に関しては、リカバリクラスターを元のクラスターとして構成することをお勧めします。新しいクラスターが復元されたら、必要に応じて設定を変更できます。

その仕組みは、オペレーターが新しいクラスターの最初のインスタンスにinitコンテナを注入し、initコンテナがオブジェクトストレージからバックアップのリカバリを開始することです。

..  Important::
   新しいPVCのベースバックアップコピーの期間は、バックアップのサイズ、およびネットワークとストレージの両方の速度によって異なります。

ベースバックアップ復旧プロセスが完了すると、オペレーターはPostgresインスタンスをリカバリモードで起動します。このフェーズでは、PostgreSQLは起動していますが、接続を受け入れることはできず、livenessプローブによれば、ポッドは正常です。
``restore_command``
を介して、PostgreSQLはアーカイブからWALファイルの取得を開始します。
``maxParallel``
オプションを設定し、並列WALリストア機能を有効にすることにより、このフェーズを高速化できます。

このフェーズは、PostgreSQLがターゲットWALの最後またはPITRの場合は必要なターゲットに到達すると終了します。オプションで\ ``recoveryTarget``
を指定して、PITRを実行できます。指定しない場合、リカバリは上の最新の使用可能なWALまで継続されます。デフォルトのターゲットタイムライン\ ``latest``

復旧が完了すると、オペレーターは必要なスーパーユーザーのパスワードをインスタンスに設定します。新しいプライマリインスタンスは通常どおり起動し、残りのインスタンスはレプリカとしてクラスターに参加します。

プロセスはユーザーに対して透過的であり、ポッドで実行されているインスタンスマネージャーによって管理されます。

バックアップセクションを使用したクラスターへのリストア
------------------------------------------------------

クラスターリストアのマニフェストには、\ ``backup``
セクションが含まれる場合があります。これは、復旧後に、新しいクラスターがWALのアーカイブと、構成されている場合にバックアップの取得を開始することを意味します。

たとえば、このセクションは、クラスター\ ``cluster-example-backup``
からブートストラップするクラスターのマニフェストの一部です。ストレージバケットに、\ ``recoveredCluster``
という名前のフォルダーを作成します。ここに、復旧したクラスターのベースバックアップとWALが保存されます。

.. code:: yaml

   backup:
     barmanObjectStore:
       destinationPath: s3://backups/
       endpointURL: http://minio:9000
       serverName: "recoveredCluster"
       s3Credentials:
         accessKeyId:
           name: minio
           key: ACCESS_KEY_ID
         secretAccessKey:
           name: minio
           key: ACCESS_SECRET_KEY
     retentionPolicy: "30d"

   externalClusters:
     - name: cluster-example-backup
       barmanObjectStore:
         destinationPath: s3://backups/
         endpointURL: http://minio:9000
         s3Credentials:

異なるクラスターで同じ\ ``barmanObjectStore``
構成を再利用しないでください。ストレージバケットの既存の情報が新しいクラスターによって上書きされる場合があります。

..  Warning::
   オペレーターには、クラスターが情報を含むストレージバケットを上書きしないことを確認する安全チェックが含まれます。既存のストレージを上書きするクラスターは、ポッドがエラー状態の`Setting up primary` 状態のままです。ポッドログには`ERROR: WAL archive check failed for server recoveredCluster: Expected empty archive` が表示されます。

..  Important::
   復旧したクラスターで`k8s.enterprisedb.io/skipEmptyWalArchiveCheck` アノテーションを`enabled` に設定すると、安全性チェックをスキップできます。一般的な使用ケースでは、チェックは正常に機能するため、チェックをスキップすることはお勧めしません。重大なデータの損失が発生する可能性があるため、PostgreSQLリカバリシステムに精通している場合にのみこのチェックをスキップしてください。
