ストレージ
==========

**ストレージは、データベースワークロードで最も重要なコンポーネントです**
。ストレージは、常に利用でき、スケーリング、パフォーマンスが良く、一貫性と耐久性を保証する必要があります。仮想マシンやベアメタルなどの従来の環境に適用されるのと同じ期待と要件は、Kubernetesによって管理されるコンテナコンテキストでも有効です。

..  Important::
   動的にプロビジョニングされるストレージに関して、Kubernetesには独自の特性があります。これらには、*ストレージクラス*、*永続ボリューム*、および*永続ボリューム要求*が含まれます。 VMおよび物理サーバー上のデータベースワークロードのストレージの観点から、長年構築してきた貴重な知識に加えて、これらの概念を所有する必要があります。

ストレージへのアクセスには、主に2つの方法があります。

-  **ネットワーク**
   直接または間接的にKubernetesを実行しているホストにローカルにマウントされたNFSボリュームを考えます。

-  **ローカル**
   ポッドが実行されているノードに直接接続されていますこれには、Kubernetesのベアメタルインストールに直接接続されたディスクも含まれます

Kubernetesで最も一般的な使用パターンであるネットワークストレージは、従来の環境で経験する可能性のあるスループットとレイテンシと同じ問題を示します。これらは、複数のアプリケーションとのI/O競合によりパフォーマンス結果のばらつきが増加する共有環境では強調される可能性があります。

ローカルストレージは、シェアードナッシングアーキテクチャを有効にします。これは、より高く予測可能なパフォーマンスを保証するため、高トランザクションの超大規模データベースVLDBワークロードに適しています。

..  Warning::
   CloudNativePGでPostgreSQLクラスターを展開する前に、使用しているストレージがデータベースワークロードに推奨されていることを確認してください。私たちのアドバイスは、最初に `fio <https://fio.readthedocs.io/en/latest/fio_doc.html>`_ などのツールを使用してストレージをベンチマークし、次に `pgbench <https://www.postgresql.org/docs/current/pgbench.html>`_ を使用してデータベースをベンチマークすることにより、パフォーマンスの期待値を明確に設定することです。

..  Note::
   CloudNativePGは、データの永続性の管理に`StatefulSet` sを使用しません。代わりに、永続ボリューム要求PVCを直接管理します。詳細については、 :ref:`カスタムポッドコントローラ <カスタムポッドコントローラ>` ドキュメントをご覧ください。

バックアップ リカバリー
-----------------------

CloudNativePGは、バックアップとリカバリーの両方のボリュームスナップショットをサポートしているため、ストレージソリューションを選択するときに、特に非常に大規模なデータベースを管理する場合、この側面も考慮することをお勧めします。

CloudNativePGのベンチマーク
---------------------------

 :ref:`guidelines in the "Benchmarking" section <ベンチマーク>` に従って、運用環境にデータベースを展開する前に、制御されたKubernetes環境でCloudNativePGのベンチマークを行うことをお勧めします。

手短に言うと、私たちのアドバイスは2つのレベルで動作することです。

-  ``fio``
   を使用して、基になるストレージのパフォーマンスを測定する。シークエンシャル読み取り、シークエンシャル書き込み、ランダム読み取り、ランダム書き込みのスループットなど、データベースワークロードの関連メトリック

-  PostgreSQLとともに配布されるデフォルトのベンチマークツール\ ``pgbench``
   を使用してデータベースのパフォーマンスを測定する

..  Important::
   ストレージとデータベースのパフォーマンスの両方の測定は、**データベースが運用開始する前に**行う必要があるアクティビティです。ただし、このような結果は、計画段階キャパシティプランニングなどでだけでなく、生産ライフサイクル、特に緊急事態この種のテストを実行する余裕がない場合でも非常に価値があります。データベースは実際に時間の経過とともに変更および進化し、データの分散も変化し、パフォーマンスに影響を与える可能性があります。シークエンシャルな読み取りまたは書き込みの理論的な最大スループットを知ることは、これらの状況で非常に役立つことがわかります。特に、外部ワークロードの影響によって結果が変化しないシェアードナッシングコンテキストでは。 **システムを知り、ベンチマークします。**

保存時の暗号化
--------------

CloudNativePGでは、保存時の暗号化が可能です。オペレーターは、それを基になるストレージクラスに委任します。この重要なセキュリティ機能については、ストレージクラスを参照してください。

Persistent Volume Claim
-----------------------

オペレーターは、\ ``PGDATA``
を保存することを目的として、各PostgreSQLインスタンスの永続ボリューム要求PVCを作成し、各ポッドにマウントします。

さらに、以下の :ref:`WALのボリューム <WALのボリューム>` で説明しているように、PostgreSQL書き込み先行ログWALを保存する別のPVCを使用したクラスターの作成をサポートします。

CloudNativePGでは、単一のPostgreSQLインスタンスに接続されたボリュームは
**PVCグループ** として定義されます。

ストレージクラスを介した構成
----------------------------

..  Important::
   CloudNativePGは、ストレージクラスに依存しないように設計されています。いつものように、運用に展開する前に、制御された環境でストレージクラスを適切にベンチマークすることをお勧めします。

PostgreSQLクラスのストレージを構成するより簡単な方法は、次の例のように、特定のサイズのストレージを要求するだけです。

.. code:: yaml

   apiVersion: postgresql.cnpg.io/v1
   kind: Cluster
   metadata:
     name: postgresql-storage-class
   spec:
     instances: 3
     storage:
       size: 1Gi

前の構成を使用すると、生成されたPVCはデフォルトのストレージクラスで満たされます。ターゲットKubernetesクラスターにデフォルトのストレージクラスがない場合、または既知のストレージクラスでPVCを満たす必要がある場合でも、カスタムリソースに設定できます。

.. code:: yaml

   apiVersion: postgresql.cnpg.io/v1
   kind: Cluster
   metadata:
     name: postgresql-storage-class
   spec:
     instances: 3
     storage:
       storageClass: standard
       size: 1Gi

PVCテンプレートを介した構成
---------------------------

生成されたPVCをさらにカスタマイズするには、次の例のように、カスタムリソース内にPVCテンプレートを提供できます。

.. code:: yaml

   apiVersion: postgresql.cnpg.io/v1
   kind: Cluster
   metadata:
     name: postgresql-pvc-template
   spec:
     instances: 3

     storage:
       pvcTemplate:
         accessModes:
           - ReadWriteOnce
         resources:
           requests:
             storage: 1Gi
         storageClassName: standard
         volumeMode: Filesystem

WALのボリューム
---------------

デフォルトでは、PostgreSQLはすべてのデータをいわゆる\ ``PGDATA``
ディレクトリに保存します。 ``PGDATA``
内のコアディレクトリの1つは\ ``pg_wal`` PostgreSQLでは\ ``pg_xlog``
として知られています。これには、データベースで発生したトランザクション変更のログがセグメントファイルの形式で含まれています。

..  Note::
   通常、各セグメントのサイズは16MBですが、サイズは :ref:`空のクラスターをブートストラップする `initdb` <空のクラスターをブートストラップする `initdb`>` で説明しているように、クラスターの初期化時に適用される`walSegmentSize` オプションを介して構成できます。

ほとんどの場合、 ``PGDATA`` が存在するのと同じボリュームに\ ``pg_wal``
があっても問題ありませんが、WALを別のボリュームに保存することからいくつかの利点があります。

-  **I/Oパフォーマンス** WALファイルを\ ``PGDATA``
   とは別のストレージに保存することにより、PostgreSQLはWAL操作通常はシークエンシャル書き込みとデータファイルテーブルやインデックスなどの並列I/Oを利用でき、したがって、垂直方向を向上させることができますスケーラビリティ

-  **信頼性の向上**
   WALファイルに専用のディスク領域を予約することにより、\ ``PGDATA``
   ボリュームの領域の枯渇がWALの書き込みを妨げず、PostgreSQLプライマリが正しくシャットダウンされることを常に保証できます。

-  **より詳細な制御** ``PGDATA`` と\ ``pg_wal``
   の両方専用の領域の量を定義し、\ `WAL
   configuration <https://www.postgresql.org/docs/current/wal-configuration.html>`__\ とチェックポイントを微調整したり、コスト最適化のために別のストレージクラスを使用したりできます

-  **より良いI/Oモニタリング** ``PGDATA`` と\ ``pg_wal``
   の両方で負荷とディスク使用量を常にモニタでき、たとえば ``PGDATA``
   のサイズ変更が必要な場合に通知する適切なアラートを設定できます。

..  Seealso::
   `Reliability and the Write-Ahead Log <https://www.postgresql.org/docs/current/wal.html>`_ を参照してください。

詳細については、 PostgreSQLの公式ドキュメントから 。

``.spec.walStorage``
オプションを介してWALの個別のボリュームを追加できます。これは、
``storage``
フィールドで説明したものと同じルールに従い、専用PVCをプロビジョニングします。例

.. code:: yaml

   apiVersion: postgresql.cnpg.io/v1
   kind: Cluster
   metadata:
     name: separate-pgwal-volume
   spec:
     instances: 3
     storage:
       size: 1Gi
     walStorage:
       size: 1Gi

..  Important::
   `walStorage` の削除はサポートされていません。追加されると、WALの別のボリュームは既存のPostgresクラスターから削除できません。

ボリュームの拡張
----------------

Kubernetesが :ref:`expanding PVCs <ストレージ>` を許可するAPIを公開

これはデフォルトで有効ですが、基になる\ ``StorageClass``
でサポートする必要があります。

特定の\ ``StorageClass``
がボリューム拡張をサポートしているかどうかを確認するには、ストレージクラスの\ ``allowVolumeExpansion``
フィールドを読み取ることができます。

::

   $ kubectl get storageclass -o jsonpath={$.allowVolumeExpansion} premium-storage
   true

ボリューム拡張Kubernetes機能の使用
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

ストレージクラスがボリューム拡張をサポートしている場合、 ``Cluster``
のサイズ要件を変更できます。オペレーターはすべてのPVCに変更を適用します。

``StorageClass`` が :ref:`online volume resizing <ストレージ>` をサポートしている場合

変更はすぐにポッドに適用されます。基になるストレージクラスがそれをサポートしていない場合、ポッドを削除してサイズ変更をトリガーする必要があります。

続行する最良の方法は、一度に1つのポッドを削除し、レプリカから始めて、各ポッドがバックアップされるまで待機することです。

AKSでのPVCボリュームの拡張
^^^^^^^^^^^^^^^^^^^^^^^^^^

現時点では、 `Azure is not able to resize the PVC's volume without restarting the pod <https://github.com/Azure/AKS/issues/1477>`_  。 CloudNativePGは、
 :ref:`オペレーター設定 <オペレーター設定>` の\ ``ENABLE_AZURE_PVC_UPDATES``
環境変数を介してこの制限を克服しました。 ``'true'``
に設定すると、CloudNativePGはPostgresクラスターのローリング更新をトリガーします。

または、以下の回避策に従って、AKSのボリュームのサイズを手動で変更できます。

AKSのボリューム拡張の回避策
^^^^^^^^^^^^^^^^^^^^^^^^^^^

次の手順に従って、AKSでPVCのサイズを手動で変更できます。例として、3つのレプリカを含むクラスターがあると仮定します。

::

   $ kubectl get pods
   NAME                READY   STATUS    RESTARTS   AGE
   cluster-example-1   1/1     Running   0          2m37s
   cluster-example-2   1/1     Running   0          2m22s
   cluster-example-3   1/1     Running   0          2m10s

 `docs <https://github.com/kubernetes-sigs/azuredisk-csi-driver/blob/master/docs/known-issues/sizegrow.md>`_ で説明しているように、Azureディスクは「未接続」状態にある場合にのみ拡張できます。これは、PostgreSQLクラスターが使用するディスクのサイズを変更するには、手動ロールアウトを実行し、最初にディスクにバインドされたPVCを使用してポッドをホストするノードを遮断する必要があることを意味します。これにより、バックグラウンドでのディスクのサイズ変更が完了する前に、オペレーターがポッドを再作成し、すぐにPVCに再接続することを防ぎます。

最初のステップは、次のように新しいサイズたとえば「2Gi」を適用してクラスター定義を編集することです。

::

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

     storage:
       storageClass: default
       size: 2Gi

``cluster-example-1``
ポッドがクラスターのプライマリであると仮定すると、最初にレプリカの使用を続行できます。たとえば、
``cluster-example-3``
ポッドをホストするkubernetesノードを遮断することから始めます。

::

   kubectl cordon <node of cluster-example-3>

次に、 ``cluster-example-3`` ポッドを削除します。

::

   $ kubectl delete pod/cluster-example-3

次のコマンドを実行します。

::

   kubectl get pvc -w -o=jsonpath={.status.conditions[].message} cluster-example-3

次の出力が表示されるまで待ちます。

::

   Waiting for user to (re-)start a Pod to finish file system resize of volume on node.

次に、ノードの遮断を解除できます。

::

   kubectl uncordon <node of cluster-example-3>

ポッドが正しく再作成され、Running and Ready状態になるまで待ちます。

::

   kubectl get pods -w cluster-example-3
   cluster-example-3   0/1     Init:0/1   0          12m
   cluster-example-3   1/1     Running   0          12m

次に、次のコマンドを実行して、PVC拡張を確認します。これは、構成済みの「2Gi」を結果ます。

::

   kubectl get pvc cluster-example-3 -o=jsonpath={.status.capacity.storage}

したがって、残りのポッドに対してこれらの手順を繰り返すことができます。

..  Important::
   `kubectl cnpg promote` たとえば、`cluster-example-3` をプライマリに昇格させるための`kubectl cnpg promote cluster-example 3` を使用して、新しいサイズ変更したポッドをスイッチオーバーで昇格させた後、プライマリインスタンスに関連付けられたディスクのサイズ変更を最後のディスクとして残してください。

ストレージの再作成
^^^^^^^^^^^^^^^^^^

ストレージクラスがボリューム拡張をサポートしていない場合でも、増加したストレージで新しいPVCを割り当て、そこにデータベースを移動することにより、別のPVCでクラスターを再生成できます。この操作は、クラスターに複数のノードが含まれる場合にのみ実行可能です。

その際、次の例のように、\ ``resizeInUseVolumes``
フラグを無効にすることにより、オペレーターが既存のPVCを変更しないようにする必要があります。

.. code:: yaml

   apiVersion: postgresql.cnpg.io/v1
   kind: Cluster
   metadata:
     name: postgresql-pvc-template
   spec:
     instances: 3

     storage:
       storageClass: standard
       size: 1Gi
       resizeInUseVolumes: False

クラスター全体を別の記憶領域に移動するには、すべてのPVCとすべてのポッドを再作成する必要があります。次の例のような3つのレプリカを持つクラスターがあると仮定します。

::

   $ kubectl get pods
   NAME                READY   STATUS    RESTARTS   AGE
   cluster-example-1   1/1     Running   0          2m37s
   cluster-example-2   1/1     Running   0          2m22s
   cluster-example-3   1/1     Running   0          2m10s

別のPVCを使用してクラスターを再作成するには、クラスター定義を編集して\ ``resizeInUseVolumes``
を無効にし、別のPVCですべてのインスタンスを再作成できます。

例として、 ``cluster-example-3``
のストレージを再作成するには、次のことができます。

::

   $ kubectl delete pvc/cluster-example-3 pod/cluster-example-3

..  Important::
   専用のWALボリュームを作成している場合、このプロセス中に両方のPVCを削除する必要があります。さらに、WALボリュームPVCを再生成する場合にも同じ手順が適用されます。これは、 `.spec.walStorage` セクションでも`resizeInUseVolumes` を無効にすることにより実行できます。

例 WALストレージ専用のPVCが存在する場合

::

   $ kubectl delete pvc/cluster-example-3 pvc/cluster-example-3-wal pod/cluster-example-3

それが完了したら、オペレーターは、サイズ変更したPVCを使用して別のレプリカの作成を調整します。

::

   $ kubectl get pods
   NAME                           READY   STATUS      RESTARTS   AGE
   cluster-example-1              1/1     Running     0          5m58s
   cluster-example-2              1/1     Running     0          5m43s
   cluster-example-4-join-v2      0/1     Completed   0          17s
   cluster-example-4              1/1     Running     0          10s

永続ボリュームの静的プロビジョニング
------------------------------------

CloudNativePGは、動的ボリュームプロビジョニングと連携するように設計されており、ユーザーが要求したときに、上記のストレージクラスと永続ボリューム要求テンプレートを介して、オンデマンドでストレージボリュームを自動的に作成できます。

ただし、場合によっては、Kubernetes管理者は、新しいストレージボリュームを
*手動*\ 作成し、Kubernetesクラスター内での表現に関連する\ ``PersistentVolume``
オブジェクトを作成することを優先します。これは、ボリュームの*\*
事前プロビジョニング**としても知られています。

..  Important::
   ボリュームの事前プロビジョニングは、オペレーターの高可用性と自己修復機能に影響を与え、CloudNativePGが構築されている完全な宣言型モデルを壊すため、回避することをお勧めします。

次の手順を実行して、CloudNativePGで事前プロビジョニングされたボリュームを使用できます。

1.Kubernetesの外部でボリュームを手動で作成する

2.実際のCSIドライバーつまり\ ``volumeHandle`` 、\ ``fsType``
、\ ``storageClassName``
などに必要な正しいパラメーターを使用して、上記のボリュームと一致するように\ ``PersistentVolume``
オブジェクトを作成します

3.ストレージセクションごとに、コヒーレントな :ref:`pvcTemplate <ストレージ>` を使用してPostgres
``Cluster`` を作成します

Kubernetesが上記の\ ``PersistentVolume``
と一致し、CloudNativePGが必要な\ ``PersistentVolumeClaim``
を作成できるようにするセクション

..  Warning::
   静的プロビジョニングでは、クラスターのアフィニティルールに基づいて、事前プロビジョニングされたボリュームが存在するKubernetesによってPostgresポッドを正しくスケジュールできることを確認するのはあなたの責任です。クラスターを展開した後、`Pending` でスタックしているポッドがないかを確認し、状態が持続する場合は、これが発生した理由を調査します。

ブロックストレージの考慮事項Ceph/Longhorn
-----------------------------------------

Kubernetesのブロックストレージソリューションのほとんどは、復元性を向上させるためにボリュームの複数の「レプリカ」を持つことを提案しています。これは、アプリケーションに復元力が組み込まれていないワークロードに適しています。ただし、CloudNativePGは、インスタンスの数とそれらに接続されている永続ボリュームを介してPostgres
``Cluster`` に直接組み込まれているこの復元力を備えています。

これらの場合、Postgresクラスターが使用するストレージクラスを1つのレプリカとして定義することは意味があります。
LonghornやCephのようなストレージソリューションで追加のレプリカを定義すると、書き込み増幅と呼ばれる問題が発生する可能性があり、ディスクI/Oと使用領域が不必要に増加します。
