AzureのVMにKubernetes v1.24をセルフインストールする

GW中にやってしまいたかったが、Kubernetes v1.24がリリースされていたのでそれのセルフインストールを試しておこうと。
いつもはAWSを使うが今回はAzureを使用。
コンテナエンジンはcontainerd、ネットワークドライバはCalicoで、kubeadmを使ってインストール。

AzureならAKSを使うのが、まあ普通かもしれない。HAではないらしいがCP(Master)がタダなのは素晴らしい。とはいえ特定ベンダのクラウド依存度を下げたいからKubernetes使うんじゃないの？という論も立たなくは無いだろう。であればIaaSのVMの上にKubernetesクラスター自作である。

# 環境
Control Planeノードを１台。Workerノードを２台。
VMのサイズはすべてD2as_v4(vCPU:2、RAM:8GiB)、OSはUbutnu Server 20.04 LTS -Gen2、ネットワークはSSH(22)だけ開いて作成。

Kubernetesは「Masterノード」という用語を廃止しようとしており、「Control Planeノード」に置き換え中。
v1.24から、新規構築クラスターのCPノード（今までのMasterノード）に「node-role.kubernetes.io/control-plane:NoSchedule」というtaintが追加されており、インフラ的に高インパクトかも。そもそもホスト名も、これからは「master1,2」とかじゃなく「cp1,2」とかいう時代である。

Dockershimサポート廃止も合わさり、v1.24は割と頭痛いバージョン。

# CPノードを作る
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/

まずは、containerd、kubeadmを入れるまで。

```bash
azureuser@cp:~$ sudo -i
# cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF
# sudo modprobe overlay
# sudo modprobe br_netfilter
# cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF
# sudo sysctl --system
# wget https://github.com/containerd/containerd/releases/download/v1.6.4/containerd-1.6.4-linux-amd64.tar.gz
# tar Cxzvf /usr/local containerd-1.6.4-linux-amd64.tar.gz
# wget https://github.com/containerd/containerd/raw/main/containerd.service
# cp containerd.service /etc/systemd/system/containerd.service
# systemctl enable --now containerd
# wget https://github.com/opencontainers/runc/releases/download/v1.1.1/runc.amd64
# install -m 755 runc.amd64 /usr/local/sbin/runc
# wget https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz
# mkdir -p /opt/cni/bin
# tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.1.1.tgz
# mkdir /etc/containerd
# containerd config default > /etc/containerd/config.toml
# sed -i /etc/containerd/config.toml -e 's/SystemdCgroup = false/SystemdCgroup = true/'
# sudo systemctl restart containerd
# sudo apt-get update
# sudo apt-get install -y apt-transport-https ca-certificates curl
# sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
# echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
# sudo apt-get update
# sudo apt-get install -y kubelet kubeadm kubectl
# sudo apt-mark hold kubelet kubeadm kubectl
```

kubeadm initでクラスターを作るが、ネットワークドライバをCalicoにするのでCIDRは192.168.0.0/16。

```bash
# kubeadm init --pod-network-cidr=192.168.0.0/16
（出力結果）
...
Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.0.0.6:6443 --token 5bwjtd.w2c2zfagwrewgal6 \
        --discovery-token-ca-cert-hash sha256:a863b41e43c6fe8e8033193b927721d4099d9abf82f3cc9d5ffdf4a68e2bae04
```

「kubeadm join～」のテキストはこの後のWorkerノードの追加に使うので手元にとっておく。

Calicoを導入するが、Tigera operatorを使ってインストールするとtaintのcontrol-planeを追加できないので使えない。中途半端なサポートだとOperatorというアプローチは良くない。仕方がないので、Calicoのyamlファイルをダウンロードして修正して導入する。

https://projectcalico.docs.tigera.io/getting-started/kubernetes/self-managed-onprem/onpremises

CIDRが192.168.0.0/16なのはデフォルトのまま変更しないで良いのだが、AzureがIP-in-IPに対応していないのでそれを無効にして、VXLANを使用する。

Switching from IP-in-IP to VXLAN
https://projectcalico.docs.tigera.io/getting-started/kubernetes/installation/config-options

あと、CPノードにcontrol-planeというtaintが追加されているので、そのtolerationを追加する。

```bash
# curl https://projectcalico.docs.tigera.io/manifests/calico.yaml -O
# vi calico.yaml
（4307行目あたり）
            - name: CALICO_IPV4POOL_IPIP
              value: "Never"    # → "Always"から"Never"に修正。
（4310行目あたり）
            - name: CALICO_IPV4POOL_VXLAN
              value: "Always"   # → "Never"から"Always"に修正。
（4489行目あたり）
        - key: node-role.kubernetes.io/master
          effect: NoSchedule
        - key: node-role.kubernetes.io/control-plane    # → 行追加
          effect: NoSchedule                            # → 行追加
```

このファイル編集の機械化はちょっと辛いので、自動化したいなら編集済みのファイルをどこかに取っておくのかな。。

ファイル修正後、Calicoをインストール。

```bash
# export KUBECONFIG=/etc/kubernetes/admin.conf
# kubectl create -f calico.yaml
```

しばらくするとCalicoと、CoreDNSが起動してくる。

```bash
root@cp:~# kubectl get pod -A
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
kube-system   calico-kube-controllers-75848c57cf-rbv4n   1/1     Running   0          35s
kube-system   calico-node-6s5ng                          1/1     Running   0          35s
kube-system   coredns-6d4b75cb6d-cmnjr                   1/1     Running   0          27m
kube-system   coredns-6d4b75cb6d-hzdh5                   1/1     Running   0          27m
kube-system   etcd-cp                                    1/1     Running   0          27m
kube-system   kube-apiserver-cp                          1/1     Running   0          27m
kube-system   kube-controller-manager-cp                 1/1     Running   0          27m
kube-system   kube-proxy-5l4h9                           1/1     Running   0          27m
kube-system   kube-scheduler-cp                          1/1     Running   0          27m
```


# Wrokerノードを追加する

kubeadmをインストールまでの実行するコマンドはCPノードと一緒。割愛。
kubeadm joinでクラスターに追加する。

```bash
# kubeadm join 10.0.0.6:6443 --token 5bwjtd.w2c2zfagwrewgal6 \
        --discovery-token-ca-cert-hash sha256:a863b41e43c6fe8e8033193b927721d4099d9abf82f3cc9d5ffdf4a68e2bae04
```

２台のWorkerノードを追加してしばらく後、CPノードでノードを確認する。

```bash
root@cp:~# kubectl get node
NAME   STATUS   ROLES           AGE     VERSION
cp     Ready    control-plane   57m     v1.24.0
wk1    Ready    <none>          7m50s   v1.24.0
wk2    Ready    <none>          63s     v1.24.0
```

# Ingressコントローラーを追加する
とりあえず、コミュニティ提供版のNginx Ingressコントローラーで。
https://kubernetes.github.io/ingress-nginx/deploy/

```bash
# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.2.0/deploy/static/provider/cloud/deploy.yaml
```

IngressコントローラーをhostPortで公開する。

```bash
# kubectl edit deploy -n ingress-nginx ingress-nginx-controller
（26行目ら辺）
   replicas: 2    # → 1から2に修正
（92行目ら辺）
        ports:
        - containerPort: 80
          name: http
          protocol: TCP
          hostPort: 80    # → 行追加
```

ingress-nginxをクラスターのデフォルトIngressコントローラーにする。

```bash
$ kubectl edit IngressClass nginx
（8行目ら辺）
   annotations:
     ingressclass.kubernetes.io/is-default-class: "true"    # → 行追加
```

wk1、wk2でIngressコントローラーが動作しているのを確認。

```bash
root@cp:~# kubectl get pod -n ingress-nginx -o wide
NAME                                        READY   STATUS      RESTARTS   AGE     IP              NODE   NOMINATED NODE   READINESS GATES
ingress-nginx-admission-create-wclgf        0/1     Completed   0          6m41s   192.168.175.1   wk1    <none>           <none>
ingress-nginx-admission-patch-zxgp7         0/1     Completed   1          6m41s   192.168.49.65   wk2    <none>           <none>
ingress-nginx-controller-6997c4694b-84shm   1/1     Running     0          3m1s    192.168.49.66   wk2    <none>           <none>
ingress-nginx-controller-6997c4694b-r9cf2   1/1     Running     0          30s     192.168.175.3   wk1    <none>           <none>
```

Ingressの動作確認。

```bash
$ kubectl run httpd --image=httpd
$ kubectl expose pod/httpd --port=80
$ cat > httpd-ingress.yaml << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: httpd
spec:
  rules:
    - http:
        paths:
        - pathType: Prefix
          path: /
          backend:
            service:
              name: httpd
              port:
                number: 80
EOF
$ kubectl create -f httpd-ingress.yaml
```

Azureでwk1とwk2の仮想マシンに80/tcpの通信を許可し、WebブラウザでそれらのPublic IPにアクセス。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146381/99ad09c3-213e-ecc6-878a-b399b2e1387d.png)

良いんじゃないか。

一応、AzureのApplication Gateway経由でのIngressコントローラーアクセスも構成してみるが、WorkerノードのPublic IPをバックエンドプールに追加するのはOK。ただ、既存マシンのPrivate IPアドレス向けにリクエスト転送するやり方がわからない。。なんかちょっと癖を感じるというか、慣れないな。