CockroachDBとPHPをMinikubeで動かしてみる

[グレンジ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/grenge) 24日目担当の 石川 です．
株式会社グレンジで，サーバサイドエンジニアをしています．

## 概要

`Minikube`上で，`CockroachDB`を構築し`PHP`のプログラムから利用する方法を説明します．
今回作成したサンプルプログラムは，[GitHub][github-sample]上で公開しています．

### CockroachDB

詳しい説明は，[CockroachDB公式サイト][cockroach]をみて頂きたいですが，主な特徴として以下のようなものがあります．

- 自動的にスケーリングする分散データベース
- 分散ACIDトランザクションを利用し一貫性のあるデータベース
- PostgreSQLの構文をサポートしている

微妙に技術やサービスに違いがありますが，`Amazon Web Service`の`Aurora`や`Google Cloud Platform`の`Spanner`などが競合のプロダクトと言えそうです．

## 環境

今回利用した環境は下記のようになっています．

- Minikube
	- v0.31.0
- kubectl
	- Client Version
		- Major:"1", Minor:"10"
	- Server Version
		- Major:"1", Minor:"10"
- helm
	- Client
		- v2.12.0
	- Server
		- v2.12.0
- VirtualBox
	- 5.2.22

### ファイル構成

今回利用するプログラムは，[GitHub][github-sample]上に用意してあります．

```
├── README.md
├── database.sql
├── main.yaml
├── nginx
│   └── image
│       ├── Dockerfile
│       ├── conf.d
│       │   └── myapp.conf
│       └── nginx.conf
├── php
│   └── image
│       ├── Dockerfile
│       ├── app
│       │   ├── composer.json
│       │   ├── composer.lock
│       │   ├── index.php
│       │   ├── phpinfo.php
│       │   └── templates
│       │       └── index.html
│       ├── php-fpm.conf
│       ├── php-fpm.d
│       │   └── www.conf
│       └── php.ini
└── rbac-config.yaml
```


## 準備

`Minikube`や`kubectl`のインストールなどは，去年の記事（[Kubernetesで作るPHPの開発環境][qiita-advent2017]）を参考にして下さい．
ここでは`Helm`の環境構築を説明していきます．

### `Helm`のインストール

今回は，`Helm`を利用して`CockroachDB`の構築を行います．
そこで，まず`Helm`のインストールから始めます．

### `Helm Client`のインストール

環境に応じて`Helm Client`をインストールして下さい．

```
$ brew install kubernetes-helm
```

参考：[INSTALLING THE HELM CLIENT][helm-install-client]

### サービスアカウントの作成

```
$ kubectl create -f rbac-config.yaml                                                                                                                                                   
serviceaccount "tiller" created
clusterrolebinding.rbac.authorization.k8s.io "tiller" created
```

### `Helm`サーバーの起動

```
$ helm init --service-account tiller
```

作成されたものを確認してみます．
※関係ないものは一覧から消してあります．

```
$ kubectl get all --all-namespaces                                                                                                                                           
NAMESPACE     NAME                                        READY     STATUS    RESTARTS   AGE
...
kube-system   pod/tiller-deploy-8586bc5c8b-pwmjc          1/1       Running   0          1m

NAMESPACE     NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
...
kube-system   service/tiller-deploy          ClusterIP   10.109.70.23    <none>        44134/TCP       1m

NAMESPACE     NAME                                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
...
kube-system   deployment.apps/tiller-deploy          1         1         1            1           1m

NAMESPACE     NAME                                              DESIRED   CURRENT   READY     AGE
...
kube-system   replicaset.apps/tiller-deploy-8586bc5c8b          1         1         1         1m
```

## CockroachDBの構築

`CockroachDB`を`Helm`を利用して作成します．

```
$ helm install --name my-release stable/cockroachdb
NAME:   my-release
LAST DEPLOYED: Sat Dec 22 14:27:12 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1beta1/PodDisruptionBudget
NAME                           MIN AVAILABLE  MAX UNAVAILABLE  ALLOWED DISRUPTIONS  AGE
my-release-cockroachdb-budget  N/A            1                0                    0s

==> v1/Service
NAME                           TYPE       CLUSTER-IP     EXTERNAL-IP  PORT(S)             AGE
my-release-cockroachdb-public  ClusterIP  10.108.245.86  <none>       26257/TCP,8080/TCP  0s
my-release-cockroachdb         ClusterIP  None           <none>       26257/TCP,8080/TCP  0s

==> v1beta1/StatefulSet
NAME                    DESIRED  CURRENT  AGE
my-release-cockroachdb  3        3        0s

==> v1/Job
NAME                         COMPLETIONS  DURATION  AGE
my-release-cockroachdb-init  0/1          0s        0s

==> v1/Pod(related)
NAME                               READY  STATUS             RESTARTS  AGE
my-release-cockroachdb-0           0/1    Pending            0         0s
my-release-cockroachdb-1           0/1    Pending            0         0s
my-release-cockroachdb-2           0/1    Pending            0         0s
my-release-cockroachdb-init-4x8vz  0/1    ContainerCreating  0         0s


NOTES:
CockroachDB can be accessed via port 26257 at the
following DNS name from within your cluster:

my-release-public.default.svc.cluster.local

Because CockroachDB supports the PostgreSQL wire protocol, you can connect to
the cluster using any available PostgreSQL client.

For example, you can open up a SQL shell to the cluster by running:

    kubectl run -it --rm cockroach-client \
        --image=cockroachdb/cockroach \
        --restart=Never \
        --command -- ./cockroach sql --insecure --host my-release-cockroachdb-public.default

From there, you can interact with the SQL shell as you would any other SQL shell,
confident that any data you write will be safe and available even if parts of
your cluster fail.

Finally, to open up the CockroachDB admin UI, you can port-forward from your
local machine into one of the instances in the cluster:

    kubectl port-forward my-release-cockroachdb-0 8080

Then you can access the admin UI at http://localhost:8080/ in your web browser.

For more information on using CockroachDB, please see the project's docs at
https://www.cockroachlabs.com/docs/
```

### 作成されたPodの確認

```
$ kubectl get pods
NAME                                READY     STATUS      RESTARTS   AGE
my-release-cockroachdb-0            1/1       Running     0          1m
my-release-cockroachdb-1            1/1       Running     0          1m
my-release-cockroachdb-2            1/1       Running     0          1m
my-release-cockroachdb-init-4x8vz   0/1       Completed   0          1m
```

### 作成されたPersistentVolumeの確認

```
$ kubectl get persistentvolumes
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                                      STORAGECLASS   REASON    AGE
pvc-3c4d6fe4-05aa-11e9-9f3e-080027f1cabf   100Gi      RWO            Delete           Bound      default/datadir-my-release-cockroachdb-0   standard                 14m
pvc-3c585364-05aa-11e9-9f3e-080027f1cabf   100Gi      RWO            Delete           Bound      default/datadir-my-release-cockroachdb-1   standard                 15m
pvc-3c5dc501-05aa-11e9-9f3e-080027f1cabf   100Gi      RWO            Delete           Bound      default/datadir-my-release-cockroachdb-2   standard                 14m
```

## SQLクライアントの起動

```
kubectl run cockroachdb -it --image=cockroachdb/cockroach --rm --restart=Never \
-- sql --insecure --host=my-release-cockroachdb-public
If you don't see a command prompt, try pressing enter.
# Welcome to the cockroach SQL interface.
# All statements must be terminated by a semicolon.
# To exit: CTRL + D.
#
# Client version: CockroachDB CCL v2.1.3 (x86_64-unknown-linux-gnu, built 2018/12/17 19:15:31, go1.10.3)
# Server version: CockroachDB CCL v2.1.2 (x86_64-unknown-linux-gnu, built 2018/12/10 20:15:47, go1.10.3)

warning: server version older than client! proceed with caution; some features may not be available.

# Cluster ID: 8fd7e1c6-dc2f-4a43-aa49-6eb01b35f0c1
#
# Enter \? for a brief introduction.
#
root@my-release-cockroachdb-public:26257/defaultdb>
```

### データベースの作成

```
root@my-release-cockroachdb-public:26257/defaultdb> CREATE DATABASE line;
CREATE DATABASE

Time: 239.555847ms
```

### テーブルの作成

```
root@my-release-cockroachdb-public:26257/defaultdb> CREATE TABLE line.yamanote_line ( 
id INT PRIMARY KEY, 
name STRING
);
CREATE TABLE

Time: 145.19769ms
```

### データの挿入

```
root@my-release-cockroachdb-public:26257/defaultdb> INSERT INTO line.yamanote_line (id, name)                                                                                                                                                   VALUES
(1, '東京'),
(2, '神田'), 
...
(29, '新橋'),
(30, '有楽町');
INSERT 30

Time: 43.602528ms
```

### データの確認

```
root@my-release-cockroachdb-public:26257/defaultdb> SELECT * FROM line.yamanote_line;
  id |       name
+----+------------------+
   1 | 東京
   2 | 神田
...
  29 | 新橋
  30 | 有楽町
(30 rows)

Time: 66.454ms
```

## 管理画面

`CockroachDB`にはデフォルトで管理画面が用意されています．
ここでは`CockroachDB`の管理画面の確認方法を紹介します．

```
$ kubectl port-forward my-release-cockroachdb-0 8080
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
```

上記コマンドでポートフォーワードしてから[http://localhost:8080](http://localhost:8080)にアクセスすると，下記のような画面が見られます．

![Cluster Overview   Cockroach Console.png](https://qiita-image-store.s3.amazonaws.com/0/50190/c3c208e6-478e-1f51-c5d4-8696fa77ed1e.png)

## PHPプログラムからの利用

### `CockroachDB`のuser作成

サンプルプログラムの中では，`maxroach`というユーザーでアクセスします．
そのためのユーザーを以下のように作成します．

```
root@my-release-cockroachdb-public:26257/defaultdb> CREATE USER maxroach;
CREATE USER 1

Time: 84.738954ms

root@my-release-cockroachdb-public:26257/defaultdb> GRANT ALL ON TABLE line.* TO maxroach;
GRANT

Time: 188.129377ms
```

### NginXとPHPのPodの作成

```
$ kubectl create -f main.yaml
service "nginx-service" created
service "php-fpm-service" created
deployment.extensions "nginx" created
deployment.extensions "php-fpm" created
```

```
$ kubectl get pods
NAME                                READY     STATUS      RESTARTS   AGE
cockroachdb                         1/1       Running     0          32m
my-release-cockroachdb-0            1/1       Running     0          44m
my-release-cockroachdb-1            1/1       Running     0          44m
my-release-cockroachdb-2            1/1       Running     0          44m
my-release-cockroachdb-init-4x8vz   0/1       Completed   0          44m
nginx-774db7fc97-mx5kr              1/1       Running     0          5m
php-fpm-6ff8879d5d-26xnj            1/1       Running     0          5m
```

### 確認

`http://192.168.99.100:30001/index.php`にアクセスすると，下記のようなページが表示されます．

注意：IPアドレスが異なっている場合があるので，見られない場合は，`minikube ip`でIPを確認して下さい．


![グレンジ Advent Calendar 2018.png](https://qiita-image-store.s3.amazonaws.com/0/50190/b0c079d1-f2ce-e26c-f9d5-b283289510d5.png)

#### Nodeの削除をシミュレーションする

`StatefulSet`により3つのPodが設定されています．

```
$ kubectl get StatefulSet
NAME                     DESIRED   CURRENT   AGE
my-release-cockroachdb   3         3         9h
```

ここで1つのNode（ここではPod）に障害が発生して削除された場合をシミュレーションしてみます．

```
$ kubectl delete po my-release-cockroachdb-0
pod "my-release-cockroachdb-0" deleted
```

上記を実行した後に，`http://192.168.99.100:30001/index.php`にアクセスしてみると問題なく見ることができます．

## 削除

### NginxとPHPの削除

```
$ kubectl delete -f main.yaml
service "nginx-service" deleted
service "php-fpm-service" deleted
deployment.extensions "nginx" deleted
deployment.extensions "php-fpm" deleted
```

### CockroachDBの削除

```
$ helm delete --purge my-release
release "my-release" deleted
```

## まとめ

今回は`CockroachDB`を`Minikube`でローカルに作成し，PHPのプログラムからデータベースにアクセスするサンプルを作成しました．
`CockroachDB`は，異なるデータセンター間での使用を想定していて，例え一部Nodeで障害が起きてもそのデータを消失することがない正に夢のようなデータベースに見えます．
ただ，実際に利用するにはトランザクションの仕組みや，スケールの仕方，速度など色々と検証しなければならないことが多い気がしますが，プロダクトの性質によっては利用箇所が限られつつも利用できるかもしれません．
今後も注目して行きたいデータベースの１つです．

## 最後に

本当は`ML-Agent`を利用した記事を作成しようと思っていたのですが，自分が作成しようとした記事がすでに上がっていたので，そちらを掲載して終わりにします．
あまりいないとは思いますが，もし楽しみにしていた方がいたら下記も合わせて御覧ください．

[Google Kubernetes EngineでUnity ML-Agentsを動かしてみる(V0.5.0対応)][ml-agents]

[//]:#(参考Start)
## 参考

- [サンプルプログラム][github-sample]
- [Kubernetesで作るPHPの開発環境][qiita-advent2018]
- [yasunoriishikawa/php-advent2018][dockerhub-php]
- [yasunoriishikawa/nginx-advent2018][dockerhub-nginx]
- Helm
	- [Helm公式サイト][helm]
	- [INSTALLING THE HELM CLIENT][helm-install-client]
- CockroachDB
	- [CockroachDB公式サイト][cockroach]
	- [Cockroach Labsが複数のクラウドにまたがるデータベースCockroachDBのマネージドサービスを開始（TechCrunch）][techcrunch-cockroach]
	- [CockroachDB(GitHub)][cockroach-github]
	- [Orchestration with Kubernetes (Insecure)][cockroach-kubernetes]
	- [Build a PHP App with CockroachDB][cockroach-php]
	- [CREATE USER][cockroach-create_user]
	- [GRANT <privileges>][cockroach-grant]
[//]:#(参考End)

[//]:#(RefUrlStart)
[github-sample]: https://github.com/YasunoriISHIKAWA/advent2018
[qiita-advent2018]: https://qiita.com/YasunoriISHIKAWA/items/7abab926c849afcb3a7f
[dockerhub-php]: https://cloud.docker.com/repository/docker/yasunoriishikawa/php-advent2018
[dockerhub-nginx]: https://cloud.docker.com/repository/docker/yasunoriishikawa/nginx-advent2018

[helm]: https://helm.sh
[helm-install-client]: https://docs.helm.sh/using_helm/#installing-the-helm-client

[cockroach]: https://www.cockroachlabs.com/
[techcrunch-cockroach]: https://jp.techcrunch.com/2018/10/31/2018-10-30-cockroach-labs-launches-cockroachdb-as-managed-service/
[cockroach-github]: https://github.com/cockroachdb/cockroach
[cockroach-kubernetes]: https://www.cockroachlabs.com/docs/stable/orchestrate-a-local-cluster-with-kubernetes-insecure.html
[cockroach-php]: https://www.cockroachlabs.com/docs/stable/build-a-php-app-with-cockroachdb.html#insecure
[cockroach-create_user]: https://www.cockroachlabs.com/docs/v2.1/create-user.html#main-content
[cockroach-grant]: https://www.cockroachlabs.com/docs/v2.1/grant.html

[ml-agents]: https://qiita.com/kai_kou/items/3a4d860f8353ff1b3110
[//]:#(RefUrlEnd)