おうちマルチノードk8sクラスタを無償版ESXiを使って構築してみる 

k8sのハンズオン環境が欲しくてクラウド上のマネージドサービスやローカルのシングルノードクラスタ等々を検討した結果
間を取ってハイパーバイザ上で複数ノードを展開してクラスタリングするローカルでマルチノード環境を作ってみようという事になったので
その顛末を備忘録代わりに置いておきます

#サーバスペック

* CPU：Ryzen 1800X
* RAM：64GB
* Storage：3TB HDD, 1TB SSD

#クラスタ構築まで
HVインストール→ゲストOSデプロイ→k8sクラスタ構築の順で説明していきます
##ESXiインストール
ここは手動でインストール
手順については特にハマりポイントもないので割愛します
AMD系のCPUの場合ESXiのバージョンが古いとSMTをサポートしておらずPSODが出て止まったりしますが
6.5.3は特に問題なく、イメージに手を加える事なくそのまま使えます


##ゲストOSデプロイ
OSはFedoraCoreOSを採用しました
いわゆるコンテナ向けOSで、コンテナランタイムやdocker、podman等のツールは含まれていますが
それ以外のパッケージは極力省かれている、一般的なLinuxディストリビューションのミニマムよりミニマルなOSです
インストールの際に一般的な対話型UIを通さず、イグニッションコンフィグというjson形式のファイルを読み込んで初期設定を行います

###OVAテンプレートを使う
今回はFCOSの公式で用意されているvmware向けOVAテンプレートを使用します
vCPUx2, RAM 4GB, Storage 8GBの仮想マシンを作成できます
[fcos download pages](https://getfedora.org/en/coreos/download)

###イグニッションファイルについて
イグニッションファイルはjson形式なのですが
YAML→jsonへの変換を行ってくれるfcctというトランスパイラツールが用意されているので書きやすいYAMLで記述します
[coreos/fcct](https://github.com/coreos/fcct)

```YAML:ignition
variant: fcos
version: 1.3.0
passwd:
  users:
    # Ansible用のユーザ、become使用時の設定簡略化のため昇格権限を与えておきます
    - name: ansUser
      groups:
        - docker
        - sudo
        - wheel
      ssh_authorized_keys:
        - {public key}
    # coreユーザはデフォルトの状態でSSH公開鍵接続が可能な特殊なユーザです
    - name: core
      ssh_authorized_keys:
        - {public key}
storage:
  files:
    # sshd設定の上書きファイル、sshd_config.dはデフォルトで存在するinclude用ディレクトリです
    - path: /etc/ssh/sshd_config.d/30-allow-pubkey-auth.conf
      mode: 0644
      overwrite: true
      contents:
        inline: |-
          PubkeyAuthentication yes
    # 固定アドレス付与のための設定です
    - path: /etc/NetworkManager/system-connections/ens192.nmconnection
      mode: 0600
      overwrite: true
      contents:
        inline: |-
          [connection]
          type=ethernet
          interface-name=ens192

          [ipv4]
          method=manual
          addresses=192.168.xxx.xxx/24
          gateway=192.168.xxx.xxx
          dns=192.168.xxx.xxx
    # CNIプラグインとしてCalicoを使う場合リバースパスフィルタを設定します
    - path: /etc/systctl.d/reverse-path-filter.conf
      mode: 0644
      overwrite: true
      contents:
        inline: |-
          net.ipv4.conf.all.rp_filter=1
systemd:
  # Pythonインストール、Dockerのようなコマンド実行がサポートされていないので一回限りのサービスを登録します
  units:
    - name: install-python.service
      enabled: true
      contents: |-
        [Unit]
        After=network-online.target
        Before=shutdown.target
        ConditionFirstBoot=yes

        [Service]
        User=root
        Type=oneshot
        RemainAfterExit=no
        ExecStart=/usr/bin/rpm-ostree install -r python libselinux-python3

        [Install]
        WantedBy=multi-user.target
        WantedBy=network-online.target
```
ESXiでテンプレートデプロイを使う場合
上述のイグニッションコンフィグはjsonから更にBase64でエンコードして読み込ませる必要があります
文字列が必要以上に肥大化しないよう、今回はローカルWebサーバ上にコンフィグを配置し
デプロイ時に読みに行くようにしました

```YAML:fetch.yml
variant: fcos
version: 1.3.0
ignition:
  config:
    replace:
      source: http://192.168.xxx.xxx/ignition.json
```

##kubesprayでクラスタ構築
[kubespray](https://github.com/kubernetes-sigs/kubespray)
変更する部分はインベントリファイルくらいだと思います
今回はMaster:2, worker:3, CNI:1の構成でクラスタを構築します
etcdのHA構成は奇数台ノードでなければならないためworkerの一台にetcdをインストールします

記述するにあたり、こちらの記事を参考にさせていただきました
[kubespray での kubernetes クラスタ構築メモ](https://qiita.com/suzuyui/items/e7531fe5e1e84c061b23)

```ini:MyInventory.ini
[all]
master-able ansible_host=192.168.xxx.xxx  ip=192.168.xxx.xxx
master-baker ansible_host=192.168.xxx.xxx  ip=192.168.xxx.xxx
worker01 ansible_host=192.168.xxx.xxx  ip=192.168.xxx.xxx
worker02 ansible_host=192.168.xxx.xxx  ip=192.168.xxx.xxx
worker03 ansible_host=192.168.xxx.xxx  ip=192.168.xxx.xxx
calico-main ansible_host=192.168.xxx.xxx  ip=192.168.xxx.xxx

[kube-master]
master-able
master-baker

[etcd]
master-able
master-baker
worker01

[kube-node]
worker01
worker02
worker03

[calico-rr]
calico-main

[rack0]
master-able
master-baker
worker01
worker02
worker03
calico-main

[rack0:vars]
cluster_id="1.0.0.1"

[k8s-cluster:children]
kube-master
kube-node
calico-rr

```

インベントリの変更が終わったらansible-playbookコマンドで構築を開始します

```bash:ansible-playbook
ansible-playbook -i ./inventory/MyInventory.ini ./cluster.yml --private-key .ssh/secret_key_file -u ansUser -b -vvv
```

構築には15分ほどかかりました
最後にmasterノードにログインしてkubectlコマンドで確認してみます

```bush:kubectl
[core@master-able ~]$ sudo kubectl get nodes
NAME           STATUS   ROLES    AGE   VERSION
calico-main    Ready    <none>   3m50s v1.19.6
master-able    Ready    master   5m29s v1.19.6
master-baker   Ready    master   4m59s v1.19.6
worker01       Ready    <none>   3m50s v1.19.6
worker02       Ready    <none>   3m50s v1.19.6
worker03       Ready    <none>   3m50s v1.19.6
```

##おわりに
さしあたりハンズオン環境が構築できました
やや曖昧な部分をそのまま駆け抜けてきたので、構築までの手順をもっとブラッシュアップさせていこうと思います