ESXi上のCentOS7にKubeadmでKubernetesクラスタを構築する

####「[ESXi上のCentOS8にKubeadmでKubernetesクラスタを構築する](https://qiita.com/yasubehe/items/51a05688d1f66d51531e)」のCentOS7版です

#環境
ESXi7.0上にVM3台作成

- vm
  - k8s-master cpu:2 mem:4GB HDD:30GB IP:192.168.123.160
  - k8s-node1  cpu:2 mem:4GB HDD:30GB IP:192.168.123.161
  - k8s-node2  cpu:2 mem:4GB HDD:30GB IP:192.168.123.162

- OS
  - CentOS7.8.2003 Minimalインストール

- インストールするKubernetesのバージョン
  - 1.18.4

[Installing kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/)によると、インストールするマシンは2GB以上のメモリ、cpu2コア以上が必要とのこと。

#はじめに
「[ESXi上のCentOS8にKubeadmでKubernetesクラスタを構築する](https://qiita.com/yasubehe/items/51a05688d1f66d51531e)」の構築に行き詰っていたとき、CentOS7なら動くだろうと思って試した内容です。
内容は上記記事とほとんど変わりませんが、参考までに手順を記載しておきます。
CenOS7で手っ取り早く環境を構築して動かしたい人向けです。

#手順
1. 各ノードで最新のアップデートを適用する

    ```
    yum update -y
    ```

1. 各ノードのswapをオフにする（ここでは設定のみ。後でノード再起動で反映させる。）
    swapをオフにし、/etc/fstabからswap領域のマウントの記載を削除する。

    ```
    # vi /etc/fstab
      → swapの行をコメントアウト
    ```

1. 各ノードで名前解決ができるようにする
    各ノードの /etc/hosts に以下の値を追加する

    ```
    192.168.123.160 k8s-master
    192.168.123.161 k8s-node1
    192.168.123.162 k8s-node2
    ```

1. 各ノードのMACアドレスと product_uuidが一意であることの確認
    - MACアドレス確認
    
        ```
        # ip link
        ```
    - product_uuid確認
        
        ```
        # cat /sys/class/dmi/id/product_uuid
        ```

1. 各ノードのFirewallの無効化（ここでは自動起動無効化のみ。後でノード再起動で反映させる。）

    ```
    # systemctl disable firewalld
    ```

1. 各ノードのselinuxの無効化（ここでは設定のみ。後でノード再起動で反映させる。）

    ```
    # vi /etc/selinux/config
    →SELINUX=permissive に変更
    ```

1. 各ノードのipv6無効化（ここでは設定のみ。後でノード再起動で反映させる。）

    ```
    # echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf
    # echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf
    ```

1. 各ノードのネットワーク・ブリッジを通過するパケットにiptablesを適用（ここでは設定のみ。後でノード再起動で反映させる。）

    ```
    # cat <<EOF >  /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    EOF
    ```

1. 各ノードのipv4のフォワード設定（ここでは設定のみ。後でノード再起動でまとめて反映させる。）

    ```
    # echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
    ```

1. これまでの設定を反映させるため、全ノードを再起動する

    ```
    # shutdown -r now
    ```

1. 各ノードでコンテナランタイムをインストール
Dockerをインストールします。
インストール手順は「[Install Docker Engine on CentOS](https://docs.docker.com/engine/install/centos/)」を参考にしています。

    ```
    # yum install -y yum-utils
    # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    # yum install docker-ce docker-ce-cli containerd.io -y
    # systemctl enable --now docker
    ```

1. 各ノードでkubeadm, kubelet, kubectlをインストール
    Kubernetesのリポジトリを追加してkubeadm, kubelet, kubectlをインストールし、kubeletを起動します。
    この時点では、kubeletは起動＆失敗を繰り返しますが、次の手順のkubeadm initを実行することで正常に起動するようになります。
    公式の手順では、ここでSELinuxをpermissiveに変更していますが、事前に変更済みのため省略しています。

    ```
    # cat <<EOF > /etc/yum.repos.d/kubernetes.repo
    [kubernetes]
    name=Kubernetes
    baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
    enabled=1
    gpgcheck=1
    repo_gpgcheck=1
    gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
    exclude=kubelet kubeadm kubectl
    EOF
    # yum install kubelet kubeadm kubectl --disableexcludes=kubernetes -y
    # systemctl enable --now kubelet
    ```

1. k8s-masterノードでkubeadmコマンドを使用してControl-plane nodeを初期化する
    - kubeadmコマンドのオプション
        - --apiserver-advertise-address：apiサーバのIPアドレス。マスターノードのIPアドレスを指定する。
        - --pod-network-cidr：Podに割り当てるIPアドレスの範囲。（ホストネットワークと重複しないように設定する）

    ```
    # kubeadm init --apiserver-advertise-address 192.168.123.160 --pod-network-cidr 10.240.0.0/16
    ```

    
    <details><summary>実行例</summary><div>
    
    ```
    [root@k8s-master ~]# kubeadm init --apiserver-advertise-address 192.168.123.160 --pod-network-cidr 10.240.0.0/16
    :
    :
    Your Kubernetes control-plane has initialized successfully!

    To start using your cluster, you need to run the following as a regular user:

      mkdir -p $HOME/.kube
      sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
      sudo chown $(id -u):$(id -g) $HOME/.kube/config

    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 192.168.123.160:6443 --token 8elmsz.6ponqf8ap0c4jkeu \
        --discovery-token-ca-cert-hash sha256:9da3ebd34793cbd6add04d1650c34a3ed13dfdb412f61dd9efb8d2bc030f4a78

    [root@k8s-master ~]#
    ```
    </div></details>

    上記実行例の出力にもある通り、一般ユーザでkubectl コマンドを実行する場合は、一般ユーザで以下のコマンドを実行する必要があります。

    ```
    $ mkdir -p $HOME/.kube
    $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    $ sudo chown $(id -u):$(id -g) $HOME/.kube/config
    ```

    rootユーザの場合は、以下のコマンドを実行すると、kubectlコマンドが実行できます。

    ```
    export KUBECONFIG=/etc/kubernetes/admin.conf
    ```

    私は以下のコマンドをrootで実行してrootコマンドでkubectlを実行できるようにしました。

    ```
    # mkdir -p $HOME/.kube
    # cp -pi /etc/kubernetes/admin.conf $HOME/.kube/config
    ```
    また、上記実行例の出力の最後に出力された以下の部分はノードを追加する際に使用するためメモしておいてください。

    ```
    kubeadm join 192.168.123.160:6443 --token 8elmsz.6ponqf8ap0c4jkeu \
        --discovery-token-ca-cert-hash sha256:9da3ebd34793cbd6add04d1650c34a3ed13dfdb412f61dd9efb8d2bc030f4a78
    ```


1. Container Network Interface(CNI)のインストール
    kubectl get all -Aでリソースを表示すると、CoreDNSが動作していません。CNIをインストールしないと動作しません（「[Installing a Pod network add-on](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network)」）。

    ```
    [root@k8s-master ~]# kubectl get all -A
    NAMESPACE     NAME                                     READY   STATUS              RESTARTS   AGE
    kube-system   pod/coredns-66bff467f8-dp8bl             0/1     Pending             0          2m17s
    kube-system   pod/coredns-66bff467f8-sqsgg             0/1     Pending             0          2m17s
    :
    NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
    kube-system   deployment.apps/coredns   0/2     2            0           2m31s
    :
    ```

    今回は「Calico」をインストールします。
    現時点での最新版となる3.15をインストールしました。

    NetworkManagerがインターフェースに干渉しないように、`/etc/NetworkManager/conf.d/calico.conf`を作成します。
    (Configure NetworkManager)[https://docs.projectcalico.org/maintenance/troubleshoot/troubleshooting#configure-networkmanager]

    全ノードで作成します。

    ```
    cat <<EOF > /etc/NetworkManager/conf.d/calico.conf
    [keyfile]
    unmanaged-devices=interface-name:cali*;interface-name:tunl*;interface-name:vxlan.calico
    EOF
    ```

    k8s-masterノードでCalioをインストール

    ```
    # kubectl apply -f https://docs.projectcalico.org/v3.15/manifests/calico.yaml
    ```
    しばらく待つと、corednsおよびcalicoがRunningになります。`kubectl get pods -n kube-system`で確認できます。


1. Kubernetesクラスタにノードを追加する
    k8s-node1, k8s-node2で以下のコマンドを実行し、Kubernetesクラスタに各ノードを追加します。

    ```
    # kubeadm join 192.168.123.160:6443 --token 8elmsz.6ponqf8ap0c4jkeu \
        --discovery-token-ca-cert-hash sha256:9da3ebd34793cbd6add04d1650c34a3ed13dfdb412f61dd9efb8d2bc030f4a78
    ```

    追加されたかどうかは`kubectl get nodes`で確認できます。

    しばらくすると、coredns、追加されたノード用のcalico-nodeの起動が完了します。
    `kubectl get pods -n kube-system`で確認できます。

1. 動作確認
    [Kubernetes pods by example](https://kubernetesbyexample.com/pods/)を参考にして作ったPodとサービス(NodePort)を動かします。


    1. k8s-master で以下のコマンドを実行してnginxのサンプルを動かします。

        ```
        # kubectl apply -f https://raw.githubusercontent.com/yasubehe/k8s-test001/master/sample-nginx-pod.yaml
        # kubectl get pods -l run=my-nginx -o wide
        # kubectl apply -f https://raw.githubusercontent.com/yasubehe/k8s-test001/master/sample-nginx-service-nodeport.yaml
        # kubectl describe svc my-nginx
        ```

        起動したことを確認します。

        ```
        [root@k8s-master ~]# kubectl get pods -l run=my-nginx -o wide
        NAME                        READY   STATUS    RESTARTS   AGE     IP               NODE        NOMINATED NODE   READINESS GATES
        my-nginx-5dc4865748-26nrr   1/1     Running   0          7m50s   10.240.169.131   k8s-node2   <none>           <none>
        my-nginx-5dc4865748-n5j9r   1/1     Running   0          7m50s   10.240.36.67     k8s-node1   <none>           <none>
        [root@k8s-master ~]# kubectl get svc my-nginx
        NAME       TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
        my-nginx   NodePort   10.97.59.136   <none>        8080:30080/TCP   6s
        [root@k8s-master ~]#
        ```
    
    1. 別のターミナルを2つ用意し、k8s-master にログインしてmy-nginxのpodのログを監視します。

        `kubectl get pods -l run=my-nginx -o wide`に出力されたPodのNAMEの1つ目

        ```
        # kubectl logs -f my-nginx-xxxxxxxxxxxxxxxx
        ```

        `kubectl get pods -l run=my-nginx -o wide`に出力されたPodのNAMEの2つ目

        ```
        # kubectl logs -f my-nginx-yyyyyyyyyyyyyyyy
        ```

    1. 別のターミナルを2つ用意し、それぞれk8s-node1、k8s-node2 にログインしてmy-nginxにアクセスします。
       コマンドを何度か実行すると、ランダムにmy-nginx-xxxxxxxxxxxxxxxx,my-nginx-yyyyyyyyyyyyyyyyにアクセスされることがわかります。

        ```
        [root@k8s-node1 ~]# curl 192.168.123.161:30080
        <!DOCTYPE html>
        <html>
        <head>
        <title>Welcome to nginx!</title>
        ```

        ```
        [root@k8s-node2 ~]# curl 192.168.123.162:30080
        <!DOCTYPE html>
        <html>
        <head>
        <title>Welcome to nginx!</title>
        ：
        ```


1. 動作確認のために作成したService, Podの削除
    k8s-masterノードで以下のコマンドを実行します。

    ```
    # kubectl delete -f https://raw.githubusercontent.com/yasubehe/k8s-test001/master/sample-nginx-service-nodeport.yaml
    # kubectl delete -f https://raw.githubusercontent.com/yasubehe/k8s-test001/master/sample-nginx-pod.yaml
    ```


#参考URL
[【Kubernetes】VirtualBox上のVM(CentOS 7)にkubeadmで1Master+2Node環境作ってみた](https://qiita.com/shinaK/items/a68b926be918f0daba24)