RM-BLOG

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【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を入れる前にきちんと適切に環境変数いれておけばこの設定ファイルにもそれが反映された…のかもしれない。
試していない。
まあ、そのうちやってみるか。