LoginSignup
3
3

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-06-26
更新

2020/07/19 Kubernetes 1.18.6, Calico 3.15.1 も同じ手順でインストール可能です。

環境

ESXi7.0上にVM3台作成

  • vm

    • k8s-master cpu:2 mem:4GB HDD:30GB IP:192.168.123.150
    • k8s-node1 cpu:2 mem:4GB HDD:30GB IP:192.168.123.151
    • k8s-node2 cpu:2 mem:4GB HDD:30GB IP:192.168.123.152
  • OS

    • CentOS8.2.2004 Minimalインストール
  • インストールするKubernetesのバージョン

    • 1.18.4

Installing kubeadmによると、インストールするマシンは2GB以上のメモリ、cpu2コア以上が必要とのこと。

はじめに

Kubernetesの勉強用に自前で環境を組んでみることにしました。
手っ取り早く環境を構築して動かしたい人向けです。
基本的に公式のBootstrapping clusters with kubeadmの通りに進めていますが、結構苦戦したので手順をまとめました。

手順

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

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

    # vi /etc/fstab
      → swapの行をコメントアウト
    
  3. 各ノードで名前解決ができるようにする
    各ノードの /etc/hosts に以下の値を追加する

    192.168.123.150 k8s-master
    192.168.123.151 k8s-node1
    192.168.123.152 k8s-node2
    
  4. 各ノードのMACアドレスと product_uuidが一意であることの確認

    • MACアドレス確認

      # ip link
      
    • product_uuid確認

      # cat /sys/class/dmi/id/product_uuid
      
  5. 各ノードのFirewallの無効化(ここでは自動起動無効化のみ。後でノード再起動で反映させる。)

    # systemctl disable firewalld
    
  6. 各ノードのselinuxの無効化(ここでは設定のみ。後でノード再起動で反映させる。)

    # vi /etc/selinux/config
    →SELINUX=permissive に変更
    
  7. 各ノードのipv6無効化(ここでは設定のみ。後でノード再起動で反映させる。)

    # echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf
    # echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf
    
  8. 各ノードのネットワーク・ブリッジを通過するパケットにiptablesを適用(ここでは設定のみ。後でノード再起動で反映させる。)

    # cat <<EOF >  /etc/sysctl.d/k8s.conf
    net.bridge.bridge-nf-call-ip6tables = 1
    net.bridge.bridge-nf-call-iptables = 1
    EOF
    
  9. 各ノードのipv4のフォワード設定(ここでは設定のみ。後でノード再起動でまとめて反映させる。)

    # echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
    
  10. これまでの設定を反映させるため、全ノードを再起動する

    # shutdown -r now
    
  11. 各ノードでコンテナランタイムをインストール
    Dockerをインストールします。
    インストール手順は「Install Docker Engine on CentOS」を参考にしています。
    手順通りにインストールしようとするとエラーが発生したので、「How to install Docker CE on RHEL 8 / CentOS 8」を参考にインストール手順を少し変更しています。(CentOS8からはDockerコンテナエンジンが削除されてpodmanを使うようになったのが原因のようです。)

    # dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
    # dnf install https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.13-3.2.el7.x86_64.rpm -y
    # dnf install docker-ce docker-ce-cli -y
    # mkdir /etc/docker
    # cat > /etc/docker/daemon.json <<EOF
    {
      "exec-opts": ["native.cgroupdriver=systemd"],
      "log-driver": "json-file",
      "log-opts": {
        "max-size": "100m"
      },
      "storage-driver": "overlay2",
      "storage-opts": [
        "overlay2.override_kernel_check=true"
      ]
    }
    EOF
    # mkdir -p /etc/systemd/system/docker.service.d
    # systemctl daemon-reload
    # systemctl enable --now docker
    
  12. 各ノードで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
    # dnf install kubelet kubeadm kubectl --disableexcludes=kubernetes -y
    # systemctl enable --now kubelet
    
  13. 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.150 --pod-network-cidr 10.240.0.0/16
    

    実行例
    [root@k8s-master ~]# kubeadm init --apiserver-advertise-address 192.168.123.150 --pod-network-cidr 10.240.0.0/16
    W0621 23:58:11.156994  134717 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
    [init] Using Kubernetes version: v1.18.4
    [preflight] Running pre-flight checks
            [WARNING Firewalld]: firewalld is active, please ensure ports [6443 10250] are open or your cluster may not function correctly
            [WARNING FileExisting-tc]: tc not found in system path
    [preflight] Pulling images required for setting up a Kubernetes cluster
    [preflight] This might take a minute or two, depending on the speed of your internet connection
    [preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
    [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
    [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
    [kubelet-start] Starting the kubelet
    [certs] Using certificateDir folder "/etc/kubernetes/pki"
    [certs] Generating "ca" certificate and key
    [certs] Generating "apiserver" certificate and key
    [certs] apiserver serving cert is signed for DNS names [k8s-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.123.150]
    [certs] Generating "apiserver-kubelet-client" certificate and key
    [certs] Generating "front-proxy-ca" certificate and key
    [certs] Generating "front-proxy-client" certificate and key
    [certs] Generating "etcd/ca" certificate and key
    [certs] Generating "etcd/server" certificate and key
    [certs] etcd/server serving cert is signed for DNS names [k8s-master localhost] and IPs [192.168.123.150 127.0.0.1 ::1]
    [certs] Generating "etcd/peer" certificate and key
    [certs] etcd/peer serving cert is signed for DNS names [k8s-master localhost] and IPs [192.168.123.150 127.0.0.1 ::1]
    [certs] Generating "etcd/healthcheck-client" certificate and key
    [certs] Generating "apiserver-etcd-client" certificate and key
    [certs] Generating "sa" key and public key
    [kubeconfig] Using kubeconfig folder "/etc/kubernetes"
    [kubeconfig] Writing "admin.conf" kubeconfig file
    [kubeconfig] Writing "kubelet.conf" kubeconfig file
    [kubeconfig] Writing "controller-manager.conf" kubeconfig file
    [kubeconfig] Writing "scheduler.conf" kubeconfig file
    [control-plane] Using manifest folder "/etc/kubernetes/manifests"
    [control-plane] Creating static Pod manifest for "kube-apiserver"
    [control-plane] Creating static Pod manifest for "kube-controller-manager"
    W0621 23:58:18.001687  134717 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
    [control-plane] Creating static Pod manifest for "kube-scheduler"
    W0621 23:58:18.002962  134717 manifests.go:225] the default kube-apiserver authorization-mode is "Node,RBAC"; using "Node,RBAC"
    [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
    [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
    [apiclient] All control plane components are healthy after 21.503071 seconds
    [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
    [kubelet] Creating a ConfigMap "kubelet-config-1.18" in namespace kube-system with the configuration for the kubelets in the cluster
    [upload-certs] Skipping phase. Please see --upload-certs
    [mark-control-plane] Marking the node k8s-master as control-plane by adding the label "node-role.kubernetes.io/master=''"
    [mark-control-plane] Marking the node k8s-master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
    [bootstrap-token] Using token: u4t96u.malq5uoi0of545r6
    [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
    [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to get nodes
    [bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
    [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
    [bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
    [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace
    [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key
    [addons] Applied essential addon: CoreDNS
    [addons] Applied essential addon: kube-proxy
    
    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.150:6443 --token u4t96u.malq5uoi0of545r6 \
        --discovery-token-ca-cert-hash sha256:1700be62aefeb52188c53ff77e0ce43b329fec3837dc83b45bd9d7d649f767e2
    [root@k8s-master ~]#
    

    上記実行例の出力にもある通り、一般ユーザで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.150:6443 u4t96u.malq5uoi0of545r6 \
        --discovery-token-ca-cert-hash sha256:1700be62aefeb52188c53ff77e0ce43b329fec3837dc83b45bd9d7d649f767e2
    
  14. Container Network Interface(CNI)のインストール
    kubectl get all -Aでリソースを表示すると、CoreDNSが動作していません。CNIをインストールしないと動作しません(「Installing a Pod network add-on」)。

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

    いくつか選択肢があるようですが、今回は「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をインストール(Calio 3.15.1も同じURLでインストールできます)

    # kubectl apply -f https://docs.projectcalico.org/v3.15/manifests/calico.yaml
    

    しばらく待つと、corednsおよびcalicoがRunningになります。kubectl get pods -n kube-systemで確認できます。

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

    # kubeadm join 192.168.123.150:6443 --token u4t96u.malq5uoi0of545r6 \
        --discovery-token-ca-cert-hash sha256:1700be62aefeb52188c53ff77e0ce43b329fec3837dc83b45bd9d7d649f767e2
    

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

    [root@k8s-master ~]# kubectl get nodes
    NAME         STATUS   ROLES    AGE   VERSION
    k8s-master   Ready    master   42m   v1.18.4
    k8s-node1    Ready    <none>   68s   v1.18.4
    k8s-node2    Ready    <none>   26s   v1.18.4
    [root@k8s-master ~]#
    

    しばらくすると、coredns、追加されたノード用のcalico-nodeの起動が完了します。

    [root@k8s-master ~]# kubectl get pods -n kube-system
    NAME                                       READY   STATUS    RESTARTS   AGE
    calico-kube-controllers-58b656d69f-4kd5f   1/1     Running   0          64m
    calico-node-2w98n                          1/1     Running   0          62m
    calico-node-cqw29                          1/1     Running   0          64m
    calico-node-fh2zw                          1/1     Running   0          61m
    coredns-66bff467f8-st5k8                   1/1     Running   0          65m
    coredns-66bff467f8-zk27f                   1/1     Running   0          65m
    :
    
  16. 動作確認
    Kubernetes pods by exampleを参考にして作った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-64l7d   1/1     Running   0          43s   10.240.169.130   k8s-node2   <none>           <none>
      my-nginx-5dc4865748-6lxhv   1/1     Running   0          43s   10.240.36.66     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.111.252.182   <none>        8080:30080/TCP   36s
      [root@k8s-master ~]#
      
    2. 別のターミナルを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
      
    3. 別のターミナルを2つ用意し、それぞれk8s-node1、k8s-node2 にログインしてmy-nginxにアクセスします。
      コマンドを何度か実行すると、ランダムにmy-nginx-xxxxxxxxxxxxxxxx,my-nginx-yyyyyyyyyyyyyyyyにアクセスされることがわかります。

      [root@k8s-node1 ~]# curl 192.168.123.151:30080
      <!DOCTYPE html>
      <html>
      <head>
      <title>Welcome to nginx!</title>
      
      [root@k8s-node2 ~]# curl 192.168.123.152:30080
      <!DOCTYPE html>
      <html>
      <head>
      <title>Welcome to nginx!</title>
      :
      
  17. 動作確認のために作成した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
    

今後は、Kubernetesダッシュボードを動かしたりPrometheusでの監視を試してみようと思います。

参考URL

Bootstrapping clusters with kubeadm
Kubernetes on CentOS on ESXi 環境を構築してみた
kubeadmでk8sクラスタを構築
VirtualBox+CentOS 7+kubeadmを利用してKubernetesクラスタのローカル構築を試してみる
Install Calico networking and network policy for on-premises deployments
calicoが起動しない(CrashLoopBackOff)
【Kubernetes】VirtualBox上のVM(CentOS 7)にkubeadmで1Master+2Node環境作ってみた

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3