Vagrant上のkubernetesでWorker Nodeのコンテナにアタッチできない問題について

Vagrant上でkubeadmを利用してkubernetes環境を構築すると、Worker Nodeのコンテナにアタッチできない、という問題に遭遇します。
問題の原因と解消をまとめましたので本記事にて紹介します。

なお、作成に利用したVagrantfileは以下の通りです。

```
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.require_version ">= 2.0.0"

CONFIG = 'vagrant/config.rb'

SUPPORTED_OS = {
  "ubuntu1604"          => {box: "generic/ubuntu1604",         user: "vagrant"},
  "ubuntu1804"          => {box: "generic/ubuntu1804",         user: "vagrant"},
  "ubuntu2004"          => {box: "geerlingguy/ubuntu2004",     user: "vagrant"},
}

# Defaults for config options defined in CONFIG
$num_instances ||= 2
$num_k8s_master ||= 1
$instance_name_prefix ||= "kube"
$vm_gui ||= false
$vm_memory ||= 2048
$vm_cpus ||= 2
$shared_folders ||= {}
$forwarded_ports ||= {}
$subnet ||= "192.168.128"
$os ||= "ubuntu1804"

$box = SUPPORTED_OS[$os][:box]

Vagrant.configure("2") do |config|

  config.vm.box = $box
  config.ssh.username = SUPPORTED_OS[$os][:user]

  (1..$num_instances).each do |i|
    config.vm.define vm_name = "%s-%01d" % [$instance_name_prefix, i] do |node|

      node.vm.hostname = vm_name

      node.vm.provider :virtualbox do |vb|
        vb.memory = $vm_memory
        vb.cpus = $vm_cpus
        vb.gui = $vm_gui
        vb.linked_clone = true
        vb.customize ["modifyvm", :id, "--vram", "8"] # ubuntu defaults to 256 MB which is a waste of precious RAM
      end

      node.vm.synced_folder ".", "/vagrant", disabled: false, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z'] , rsync__exclude: ['.git','venv']
      $shared_folders.each do |src, dst|
        node.vm.synced_folder src, dst, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z']
      end

      ip = "#{$subnet}.#{i+100}"
      node.vm.network :private_network, ip: ip

      #host_port = 10022+i
      #config.vm.network "forwarded_port", guest: 22, host: $host_port, host_ip: "127.0.0.1"

      node.vm.provision "shell", run: "always", inline: "swapoff -a"

      node.vm.provision "shell", inline: "apt-get update"
      node.vm.provision "shell", inline: "apt-get install -y docker.io apt-transport-https curl"
      node.vm.provision "shell", inline: "systemctl start docker"
      node.vm.provision "shell", inline: "systemctl enable docker"
      node.vm.provision "shell", inline: "curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -"
      node.vm.provision "shell", inline: "apt-add-repository 'deb http://apt.kubernetes.io/ kubernetes-xenial main'"
      node.vm.provision "shell", inline: "apt-get update"
      node.vm.provision "shell", inline: "apt-get install -y kubelet kubeadm kubectl"

      if i == $num_k8s_master
        node.vm.network "forwarded_port", guest: 6443, host: 16443, host_ip: "127.0.0.1", auto_correct: true

        node.vm.provision "shell", inline: "kubeadm init --apiserver-advertise-address=#{$subnet}.#{i+100} --pod-network-cidr=10.244.10.0/16 --apiserver-cert-extra-sans=127.0.0.1"
        node.vm.provision "shell", inline: "mkdir /home/vagrant/.kube"
        node.vm.provision "shell", inline: "cp /etc/kubernetes/admin.conf /home/vagrant/.kube/config"
        node.vm.provision "shell", inline: "chown vagrant:vagrant /home/vagrant/.kube/config"
        node.vm.provision "shell", inline: "kubectl --kubeconfig=/etc/kubernetes/admin.conf apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml"
#        node.vm.provision "shell", inline: "kubectl --kubeconfig=/etc/kubernetes/admin.conf taint nodes --all node-role.kubernetes.io/master-"
      end

    end
  end
end
```
※Master Node/Worker Node1台ずつ、という構成です

## 原因

kubectl execでWorker Nodeのコンテナにアタッチしようとすると、該当のpodが見つからないというエラーが出てしまいます。

```
sho@Desktop $ kubectl get po -o wide                                                                              [~/workspace/vm/kubeadm]
NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
nginx-deployment-5bf87f5f59-g5w8b   1/1     Running   1          68m   10.244.1.5   kube-2   <none>           <none>
nginx-deployment-5bf87f5f59-t6j7s   1/1     Running   1          68m   10.244.1.4   kube-2   <none>           <none>
sho@Desktop $ kubectl exec -it nginx-deployment-5bf87f5f59-g5w8b sh                                              [~/workspace/vm/kubeadm]
error: unable to upgrade connection: pod does not exist
sho@Desktop $                                                                                       [~/workspace/vm/kubeadm]
```

原因としては、Vagrantで作成したVMのIPが同じ値になっているためです。
これにより各NodeのINTERNAL-IPが同じになり、api serverからWorker Nodeのコンテナに到達できなくなっています。

```
vagrant@kube-1:~$ ip a show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:69:8a:cd brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic eth0
       valid_lft 83836sec preferred_lft 83836sec
    inet6 fe80::a00:27ff:fe69:8acd/64 scope link 
       valid_lft forever preferred_lft forever
vagrant@kube-1:~$ 
```

```
vagrant@kube-2:~$ ip a show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:69:8a:cd brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic eth0
       valid_lft 83873sec preferred_lft 83873sec
    inet6 fe80::a00:27ff:fe69:8acd/64 scope link 
       valid_lft forever preferred_lft forever
vagrant@kube-2:~$ 
```

```
sho@Desktop $ kubectl get no -o wide                                                                             [~/workspace/vm/kubeadm]
NAME     STATUS   ROLES    AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
kube-1   Ready    master   36m   v1.18.2   10.0.2.15     <none>        Ubuntu 18.04.4 LTS   4.15.0-99-generic   docker://19.3.6
kube-2   Ready    <none>   29m   v1.18.2   10.0.2.15     <none>        Ubuntu 18.04.4 LTS   4.15.0-99-generic   docker://19.3.6
sho@Desktop $ k get no -o wide                                                                             [~/workspace/vm/kubeadm]
```

## 解決法

eth1には異なるIPが設定されているため、eth1の値をINTERNAL-IPになるようkubeletの設定を変更することで解消できます。

```
vagrant@kube-1:~$ ip a show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:06:7e:a7 brd ff:ff:ff:ff:ff:ff
    inet 192.168.128.101/24 brd 192.168.128.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe06:7ea7/64 scope link 
       valid_lft forever preferred_lft forever
vagrant@kube-1:~$ 
```

```
vagrant@kube-2:~$ ip a show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:b8:ec:3a brd ff:ff:ff:ff:ff:ff
    inet 192.168.128.102/24 brd 192.168.128.255 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:feb8:ec3a/64 scope link 
       valid_lft forever preferred_lft forever
vagrant@kube-2:~$ 
```

Master Node/Worker Nodeそれぞれで設定を変更していきます。
（設定自体は同じなので、解説は片方のみ掲載します）

```
vagrant@kube-1:~$ sudo cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
Environment="KUBELET_EXTRA_ARGS=--node-ip=192.168.128.101"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/default/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
vagrant@kube-1:~$ 
```

以下の部分が追加した箇所です。

```
Environment="KUBELET_EXTRA_ARGS=--node-ip=192.168.128.101"
```

kubeletはsystemdのサービスとして動作してるので、設定変更後はsystemdの流儀に沿ってサービス・リスタートしていきます。

```
$ sudo systemctl daemon-reload
$ sudo systemctl restart kubelet
```

INTERNAL-IPが異なる値になっているのが確認でき、Worker Nodeのコンテナにアタッチできるようになっています。

```
sho@Desktop $ kubectl get no -o wide                                                                              sho@Desktop $ kubectl get po -o wide                                                                       [~/workspace/vm/kubeadm]
NAME                                READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
nginx-deployment-5bf87f5f59-g5w8b   1/1     Running   1          71m   10.244.1.5   kube-2   <none>           <none>
nginx-deployment-5bf87f5f59-t6j7s   1/1     Running   1          71m   10.244.1.4   kube-2   <none>           <none>
sho@Desktop $ kubectl exec -it nginx-deployment-5bf87f5f59-g5w8b sh                                        [~/workspace/vm/kubeadm]
# 
```