【Kubernetes】kubectl execができなかった件


自分で勉強目的に作ったk8s環境について、kubectl execがなぜか失敗して、なんでだろ、と思って調べた記録。
ググれば出てくるが自身への備忘録としてまとめる


事象

kubectl execを実行すると以下のエラーがかえってきた

$ kubectl exec hogehoge -- ls /  
error: unable to upgrade connection: pod does not exist

kubectl exec --helpを実行すると以下のような内容

  # Get output from running 'date' command from the first pod of the deployment mydeployment, using the first container  
by default  
  kubectl exec deploy/mydeployment -- date

も確認できたのと、実際の環境が実際DeploymentでつくったPodだったのもあって、kubectl exec deploy/hogehoge -- ls /とか書かないとだめなのかなと思ったが、これもだめ。
エラーメッセージがそもそも「Podが見つからない」なので、違うだろうなとは思ったが…。
Kubernetes.ioのexecコマンドの説明を見てもPodを指定するという点には間違っていないし。
う~ん??
まあPod動いてるし後で調べればいいかと思ってちょっと放置してしまっていた。

原因

内容的にはこれが一番近かった。(これはVagrantの例だけど)
確かに見てみたらマスター、ワーカー、各ノードの「INTERNAL-IP」が同じ値になっていた。

$ kubectl get no -o wide  
NAME       STATUS   ROLES                  AGE     VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME  
ubuntu00   Ready    control-plane,master   2d13h   v1.20.1   10.0.2.15        <none>        Ubuntu 20.04.1 LTS   5.4.0-58-generic   docker://20.10.1  
ubuntu01   Ready    <none>                 47h     v1.20.1   10.0.2.15        <none>        Ubuntu 20.04.1 LTS   5.4.0-58-generic   docker://20.10.1  
ubuntu02   Ready    <none>                 21h     v1.20.1   10.0.2.15        <none>        Ubuntu 20.04.1 LTS   5.4.0-58-generic   docker://20.10.1

解決法として、稼働する各ノードに一意のIPを指定してあげる必要がある。
具体的にはkubeletの起動オプションに

Environment="KUBELET_EXTRA_ARGS=--node-ip=[ノードIP]"

を追加するということのようだ。
今回の例では

Node IP Address
Master Node 192.168.56.100
Worker Node 192.168.56.101
Worker Node 192.168.56.102

だったので、それぞれのノードの/etc/systemd/system/kubelet.service.d/10-kubeadm.confを修正して↑の一行(IPアドレスは各ノードで変える)を追加し、sudo systemctl daemon-reload及びsudo systemctl restart kubeletでkubeletを再起動する。
これで各ノードのIPが変わる。

$ kubectl get no -o wide  
NAME       STATUS   ROLES                  AGE     VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME  
ubuntu00   Ready    control-plane,master   2d13h   v1.20.1   192.168.56.100   <none>        Ubuntu 20.04.1 LTS   5.4.0-58-generic   docker://20.10.1  
ubuntu01   Ready    <none>                 47h     v1.20.1   192.168.56.101   <none>        Ubuntu 20.04.1 LTS   5.4.0-58-generic   docker://20.10.1  
ubuntu01   Ready    <none>                 21h     v1.20.1   192.168.56.102   <none>        Ubuntu 20.04.1 LTS   5.4.0-58-generic   docker://20.10.1

これで無事にkubectl execが実行できた。
このあと滅茶苦茶execした。

$ kubectl exec test-nginx -- ls /  
bin  
boot  
dev  
docker-entrypoint.d  
docker-entrypoint.sh  
etc  
home  
lib  
lib64  
media  
mnt  
opt  
proc  
root  
run  
sbin  
srv  
sys  
tmp  
usr  
var

ちなみに中に入る(?)ときは

$ kubectl exec test-nginx --tty --stdin -- bash  
root@test-nginx:/# ls  
bin  boot  dev  docker-entrypoint.d  docker-entrypoint.sh  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

こんなかんじ。
要するに--tty--stdinのオプションが必要だ。
(このオプション付けないとbashだけ実行されて速攻コマンドが終わる)

余談

昔(1~2年前?よく覚えていない)同じことをやったときに、ユーザーの環境変数に指定しておけばいいと思って、/home/xxx/.profileexport KUBELET_EXTRA_ARGS=...を指定してkubelet起動させて、これはこれでexecが実行できていた記憶があり、自分の手元でKubernetesの環境作ったときも、最初はこれでやっていた。
まあ今回はrootの環境変数をいじってなかった(自ユーザーの変数いじってたから効くわけない。kubeletのサービスはrootで起動するので、環境変数設定するにしてもrootのほうに設定する必要があった)ので結局駄目だったんだけどね。。。
ただ/etc/environmentとかにいれても反応してくれず、どうしたもんかとずっと思っていたら、kubeadmでkubeletを入れた場合は、上述した設定ファイル/etc/systemd/system/kubelet.service.d/10-kubeadm.confがもう出来上がっていて、そっちの設定が優先されるようになってるらしい。
そんなこと言ってるのをちょっと見かけた。
だから一度この設定ファイルができてしまうと後でいくら環境変数をいじくっても無駄のようだ。
逆にいうとkubeadmを入れる前にきちんと適切に環境変数いれておけばこの設定ファイルにもそれが反映された…のかもしれない。
試していない。
まあ、そのうちやってみるか。