OCI（OracleのIaaS）上のKubernetesでストレージの動的プロビジョニング

これはなに
----------
OCI（OracleのIaaS）上のKubernetesで、StorageClassを使ったストレージの動的プロビジョニングを行う方法を書きます。<br>
ストレージには、OCIのストレージサービスを利用します。


前提条件
--------
OCI用のTerraformベースのKubernetesインストーラーを使って、Kubernetesクラスターを構築しているものとします。
当該Kubernetesクラスターの構築手順は、[こちらのエントリー](https://qiita.com/hhiroshell/items/a5107a5ed136867602ca)を参照ください。


全体の流れ
==========
StorageClassを使ったストレージの動的プロビジョニングを行うには、（たぶんOCIに限らず、一般的に）以下の準備作業が必要です。

1. 準備作業
    - 1-1. Volume Provisionerをデプロイする
    - 1-2. 1-1.を呼び出すStorage Classを作成する
    - 1-3. Volume Provisionerを実行するための権限周りの設定を行う
2. DeploymentやStatefulSetのmanifestで、StorageClassを使うように記述する


このエントリーの前提条件に該当する環境では、1-2. 1-3.は既に実施済みとなっているため、準備作業は1-1.だけやればOKです。<br>
Terraformベースのインストーラーを使わずに自力で構築するなどした場合、すべての準備作業が必要になります。この場合の手順は、[OCI Volume ProvisionerのMREADME](https://github.com/oracle/oci-volume-provisioner/blob/master/README.md)を参照してください。


手順
====
それではやってみます。


準備作業
--------
Volume Provisionerをクラスターにデプロイします。

[OCI Volume Provisionerのリポジトリ](https://github.com/oracle/oci-volume-provisioner)のReleaseに、必要なmanifestが公開されていますので、これを使って>デプロイします。
このエントリーの執筆時点では0.4.1が最新なので、ここではこれを使います。

    > kubectl apply -f https://github.com/oracle/oci-volume-provisioner/releases/download/0.4.1/oci-volume-provisioner.yaml

バージョンを変えたい場合は、0.4.1の部分を適宜置き換えてください。


StorageClassを使うようにmanifestを書く
--------------------------------------
Volume Provisionerを呼び出すStorageClassは、"oci"という名前で作成済みなので、これを使うようにmanifestを書いていきます。

    > kubectl get storageclass
    NAME            PROVISIONER      AGE
    oci (default)   oracle.com/oci   4h
    oci-ext3        oracle.com/oci   4h

### PersistentVolumeClaimを使う場合
PersistentVolumeClaimでStorageClassを指定し、そのPersistentVolumeClaimを使うようにDeploymentを記述します。

以下は、[Terraform Kubernetes Installerにあるサンプル](https://github.com/oracle/terraform-kubernetes-installer/blob/master/docs/example-deployments.md)での記述例です。

まず、PersistentVolumeClaim。

```yaml:nginx-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nginx-volume
spec:
  storageClassName: "oci"
  selector:
    matchLabels:
      oci-availability-domain: "US-ASHBURN-AD-1"
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 50Gi
```

``storageClassName``に"oci"を指定しています。ストレージ容量は、OCIでは50Gが下限のため、これ以上の値にする必要があります。<br>
``selector``以下は、ストレージをプロビジョニングするAvailability Domain（AWSでいうAvailability Zone）を指定しています。


続いてDeployment本体。

```yaml:nginx-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  template:
    metadata:
      labels:
        name: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
          volumeMounts:
            - name: nginx-storage
              mountPath: "/usr/share/nginx/html"
      volumes:
      - name: nginx-storage
        persistentVolumeClaim:
          claimName: nginx-volume
```

``volume``のところで、persistetVolumeClaimとして上に書いたものを指定します。

### VolumeClaimTemplatesを使う場合
StatefulSetのmanifestでは、``VolumeClaimTemplates``配下にVolumeの情報を書きます。この場合、annotationを使ってStorageClassを指定します。<br>
このannotationは省略することもでき、他にVolumeを確保する手段がなければociのProvisionerが使われます。複数の手段が取れる場合にどういった優先順位となるかは、おいおい調査していきます。

以下は、zookeeperをデプロイするStatefulSetの例です。

```yaml:zookeeper.yaml
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: pzoo
  namespace: kafka
spec:
  serviceName: "pzoo"
  replicas: 3
  template:
    metadata:
      labels:
        app: zookeeper
        storage: persistent
    spec:
      containers:
      - name: zookeeper
        --- 中略 ---
        volumeMounts:
        - name: config
          mountPath: /etc/kafka
        - name: data
          mountPath: /var/lib/zookeeper/data
      volumes:
      - name: config
        configMap:
          name: zookeeper-config
  volumeClaimTemplates:
  - metadata:
      name: data
      annotations:
        volume.beta.kubernetes.io/storage-class: "oci"
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 50Gi
```

この場合、PodがデプロイされるAvailability Domainに、ストレージがプロビジョニングされます。


以上、OCI上のKubernetesでストレージの動的プロビジョニングを行う方法でした。