KubeDBを使ってサクッとKubernetes上にDBを作成する

# KubeDBとは

[KubeDB](https://kubedb.com/)はKubernetes上で簡単にプロダクションレベルのDBが作成できるツールです。

### コンセプト

https://kubedb.com/docs/0.9.0/concepts/what-is-kubedb/overview/

- CRDをつかって宣言的にDBを作成できる
- 一回限りのバックアップor定期的バックアップを、S3やGCSのようなクラウドストレージサービスに保存が可能
- バックアップからリストアできたり、DBの複製が可能
- Prometheusと連携可能
- 削除済みDBを追跡していて、以前のスナップショットをコマンド一発で削除可能
- kubectlと同じような操作感で、CLIを使ってDBを操作/管理することが可能


### サポートしているミドルウェア

- PostgreSQL
- Elasticsearch
- MySQL
- MongoDB
- Memcached
- Redis


### 機能

ミドルウェアによってサポートされる機能は若干違いますが、大まかな機能としては以下。

- StatefulSet/Service/Storage/Secret/Snapshot 周りをまるっと面倒をみてくれる
- クラスタリング
- レプリケーション
- インスタントバックアップ/スケジュールバックアップ
- スナップショット/(sqlファイル等の)スクリプトを元にDBを作成
- Prometheus対応
- etc...

特にスナップショット機能は便利そうですね。

# 試してみる

試すKubeDBのバージョンは0.9.0です。
ローカルのminikubeで試し、Kubernetesはv1.10.0です。

## KubeDBのセットアップ

まずはセットアップが必要です。
https://kubedb.com/docs/0.9.0/setup/install/ に従ってやっていきます。
セットアップには、以下の2つを行います。

- 自身のKubernetesクラスタに対してKubeDB Operatorのインストール
- 自身のPCにKubeDB CLIのインストール



#### KubeDB Operatorのインストール

ScriptとHelmの2種類がインストール方法として選べますが、ScriptでやったらこけたのでHelmでやりました。
https://kubedb.com/docs/0.9.0/setup/install/#install-kubedb-operator

Helmのインストールは[こちら](https://github.com/helm/helm)から。

#### KubeDB CLIのインストール

https://kubedb.com/docs/0.9.0/setup/install/#install-kubedb-cli

## MySQL DBを作成する

https://kubedb.com/docs/0.9.0/guides/mysql/quickstart/quickstart/ を元にやっていく。

#### 事前準備(phpMyAdminのインストール)

まず、DBに接続するためのphpMyAdminをKubernetes上に作成する。(DB接続確認のためなので別にphpMyAdminじゃなくてもいい)

phpMyAdminも、作成するMySQLも `demo` ネームスペース上で作成する。

```
$ kubectl create ns demo
namespace "demo" created
```

```
$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0/docs/examples/mysql/quickstart/demo-1.yaml
deployment "myadmin" created
service "myadmin" created

# しばらくするとRunningになるので待つ
$  kubectl create -f $ kubectl get pods -n demo --watch
NAME                       READY     STATUS              RESTARTS   AGE
myadmin-575b7dcbb7-5xpsr   0/1       ContainerCreating   0          7s
myadmin-575b7dcbb7-5xpsr   1/1       Running   0         19s

$ ~/ws/sandbox/kubedb% kubectl get service -n demo
NAME      TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
myadmin   LoadBalancer   10.106.84.64   <pending>     80:30242/TCP   33s
```

```
$ minikube service myadmin -n demo --url
http://192.168.99.108:30242
```

上記で表示された、`http://192.168.99.108:30242`をおもむろにブラウザに打ち込むとphpMyAdminの画面が表示される。

#### MySQL DBの作成

インストールできるMySQL Versionを確認します。ここで何も出力されない場合、KubeDBのインストールが正常にできていないということなので、 https://kubedb.com/docs/0.9.0/setup/install/ をやってください。

```
$ kubectl get mysqlversions
NAME      AGE
5         7s
5-v1      7s
5.7       7s
5.7-v1    7s
8         7s
8-v1      7s
8.0       7s
8.0-v1    7s
```

まず作成するMySQL DBの定義ファイルを見てみます

```yaml
$ curl https://raw.githubusercontent.com/kubedb/cli/0.9.0/docs/examples/mysql/quickstart/demo-2.yaml
apiVersion: kubedb.com/v1alpha1
kind: MySQL
metadata:
  name: mysql-quickstart
  namespace: demo
spec:
  version: "8.0-v1"
  storageType: Durable
  storage:
    storageClassName: "standard"
    accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 50Mi
  terminationPolicy: DoNotTerminate
```

MySQLバージョン、storageの指定、terminationPolicyの指定がされているのがわかりますね。シンプルでわかりやすいです。
さて、いよいよDBを作成します。
注意点としては、`kubectl`コマンドではなく`kubedb`コマンドを使う点です。

```
$ kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0/docs/examples/mysql/quickstart/demo-2.yaml
mysql.kubedb.com/mysql-quickstart created
```

しばらくすると、`kubedb describe mysql mysql-quickstart -n demo `の結果の`Events:`欄が以下のようになります。

```yaml
$ kubedb describe mysql mysql-quickstart -n demo
Name:               mysql-quickstart
Namespace:          demo
CreationTimestamp:  Sat, 22 Dec 2018 00:50:07 +0900
Labels:             <none>
Annotations:        <none>
Replicas:           1  total
Status:             Running
  StorageType:      Durable
Volume:
  StorageClass:  standard
  Capacity:      50Mi
  Access Modes:  RWO

StatefulSet:
  Name:               mysql-quickstart
  CreationTimestamp:  Sat, 22 Dec 2018 00:50:09 +0900
  Labels:               kubedb.com/kind=MySQL
                        kubedb.com/name=mysql-quickstart
  Annotations:        <none>
  Replicas:           824642137324 desired | 1 total
  Pods Status:        1 Running / 0 Waiting / 0 Succeeded / 0 Failed

Service:
  Name:         mysql-quickstart
  Labels:         kubedb.com/kind=MySQL
                  kubedb.com/name=mysql-quickstart
  Annotations:  <none>
  Type:         ClusterIP
  IP:           10.111.203.108
  Port:         db  3306/TCP
  TargetPort:   db/TCP
  Endpoints:    172.17.0.10:3306

Database Secret:
  Name:         mysql-quickstart-auth
  Labels:         kubedb.com/kind=MySQL
                  kubedb.com/name=mysql-quickstart
  Annotations:  <none>

Type:  Opaque

Data
====
  password:  16 bytes
  username:  4 bytes

No Snapshots.

Events:
  Type    Reason      Age   From             Message
  ----    ------      ----  ----             -------
  Normal  Successful  4m    KubeDB operator  Successfully created Service
  Normal  Successful  3m    KubeDB operator  Successfully created StatefulSet
  Normal  Successful  3m    KubeDB operator  Successfully created MySQL
  Normal  Successful  3m    KubeDB operator  Successfully created appbinding
  Normal  Successful  2m    KubeDB operator  Successfully patched StatefulSet
  Normal  Successful  2m    KubeDB operator  Successfully patched MySQL
```

もろもろのリソースが作成されているのがわかりますね。

```
$ kubectl get statefulset -n demo
NAME               AGE
mysql-quickstart   3m

$ kubectl get pvc -n demo
NAME                      STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
data-mysql-quickstart-0   Bound     pvc-187689b7-0538-11e9-bfb3-080027921b19   50Mi       RWO            standard       3m

$ kubectl get pv -n demo
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                          STORAGECLASS   REASON    AGE
pvc-187689b7-0538-11e9-bfb3-080027921b19   50Mi       RWO            Delete           Bound     demo/data-mysql-quickstart-0   standard                 4m

$ kubectl get service -n demo
NAME               TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
kubedb             ClusterIP      None             <none>        <none>         4m
myadmin            LoadBalancer   10.102.17.211    <pending>     80:32144/TCP   5m
mysql-quickstart   ClusterIP      10.111.203.108   <none>        3306/TCP       4m
```

```
$ kubedb get mysql mysql-quickstart -n demo -o yaml
apiVersion: kubedb.com/v1alpha1
kind: MySQL
metadata:
  clusterName: ""
  creationTimestamp: "2018-12-21T15:50:07Z"
  finalizers:
  - kubedb.com
  generation: 1
  name: mysql-quickstart
  namespace: demo
  resourceVersion: "1201"
  selfLink: /apis/kubedb.com/v1alpha1/namespaces/demo/mysqls/mysql-quickstart
  uid: 175df6cf-0538-11e9-bfb3-080027921b19
spec:
  databaseSecret:
    secretName: mysql-quickstart-auth
  podTemplate:
    controller: {}
    metadata: {}
    spec:
      resources: {}
  replicas: 1
  serviceTemplate:
    metadata: {}
    spec: {}
  storage:
    accessModes:
    - ReadWriteOnce
    dataSource: null
    resources:
      requests:
        storage: 50Mi
    storageClassName: standard
  storageType: Durable
  terminationPolicy: DoNotTerminate
  updateStrategy:
    type: RollingUpdate
  version: 8.0-v1
status:
  observedGeneration: 1$4210395375389091791
  phase: Running
```

上記のようにstatus.phaseがRunningになっていたら作成成功です。

次にDBに接続してみます。

```
% kubectl get pods mysql-quickstart-0 -n demo -o yaml | grep podIP
  podIP: 172.17.0.10
$ kubectl get secrets -n demo mysql-quickstart-auth -o jsonpath='{.data.\username}' | base64 -D
root
$ kubectl get secrets -n demo mysql-quickstart-auth -o jsonpath='{.data.\password}' | base64 -D
hGKfBYMieeuET1kR
```

上記のコマンド結果から、

- MySQL HostIP: 172.17.0.10
- username: root
- password: hGKfBYMieeuET1kR

がわかります。(passwordは作成されるDBごとに違うはず)

これらの情報を先のphpMyAdminに入力するとMySQLにログインできます。
試しにphpMyAdminの画面からDBやテーブルを作ります。

#### DBの復旧を試す

さて、先のMySQL DBの定義ファイルに`terminationPolicy: DoNotTerminate`とありました。
そのため `kubedb delete my mysql-quickstart -n demo`を実行して削除しようとしても削除できないようになっています。
`kubedb edit my mysql-quickstart -n demo`を実行して、
terminationPolicyの`DoNotTerminate`を`Pause`に変更します。
`Pause`はDBを削除する際に、StatefulSetは削除するが、PVCsは削除しないという効果になります。
KubeDBではこの状態を`dormant state`に入るといいます。
Pauseにすると以下のように削除できるようになります。

```
$ kubedb delete my mysql-quickstart -n demo
mysql.kubedb.com "mysql-quickstart" deleted
```

`kubedb get drmn -n demo mysql-quickstart -o yaml`を実行すると下の方にstatus.phaseがPausedになっているのが確認できます。

DBの復旧、つまり`dormant state`からresumeさせるためには、DBを作り直します。

```
kubedb create -f https://raw.githubusercontent.com/kubedb/cli/0.9.0/docs/examples/mysql/quickstart/demo-2.yaml
mysql.kubedb.com/mysql-quickstart created
```

作成されたら、またphpMyAdminからDBに接続するとさっき作ったDBやテーブルが生きているのが確認できると思います。


# 感想

- ストレージ周りをあまり意識しなくて使えるのは便利。
- とはいえ実際にプロダクションでKubernetes上でDBを動かすのは検証と知見が必要そう。
- ローカルや開発環境とかでサクッと使う分にはよさそう。