microk8sのdashboardとmicrok8s-hostpath(PersistentVolume)を直す(Kubernetes v1.14)

毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。

Kubernetesをサーバー1台で動かすには便利なMicroK8sですが、Kubernetes 1.14.6を動かしたときにいろいろエラーではまったので困る人が減るようにここに書いておきます。

# 0. Kubeflow 0.5.1がKubernetes v1.15に対応していない問題

Kubeflow v0.5.1をインストールしようとしたのですが、Kubernetes v1.15 には対応していません。理由は、Ksonnetがv1.15には対応していないからです。Ksonnetはもうメンテナンスされず、Kubernets v1.15に対応する予定もありません。
**※注：Kubeflow 0.6では、Ksonnetの代わりにKustomizeを使います。Kubeflow 0.6は、Kubernetes v1.15にも対応しています。**

こちらの件は、本記事とは関係ないので以下をご覧下さい。
Kubeflow 0.5.1をMicroK8S(Kubernetes v1.14.6)で動かす - Qiita
https://qiita.com/ynott/items/b250373e39938b1d4e7a

# 1. Kubernetesをバージョンダウンする
とりあえず、Kubernetesをv1.14.6にすればよいかと思い、バージョンダウンしてみました。

```bash
$ microk8s.reset
$ sudo snap refresh microk8s --channel=1.14/stable --classic
```

## 1-1. RBACとDNSとdashboardを有効にする

```bash
$ microk8s.enable rbac
$ microk8s.enable dns
$ microk8s.enable dashboard
```

一応、全てのPodが起動しているか確認する

```bash
$ kubectl get pods -A
NAMESPACE     NAME                                              READY   STATUS             RESTARTS   AGE
kube-system   heapster-v1.5.2-5c5498f57c-slz9b                  4/4     Running            0          73s
kube-system   kube-dns-6bfbdd666c-lnztc                         3/3     Running            0          96s
kube-system   kubernetes-dashboard-6fd7f9c494-lr9vl             0/1     CrashLoopBackOff   3          73s
kube-system   monitoring-influxdb-grafana-v4-78777c64c8-skltl   2/2     Running            0          73s
```

dashboardがCrashLoopBackOff....(涙)。

## 2. Dashboardが動いていない問題

DashboardのPodのログを見ると以下のようなエラーが出ていた

```bash
$ kubectl log -n kube-system kubernetes-dashboard-6fd7f9c494-lr9vl
2019/09/11 04:37:02 Storing encryption key in a secret
panic: secrets is forbidden: User "system:serviceaccount:kube-system:kubernetes-dashboard" cannot create resource "secrets" in API group "" in the namespace "kube-system"
```

## 2-1. DashboardのRoleとRoleBindingを設定する

`kubectl get clusterrole -n kube-system`で見るとdashboardのroleが無い..。当然clusterrolebindingも。
`kubernetes-dashboard`のserviceaccountはあった。ググってroleを見つける。

https://github.com/kubernetes/dashboard/issues/2681#issuecomment-405476414
こっちから必要そうなのを抜き出しても良い
https://github.com/ubuntu/microk8s/blob/master/microk8s-resources/actions/dashboard.yaml

```yaml:dashboard-role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: kubernetes-dashboard-minimal-role
  namespace: kube-system
rules:
  # Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret.
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["create"]
  # Allow Dashboard to create 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["create"]
  # Allow Dashboard to get, update and delete Dashboard exclusive secrets.
- apiGroups: [""]
  resources: ["secrets"]
  resourceNames: ["kubernetes-dashboard-key-holder", "kubernetes-dashboard-certs"]
  verbs: ["get", "update", "delete"]
  # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames: ["kubernetes-dashboard-settings"]
  verbs: ["get", "update"]
  # Allow Dashboard to get metrics from heapster.
- apiGroups: [""]
  resources: ["services"]
  resourceNames: ["heapster"]
  verbs: ["proxy"]
- apiGroups: [""]
  resources: ["services/proxy"]
  resourceNames: ["heapster", "http:heapster:", "https:heapster:"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: kubernetes-dashboard-minimal-rolebinding
  namespace: kube-system
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: kubernetes-dashboard-minimal-role
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard
  namespace: kube-system
```

適用する

```
kubectl apply -f dashboard-role.yaml
```

しばらく待つと、Runningになりました。

## 3. storageを有効にする

```bash
$ microk8s.enable storage
Enabling default storage class
deployment.extensions/hostpath-provisioner created
storageclass.storage.k8s.io/microk8s-hostpath unchanged
Storage will be available soon
```

一見普通に動いているように見える

```bash
$ kubectl get pods -A
NAMESPACE     NAME                                              READY   STATUS    RESTARTS   AGE
kube-system   heapster-v1.5.2-5c5498f57c-slz9b                  4/4     Running   0          30m
kube-system   hostpath-provisioner-6d744c4f7c-8hn9k             1/1     Running   0          2m47s
kube-system   kube-dns-6bfbdd666c-lnztc                         3/3     Running   0          31m
kube-system   kubernetes-dashboard-6fd7f9c494-lr9vl             1/1     Running   9          30m
kube-system   monitoring-influxdb-grafana-v4-78777c64c8-skltl   2/2     Running   0          30m
```

## 3-1. hostpath-provisionerが動いていない問題
hostpath-provisioner-6d744c4f7c-8hn9kを見る

```bash
kubectl logs -f pod/hostpath-provisioner-6d744c4f7c-8hn9k -n kube-system
E0911 05:07:23.834527       1 reflector.go:201] github.com/juju-solutions/hostpath-provisioner/vendor/github.com/kubernetes-incubator/external-storage/lib/controller/controller.go:295: Failed to list *v1.PersistentVolume: persistentvolumes is forbidden: User "system:serviceaccount:kube-system:default" cannot list resource "persistentvolumes" in API group "" at the cluster scope
E0911 05:07:23.834720       1 reflector.go:201] github.com/juju-solutions/hostpath-provisioner/vendor/github.com/kubernetes-incubator/external-storage/lib/controller/controller.go:294: Failed to list *v1.PersistentVolumeClaim: persistentvolumeclaims is forbidden: User "system:serviceaccount:kube-system:default" cannot list resource "persistentvolumeclaims" in API group "" at the cluster scope
E0911 05:07:23.835713       1 reflector.go:201] github.com/juju-solutions/hostpath-provisioner/vendor/github.com/kubernetes-incubator/external-storage/lib/controller/controller.go:265: Failed to list *v1.StorageClass: storageclasses.storage.k8s.io is forbidden: User "system:serviceaccount:kube-system:default" cannot list resource "storageclasses" in API group "storage.k8s.io" at the cluster scope
```

あかんがな。。

## 3-2. ServiceAccount、ClusterRole、ClusterRoleBindingを適用する

最新のstorage.yamlは直っているので、
https://raw.githubusercontent.com/ubuntu/microk8s/master/microk8s-resources/actions/storage.yaml
を取ってきて再度kubectl apply -f storage.yamlする。
しかし、そのままでは `$ARCH` と `$SNAP_COMMON` がnullなので置換しておく

```bash
$ wget https://raw.githubusercontent.com/ubuntu/microk8s/master/microk8s-resources/actions/storage.yaml
$ sed -i -e 's|\$ARCH|amd64|g' storage.yaml
$ sed -i -e 's|\$SNAP_COMMON|/var/snap/microk8s/common|g' storage.yaml
```

kubectl applyで適用する

```bash
$ kubectl apply -f storage.yaml
deployment.extensions/hostpath-provisioner configured
storageclass.storage.k8s.io/microk8s-hostpath unchanged
serviceaccount/microk8s-hostpath created
clusterrole.rbac.authorization.k8s.io/microk8s-hostpath unchanged
clusterrolebinding.rbac.authorization.k8s.io/microk8s-hostpath unchanged
```

```
$ kubectl logs -n kube-system hostpath-provisioner-58c4d46947-2f6lh
I0911 05:47:41.651964       1 controller.go:293] Starting provisioner controller ab8727d6-d457-11e9-9d85-ee707c114ee2!
```

動いた。よさそう。

## 4. PVCが動くか確認する

以下のようなPVCを用意する

```yaml:demo-persistent-volume-claim.yml 
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name:  demo-volume-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: microk8s-hostpath
  resources:
    requests:
      storage: 500M
---
```

kubectl applyで適用する

```bash
$ kubectl apply -f demo-persistent-volume-claim.yml
persistentvolumeclaim/demo-volume-claim created
$ kubectl get pvc -A
NAMESPACE   NAME                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE
default     demo-volume-claim   Bound    pvc-f501dd62-d459-11e9-b7a7-000c29ab8f9c   500M       RWO            microk8s-hostpath   6s
```

よさそうなので、削除する

```bash
$ kubectl delete -f demo-persistent-volume-claim.yml
persistentvolumeclaim "demo-volume-claim" deleted
$ kubectl get pvc -A
No resources found.
```