CockroachDBのデプロイ

さてではPOSTメソッドの実装に向けて、ストレージをデプロイします。
データストアとして何が適切であるかはワークロードの特性やチームの技術スタックにより変わるので特に決まりごとはありません。
あるチームはmongoを使用したり、あるいは「このアクセスの仕方なら」とetcdを使用したりなど選定の理由はさまざまです。
僕が所属するチームでもいくつかのストレージを使い分けていますが、単純なWebアプリの場合は[CockroachDB](https://www.cockroachlabs.com/)を選択する場合が多いです。

分散型のSQLデータベースでPostgresと互換性があり、癖がなく使いやすいです。

今回もこのCockroachDBにデータを保存していきたいと思います。

## CockroachDBのデプロイ

CockroachDBをデプロイするためのKubernetesマニフェストファイルをみていきましょう。
概ね[こちら](https://www.cockroachlabs.com/docs/stable/orchestrate-a-local-cluster-with-kubernetes-insecure.html#manual)に掲載されている手順と同様です。

```yaml:kubernetes/cockroach-statefulset.yaml
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: cockroachdb-budget
  namespace: qiita
  labels:
    app: cockroachdb
spec:
  selector:
    matchLabels:
      app: cockroachdb
  maxUnavailable: 1
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: cockroachdb
  namespace: qiita
  labels:
    app: cockroachdb
spec:
  serviceName: "cockroachdb"
  replicas: 3
  selector:
    matchLabels:
      app: cockroachdb
  template:
    metadata:
      labels:
        app: cockroachdb
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - cockroachdb
              topologyKey: kubernetes.io/hostname
      containers:
      - name: cockroachdb
        image: cockroachdb/cockroach:v2.1.4
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 26257
          name: grpc
        - containerPort: 8080
          name: http
        livenessProbe:
          httpGet:
            path: "/health"
            port: http
            scheme: HTTP
          initialDelaySeconds: 30
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: "/health?ready=1"
            port: http
            scheme: HTTP
          initialDelaySeconds: 60
          failureThreshold: 2
        volumeMounts:
        - name: datadir
          mountPath: /cockroach/cockroach-data
        env:
        - name: COCKROACH_CHANNEL
          value: kubernetes-insecure
        command:
        - "/bin/bash"
        - "-ecx"
        # The use of qualified `hostname -f` is crucial:
        # Other nodes aren't able to look up the unqualified hostname.
        - "exec /cockroach/cockroach start --logtostderr --insecure --advertise-host $(hostname -f) --http-addr 0.0.0.0 --join cockroachdb-0.cockroachdb,cockroachdb-1.cockroachdb,cockroachdb-2.cockroachdb --cache 25% --max-sql-memory 25%"
      # No pre-stop hook is required, a SIGTERM plus some time is all that's
      # needed for graceful shutdown of a node.
      terminationGracePeriodSeconds: 60
      volumes:
      - name: datadir
        persistentVolumeClaim:
          claimName: datadir
  podManagementPolicy: Parallel
  updateStrategy:
    type: RollingUpdate
  volumeClaimTemplates:
  - metadata:
      name: datadir
    spec:
      accessModes:
      - "ReadWriteOnce"
      resources:
        requests:
          storage: 100Gi
```

```yaml:cockroach-service.yaml
apiVersion: v1
kind: Service
metadata:
  # This service is meant to be used by clients of the database. It exposes a ClusterIP that will
  # automatically load balance connections to the different database pods.
  name: cockroachdb-proxy
  namespace: qiita
  labels:
    app: cockroachdb
spec:
  ports:
  # The main port, served by gRPC, serves Postgres-flavor SQL, internode
  # traffic and the cli.
  - port: 26257
    targetPort: 26257
    name: grpc
  # The secondary port serves the UI as well as health and debug endpoints.
  - port: 8000
    targetPort: 8000
    name: http
  selector:
    app: cockroachdb
---
apiVersion: v1
kind: Service
metadata:
  # This service only exists to create DNS entries for each pod in the stateful
  # set such that they can resolve each other's IP addresses. It does not
  # create a load-balanced ClusterIP and should not be used directly by clients
  # in most circumstances.
  name: cockroachdb
  namespace: qiita
  labels:
    app: cockroachdb
  annotations:
    # Enable automatic monitoring of all instances when Prometheus is running in the cluster.
    prometheus.io/scrape: "true"
    prometheus.io/path: "_status/vars"
    prometheus.io/port: "8000"
spec:
  ports:
  - port: 26257
    targetPort: 26257
    name: grpc
  - port: 8000
    targetPort: 8000
    name: http
  # We want all pods in the StatefulSet to have their addresses published for
  # the sake of the other CockroachDB pods even before they're ready, since they
  # have to be able to talk to each other in order to become ready.
  publishNotReadyAddresses: true
  clusterIP: None
  selector:
    app: cockroachdb
```

実際にはsecureモードで立ち上げるため、認証局のデプロイや証明書更新用のサイドカーを乗せる工夫などがありますがここでは割愛します。

ではデプロイしてみましょう。

```sh
$ kubectl apply -f kubernetes/cockroach-statefulset.yaml
poddisruptionbudget.policy/cockroachdb-budget created
statefulset.apps/cockroachdb created
$ kubectl apply -f kubernetes/cockroach-service.yaml
service/cockroachdb-proxy created
service/cockroachdb created
```

```sh
$ kubectl -n qiita get pods
NAME                                          READY   STATUS    RESTARTS   AGE
cockroachdb-0                                 0/1     Running   0          87s
cockroachdb-1                                 0/1     Running   0          87s
cockroachdb-2                                 0/1     Running   0          86s
qiita-advent-calendar-2019-7c885c5698-hwkts   1/1     Running   1          5d21h

$ kubectl -n qiita get statefulsets.apps
NAME          READY   AGE
cockroachdb   0/3     2m52s

$ kubectl -n qiita get service
NAME                         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)              AGE
cockroachdb                  ClusterIP   None            <none>        26257/TCP,8000/TCP   15m
cockroachdb-proxy            ClusterIP   10.111.34.61    <none>        26257/TCP,8000/TCP   15m
qiita-advent-calendar-2019   ClusterIP   10.108.124.86   <none>        8080/TCP             5d21h

$ kubectl -n qiita get poddisruptionbudgets.policy
NAME                 MIN AVAILABLE   MAX UNAVAILABLE   ALLOWED DISRUPTIONS   AGE
cockroachdb-budget   N/A             1                 0                     3m17s
```

ひとまずリソースの作成は完了です。

## Jobの実行

次にCockroachクラスタの初期設定のためのJobを流します。

```yaml:cockroach-init-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: cockroach-init
  namespace: qiita
  labels:
    app: cockroachdb
spec:
  template:
    spec:
      containers:
      - name: cluster-init
        image: cockroachdb/cockroach:v2.1.4
        imagePullPolicy: IfNotPresent
        command:
        - "/cockroach/cockroach"
        - "init"
        - "--insecure"
        - "--host=cockroachdb-0.cockroachdb"
      restartPolicy: OnFailure
```

実行。

```sh
$ kubectl apply -f kubernetes/cockroach-init-job.yaml
job.batch/cockroach-init created
```

```sh
$ kubectl -n qiita get jobs.batch
NAME             COMPLETIONS   DURATION   AGE
cockroach-init   1/1           3s         8s

$ kubectl -n qiita get pod
NAME                                          READY   STATUS      RESTARTS   AGE
cockroach-init-5zmpg                          0/1     Completed   0          15s
cockroachdb-0                                 1/1     Running     0          8m26s
cockroachdb-1                                 1/1     Running     0          8m26s
cockroachdb-2                                 1/1     Running     0          8m25s
qiita-advent-calendar-2019-7c885c5698-hwkts   1/1     Running     1          5d21h
```


Podが`Ready`になっているのが確認できました。

## DBとユーザーの作成

......と思ったのですが、いまいち筆のノリがよくないので一旦区切って明日みていくことにしたいと思います。笑