kubeadm で構築した Kubernetes に Rancher をデプロイ

# はじめに
一時期 Kubernetes のマルチクラスタ管理ツールである Rancher について記事を投稿していました。
もう２年前になるんですね・・・

> 2018/12/26：[Rancher の取り扱い説明書](https://qiita.com/t_ume/items/5ee3074a2ae173f1ed30)
> 2019/05/29：[Rancher on k3os](https://qiita.com/t_ume/items/2fde5ebeee404b8c281c)
> 2020/03/02：[To Deploy k8s on WindowsServer with Rancher](https://qiita.com/t_ume/items/d077dbb923ac1ad572fd)

今回は前回 ```kubeadm``` で構築した Kubernetes に Rancher をデプロイしていきます。
新しくなってインタフェースなども変わっているため、動作確認で WebUI も合わせて確認していきます。

# 環境情報

OS：Ubuntu 18.04.5 LTS
containerd：1.4.3
kubeadm：v1.19.7
Kubernetes：v1.19.7
kubectl：v1.19.7
helm：3.5.2
Ansible：2.9.17

|Role|hostname|IP Address|
|:---|:---|:---|
|ReverseProxy|rp01|192.168.10.51|
|ControlPlane|cp01<br>cp02<br>cp03|192.168.10.61<br>192.168.10.62<br>192.168.10.63|
|Node|nd01<br>nd02|192.168.10.71<br>192.168.10.72|

※ ```rp01``` はリバプロ 兼 開発ツール（```kubectl```、```helm```）をインストールしています。

# 構築順序
以下の順番で各プロダクトをデプロイしていきます。

1. Kubernetes 構築
2. helm リポジトリ登録
3. cert-manager デプロイ
4. NGINX Ingress Controller デプロイ
5. Rancher デプロイ
6. 動作確認

# Kubernetes 構築
※マネージドな Kubernetes の方はここはスキップです。
前回の記事を参考にクラスタを構築しました。

> [kubeadm / Ansible で Kubernetes HA クラスタ構築ハンズオン](https://qiita.com/t_ume/items/74831283a9eea8098379)

前回の構築との差分は以下のとおりです。

- Kubernetes のバージョンが異なる（v1.20.2 ⇒ v1.19.7）<br>※ v1.20 では構築できなかったため、バージョンを下げています。
- helm の導入
- 各コントロールプレーン、ノードの /etc/hosts に Rancher アクセス用の URL を登録

これに伴い以下の Ansible を変更しています。

```diff:roles/k8s-server/tasks/main.yml
 - name: Install kubeadm, kubelet
   apt:
     pkg:
-    - kubelet
-    - kubeadm
+    - kubelet=1.19.7-00
+    - kubeadm=1.19.7-00
     update_cache: yes
     state: present
+
+- name: Add hosts record for rancher
+  blockinfile:
+    path: /etc/hosts
+    block: |
+      192.168.10.51 www.rancher.internal
+    insertafter: EOF
```

```diff:roles/k8s-client/tasks/main.yml
 - name: Install kubeadm, kubectl
   apt:
     pkg:
-    - kubectl
+    - kubectl=1.19.7-00
     update_cache: yes
     state: present
+
+- name: download & deploy helm
+  unarchive:
+    src: https://get.helm.sh/helm-v3.5.2-linux-amd64.tar.gz
+    dest: /usr/local/sbin/
+    creates: /usr/local/sbin/helm
+    remote_src: yes
+    owner: root
+    group: root
+    mode: '0755'
+    extra_opts:
+      - --strip-components=1
+      - linux-amd64/helm
```

また、```kubeadm``` の１台目のコントロールプレーンを構築時に以下の引数を追加しています。

```diff:kubeadm
  sudo kubeadm init \
  --control-plane-endpoint "192.168.10.51:6443" \
  --pod-network-cidr 172.16.0.0/16 \
  --apiserver-advertise-address 192.168.10.61 \
+ --kubernetes-version 1.19.7 \
  --upload-certs
```

クラスタ構築後の状態です。

```console
$ kc get node -o wide
NAME   STATUS   ROLES    AGE   VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
cp01   Ready    master   19m   v1.19.7   192.168.10.61   <none>        Ubuntu 18.04.5 LTS   4.15.0-124-generic   containerd://1.4.3
cp02   Ready    master   16m   v1.19.7   192.168.10.62   <none>        Ubuntu 18.04.5 LTS   4.15.0-124-generic   containerd://1.4.3
cp03   Ready    master   16m   v1.19.7   192.168.10.63   <none>        Ubuntu 18.04.5 LTS   4.15.0-124-generic   containerd://1.4.3
nd01   Ready    <none>   13m   v1.19.7   192.168.10.71   <none>        Ubuntu 18.04.5 LTS   4.15.0-124-generic   containerd://1.4.3
nd02   Ready    <none>   13m   v1.19.7   192.168.10.72   <none>        Ubuntu 18.04.5 LTS   4.15.0-124-generic   containerd://1.4.3
```

# リポジトリ登録
各プロダクトは ```helm``` を使ってデプロイします。
デプロイに先駆けて各プロダクトのリポジトリを ```helm``` に登録します。

```console:作業サーバ：rp01
# cert-manager の chart リポジトリ追加
$ helm repo add jetstack https://charts.jetstack.io
"jetstack" has been added to your repositories

# NGINX Ingress Controller の chart リポジトリ追加
$ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories

# Rancher の chart リポジトリ追加
$ helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
"rancher-stable" has been added to your repositories

# 登録したリポジトリから情報を取得
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "ingress-nginx" chart repository
...Successfully got an update from the "rancher-stable" chart repository
...Successfully got an update from the "jetstack" chart repository
Update Complete. ?Happy Helming!?
```

※ ```helm``` コマンドで以下の警告文が出た場合は、```~/.kube/config``` のパーミションを ```600``` などに限定すると解消します。

```
$ helm list
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /home/vagrant/.kube/config
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /home/vagrant/.kube/config
NAME    NAMESPACE       REVISION        UPDATED STATUS  CHART   APP VERSION

$ chmod 600 ~/.kube/config

$ helm list
NAME    NAMESPACE       REVISION        UPDATED STATUS  CHART   APP VERSION
```

# cert-manager デプロイ
Rancher が利用する TLS 証明書の管理として cert-manager をデプロイします。

```console:作業サーバ：rp01
# デプロイ準備として CRD（Custom Resource Definition）をデプロイ
$ kubectl apply --validate=false \
-f https://github.com/jetstack/cert-manager/releases/download/v1.2.0/cert-manager.crds.yaml

customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created

# 個別 namespace の作成
$ kubectl create ns cert-manager
namespace/cert-manager created

# cert-manager のデプロイ
# helm install [ リリース名（識別子） ] [ CHART ] -n [ デプロイ先 namespace ] --version [ Chart のバージョン指定 ]
$ helm install cert-manager jetstack/cert-manager -n cert-manager --version v1.2.0

NAME: cert-manager
LAST DEPLOYED: Sun Feb 14 17:16:26 2021
NAMESPACE: cert-manager
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
cert-manager has been deployed successfully!
・・・

# デプロイ確認
$ kubectl get pods -n cert-manager
NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-85f9bbcd97-87kgt              1/1     Running   0          2m10s
cert-manager-cainjector-74459fcc56-s4kgk   1/1     Running   0          2m10s
cert-manager-webhook-57d97ccc67-t7lts      1/1     Running   0          2m10s
```

# NGINX Ingress Controller デプロイ
Ingress を利用するため、今回は NGINX Ingress Controller をデプロイします。
こちらも helm からインストールしますが、ポートを指定するためにパラメータファイルを用意します。
※ NodePort として http に 32080、https に 32443 を割り当てます。

```yaml:values_ingress.yaml
controller:
  service:
    type: NodePort
    nodePorts:
      http: 32080
      https: 32443
```

作成したパラメータファイルを使ってデプロイをします。

```console:作業サーバ：rp01
# 個別 namespace の作成
$ kubectl create ns ingress-nginx

# NGINX Ingress Controller デプロイ
# helm install [ リリース名（識別子） ] [ CHART ] -n [ デプロイ先 namespace ] -f [ パラメータファイル ]
$ helm install ingress-nginx ingress-nginx/ingress-nginx -n ingress-nginx -f values_ingress.yaml

NAME: ingress-nginx
LAST DEPLOYED: Sun Feb 14 18:09:56 2021
NAMESPACE: ingress-nginx
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
・・・

$ kubectl get po -n ingress-nginx
NAME                                        READY   STATUS    RESTARTS   AGE
ingress-nginx-controller-7fc74cf778-w4nnv   1/1     Running   1          20h
```

コンテナデプロイができたところで今度はリバースプロキシに Node へ振り分けるための設定を追記します。
先程指定した NodePort に対して振り分け設定を行います。
※前回の設定との diff は以下のとおりです。

```diff:/etc/nginx/nginx.conf
 user www-data;
 worker_processes auto;
 pid /run/nginx.pid;
 include /etc/nginx/modules-enabled/*.conf;

 error_log /var/log/nginx/error.log warn;

 events {
    worker_connections  1024;
 }

 stream {
    upstream kubernetes {
       server 192.168.10.61:6443 max_fails=2 fail_timeout=30s;
       server 192.168.10.62:6443 max_fails=2 fail_timeout=30s;
       server 192.168.10.63:6443 max_fails=2 fail_timeout=30s;
    }
    server {
       listen 6443;
       proxy_pass kubernetes;
    }
+   upstream ingress80 {
+      server 192.168.10.71:32080 max_fails=2 fail_timeout=30s;
+      server 192.168.10.72:32080 max_fails=2 fail_timeout=30s;
+   }
+   server {
+      listen 80;
+      proxy_pass ingress80;
+   }
+   upstream ingress443 {
+      server 192.168.10.71:32443 max_fails=2 fail_timeout=30s;
+      server 192.168.10.72:32443 max_fails=2 fail_timeout=30s;
+   }
+   server {
+      listen 443;
+      proxy_pass ingress443;
+   }
 }
```

```systemctl reload nginx``` で nginx に適用しておきます。

# Rancher デプロイ
周辺環境のデプロイが完了したので、Rancher をデプロイしていきます。

```
# 個別 namespace の作成
$ kubectl create ns cattle-system

# Rancher デプロイ（アクセスする際の URL を今回は指定）
# helm install [ リリース名（識別子） ] [ CHART ] -n [ デプロイ先 namespace ] --set [ 変数指定（key=value） ]
$ helm install rancher rancher-stable/rancher -n cattle-system --set hostname=www.rancher.internal
NAME: rancher
LAST DEPLOYED: Sun Feb 14 18:27:08 2021
NAMESPACE: cattle-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Rancher Server has been installed.
・・・
Browse to https://www.rancher.internal

Happy Containering!

# デプロイ状況を確認
$ kubectl -n cattle-system rollout status deploy/rancher
deployment "rancher" successfully rolled out

# デプロイしたオブジェクトの確認
$ kubectl -n cattle-system get deploy rancher
NAME      READY   UP-TO-DATE   AVAILABLE   AGE
rancher   3/3     3            3           11m
```

※ helm で指定できるパラメータは以下のコマンドで yaml ファイルとしてエクスポートできます。

```console
# helm inspect values [ CHART ]
$ helm inspect values rancher-stable/rancher > values.yml
```

# 動作確認
Rancher がデプロイできたので画面アクセスして動作確認していきます。
今回はクライアント PC の hosts（ ```C:\Windows\System32\drivers\etc\hosts``` ）に以下を登録しました。

```
192.168.10.51 https://www.rancher.internal
```

これで ``` https://www.rancher.internal ``` にアクセスして確認します。

最初に Welcome 画面で管理者のパスワードを変更します。
また、デフォルトビューを選択（マルチクラスタ、またはローカルのクラスタ用のビュー）して、「Continue」で次に進みます。

![01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/e9645e8d-ea8a-34b0-6e25-4760e1077099.jpeg)

各ノードから Rancher にアクセスする際の URL を指定します。このまま「Save URL」で進みます。

![02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/5e9795cd-6c82-99a3-e46e-159917900efb.jpeg)

ログイン完了し、ダッシュボード画面が表示されました。Controller や Scheduler のエラーが出ていますがインポート時の仕様？みたいです。※ Deprecated な ```kubectl get cs``` から取得しているため？
> https://forums.rancher.com/t/kubectl-get-componentstatus-fails-for-scheduler-and-controller-manager/15801
> https://stackoverflow.com/questions/63136175/kubectl-get-componentstatus-shows-unhealthy

![03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/e63a365e-7016-cbd0-6f15-ac79a5662d80.jpeg)

上記画面から右上の「Cluster Explorer」をクリックすると、クラスタ毎の管理画面に移動します。最近はこっちの WebUI が主流？みたいです。私的には上記画面の方が馴染み深かったので、ちょっと慣れないです・・・

![04.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/78311960-c0f5-94c0-0553-f51c05a99aaa.jpeg)

ノード一覧の画面はこんな感じです。

![05.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/e4984dfc-0fee-40aa-0d14-0afe5bdf2023.jpeg)

以下は昔カタログと呼ばれていた画面です。helm レポジトリの登録や画面からデプロイできるのは変わらず便利そうです。

![06.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/36072ff7-ffff-62ac-58e8-8b6076d107f6.jpeg)

こちらはデプロイしたアプリの一覧です。helm コマンドから実行したアプリも管理されているみたいですね。cert-manager や NGINX Ingress Controller 、Rancher がデプロイされていることを確認できました。

![07.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317159/4bc214c4-bcb4-8821-af5b-48f344e875e3.jpeg)

# まとめ
Rancher を Kubernetes 上に構築したのは初めてでしたが、```helm``` を使って簡単にデプロイできたのは楽でした。
helm のパラメータファイルを利用することで、カスタマイズの幅は広がるかと思います。

今回参考にしたインストールドキュメントは以下です。
> [Install/Upgrade Rancher on a Kubernetes Cluster](https://rancher.com/docs/rancher/v2.x/en/installation/install-rancher-on-k8s/)

また、Rancher については少し古いですが、以下の書籍も是非。私は買ってまだ読んでないですが・・・
> [RancherによるKubernetes活用完全ガイド](https://www.amazon.co.jp/Rancher%E3%81%AB%E3%82%88%E3%82%8BKubernetes%E6%B4%BB%E7%94%A8%E5%AE%8C%E5%85%A8%E3%82%AC%E3%82%A4%E3%83%89-ThinkIT-Books-%E5%B8%82%E5%B7%9D%E8%B1%8A-ebook/dp/B07VCRBSRW/r)

2020/10 になりますが、執筆者の I 氏が上記書籍を解説している動画もあるので合わせてどうぞ。
> [インフラエンジニアBooks](https://infra-eng-books.connpass.com/)
> [インフラエンジニアBooks#02 市川豊氏と読む「RancherによるK8s活用完全ガイド」](https://www.youtube.com/watch?v=swX40tevth8)