この記事は MicroAd Advent Calendar 2023 と Kubernetes Advent Calendar 2023 の5日目の記事です。
オンプレあるあるな悩みとして、データセンターと外の通信にはインターネットを経由する都合、1つのアプリで契約している帯域を専有してしまいインターネット通信が輻輳1 (ふくそう)し、他のシステムの本番環境に影響させてしまう事があったりします。
今回は、RKE22 で構築したKubernetesノードにて、Pod発の通信に対して帯域制限をかける方法について紹介します。
- 環境
- 種明かし
- 利用できるか確認する
- Nodeのセットアップ
- CiliumのBandwidth Managerが有効になっているか確認
- Podに帯域制限をかけるには?
- 実際に試してみてる
- 最後に
- おまけ
環境
- Kubernetes: RKE2 v1.23.17+rke2r1 ※Kubernetes v1.23以降なら大丈夫
- CNI:RKE2標準の Cilium L2モード
- OS: Ubuntu 20.04 LTS ※Linux Kernel v5.1.x 以降ならOK
- Rancher: v2.6.8以降 ※無くてもOK
種明かし
帯域制限については、以下のCiliumのBandwidth Managerを使います。これはeBPFを使用して個々のPodの帯域を制限します。
これを有効にすると、マニフェストに特定のアノテーションを追加するだけで、指定の帯域を上限として制限がかけられる優れものです。 ただ、残念ながら、Pod発の通信のみで、Pod着の通信については対象外です。
詳しい話は上記のドキュメントでも紹介されてますが、 KubeCon + CloudNativeCon North America 2022 の動画が課題感といった背景や仕組みについて話されているので面白いです。
利用できるか確認する
CiliumのBandwidth Managerは、Linux Kernel v5.1.x 以降ならOKです。 以下のようにして、Kernelのバージョンを確認して、v5.1以降なら利用できるはずです。
$ uname -r 5.4.0-164-generic
念のため、Base Requirements 及び Requirements for the Bandwidth Manager で挙げられているカーネルオプションが有効になっているかを確認します。値がn
でなければ大丈夫です3 。
$ cat /boot/config-`uname -r` | grep -E '\b(CONFIG_BPF|CONFIG_BPF_SYSCALL|CONFIG_NET_CLS_BPF|CONFIG_BPF_JIT|CONFIG_NET_CLS_ACT|CONFIG_NET_SCH_INGRESS|CONFIG_CRYPTO_SHA1|CONFIG_CRYPTO_USER_API_HASH|CONFIG_CGROUPS|CONFIG_CGROUP_BPF|CONFIG_PERF_EVENTS|CONFIG_SCHEDSTATS|CONFIG_NET_SCH_FQ)\b' CONFIG_CGROUPS=y CONFIG_CGROUP_BPF=y CONFIG_BPF=y CONFIG_BPF_SYSCALL=y CONFIG_PERF_EVENTS=y CONFIG_NET_SCH_FQ=m CONFIG_NET_SCH_INGRESS=m CONFIG_NET_CLS_BPF=m CONFIG_NET_CLS_ACT=y CONFIG_BPF_JIT=y CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_USER_API_HASH=m CONFIG_SCHEDSTATS=y
これで利用出来るか確認出来たので、次に、実際にCiliumのBandwidth Managerを有効にします。
Nodeのセットアップ
今回は、RKE2に対して有効にしてきます。
RKE2のみの場合
RKE2周りのセットアップについては、去年のアドカレの記事をどうぞ。
補足: ↑に書いてないことといえば、HTTP Proxyが関係するなら、ここ も必要です。
ただし、今回はデフォルトの設定だけではBandwidth Managerを有効に出来ません。
そこで、rke2-serverを起動する前に、 /etc/rancher/rke2/config.yaml
に追加して、 /var/lib/rancher/rke2/server/manifests/rke2-cilium-config.yaml
を作成して、以下のように記述します。
# /var/lib/rancher/rke2/server/manifests/rke2-cilium-config.yaml --- apiVersion: helm.cattle.io/v1 kind: HelmChartConfig metadata: name: rke2-cilium namespace: kube-system spec: valuesContent: |- bandwidthManager: enabled: true
上記を記述したら、 systemctl enable --now rke2-server.service
してRKE2を起動してください。
CNIのデフォルト設定の変更については以下を参考にしてください。
Rancherを使ってクラスターをCreateする場合
Downstream User Cluster をCreateする際に、下図のように、Add-On-ConfigにてbandwidthManager.enabled
をfalse
→true
にしてからCreateしてください。
CiliumのBandwidth Managerが有効になっているか確認
以下の様にして確認します。
$ kubectl -n kube-system exec ds/cilium -- cilium status | grep BandwidthManager BandwidthManager: EDT with BPF [CUBIC] [eth0]
また、有効になっていない場合は以下のようになるので、この場合はセットアップを見直してください。
$ kubectl -n kube-system exec ds/cilium -c cilium-agent -- cilium status | grep BandwidthManager BandwidthManager: Disabled
Podに帯域制限をかけるには?
帯域制限をかける場合は、アノテーションを以下のように付与します。
--- apiVersion: v1 kind: Pod metadata: annotations: # Pod発の通信に対して 10Mbit/s の上限を用いたい場合 kubernetes.io/egress-bandwidth: "10M"
実際に試してみてる
Ciliumのドキュメントにあるサンプルを使って実践してみます。
💡注意点としては、このサンプルは2ノード必要です。
以下を適当なファイルに保存して、applyします。
--- apiVersion: v1 kind: Pod metadata: annotations: # Limits egress bandwidth to 10Mbit/s. kubernetes.io/egress-bandwidth: "10M" labels: # This pod will act as server. app.kubernetes.io/name: netperf-server name: netperf-server spec: containers: - name: netperf image: cilium/netperf ports: - containerPort: 12865 --- apiVersion: v1 kind: Pod metadata: # This Pod will act as client. name: netperf-client spec: affinity: # Prevents the client from being scheduled to the # same node as the server. podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: - netperf-server topologyKey: kubernetes.io/hostname containers: - name: netperf args: - sleep - infinity image: cilium/netperf
applyしたら、以下を実行すると、Throughput が10Mbit/sを下回らないことが分かります。
$ NETPERF_SERVER_IP=$(kubectl get pod netperf-server -o jsonpath='{.status.podIP}') $ kubectl exec netperf-client -- \ > netperf -t TCP_MAERTS -H "${NETPERF_SERVER_IP}" MIGRATED TCP MAERTS TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.18.3.247 (172.18.) port 0 AF_INET Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 65536 65536 10.00 9.54
ちなみにアノテーションなしの場合は以下のように、Throughput が10Mbit/sを簡単に超えます。
$ NETPERF_SERVER_IP=$(kubectl get pod netperf-server -o jsonpath='{.status.podIP}') $ kubectl exec netperf-client -- netperf -t TCP_MAERTS -H "${NETPERF_SERVER_IP}" MIGRATED TCP MAERTS TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.18.3.163 (172.18.) port 0 AF_INET Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 65536 65536 10.00 906.00
最後に
いかがだったでしょうか。 他にも方法があったり改善点があれば是非コメントください。
以上、MicroAd Advent Calendar 2023 と Kubernetes Advent Calendar 2023 の5日目の記事でした。
さーて、明日、6日目の記事は、、、
MicroAd Advent Calendar 2023 は、PolarsのSQLで何ができるかをまとめる話。
そして、Kubernetes Advent Calendar 2023 は、AlloyDB Omni on Kuberentesのオペレーターを眺める話。
どちらも楽しみですね!
おまけ
以下の運営やってます。近々Rancher v2.8も出るので2024年の早めにはMeetupをやりたいと考えてます(オフサイトでやりたいなぁ、、会場、、、) ただ、コロナ前の様にもっとMeetupを開催したいのですが、アクティブに動ける運営が少ないので、興味ある方は @yassan168 までDMください!
- 「輻輳」とは、ネットワークトラフィックが集中して、通信速度が低下すること↩
- docs.rke2.io↩
- What does m mean in kernel configuration file? - Stack Overflow↩