#21 EBSでも出来るよ-PostgreSQL on k8s-

本記事は[PostgreSQL on Kubernetes Advent Calendar 2018](https://qiita.com/advent-calendar/2018/postgresonk8s)の21日目です。


\#20として「[RancherでKubernetesクラスタ構築](https://qiita.com/tzkoba/items/7fe4074c9daf66b1c0d4)」を投稿しましたが、内容に誤りがありました（現在も修正中）。RancherとKubernetes、そしてAWSの関係を理解するに至っておらず、恥ずかしい限りです。

前回の内容は本日のPostgreSQL on EBSをやる準備だったのですが、想定よりも随分シンプルに出来ることが分かったのは大きな収穫でした。改めて、@t-umeさんに感謝致します。

# TL;DR

+ PostgreSQL on k8sはEBSでも十分に構築できる。
+ むしろそっちのほうが簡単？
+ 当然ポッドをフェイルオーバさせると、EBSの追随するよ。

# PostgreSQL on Kubernetes（EBS）の構成
Rookに変わってEBSをストレージとして使っても、PostgreSQL on Kubernetesのコンセプト自体は変わりません。[#2](https://qiita.com/tzkoba/items/cd0d1120ee5bc38cd634#pgecons%E3%81%8C%E6%8F%90%E7%A4%BA%E3%81%99%E3%82%8Bpostgresql%E3%81%AE%E4%BB%A3%E8%A1%A8%E7%9A%84%E3%81%AA%E6%A7%8B%E6%88%90)で触れたようにストレージ・レイヤでデータ冗長化を担保する**シンプルなDBクラスタ**、です。

実はこれ、クラウドストレージを使ってしまえば簡単に出来るのです。
下図はEC2インスタンス上のPostgreSQLコンテナからEBSをマウントした構成になっていますが、図にあるように現在のKubernetesではPodの動きにEBSが追随してくれます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/54853/c5312369-6a5d-56fb-93c9-5a598991776b.png)

当然EBSのデータは単一ディスクへの書き込みではありませんし、簡単に消えるということもないため、冗長化もここで担保されます。

## 前提条件
前回記したようにRancherを使ってKubernetesクラスタを構築しています。そのため、@t-umeさんの[こちらの記事](https://qiita.com/t_ume/items/9ad3b34a83d40bc1d023)を参考にCloud Providerの設定を終えておく必要があります。

更にActive-StandbyのDBクラスタとなりますので、DBノードは2台必要、ストレージノードはEBSなので不要です。

+ DBノード2台、ラベルとしてtype=node.db.postgresを作成しておく

以降では今回のPostgreSQL on Kubernetes（EBS）の構成をPg-EBSと表記してますので、その前提でお読み下さい。

## Pg-EBSのインストール
このAdvent Calenderを書きながらgithubもどんどん更新してますので、まずgit cloneしてPg-EBSのディレクトリに移動します。

```terminal:git&nbsp;cloneとディレクトリ移動
$ git clone https://github.com/tzkoba/postgres-on-k8s.git
$ cd postgres-on-k8s/postgres-install/pg-ebs/
```


ConfigMapを2つ作成します。

```terminal:ConfigMapの作成
$ kubectl apply -f pg-ebs-configmap.yaml
$ kubectl apply -f pg-ebs-postgres_conf.yaml
```

次にEBSを使うためのStorageClassとPersistent Volume Claimを作成して確認します。[こちら](https://qiita.com/tzkoba/items/56fdc60126d4b2350ad5)でRook利用の構成でも書いたように、データ・ディレクトリとアーカイブログ・ディレクトリ用に2つのボリュームを作成しています。

```terminal:StorageClassとPVCの作成
$ kubectl apply -f pg-ebs-storageclass.yaml
$ kubectl apply -f pg-ebs-sf-pvc.yaml

# 作成状況の確認
$ kubectl get sc,pvc
NAME                                          PROVISIONER             AGE
storageclass.storage.k8s.io/rook-ceph-block   ceph.rook.io/block      1d
storageclass.storage.k8s.io/sc-ebs-001        kubernetes.io/aws-ebs   1d

NAME                                       STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/pvc-pg-ebs-sf        Bound     pvc-ee233cc4-04df-11e9-9405-02ef0b761764   3Gi        RWO            sc-ebs-001     1d
persistentvolumeclaim/pvc-pg-ebs-sf-xlog   Bound     pvc-ee261ebd-04df-11e9-9405-02ef0b761764   2Gi        RWO            sc-ebs-001     1d
```

上記のStorageClassは中身も見ておきましょう。

```yaml:pg-ebs-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: sc-ebs-001
parameters:
  encrypted: "false"
  type: gp2
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Delete
```

これだけです。provisionerとして**kubernetes.io/aws-ebs**を指定し、固有のパラメータを渡しています。


ボリュームの準備が出来ましたので、PostgreSQLのStatefulSetとServiceを作って構築完了です。

```terminal:StatefulSetとServiceの作成
$ kubectl apply -f pg-ebs-sf.yaml
$ kubectl apply -f pg-ebs-sf-service.yaml

$ kubectl get pod,sts
NAME              READY     STATUS    RESTARTS   AGE
pod/pg-ebs-sf-0   1/1       Running   0          1d

NAME                         DESIRED   CURRENT   AGE
statefulset.apps/pg-ebs-sf   1         1         1d
```

## フェイルオーバさせてみる
では、このDBクラスタがどのように動くかを確認しておきましょう。

最初にStatefulSetによるポッドのデプロイ状況を確認しておきます。

```
$ kubectl get pod -o wide
NAME          READY     STATUS    RESTARTS   AGE       IP          NODE
pg-ebs-sf-0   1/1       Running   0          1d        10.42.2.2   rke_worker_db02i
```

AWSのボリュームのマウント状況は以下のようになっており、KubernetesからプロビジョニングされたEBSがrke_worker_db02iというノードにアタッチされています。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/54853/27bebee2-9c23-a1f9-1dae-37a4cf9da7c8.png)


では、このポッドをフェールオーバしてStandbyノードに移動させて見ましょう。検証には[#15](https://qiita.com/tzkoba/items/c082a67585297c0541d5)で書いたように**kubectl drain**コマンドを使います。

```terminal:kubectl&nbsp;drainと結果確認
$ kubectl drain rke_worker_db02i --force --ignore-daemonsets
rke_worker_db02i cordoned
WARNING: Ignoring DaemonSet-managed pods: cattle-node-agent-ptr6m, nginx-ingress-controller-sk8j2, canal-nnmlp, rook-ceph-agent-p4qmc, rook-discover-px5n7
pod/pg-ebs-sf-0 evicted

# ポッドが移動したことを確認する
$ kubectl get pod -o wide
NAME          READY     STATUS    RESTARTS   AGE       IP          NODE
pg-ebs-sf-0   1/1       Running   0          3m        10.42.1.7   rke_worker_db01i
```

ポッドはStandyノード、この際はrke_worker_01iで正常に稼動しています。AWS側でもEBSのアタッチ状況を確認すると以下のようになっています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/54853/5ea8dcc6-cf16-bc6a-9c09-caf640df6610.png)

PostgreSQLインスタンスの移動に伴って、**EBSボリュームが自動的にデタッチ/アタッチされている**ことが分かるかと思います。

# まとめ
これまではPostgreSQL on Kubernetesでは分散ストレージのRookを使った構成を試してきました。今日はEBSを使ったPostgreSQLインスタンスを構築しましたが、これを使って明日は簡単なベンチマージ句を実行し、性能比較をしてみたいと思います。

よろしくお願いします。