Hyper-Vでkubernetes環境を構築　リソース準備編

Hyper-Vに作成したkubernetes環境([前回記事](https://qiita.com/k5o/items/5e5d2e385da2873aa98f))にはLoadBalancerやIngressなどが用意されていない基本的な環境である。
今回、前回作成したkubernetes環境にLoadBalancerやIngress、DynamicVolumeProvisioningを導入する。

# インストールするリソース
- LoadBalancer: metallb
- Volume: rook/ceph
- Registry: harbor
- ServiceMesh,Ingress: Istio
- DNS: ExternalDNS

# 0. control-planeのtaintを削除してpodがスケジュールされるようにする

ベアメタルのkubernetesだとcontrol-planeのmasterノードにはpodがスケジューリングされないが、
なるべく全ノードのリソースを活用したいためスケジューリングされるように設定を変更する。
設定はtaintという仕組みで行われているので、以下コマンドでtaintを外す。

```
kubectl taint nodes k8s0 node-role.kubernetes.io/control-plane-
```

# 1. Helmのインストール

kubernetes上で複数のpodにより構成されたシステムをデプロイしたいなど、
kubernetesリソースを組み合わせて管理したい場合にはhelmという
パッケージ管理ソフトウェアを使って行うことができる。
helmはリモートレジストリに多数のパッケージがすでに登録されており、
そちらを使うことですぐに自分のkubernetesにシステムをデプロイすることができる。

# 2. Metallbのインストール

kubernetesのpodに外部からアクセスできるようにするためにServiceを通してアクセスすることができる。
Serviceにはいくつか種類があるが、helmで導入するパッケージなどでもよく使われているLoadBalancerを導入する。

ufwを無効にする。
```
ufw disable
```

kube-proxyの設定を変更する。
```
> kubectl edit configmap -n kube-system kube-proxy
strictARP: true
```

公式サイトに従いインストールする。
[Metallb公式](https://metallb.universe.tf/installation/)

```
# helmリポジトリを追加する
helm repo add metallb https://metallb.github.io/metallb
helm install metallb metallb/metallb

# metallb-systemにインストール
kubectl create ns metallb-system
helm install -n metallb-system metallb metallb/metallb -f values.yaml
```

LoadBalancerで使うIPアドレスの範囲を指定する。
以下ファイルでは172.20.0.200-172.20.0.254の範囲でLoadBalancerから
IPアドレスが配布される。

```
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: default
  namespace: metallb-system
spec:
  addresses:
  - 172.20.0.200-172.20.0.254
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: default
  namespace: metallb-system
```

実際に以下コマンドを実行して、LoadBalancerからIPアドレスが配布されることを確認する。
```
# nginxのpodをデプロイしてLoadBalancerで外部に公開する
kubectl run --restart=Never nginx --image=nginx:alpine
kubectl expose pod/nginx --type=LoadBalancer --port=80
```

デプロイが完了すると、以下のようにExternal-IPにIPアドレスが割り振られていることが確認できる。
```
> kubectl get svc
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1       <none>         443/TCP        4d12h
nginx        LoadBalancer   10.97.171.254   172.20.0.200   80:30379/TCP   61s
```

# Rook/Cephをインストールする
kubernetesではpod内にデータを保存しておいて再利用することができない。
それは、podがいつのタイミングで作り直されるか保証されていないし、
pod内のデータは初期化されて前の起動時から引き継がれないためである。
そこで、kubernetesではpodの外部にデータを保存する方法がいくつか提供されている。
外部ストレージ領域をHyper-Vで用意して、これをkubernetesのデータの保存先として活用することを考える。
Rook/Cephを使えば簡単にノードに接続されている外部ストレージをkubernetesのデータ保存に活用することができる。

まず、外部ストレージをHyper-Vで作成してマシンのハードディスクとして設定する。
マシンの設定画面を開き、「SCSIコントローラー」にハードドライブを追加する。
どのマシンで作業を行ってもよく、また複数のノードにハードディスクを追加した場合、
各ハードディスクをまとめてRook/Cephから利用できる。
以下の例では3つのノードすべてにハードディスクが追加されている場合の例である。
データを保存する際に各ノードの障害にどれくらい耐久性があるかを設定するStorageClassに
3つのコピーを作成するように指定しているため(replicated)、最低3ノードが必要となるが、
こちらの値を変えることで必要なノードの数を変更できる。

ハードディスクを用意したら、(Rookの公式)[https://rook.io/]を確認してインストールを行う。

```
# リポジトリを任意のディレクトリにclone
git clone --single-branch --branch v1.13.5 https://github.com/rook/rook.git

# CRDなど必要な定義、設定をデプロイ
cd deploy/examples
kubectl create -f crds.yaml -f common.yaml -f operator.yaml

# インストール
kubectl create -f cluster.yaml
```

これでRook/Cephがkubernetesに導入できたが、kubernetesのpodからデータ保存領域として活用するためには、
StorageClassを定義する必要がある。
以下ファイルをデプロイすることで、「rook-ceph-block」という名前のStorageClassが作成できる。

```
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
  name: replicapool
  namespace: rook-ceph
spec:
  failureDomain: host
  replicated:
    size: 3
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: rook-ceph-block
   annotations:
     storageclass.kubernetes.io/is-default-class: "true"
# Change "rook-ceph" provisioner prefix to match the operator namespace if needed
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
    # clusterID is the namespace where the rook cluster is running
    clusterID: rook-ceph
    # Ceph pool into which the RBD image shall be created
    pool: replicapool

    # (optional) mapOptions is a comma-separated list of map options.
    # For krbd options refer
    # https://docs.ceph.com/docs/master/man/8/rbd/#kernel-rbd-krbd-options
    # For nbd options refer
    # https://docs.ceph.com/docs/master/man/8/rbd-nbd/#options
    # mapOptions: lock_on_read,queue_depth=1024

    # (optional) unmapOptions is a comma-separated list of unmap options.
    # For krbd options refer
    # https://docs.ceph.com/docs/master/man/8/rbd/#kernel-rbd-krbd-options
    # For nbd options refer
    # https://docs.ceph.com/docs/master/man/8/rbd-nbd/#options
    # unmapOptions: force

    # RBD image format. Defaults to "2".
    imageFormat: "2"

    # RBD image features
    # Available for imageFormat: "2". Older releases of CSI RBD
    # support only the `layering` feature. The Linux kernel (KRBD) supports the
    # full complement of features as of 5.4
    # `layering` alone corresponds to Ceph's bitfield value of "2" ;
    # `layering` + `fast-diff` + `object-map` + `deep-flatten` + `exclusive-lock` together
    # correspond to Ceph's OR'd bitfield value of "63". Here we use
    # a symbolic, comma-separated format:
    # For 5.4 or later kernels:
    #imageFeatures: layering,fast-diff,object-map,deep-flatten,exclusive-lock
    # For 5.3 or earlier kernels:
    imageFeatures: layering

    # The secrets contain Ceph admin credentials.
    csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
    csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
    csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
    csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
    csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
    csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph

    # Specify the filesystem type of the volume. If not specified, csi-provisioner
    # will set default as `ext4`. Note that `xfs` is not recommended due to potential deadlock
    # in hyperconverged settings where the volume is mounted on the same node as the osds.
    csi.storage.k8s.io/fstype: ext4

# Delete the rbd volume when a PVC is deleted
reclaimPolicy: Delete

# Optional, if you want to add dynamic resize for PVC.
# For now only ext3, ext4, xfs resize support provided, like in Kubernetes itself.
allowVolumeExpansion: true
```

実際に上記のStorageClassを使ってpodをデプロイしてみる。
公式で用意された以下のファイルをデプロイすることで、mysqlのデータを永続化してpodを使用できる。

```
cd deploy/example
kubectl apply -n rook-ceph -f mysql.yaml
```

# 4. istioのインストール
ServiceMeshをインストール。Ingressも導入。
以下公式を参考にインストール。

(公式サイト)[https://istio.io/latest/docs/setup/getting-started/]

```
curl -L https://istio.io/downloadIstio | sh -
cd istio-1.20.3
```

istioctlコマンドをbashrcに追記
```
export PATH=$PWD/bin:$PATH
```

```
istioctl install --set profile=demo -y
kubectl label namespace default istio-injection=enabled
# sample
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

# kiali
kubectl apply -f samples/addons
kubectl rollout status deployment/kiali -n istio-system

```

# 5. Harborのインストール
```
helm repo add harbor https://helm.goharbor.io
helm show values harbor/harbor > values.yaml
```
value.yamlのingressをnodePortに変更する。
commonNameは適当に設定。
```
helm install -n harbor harbor -f values.yaml harbor/harbor
```
ブラウザからアクセスするとログイン画面がでるので、
admin/Harbor12345でログイン。

containerdでimageをpullできるように/etc/containerd/config.tomlを設定

```
[plugins."io.containerd.grpc.v1.cri".registry.configs]
        [plugins."io.containerd.grpc.v1.cri".registry.configs."172.20.0.101".tls]
          insecure_skip_verify = true
        [plugins."io.containerd.grpc.v1.cri".registry.configs."172.20.0.101".auth]
          username = "admin"
          password = "Harbor12345"

      [plugins."io.containerd.grpc.v1.cri".registry.headers]

      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."172.20.0.101"]
          endpoint = ["http://172.20.0.101"]

```

また、dockerからpushできるようにinseruce_repositoriesにharborを追加する。