Azure Kubernetes Service（旧kubenetネットワークモデル）の内部構造について

# はじめに
4回に分けてDockerとAzure Kubernetes Service（以下、AKS）の内部ネットワーク構造に注目し、深堀りしていきます。最終回では、両者を比較し共通点・相違点についてまとめます。
第2回目は、AKSのkubenetネットワークモデルにおける内部構造について整理していきます。
なお、検証環境は以下の通りです。

### 検証環境（Azure VM）
OS：Linux (ubuntu 20.04)
Size：Standard D2s v3 (2 vcpus, 8 GiB memory)

### 前回の記事

https://qiita.com/maplejava/items/a70ef1a4e62b73085aa1

### 注意点
この記事の検証時点でのAKSのネットワークモデルは「kubenet」と「Azure CNI」の2つでしたが、それぞれ2024年6月頃に名称が変更になり技術要素も（微妙に）変わりました。それぞれ現在では「Azure CNIオーバーレイ」と「フラットネットワーク」という名前になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/b83d197e-b784-d1ce-20b5-8a6017f0a05a.png)

よって「kubenet」ネットワークモデルはレガシなモードとなりましたが、根本的な考え方は同じですし、Dockerとの比較という意味で検証内容自体は参考になると思いますので、以下に整理していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/8e4297e7-d2a5-fbb3-e99d-28cb3c18bdd7.png)

参考

https://learn.microsoft.com/ja-jp/azure/aks/concepts-network-cni-overview

# Kubernetesとは
- コンテナ化されたアプリケーションのデプロイメント、スケーリング、および管理を自動化するオープンソースのコンテナオーケストレーションプラットフォームです。以下、k8sと記載します。
- クラウドではサーバ機器や回線など物理的な要素が抽象化されていますが、kubernetesでは負荷分散やIaaSとしてのサーバ、ルーティングテーブルなどのコンポーネントが抽象化されています（ServiceやNode、Podなど）。
- AKSの裏ではAzure Load Balancer、仮想マシンスケールセット（VMSS）、OSのiptablesなどのコンポーネントが組み合わさってk8sの機能が実装されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/79035826-00fc-d3db-1289-80130522c66f.png)

詳しくは以下の以前の記事を参考にしてください。

https://qiita.com/maplejava/items/d56983a194c2448952c3

# AKSとは
AKSはフルマネージドKubernetesサービスです。AKSは、Kubernetesクラスタのデプロイ、管理、スケーリングを簡素化することを目的としています。

詳しくは以下の以前の記事を参考にしてください。

https://qiita.com/maplejava/items/f5e9ce8ba21afeb02d4b

# AKSにおけるネットワークモデル
AKSには2つのネットワークモデルがありました（先述の通り下記の画像は検証時点でのものです）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/e3af872a-8d24-0fc4-964d-489a91e57bae.png)

# kubenetとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/75598055-7733-6249-5490-2152c2aeac42.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/796c723a-7691-be13-5b3b-6b96f9713669.png)


上記の通り、NodeのサブネットとPodのサブネットが異なることがわかります。
図にすると以下のようなイメージ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/dac69cff-ff57-5b72-95b1-adbfa01b3797.png)

ポイント
1. 黄色部分はAKSによって作成される仮想ブリッジで、各Podのvethと接続されています。Pod間で通信するときは、このブリッジを使って通信を行います。コンテナ間ではvethは共有されているため、ローカルホストで通信できます。ちなみに、ブリッジの名前はデフォルトで「cbr0」です
2. Podごとに異なるネットワーク名前空間が割り当てられます。これにより、Pod間やPod‐Node間のネットワークを隔離しています
3. PodのサブネットとNodeのサブネットはレンジが異なります

ん…？ネットワーク構造もポイントも何かに似ていませんか？

そう、前回の記事で紹介した、Dockerのbridgeネットワークの構造とそっくりなのがkubenetネットワークモデルなのです！
Dockerのbridgeネットワーク構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/ee6d4313-3d1d-6da1-9468-577464902c8b.png)

DockerにおけるHostとコンテナが、AKSにおけるNodeとPodに対応しているようなイメージですね。
では、今回も本当にその通りになっているか検証してみましょう。

# 検証
AKSをkubenetネットワークモデルで作成します。
```
az aks create --name azfooaks01 --resource-group AZ-foo --node-count 2 --kubernetes-version 1.26.3 --node-vm-size Standard_DS2_v2 --generate-ssh-keys --service-principal $APP_ID --client-secret $SP_PWD 
```

※以前はデフォルトでkubenetネットワークモデルでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/8dc7b56f-f8d1-5156-92c3-930bdd8a88a6.png)

AKSは通常、Nodeの存在は隠ぺいされていますが、以下の記事を参考にすればNodeにログインすることができます。

https://qiita.com/maplejava/items/810a93d0b293eae1f2a0

色々と情報を取得すると以下のようになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/577ad069-9f22-ea15-d33a-888cc5deafb6.png)

1～3のポイントについて全てその通りになっていますね（Podのサブネットは10.244.2.XでNodeのサブネットは10.224.0.Xであり、分かりにくいですがレンジが異なっています）。

ここで疑問なのは、Dockerのbridgeネットワークにあった4つめの以下のポイントです。
- コンテナがホスト外と通信するときはブリッジを経由し、ホストのeth0でIPマスカレード（iptables）されます

kubenetネットワークでPodがNode外と通信するときはどのように通信が行われるのでしょうか？検証してみます。

# Node間通信
AKSを作成した時にNodeを2つ作るよう指定したので、もう片方のNodeを使って検証してみます。
左側のNodeのPod（busy-pb4p7）から右側のPod（busy-q7dn2）に対してpingコマンドを実行してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/f8acc5e1-00de-7c3b-f22f-ea07475fccbb.png)

busy-pb4p7のeth0でキャプチャすると、送信元IPアドレスはPodの名前解決名を表す「busy-pb4p7」となっているのでまだNATされていないですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/19c101b3-30e8-7e01-d6e9-4eab3256e75c.png)

Nodeのeth0でキャプチャすると、送信元IPアドレスは「busy-pb4p7」となっていて、**NATされていないことがわかります**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/94ed40b6-88c4-9cf7-0dfe-2c73ccd142dd.png)

送信先のPodのeth0でキャプチャしても同じく**NATされていません。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/b6bceae7-d2ac-840f-f427-3c13366ca093.png)

Dockerの時はNATされていましたが、kubenetではされていないようですね。

# 解決

MSLearnをよくよく見てみると、下記の通りNATされるのはAKSクラスター外との通信のみであり、AKSクラスター内の通信はNATされない仕様となっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/1585abad-f00a-faa7-43d1-0bf08ed85cec.png)

AKSクラスター内の通信はNATされるのではなく、AKSによって自動作成される**UDR**（Azureの”ルートテーブル”リソースのこと）に定義されたルートによって、IPフォワーディングされることで通信が成り立っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/7e5df3a3-ae8a-b984-9c8e-854fdaca65b1.png)

実際にkubenetネットワークのAKSを作成すると”mc_”から始めるリソースグループのUDRが自動的に作成されます（Azure CNIネットワークの場合は作成されない）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475719/c094617b-3c1e-614c-5056-036eb6c23718.png)
ルートを見てみると、宛先がPodのサブネット（10.244.x.x/24）であるトラフィックについて、対応するNodeのeth0（10.224.x.x/32）にホップするように定義されているのがわかります。

# まとめ
kubenetネットワークモデルにおける特徴をまとめると以下の通りとなります。

1. Node内にbridgeが作られる
2. PodごとにNW namespaceが異なる
3. PodのサブネットとNodeのサブネットは、レンジが異なる
4. AKSクラスター外の通信の場合、bridgeからNodeのeth0に転送されるときにNATされる
AKSクラスター内の通信の場合、UDRによってIPフォワーディングされる

次回はAzure CNIネットワークモデルについて深堀りします。