Persistent Volumes のチュートリアルを試す

以下のチュートリアルを試した時のメモ

[Example: Deploying WordPress and MySQL with Persistent Volumes](https://kubernetes.io/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/)

# 環境

+ クラスター作成済み(minikube ではない）
+ kubectl コマンド設定済み

```bash
# バージョン情報
$kubectl version
Client Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.3", GitCommit:"2bba0127d85d5a46ab4b778548be28623b32d0b0", GitTreeState:"clean", BuildDate:"2018-05-28T20:03:09Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"10", GitVersion:"v1.10.3", GitCommit:"2bba0127d85d5a46ab4b778548be28623b32d0b0", GitTreeState:"clean", BuildDate:"2018-05-28T20:13:43Z", GoVersion:"go1.9.3", Compiler:"gc", Platform:"linux/amd64"}

# ノードもクラスターに参加済み
$kubectl get nodes
NAME                                           STATUS    ROLES     AGE       VERSION
ip-192-168-111-32.us-west-2.compute.internal   Ready     <none>    40d       v1.10.3
ip-192-168-150-4.us-west-2.compute.internal    Ready     <none>    40d       v1.10.3
ip-192-168-194-26.us-west-2.compute.internal   Ready     <none>    40d       v1.10.3

```

# やってみる

## Before you begin

この章はクラスターを作っておいて下さいという趣旨の内容がメインなので今回は既に準備済みのためパス

## Create PersistentVolumeClaims and PersistentVolumes

>Many cluster environments have a default StorageClass installed. When a StorageClass is not specified in the PersistentVolumeClaim, the cluster’s default StorageClass is used instead.

ここで StorageClass の話が記載されており PersistentVolumeClaim
において StorageClass が記載されていない場合、デフォルトの StorageClass を利用してプロビジョンされる点が明記されている。
デフォルトの StorageClass を確認する。

```bash
# StorageClass が2つ定義されており、「gp2」がデフォルトとなっている
$kubectl get storageclass
NAME            PROVISIONER             AGE
gp2 (default)   kubernetes.io/aws-ebs   6d
gp2-2           kubernetes.io/aws-ebs   4d
```

自分の環境では既にデフォルトの StorageClass が設定されていることが確認出来たのでこのまま進む。

## Create a Secret for MySQL Password

MySQL パスワードのための[Secrets](https://kubernetes.io/docs/concepts/configuration/secret/)  を作成する。
Secret の詳細は以下に記載あり

```bash
# secret を作成する
$kubectl create secret generic mysql-pass --from-literal=password=YOUR_PASSWORD
secret "mysql-pass" created

# mysql-pass という secret が作成されている点を確認
$kubectl get secrets
NAME                  TYPE                                  DATA      AGE
default-token-9jhrf   kubernetes.io/service-account-token   3         41d
mysql-pass            Opaque                                1         21s

```

## Deploy MySQL


MySQL をデプロイする

```mysql-deployment.yaml 
apiVersion: v1
kind: Service
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress
    tier: mysql
  clusterIP: None
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress-mysql
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

```

+ Service, PersistentVolumeClaim, Deploymentを kind で定義
+ 環境変数で先ほど作成した secret の「MYSQL_ROOT_PASSWORD」を利用
+ PersistentVolumeClaim を定義し、20GB のストレージを要求。また、MySQL では PersistentVolume を「/var/lib/mysql」にマウントする

ではデプロイします。

```bash
# Service, PersistentVolumeClaim, Deploymentを作成
$kubectl create -f https://k8s.io/examples/application/wordpress/mysql-deployment.yaml
service "wordpress-mysql" created
persistentvolumeclaim "mysql-pv-claim" created
deployment.apps "wordpress-mysql" created

# PersistentVolumeClaim の作成を確認
$ kubectl get pvc
NAME             STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pv-claim   Bound     pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c   20Gi       RWO            gp2            17s

# PersistentVolume の作成も確認。CLAIM 列が「mysql-pv-claim」となっている
$kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                    STORAGECLASS   REASON    AGE
pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c   20Gi       RWO            Retain           Bound     default/mysql-pv-claim   gp2                      1m

# デプロイしたので MySQL の Pod の起動も確認
$kubectl get pods
NAME                              READY     STATUS    RESTARTS   AGE
wordpress-mysql-bcc89f687-bjb6g   1/1       Running   0          2m

# descibe コマンドで詳細を見るとボリュームがアタッチされたことが確認出来る。
$kubectl describe pods wordpress-mysql-bcc89f687-bjb6g |less

(一部省略)
Events:
  Type     Reason                  Age              From                                                   Message
  ----     ------                  ----             ----                                                   -------
  Warning  FailedScheduling        6m (x5 over 6m)  default-scheduler                                      pod has unbound PersistentVolumeClaims (repeated 3 times)
  Normal   Scheduled               6m               default-scheduler                                      Successfully assigned wordpress-mysql-bcc89f687-bjb6g to ip-192-168-194-26.us-west-2.compute.internal
  Normal   SuccessfulMountVolume   6m               kubelet, ip-192-168-194-26.us-west-2.compute.internal  MountVolume.SetUp succeeded for volume "default-token-9jhrf"
  Normal   SuccessfulAttachVolume  6m               attachdetach-controller                                AttachVolume.Attach succeeded for volume "pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c"
  Normal   SuccessfulMountVolume   6m               kubelet, ip-192-168-194-26.us-west-2.compute.internal  MountVolume.SetUp succeeded for volume "pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c"
  Normal   Pulled                  6m               kubelet, ip-192-168-194-26.us-west-2.compute.internal  Container image "mysql:5.6" already present on machine
  Normal   Created                 6m               kubelet, ip-192-168-194-26.us-west-2.compute.internal  Created container
  Normal   Started                 6m               kubelet, ip-192-168-194-26.us-west-2.compute.internal  Started container
  
# インスタンスにログインして確認。xvdf が見える
$ lsblk
NAME    MAJ:MIN   RM SIZE RO TYPE MOUNTPOINT
xvda    202:0      0  20G  0 disk
└─xvda1 202:1      0  20G  0 part /
xvdbf   202:14592  0  20G  0 disk /var/lib/kubelet/pods/cfebfda3-897d-11e8-a565-

# dokcer inspect で見ると /varlib/mysql として xvdf がマウントされているのが分かる
$docker inspect 1a25629da4ca |less
(一部省略)
            "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/cfebfda3-897d-11e8-a565-06fc7dc53c2c/volumes/kubernetes.io~aws-ebs/pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c",
                "Destination": "/var/lib/mysql",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },

  
```

良さそうなので次に進む。

## Deploy WordPress

```wordpress-deployment.yaml 
apiVersion: v1
kind: Service
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  ports:
    - port: 80
  selector:
    app: wordpress
    tier: frontend
  type: LoadBalancer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-pv-claim
  labels:
    app: wordpress
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: wordpress
  labels:
    app: wordpress
spec:
  selector:
    matchLabels:
      app: wordpress
      tier: frontend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress
        tier: frontend
    spec:
      containers:
      - image: wordpress:4.8-apache
        name: wordpress
        env:
        - name: WORDPRESS_DB_HOST
          value: wordpress-mysql
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-pass
              key: password
        ports:
        - containerPort: 80
          name: wordpress
        volumeMounts:
        - name: wordpress-persistent-storage
          mountPath: /var/www/html
      volumes:
      - name: wordpress-persistent-storage
        persistentVolumeClaim:
          claimName: wp-pv-claim
```

+ Service, PersistentVolumeClaim, Deploymentを kind で定義
+ PersistentVolumeClaim を定義し、20GB のストレージを要求。また、WordPress では PersistentVolume を「/var/www/html」にマウントする

デプロイする。

```bash
# Service, PersistentVolumeClaim, Deploymentを作成
$kubectl create -f https://k8s.io/examples/application/wordpress/wordpress-deployment.yaml
service "wordpress" created
persistentvolumeclaim "wp-pv-claim" created
deployment.apps "wordpress" created

# wp-pv-claim が増えている
$ kubectl get pvc
NAME             STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mysql-pv-claim   Bound     pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c   20Gi       RWO            gp2            26m
wp-pv-claim      Bound     pvc-6ad87529-8981-11e8-971c-022ca775d168   20Gi       RWO            gp2            29s

# pv も増えている
$kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                    STORAGECLASS   REASON    AGE
pvc-6ad87529-8981-11e8-971c-022ca775d168   20Gi       RWO            Retain           Bound     default/wp-pv-claim      gp2                      4m
pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c   20Gi       RWO            Retain           Bound     default/mysql-pv-claim   gp2                      30m


# service の URL を取得
$ kubectl describe services wordpress
Name:                     wordpress
Namespace:                default
Labels:                   app=wordpress
Annotations:              <none>
Selector:                 app=wordpress,tier=frontend
Type:                     LoadBalancer
IP:                       10.100.124.11
LoadBalancer Ingress:     a6ac6da84898111e8971c022ca775d16-182335252.us-west-2.elb.amazonaws.com
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  30000/TCP
Endpoints:                192.168.191.64:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason                Age   From                Message
  ----    ------                ----  ----                -------
  Normal  EnsuringLoadBalancer  2m    service-controller  Ensuring load balancer
  Normal  EnsuredLoadBalancer   2m    service-controller  Ensured load balancer

```

ブラウザなどで「http://a6ac6da84898111e8971c022ca775d16-182335252.us-west-2.elb.amazonaws.com/」にアクセスすると WordPress の画面が表示されることを確認。

## Cleaning up

検証が終わったので削除する。

```bash
# secret を削除する
$kubectl delete secret mysql-pass
secret "mysql-pass" deleted

# deploymnet と service を削除する -l は Selector (label query)。どちらにも app=wordpress のラベル付がされているので削除できる
$kubectl delete deployment -l app=wordpress
deployment.extensions "wordpress" deleted
deployment.extensions "wordpress-mysql" deleted
$kubectl delete service -l app=wordpress
service "wordpress" deleted
service "wordpress-mysql" deleted

# ラベル付けされた PersistentVolumeClaims も削除
$kubectl delete pvc -l app=wordpress
persistentvolumeclaim "mysql-pv-claim" deleted
persistentvolumeclaim "wp-pv-claim" deleted

# pvc は削除された
$kubectl get pvc
No resources found.
```

ただし、デフォルトに設定した StorageClass において Policy が「Retain」の場合、pvc が削除されても pv が残っている。
これは pv の Policy を変更すれば良い。

[Change the Reclaim Policy of a PersistentVolume](https://kubernetes.io/docs/tasks/administer-cluster/change-pv-reclaim-policy/)

```bash
# POLICY が Retain なので pvc がなくても残っている
$kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                    STORAGECLASS   REASON    AGE
pvc-6ad87529-8981-11e8-971c-022ca775d168   20Gi       RWO            Retain           Released   default/wp-pv-claim      gp2                      11m
pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c   20Gi       RWO            Retain           Released   default/mysql-pv-claim   gp2                      37m

# patch で poilicy を変える
$kubectl patch pv pvc-6ad87529-8981-11e8-971c-022ca775d168 -p '{"spec": {"persistentVolumeReclaimPolicy":"Delete"}}'

persistentvolume "pvc-6ad87529-8981-11e8-971c-022ca775d168" patched


# 既に pvc がないので削除される
$kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                    STORAGECLASS   REASON    AGE
pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c   20Gi       RWO            Retain           Released   default/mysql-pv-claim   gp2                      41m

# 同じように対応
$ kubectl patch pv pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c -p '{"spec": {"persistentVolumeReclaimPolicy":"Delete"}}'

persistentvolume "pvc-cfd92d33-897d-11e8-a565-06fc7dc53c2c" patched

$kubectl get pv
No resources found.
```

おしまい。