fbpx

CL LAB

HOME > CL LAB > k0sとkubeadmでKonnectivityの動きを調べてみよう #k0s #mirantis #kubernetes #konnectivity

k0sとkubeadmでKonnectivityの動きを調べてみよう #k0s #mirantis #kubernetes #konnectivity

 ★ 40

k0sとは、軽量かつ使いやすい、100%オープンソースのKubernetesディストリビューションです。主な特徴としては、

  • フル機能のKubernetesを構築するために必要なすべてを単一バイナリに同梱
  • k0s特有の改変を加えていない、CNCF認定の純正なKubernetesをデプロイ
  • 最低必要リソース1vCPU・1GBメモリ・2GBストレージのシングルノードから、HA構成の大規模クラスタまでサポート
  • Konnectivityをデフォルトで有効化

などが挙げられます。より詳しい情報は公式ドキュメントをご覧ください。

本稿では、k0sのデフォルトで有効化されているKonnectivityの動きについて、それを持たないkubeadmと比較して調べてみます。

Konnectivityの簡単な説明については以前の記事「k0sでEC2マスターとVirtualboxワーカーのKubernetesクラスタを作成してみよう」をご参照ください。

kubeadmの場合(Konnectivityなし)

パブリックラウド(AWS)上のKubernetesコントロールプレーンと、ローカルPC上のVirtualBoxワーカーという構成を、kubeadmでKonnectivityなしで構築した場合を見てみましょう。

  • AMI: Ubuntu Server 20.04 LTS (HVM), SSD Volume Type (x86)
  • インスタンスタイプ: t2.medium (2vCPU・4GiBメモリ)
  • セキュリティグループでローカルPCのIPアドレスを全許可。

これで作成したコントロールプレーン用のEC2インスタンスのグローバルIPアドレスは 54.213.94.242 とします。

ローカルPCにVagrantとVirtualBoxがインストール済みで2台のゲストが準備済みであり、グローバルIPアドレスは XXX.YYY.ZZZ.254 とします。

これらのIPアドレスは適宜読み替えてください。

まず 54.213.94.242 にて Installing kubeadm の手順に従って kubeadm をインストールしコントロールプレーンを作成します。ここではCRIにDockerではなくcontainerdを使用しており、 --control-plane-endpoint に 54.213.94.242 のFQDNを指定することがポイントです。

ubuntu@ip-172-31-17-165:~$ sudo kubeadm init --ignore-preflight-errors=NumCPU \
--pod-network-cidr=10.244.0.0/16 --service-cidr=10.244.0.0/16 \
--control-plane-endpoint=ec2-54-213-94-242.us-west-2.compute.amazonaws.com \
--cri-socket=/run/containerd/containerd.sock

これで出力された kubeadm join コマンドを、ローカルPCのVirtualBoxゲスト2台で実施します。

kubectl get nodes と netstat で状況を確認してみましょう。

ubuntu@ip-172-31-17-165:~$ kubectl get node
NAME               STATUS     ROLES                  AGE    VERSION
ip-172-31-17-165   NotReady   control-plane,master   106s   v1.22.3
node01             NotReady   <none>                 41s    v1.22.3
node02             NotReady   <none>                 9s     v1.22.3
ubuntu@ip-172-31-17-165:~$ sudo netstat -atnp | grep XXX.YYY
tcp        0     36 172.31.17.165:22        XXX.YYY.ZZZ.254:49670      ESTABLISHED 1213/sshd: ubuntu [
tcp6       0      0 172.31.17.165:6443      XXX.YYY.ZZZ.254:40038      TIME_WAIT   -
tcp6       0      0 172.31.17.165:6443      XXX.YYY.ZZZ.254:40032      ESTABLISHED 8865/kube-apiserver
tcp6       0      0 172.31.17.165:6443      XXX.YYY.ZZZ.254:40060      ESTABLISHED 8865/kube-apiserver
tcp6       0      0 172.31.17.165:6443      XXX.YYY.ZZZ.254:40078      ESTABLISHED 8865/kube-apiserver
tcp6       0      0 172.31.17.165:6443      XXX.YYY.ZZZ.254:40020      ESTABLISHED 8865/kube-apiserver

このようにワーカー(node01,node02)がクラスタに参加できており、ワーカー側からkube-apiserverに接続できていることがわかります。

なお、この状態でCalicoをインストールしようとしても、コントロールプレーンもワーカーも同じEC2上にある場合と異なり、正常に動作しませんが、本稿では本質的な部分ではないため解決は試みません。

では、既に起動しているシステムPodに対してkubectl logsを実行してみましょう。

ubuntu@ip-172-31-17-165:~$ kubectl -n kube-system get pod -o wide
NAME                                       READY   STATUS    RESTARTS   AGE   IP               NODE               NOMINATED NODE   READINESS GATES
coredns-78fcd69978-4s4v7                   0/1     Pending   0          17m   <none>           <none>             <none>           <none>
coredns-78fcd69978-n7vwc                   0/1     Pending   0          17m   <none>           <none>             <none>           <none>
etcd-ip-172-31-17-165                      1/1     Running   4          17m   172.31.17.165    ip-172-31-17-165   <none>           <none>
kube-apiserver-ip-172-31-17-165            1/1     Running   4          17m   172.31.17.165    ip-172-31-17-165   <none>           <none>
kube-controller-manager-ip-172-31-17-165   1/1     Running   5          17m   172.31.17.165    ip-172-31-17-165   <none>           <none>
kube-proxy-f6bkh                           1/1     Running   0          17m   172.31.17.165    ip-172-31-17-165   <none>           <none>
kube-proxy-p8f9f                           1/1     Running   0          16m   192.168.123.22   node02             <none>           <none>
kube-proxy-w5v8x                           1/1     Running   0          16m   192.168.123.21   node01             <none>           <none>
kube-scheduler-ip-172-31-17-165            1/1     Running   5          17m   172.31.17.165    ip-172-31-17-165   <none>           <none>

ここではnode01で起動しているkube-proxy-w5v8xに対してkubectl logsを実行してみます。

ubuntu@ip-172-31-17-165:~$ kubectl -n kube-system logs kube-proxy-w5v8x
^Z
[1]+  Stopped                 kubectl -n kube-system logs kube-proxy-w5v8x

なかなか結果が返ってこないのでCTRL+Zで一旦停止し、netstatで接続状況を見てみます。

ubuntu@ip-172-31-17-165:~$ sudo netstat -atnp | grep SYN
tcp        0      1 172.31.17.165:48460     192.168.123.21:10250    SYN_SENT    8865/kube-apiserver

このようにkube-apiserverから、プライベートIPアドレスを持っているローカルPCのnode01に接続しようとしています。当然これは不可能であるため、

Error from server: Get "https://192.168.123.21:10250/containerLogs/kube-system/kube-proxy-w5v8x/kube-proxy": dial tcp 192.168.123.21:10250: i/o timeout
[1]+  Exit 1                  kubectl -n kube-system logs kube-proxy-w5v8x

しばらくするとタイムアウトしてしまいます。kubectl execやkubectl port-forwardも同様です。

ubuntu@ip-172-31-17-165:~$ kubectl -n kube-system exec kube-proxy-w5v8x -- sh
Error from server: error dialing backend: dial tcp 192.168.123.21:10250: i/o timeout
ubuntu@ip-172-31-17-165:~$ kubectl -n kube-system port-forward kube-proxy-w5v8x 8888:8888
error: error upgrading connection: error dialing backend: dial tcp 192.168.123.21:10250: i/o timeout

何が起きているのでしょうか? Kubernetes公式ドキュメントを見てみましょう。

ワーカーノードはKubelet APIを受け付けるため10250/tcpを開放していなければいけません。ではKubelet APIとは何でしょうか? 簡単には先ほどのkubelet logs/exec/port-forwardに利用されます。

このように、パブリックラウド上にコントロールプレーン、ローカルPC上にワーカーという構成で単純にKubernetesをインストールすると、正常に動作しないことがわかりました。
図の青矢印のようにkubeletからkube-apiserverへの接続は可能ですが、黄矢印のようにkube-apiserverからkubeletへの接続は不可能であるためです。

k0sの場合(Konnectivityあり)

では、パブリックラウド(AWS)上のKubernetesコントロールプレーンと、ローカルPC上のVirtualBoxワーカーという構成を、k0sで構築した場合を見てみましょう。内容としては以前の記事「k0sでEC2マスターとVirtualboxワーカーのKubernetesクラスタを作成してみよう」とほぼ同一です。

  • AMI: Ubuntu Server 20.04 LTS (HVM), SSD Volume Type (x86)
  • インスタンスタイプ: t2.medium (2vCPU・4GiBメモリ)
  • セキュリティグループでローカルPCのIPアドレスを全許可。

これで作成したコントロールプレーン用のEC2インスタンスのグローバルIPアドレスは 34.221.254.215 とします。

ローカルPCにVagrantとVirtualBoxがインストール済みで2台のゲストが準備済みであり、グローバルIPアドレスは XXX.YYY.ZZZ.254 とします。

これらのIPアドレスは適宜読み替えてください。

以前の記事「k0sでEC2マスターとVirtualboxワーカーのKubernetesクラスタを作成してみよう」と同じく、spec.api.externalAddressキーとspec.api.sansキーにEC2インスタンスのグローバルIPアドレス 34.221.254.215 を追加するだけでOKです。

ubuntu@ip-172-31-30-231:~$ k0s default-config > k0s.yaml
ubuntu@ip-172-31-30-231:~$ cp k0s.yaml k0s.yaml.orig
ubuntu@ip-172-31-30-231:~$ vi k0s.yaml
ubuntu@ip-172-31-30-231:~$ diff -u k0s.yaml.orig k0s.yaml
--- k0s.yaml.orig   2021-11-10 03:16:32.102876955 +0000
+++ k0s.yaml    2021-11-10 03:18:00.956487688 +0000
@@ -5,10 +5,12 @@
 spec:
   api:
     address: 172.31.30.231
+    externalAddress: 34.221.254.215
     port: 6443
     k0sApiPort: 9443
     sans:
     - 172.31.30.231
+    - 34.221.254.215
   storage:
     type: etcd
     etcd:

これでコントロールプレーンをインストールし、手順に従ってローカルPCのVirtualBoxゲスト2台を登録し、Kubernetesクラスタを構築します。

では、kubectl get nodes と netstat で状況を確認してみましょう。

ubuntu@ip-172-31-30-231:~$ k0s kubectl get nodes
NAME     STATUS   ROLES    AGE   VERSION
node01   Ready    <none>   11m   v1.22.3+k0s
node02   Ready    <none>   11m   v1.22.3+k0s
ubuntu@ip-172-31-30-231:~$ sudo netstat -atnp | grep XXX.YYY
tcp        0     36 172.31.30.231:22        XXX.YYY.ZZZ.254:53788      ESTABLISHED 633/sshd: ubuntu [p
tcp6       0      0 172.31.30.231:6443      XXX.YYY.ZZZ.254:57870      ESTABLISHED 1038/kube-apiserver
tcp6       0      0 172.31.30.231:6443      XXX.YYY.ZZZ.254:57838      ESTABLISHED 1038/kube-apiserver
tcp6       0      0 172.31.30.231:6443      XXX.YYY.ZZZ.254:57856      ESTABLISHED 1038/kube-apiserver
tcp6       0      0 172.31.30.231:6443      XXX.YYY.ZZZ.254:57898      ESTABLISHED 1038/kube-apiserver
tcp6       0      0 172.31.30.231:6443      XXX.YYY.ZZZ.254:57884      ESTABLISHED 1038/kube-apiserver
tcp6       0      0 172.31.30.231:6443      XXX.YYY.ZZZ.254:57864      ESTABLISHED 1038/kube-apiserver
tcp6       0      0 172.31.30.231:6443      XXX.YYY.ZZZ.254:57854      ESTABLISHED 1038/kube-apiserver
tcp6       0      0 172.31.30.231:6443      XXX.YYY.ZZZ.254:57808      ESTABLISHED 1038/kube-apiserver
tcp6       0      0 172.31.30.231:8132      XXX.YYY.ZZZ.254:55562      ESTABLISHED 1086/konnectivity-s
tcp6       0      0 172.31.30.231:8132      XXX.YYY.ZZZ.254:55564      ESTABLISHED 1086/konnectivity-s
tcp6       0      0 172.31.30.231:6443      XXX.YYY.ZZZ.254:57886      ESTABLISHED 1038/kube-apiserver

このようにワーカー(node01,node02)がクラスタに参加できており、ワーカー側からkube-apiserverと、加えてkonnectivity-serverに接続できていることがわかります。

なお、k0sはデフォルトで自動的にKube-Routerをインストール・設定するため、kubeadmのように別途CNIプラグインをインストールする必要はありません。システムPodを見てみましょう。

ubuntu@ip-172-31-30-231:~$ k0s kubectl -n kube-system get pod -o wide
NAME                              READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
coredns-77b4ff5f78-l7hkv          1/1     Running   0          20m   10.244.0.5       node01   <none>           <none>
coredns-77b4ff5f78-lddjd          1/1     Running   0          13m   10.244.0.3       node01   <none>           <none>
konnectivity-agent-gtqd7          1/1     Running   0          11m   10.244.1.2       node02   <none>           <none>
konnectivity-agent-rd98z          1/1     Running   0          12m   10.244.0.4       node01   <none>           <none>
kube-proxy-hzv4c                  1/1     Running   0          13m   192.168.123.22   node02   <none>           <none>
kube-proxy-k9kx9                  1/1     Running   0          14m   192.168.123.21   node01   <none>           <none>
kube-router-p749h                 1/1     Running   0          13m   192.168.123.22   node02   <none>           <none>
kube-router-rdh9q                 1/1     Running   0          14m   192.168.123.21   node01   <none>           <none>
metrics-server-5b898fd875-glfj2   1/1     Running   0          20m   10.244.0.2       node01   <none>           <none>

では、node01で起動しているkube-proxy-k9kx9に対してkubectl logsを実行してみます。

ubuntu@ip-172-31-30-231:~$ k0s kubectl -n kube-system logs kube-proxy-k9kx9 | head -5
I1110 01:52:46.187150       1 node.go:172] Successfully retrieved node IP: 192.168.123.21
I1110 01:52:46.187236       1 server_others.go:140] Detected node IP 192.168.123.21
I1110 01:52:46.262041       1 server_others.go:206] kube-proxy running in dual-stack mode, IPv4-primary
I1110 01:52:46.262115       1 server_others.go:212] Using iptables Proxier.
I1110 01:52:46.262140       1 server_others.go:219] creating dualStackProxier for iptables.

正しくログを取ることができました。kubectl logsをバックグラウンドで動作させ、ネットワークの接続状態を見てみましょう。

ubuntu@ip-172-31-30-231:~$ k0s kubectl -n kube-system logs -f kube-proxy-k9kx9 > /dev/null 2> /dev/null &
[1] 1354
ubuntu@ip-172-31-30-231:~$ sudo netstat -atnp | grep SYN
ubuntu@ip-172-31-30-231:~$

Konnectivityが動作していないkubeadmでのクラスタ構築では、パブリックのkube-apiserverからプライベートのkubeletに接続しようとして失敗していましたが、Konnectivityが動作しているk0sによるインストールではそのようなことは起きていないようです。

Konnectivityの動作状況をnode01で調べてみます。しかし、単純にnode01ゲスト上でnetstatしても、パブリッククラウド上のkonnectivity-serverへの接続状態は見えません。なぜなら、node01で動作しているkonnectivity-agentはPodとして動いているため、別のネットワークネームスペースに存在しているからです。konnectivity-agentのネットワークネームスペースを調べてみましょう。

まず、konnectivity-agent (proxy-agent)のPIDから、ip netns identifyコマンドを使って、ネットワークネームスペース名を割り出します。

vagrant@node01:~$ ps auxwwwf|grep '[ p]roxy-agent'
root      4247  0.0  0.1 715128 13956 ?        Ssl  10:54   0:01  _ /proxy-agent --logtostderr=true --ca-cert=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt --proxy-server-host=34.221.254.215 --proxy-server-port=8132 --service-account-token-path=/var/run/secrets/tokens/konnectivity-agent-token
vagrant@node01:~$ sudo ip netns identify 4247
cni-2b1226ec-c0f3-1436-5440-1e1349bccee5

konnectivity-agent (proxy-agent)が動作しているネットワークネームスペースがわかったので、こちらでnetstatしてみます。

vagrant@node01:~$ sudo ip netns exec cni-2b1226ec-c0f3-1436-5440-1e1349bccee5 netstat -atnp | grep 34.221.254.215
tcp        0      0 10.244.0.4:59084        34.221.254.215:8132     ESTABLISHED 4247/proxy-agent

このようにkonnectivity-agentが、EC2インスタンス(34.221.254.215)上のkonnectivity-server (8132/tcp)に接続しています。

Konnectivityを有効にしてkubectl logs/exec/port-forwardを実行すると、kube-apiserverからkonnectivity-serverへ、konnectivity-serverに接続しているkonnectivity-agentからkubeletへと、konnectivity-server/agentを介して動作することになります。

kubeadmでクラスタ構築した場合はSet up Konnectivity serviceの手順に従ってKonnectivityを有効にする必要があるようですが、k0sならばデフォルトでKonnectivityが有効なのですぐに使うことができるようになっています。

まとめ

本稿ではKonnectivityについて、それがないkubeadmでKubernetesクラスタを構築した場合と、デフォルトで有効になるk0sでKubernetesクラスタを構築した場合のそれぞれで、kube-apiserverとkubeletの動きも含めて調べてみました。

Konnectivityによってkube-apiserverから直接疎通できないkubeletに対しても通信できるようになっています。またk0sはKonnectivityがデフォルトで有効なので、k0sの通常のクラスタ構築手順でもすぐ使うことができます。

パブリッククラウドにコントロールプレーンを置き、プライベートネットワークやIoT機器をワーカーとするKubernetesクラスタを構築する際に、軽量かつデフォルトで有効なKonnectivityを備えるk0sは適した選択肢と考えられます。本ブログでは引き続きk0sのさまざまな情報を発信していく予定です。

CL LAB Mail Magazine

CL LABの情報を逃さずチェックしよう!

メールアドレスを登録すると記事が投稿されるとメールで通知します。

メールアドレス: 登録

※登録後メールに記載しているリンクをクリックして認証してください。

Related post

[無料ウェビナー] GitLab_CI/CDハンズオン_2023111