Kubernetes のデータ永続化が複雑でよくわからないから調べた

## 前提
- 本記事執筆時の各ツールのバージョン  
kubernetes v1.16.5  
docker 19.03.12
- 書いている人は k8s をこれから使ってみようとしている人。

## 悩み
- k8s で Node 外のストレージを使ってデータ永続化する手法としていろんなリソースが出てくる（PersistentVolume, PersistentVolumeClaim, StorageClass, StatefulSet などなど）が、なんでこんなにいっぱい出てくるのかわからない。しかし設定ファイルの書き方はわかるので使えている。

## 結論
- ストレージを扱いやすいように抽象化しているのだが、誰にとって扱いやすいのかが個人的には理解のポイントだった。インフラを管理する人と、システム開発する人がいることを頭に入れると理解しやすくなった。
- [Kubernetesのデータ永続化入門](https://www.netone.co.jp/knowledge-center/netone-blog/20191206-1/)の図がとてもわかりやすかったので見てみてください。
- そして結局[公式ドキュメント](https://kubernetes.io/ja/docs/concepts/storage/persistent-volumes/)にたどり着くので、詳しくはこちらを見てください。（はじめっからここ見とけばよくわからなくなることもなかった説）

## 各種リソースの説明
### Volume に直接外部ストレージを指定する
いきなり Kubernetes のリソースではない話ですが、`Pod`の yaml ファイルの`.spec.volumes`に直接ボリュームの具体的な指定を記述するやつです。
[公式ドキュメント](https://kubernetes.io/docs/concepts/storage/volumes/)を見ると、いろんな種類の Volume が並んでいます。外部ストレージを直接指定する場合は、`nfs`とか`iscsi`とかを指定します（ネットワークストレージの種類に全然詳しくないので、この辺はよくわかってない）。GKE とか EKS みたいなマネージドのサービスだと独自のストレージが用意されていたりします。
そして後述の`PersistentVolume`も`volumes`の指定として並列になっています。

ちなみに、外部ストレージを直接具体的に指定すると、`Pod`とストレージが密結合になってしまうので、間に抽象レイヤーを入れる、というのはわかります。それが`PersistentVolume`だと理解していたけれど、なぜ`PersistentVolumeClaim`とわかれているのかが、いまいち腑に落ちていなかったのが動機で調べたのがこの記事です。

ひとりでいじっているときの盲点だったのですが、実際の k8s 使うような規模の開発では、インフラ管理者とシステムの開発者はだいたい別だし、開発者は複数の人たちが入れ替わったり増減したりするという当たり前のことを思い出すと理解できました。

### PersistentVolume (PV)
これが外部ストレージの実体となるリソースです。具体的な実装内容が定められています。名前の通り、データを永続化するためのボリュームで、`Pod`とは違うライフサイクルでクラスター内に存在します。
後述する`StorageClass`を基に動的に生成され確保されることもあれば、インフラ管理者があらかじめ手動で用意することもあります。
調べた感じ、動的に確保されるのが主流のようなので、PVリソースを直接手動で用意するのは少なそうですが、インフラを厳密に管理したい時に手動で用意するんだろうか。

### PersistentVolumeClaim (PVC)
これは開発者側のストレージへの要求です。
欲しいパフォーマンスや挙動を記述すると、それを満たすPVが確保されます。
また、その要求も`StorageClass`によって抽象化されているので、実際には全部を具体的に指定することはありません。インフラ管理者が用意した`StorageClass`から適切なものを選ぶことになります。
ちなみに、後述する`StatefulSet`を使う場合は yaml ファイルに`volumeClaimTemplates`というのがあり、それによってこのPVCも直接作成しなくてもよいです。

### StorageClass (SC)
PV のクラスです。プログラミングで言うクラスと同様で、確保する PV の雛形です。
これによって、インフラ管理者は PV の具体的な実装を抽象化しつつ開発者からのストレージ要求に答えることができます。
また、開発者もインフラの中身を気にすることなく欲しいストレージを確保することができます。

### StatefulSet
これだけ、ここまで説明してきたものとは毛色が違うリソースなのですが、`Deployment`と同じコントローラーという種類に属するリソースです。アプリケーション（一群の`Pod`）をクラスターにデプロイします。
各 PV に固有のIPアドレスやDNS名がついたり、起動順序が保証されることにより、`Pod`と PV の紐付けが簡単になります。名前の通り、ステートフルなアプリケーションに向いたものです。
例えばよく出てくる用途としては、プライマリ/レプリカ構成のデータベースなどです。
`Deployment`との大きな違いは、`Deployment`が複数の`Pod`に共通の PV が紐付けられるのに対し、`Pod`ごとに専用の PV が紐付けられるということや、世代管理はしていないので`Deployment`のようにロールバックはできないということじゃなかろうかと思います。
調べただけで、まだ使ってないので使ってみてわかったことがあったら追記する。

## ということで
わかってみれば難しいことではなかったんですが、やっぱり前提になってる状況とか課題とかを把握していないと、ちゃんと理解するのは難しいなと思った次第です。

## 参考文献
- [k8sの永続化調べ ver1](https://qh8pik1c1k755ety.qrunch.io/entries/xf0ICWQV28CYx3kM)
- [Kubernetesのデータ永続化入門](https://www.netone.co.jp/knowledge-center/netone-blog/20191206-1/)
- [StatefulSetっていつ使うの？PersistentVolumesでいいんじゃないの？](https://scrapbox.io/blackawa/StatefulSet%E3%81%A3%E3%81%A6%E3%81%84%E3%81%A4%E4%BD%BF%E3%81%86%E3%81%AE%EF%BC%9FPersistentVolumes%E3%81%A7%E3%81%84%E3%81%84%E3%82%93%E3%81%98%E3%82%83%E3%81%AA%E3%81%84%E3%81%AE%EF%BC%9F)
- [KubernetesのControllerについて(StatefulSet)](https://gadgeterkun.hatenablog.com/entry/20190726/1564106400)
- [Kubernetes PVC と Deployment, StatefulSet の関係を検証してみた](https://qiita.com/sugimount/items/b163b08fe9a3b1b102d9)
- [公式ドキュメント - 永続ボリューム](https://kubernetes.io/ja/docs/concepts/storage/persistent-volumes/)
- [公式ドキュメント - Volume](https://kubernetes.io/docs/concepts/storage/volumes/)
- [公式ドキュメント - StatefulSet](https://kubernetes.io/ja/docs/concepts/workloads/controllers/statefulset/)