rancher1.6_on_kubernetes1.7でPVをazurefileにしてみた話

dockerまわり全く使いこなせていない初心者です。とりあえずできたとこだけ書く体で失礼します。
最近Azureのまわしものみたいになってるのでなんとなく言い訳しますが個人的には他意は特に無くて使えれば何でもいいです。


###目的と経緯など

勉強がてらやってみろということだったのでrancherでgitlabとか動かすくらいで済む予定だったのですがprometheusって言われたのでそれもやろうとして、
prometheusの立て方や連携方法は色々あってrancherのカタログからポチでもgrafanaと連携されてるものが上がってくるのですがalertmanagerの機能が必要な割にそのカタログには組み込まれておらず、カタログの自作とカスタマイズの方法が若干やってみた程度では全く成功せず解決方法がさっぱりわからなかったしそのカタログは設定ファイル自体のコンテナビルド的な私には理解不能(ビルドしないで設定更新したくないです？どうして？)な構成だったのでkubernetesでhelmつかうのがhelmのstableのポリシー見た感じよさそうかもしれないと思った次第。
で、AzureFileを永続ボリュームにするのは成功したんですが、
helmクライアントがhttpsのnginx-proxyの裏のtillerサーバに到達できない？
みたいでhelmでkubernetesクラスタを操ることができない状況だったけど
[RancherのGUIのkubectl用CLIの画面から`helm init;helm repo update`とかするとhelm実行できた](http://rancher.com/docs/rancher/v1.6/en/kubernetes/addons/)
すぐセッションきれてリロードしないと繋げないけど毎回initしなけいけないわけじゃないからいいかな　←イマココ
（[ELBの人はリスナープロトコルをHTTPSからSSLにしたらアッサリ解決とか書いてた](https://github.com/kubernetes/helm/issues/2419)）

~~たすけてドラえも～ん！！といえる相手がこれに関してはあんまり周りにいないので追ってふつうにyamlのマニフェスト書くしかないのかrancherで動かすのやめて自前ビルド(単純に難しそう)かマネージドサービスが楽そうかなー（たぶん勉強がてらなのでマネージドは許されない気がする）とか思ってるとこです。~~

それはともかくkubnernetesのPVとPVCをAzureFileでやってみてる人少なそうだったので書いときます。
ちなみにRancherからはnfsはできるけどcifs・samba(azurefile)はストレージドライバとして使えるようには1.6時点でなってない模様（検索してたら[PR](https://github.com/rancher/storage/pull/53)は見かけた気がする）

###kubernetesの用語備忘録など

WEB+DBのvol99が良いということで運よく会社にあったのを拝借してちょっと読んでみたその解説によるととりあえず座学っぽいとこは以下のような感じでした。（あとkubernetesは綴りが長いせいかk8sて書いてる人おおいのでそれが略称の模様）

* Podは同一ノードで動くコンテナのセットでPodごとにIPが振られる。apiとwebやリバプロとwebを一緒にしとく
* Labelをはっとくと検索して同じラベルのリソースがグルーピングされてそれに同じ処理をするとかできる
* Serviceは複数のpodがぶら下がった外部からのアクセスを制御するエンドポイントでいくつかの種類がある
　（ClusterIPはDNS、NodePortはポートマッピング、LoadbalancerはIngress、ExternalNameはCNAMEレコード、HeadlessはStatefulsetにつかう内部DNSっぽいのという理解）
* IngressはpodへのアクセスをHTTPプロキシするやつでTLSもいけるらしい
* Volumeはデータの格納領域で幾つか種類があるが複数ノードからのアクセスを可能にしておく永続的なものが推奨される
　（emptyDirVolumeはホストの領域をつかうがPodが削除されると消える、hostPathVolumeはホストのマウントパスを明示的に指定するがホストが消えると消えてしまう
* PersistentVolume(PV)を作っといてPersistentVolumeClaim(PVC)でPVリソースからどれだけ利用するかを指定する。（そうするとデータの永続化ができる、PVとPVCは1対1の紐づけのみ）
　動的なプロビジョニングの場合にはStorageClassという仕組みを利用してプロビジョニングをする。StorageClass名をPVC側で指定するとよきようにマッピングしてくれる
* ConfigMap/Secretで設定をコンテナイメージから切り離す。それをつかうにはVolumeとしてマウントするか環境変数に設定するなどの方法がある
* podそのものは自分の状態を管理することができないので各コントローラというリソースを用いる
* ReplicaSetは水平スケーリング用のコントローラで複数の同一の内容のpodをいくつつくるかを管理する
* DeploymentはイメージをBGデプロイしてデフォルト1世代のこしといて切り戻しができるコントローラ
* HorizontalPodAutoscalingによる自動水平スケーリングではCPU負荷(2017/7月時点)の増減により処理を行う
* DaemonSetは各ノードに1コンテナずつ配置するコントローラでFluentdやPrometheusのNodeExporterなどが例としてある
* Statefulsetはその名の通りデータ持ってるやつでIDが順繰り振られてその順に起動するので0をマスタにするDBコンテナに適してる。削除後に同じIDのpodが起動するし全く同じボリュームが割り当たる
* Job/CronJobはタスクの実行を行うものでPodからの成功通知を待って終了するのとparallismの数だけpodが作成される


###AzureFileを準備

ストレージアカウントを作りアカウント名とKeyを控えてAzureFileのコンテナを作成する必要があります。
ポータルからポチポチでもazコマンドでもググるといいしポータルのUIはわかりやすいのでググらなくてもどうとでもなると思うので準備が必要という点だけ書いておきます。

###Secretを登録する

先にストレージアカウント情報をSecretに登録しておきます。

```
# mkdir /home/docker/k8s;cd /home/docker/k8s
# echo -n 'ストレージアカウントのKEY' > azstorage-secret.txt
# kubectl create secret generic azstorage-secrets \
  --from-file=azurestorageaccountkey=azstorage-secret.txt \
  --from-literal=azurestorageaccountname=${mystrageaccount}
```
なぜかbase64で文字列を暗号化してからyamlに書いてそれを登録という方法だとうまくいかなかったんですが、たぶんストレージアカウント名も暗号化しないといけなかったんだなとできたほうの出力を見て思いました（確かめてはいない）

createするときに`--namespace monitor`とかつけとくとnamespace分けられるのでCLIやダッシュボードの表示が見やすくなったりなどしますが指定しないとdefaultで後からだとsecretから登録しなおす感じでした。リポジトリ単位で分けるとよいとか見た気がします。
[Kubernetes の各リソースに対するメモ - Qiita](https://qiita.com/apstndb/items/e75c40975183b8aabba6)

登録されたことを確認

```
# kubectl get secrets azstorage-secrets -o yaml
apiVersion: v1
data:
  azurestorageaccountkey: ***********L3c9PQ==
  azurestorageaccountname: *****hdGlvbg==
kind: Secret
metadata:
  creationTimestamp: 2017-12-08T07:09:02Z
  name: azstorage-secrets
  namespace: default
  resourceVersion: "8462" 
  selfLink: /api/v1/namespaces/default/secrets/azstorage-secrets
  uid: abd5529c-dbe6-11e7-9680-02de519233a2
type: Opaque
```

k8sのダッシュボードを見てみるとシークレットが増えてました。

[azureのストレージアカウント情報登録した瞬間にvolumeに指定すればPodからマウントできるっぽいようにPodのyaml書いてる人いました。](http://tech.tanaka733.net/entry/azure-file-storage-as-a-kubernetes-volume)
[wordpressの例とかもあった](https://kvaes.wordpress.com/2017/05/19/azure-container-service-using-the-azure-file-storage-as-a-persistent-kubernetes-volume/)

[ここにあるストレージの一覧](https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes)をみるとReadWriteManyにAzureFileが入ってて複数ノードからの読み書きができるという話。
AzureFileのノード上でのmountコマンドの戻り値みたときrsize=1048576,wsize=1048576とかだった。


###PersistentVolume(PV)をつくる

永続ボリュームを以下のようにAzureFileで作ってみます。[nfsのやり方はここらへんで見かけました](https://qiita.com/cvusk/items/e79cf0efb2454a195f07#kubernetes-persistentvolume%E3%81%AE%E8%A8%AD%E5%AE%9A)

```
# vi azfile-pv.yaml
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    name: pv001
spec:
  capacity:
    storage: 1024Gi
  accessModes:
    - ReadWriteMany
  azureFile:
    secretName: azstorage-secrets
    shareName: k8s-data
    readOnly: false

# kubectl create -f azfile-pv.yaml
persistentvolume "pv001" created
```

ハイフン3つで区切ってPVCも一緒に書いて作っても大丈夫です。
注意点としてaccessModesはPVとPVCでの両方で一致してないとPVC作ったときにステータスがPendingのままで使えないしダッシュボードにも表示されないです。
[複数ボリュームがある場合にPVにlabelをつけとくとPVCからselector指定して明示的にできる模様](https://qiita.com/MahoTakara/items/2c34aa7d66766e880041)
label/selectorはこのほかにもルーティング等いろいろ使う模様。
PVとPVCは1対1の紐づけのみ。

###PersistentVolumeClaim(PVC)をつくる

永続ボリューム要求は用語のところで書いてるとおり、永続ボリュームに対するリクエスト。これをPodのyamlにvolumesとして指定します。

```
# vi azfile-pvc.yml 
# cat azfile-pvc.yml 
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: azfileclaim01
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 8Gi
 selector:
    matchLabels:
      name: pv001

# kubectl create -f azfile-pvc.yml 
persistentvolumeclaim "azfileclaim01" created
```

###storageclassをつくってみる

なんかダッシュボードにワーニングが出てたので一応作ってみた次第（PV作る時には指定してもしなくても大丈夫でPVCに指定すると自動で割り当てたいときにいいらしい）

```
# vi azstorageclass.yml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: azurefile
provisioner: kubernetes.io/azure-file
parameters:
  skuName: Standard_LRS
  location: japanwest
  storageAccount: mystorageaccount

  # kubectl create -f azstorageclass.yml
  storageclass "azurefile" created
```

[pvやpvcに書くときは`storageClassName: azurefile`という行を追加する感じの模様](https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/)

###CLI、ダッシュボードから確認

```
# kubectl get persistentvolumeclaims
NAME            STATUS    VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
azfileclaim01   Bound     pv001     1Ti        RWX                           6s

# kubectl get persistentvolume
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                   STORAGECLASS   REASON    AGE
nfs       20Gi       RWX            Retain           Bound     default/nfsclaim01                               1d
pv001     1Ti        RWX            Retain           Bound     default/azfileclaim01                            7d
```

###PVCを使いPodを立ててみて更新データがAuzreFileからみられることを確認する

```
# vi /opt/rc-azfile.yml 
kind: Pod
apiVersion: v1
metadata:
  name: rc-azfile-test
  labels:
    app: nginx
spec:
  volumes:
    - name: azurefile
      persistentVolumeClaim:
          claimName: azfileclaim01
  containers:
    - name: nginx
      image: nginx
      ports:
        - name: nginx
          containerPort: 80
      volumeMounts:
            - name: azurefile
              mountPath: "/usr/share/nginx/html"
# kubectl create -f /opt/rc-azfile.yml
pod "rc-azfile-test" created
# kubectl get pods
NAME                        READY     STATUS    RESTARTS   AGE
rc-azfile-test              1/1       Running   0          45m
```

k8sかrancherダッシュボードまたはdockerコマンドでもなんでもいいのでコンテナに入ってdfでもみてみるとなんかマウントできてるのが見えます

```
root@rc-azfile-test:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@rc-azfile-test:/# df -h
Filesystem                                      Size  Used Avail Use% Mounted on
none                                             30G  4.0G   26G  14% /
tmpfs                                           1.7G     0  1.7G   0% /dev
tmpfs                                           1.7G     0  1.7G   0% /sys/fs/cgroup
/dev/sda1                                        30G  4.0G   26G  14% /etc/hosts
shm                                              64M     0   64M   0% /dev/shm
//mystorageaccount.file.core.windows.net/k8s-data  1.0T   64K  1.0T   1% /usr/share/nginx/html　←★これ
tmpfs                                           1.7G   12K  1.7G   1% /run/secrets/kubernetes.io/serviceaccount
```

ここでなんかファイル作るとAzureFileのポータル画面からもダウンロード可能に。
サブディレクトリ切ったほうが良かったですね。


###helmが便利そうだなと思った件

失敗してるのが超残念なんですがhelmのstableはわりと便利そうだなあと思った次第。
・データ永続化の方法が提供される
・アプリケーションのアップグレードがサポートされる
・アプリケーション設定のカスタマイズを許可する
・セキュアなデフォルト設定を持つ
・Kubernetesのアルファ機能を利用しない
ということだそうでつかいやすそう。

[helmの入れ方はこちら](https://github.com/kubernetes/helm/blob/master/docs/install.md)


~~もしhelmが使えてたら以下のようなコマンドを実行してみたかった。一時的にhttpsやめて切り分けてみてもいいかな。~~
以下例。アクセスモードが一致するPV,PVCが用意されてないとexporterとかは上がってくるけどPrometheusとalertmanagerのサーバが起動しないので一致するアクセスモードのPersistentVolumeとPersistentVolumeClaimを用意しないといけなかったりします。[prometheus側のPVCはエラー検索したらどうやらファイル共有がロックの仕組み的にNGっぽいIssueを見かけました。](https://github.com/prometheus/prometheus/issues/1600)なのでhost_path的な何かでやるしかなさげ。helm statusでも稼働してる数とかみると状況はわかるけどkubernetes側のダッシュボードで赤くなってるしエラーメッセージがわかりやすいです。あと個人的にはrancherの方が過去ログを追いやすい気がしました。

```
> helm install stable/prometheus --name monitor --namespace monitor  --set \
>  persistence.enabled=true,alertmanager.persistentVolume.existingClaim=alertmanager-claim-rwm,alertmanager.persistentVolume.accessModes=ReadWriteMany,server.persistentVolume.existingClaim=prom-pv-claim,server.persistentVolume.accessModes=ReadWriteOnce
```

ちなみにhostpathのpvとpvcは以下のような感じでよいようでした。hostpathはコンテナからホストにマウントされるのでホストがお陀仏するまでは大丈夫で１ホストからしかアクセスできないやつですね。昨今はホストも使い捨てだし形あるものは必ず壊れるのでデータのバックアップは要りそうですね。

```
# cat prom-hostpath-pv*
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: prom-pv-claim
  namespace: monitor
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: prom-hostpath-pv
  labels:
    type: local
  namespace: monitor
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /var/lib/prometheus
    # type: DirectoryOrCreate

# kubectl create -f prom-hostpath-pv.yml 
# kubectl create -f prom-hostpath-pvc.yml 
# kubectl --namespace=monitor get pv,pvc
NAME                  CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                            STORAGECLASS   REASON    AGE
pv/prom-hostpath-pv   5Gi        RWO            Retain           Bound     monitor/prom-pv-claim                                     35m

NAME                         STATUS    VOLUME             CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc/prom-pv-claim            Bound     prom-hostpath-pv   5Gi        RWO                           35m
```


RancherのGUIのkubectl用CLI以外のノードから実行だと以下のようなエラーでるのは変わらないですね。解決方法をご存知の方がいらしたらおしえてください。ぜひ！

```
# helm version --debug
[debug] Created tunnel using local port: '38139'

[debug] SERVER: "127.0.0.1:38139"

Client: &version.Version{SemVer:"v2.7.2", GitCommit:"8478fb4fc723885b155c924d1c8c410b7a9444e6", GitTreeState:"clean"}
E1215 22:59:36.901993   31974 portforward.go:271] error creating error stream for port 38139 -> 44134: Timeout occured
[debug] rpc error: code = Internal desc = transport is closing
Error: cannot connect to Tiller

# kubectl -n kube-system get po
NAME                                    READY     STATUS    RESTARTS   AGE
heapster-76b8cd7b5-7qvbl                1/1       Running   0          7d
kube-dns-5d7b4487c9-4wzsn               3/3       Running   0          7d
kubernetes-dashboard-5ffb9c9bb7-9jczl   1/1       Running   0          7d
monitoring-grafana-997796fcf-wpwtr      1/1       Running   0          7d
monitoring-influxdb-56fdcd96b-k85vt     1/1       Running   0          7d
tiller-deploy-79c88c5d98-n7qgm          1/1       Running   0          7d
```

なお、PrometheusとAlertmanagerカタログから起動とサービス追加して若干触ったのと調べてた限りgrafanaでの表示はとてもきれいだったのと既成メトリクスとexporterが多いとこはいいし通知まとめられるのいいけど設定がyamlのみでGUIがないようだと監視オペレータ連携運用が事実上難しくそこそこ工数かかるエンジニアの人手がいる運用になりそうな予感しかないです。

###rancherの環境をkubernetesにして起動した場合の気づいたことなど

・アクセスコントロールの設定をしてる場合、rancher側でログイン認証しないとログアウト状態でkubernetesのダッシュボードを操作することができない（認証連携されてた）
・初回起動時に環境をkubernetesに切り替えてからホスト登録しないとだめっぽい。
　既存のクラスタにrancherのkubernetesの環境からノードついかするとkubernetesのダッシュボードにも表示される
・kubernetesクラスタのmasterとかnodeとかそういうロールについては起動しただけだと定義されてないっぽい
・rancher2.0はpreviewで認証機能が無効なので真面目に使うとすると手前のnginx的なリバースプロキシに何か認証機能を持たせるとかしないとだめそう。AzureADだとnginx自前ビルドでsub_filterモジュール有効化してどうこうしないとという地雷臭がする感じ。
・rancherのほうがUIが見やすいきがするがkubernetesのダッシュボードでもrancherでできることは大体できる気がする（別に両方使いこなせてないですがコンテナにつなぐとかログ見るくらいのことはどっちもできる）
・kubernetesのダッシュボードは手動更新がほとんどできなくて主にkubectlとyamlで色々やる体でrancherは画面からポチポチしてあとでyaml確認して取っとくみたいな違いがあるかなあと思いました。先か後かは別としてどっちもまあ見える化に配慮しているのかなと思いました。

###参考
・kubenetes関連
[Azureコンテナサービス：Azureファイルストレージを永続的な（kubernetes）ボリュームとして使用する - Karim Vaes](https://kvaes.wordpress.com/2017/05/19/azure-container-service-using-the-azure-file-storage-as-a-persistent-kubernetes-volume/)
[Docker と Kubernetes を使って『変化に強いインフラ』を作る | Wantedly Engineer Blog](https://www.wantedly.com/companies/wantedly/post_articles/46089)
[RancherでKubernetesでHelmでDockerでJenkinsを動かす方法 - Qiita](https://qiita.com/cvusk/items/e79cf0efb2454a195f07)
[Configure a Pod to Use a PersistentVolume for Storage | Kubernetes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/)
[永続的なボリューム| Kubernetes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/)
[kubernetes入門コンテンツまとめ - Qiita](https://qiita.com/mihirat/items/73d299611c7ed03f5ca8)
[第2回 Kubernetesの歩き方](https://ladicle.github.io/post/k8s2/)
[Kubernetesに入門したい // Speaker Deck](https://speakerdeck.com/hihihiroro/kubernetesniru-men-sitai)
[Kubernetesクラスタ環境を構築してDashboardで見える化を試してみた - Taste of Tech Topics](http://acro-engineer.hatenablog.com/entry/2016/10/04/120000)
[トラブルシューティング  |  Kubernetes Engine ドキュメント  |  Google Cloud Platform](https://cloud.google.com/kubernetes-engine/docs/troubleshooting?hl=ja)
[https://qiita.com/apstndb/items/9d13230c666db80e74d0](https://qiita.com/apstndb/items/9d13230c666db80e74d0)
[Kubernetes ときどき Serverless -- cndjp第1回勉強会](https://www.slideshare.net/charlier-shoe/kubernetes-serverless-cndjp1)
[Kubernetes in プロダクション！ -- cndjp第2回](https://www.slideshare.net/charlier-shoe/kubernetes-in-cndjp2)
[【IBM Cloud k8s検証メモ】二つ以上の永続ストレージを識別してマウント - Qiita](https://qiita.com/MahoTakara/items/2c34aa7d66766e880041)


・helm関連
[Kubernetes: パッケージマネージャHelm - Qiita](https://qiita.com/tkusumi/items/12857780d8c8463f9b9c)
[Helm を使用して Azure Kubernetes にコンテナーをデプロイする | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/container-service/kubernetes/container-service-kubernetes-helm)
[helm/install.md at master · kubernetes/helm](https://github.com/kubernetes/helm/blob/master/docs/install.md)
[charts/stable/prometheus at master・kubernetes / charts](https://github.com/kubernetes/charts/tree/master/stable/prometheus)
[Ladicle/kubernetes-helm-jp-doc: Kubernetes helm Japanese document](https://github.com/Ladicle/kubernetes-helm-jp-doc/)
[Kubernetes Addons in Rancher](http://rancher.com/docs/rancher/v1.6/en/kubernetes/addons/)

・prometheus関連
[prometheus で雑に始めるサーバ監視 - Qiita](https://qiita.com/nise_nabe/items/b9d70833d50cdccba547)
[Alertmanagerについて書いてみる - wyukawa’s blog](http://d.hatena.ne.jp/wyukawa/20160729/1469779169)
[Exporters and integrations | Prometheus](https://prometheus.io/docs/instrumenting/exporters/)
[Monitoring at AbemaTV - SSSSLIDE](http://sssslide.com/speakerdeck.com/nghialv/monitoring-at-abematv)
[AbemaTVにPrometheusというモニタリングシステムを導入した話](https://developers.cyberagent.co.jp/blog/archives/3814/)