先日、KongのAPI Gatewayを触っていた時に、Kongが開発しているService MeshのKumaがあることを知った。
機能を見るとTanzu Service Mesh(以下TSM)のGlobal Namespaceのように全体を俯瞰するControlPlaneを置いてクラスタ間通信を制御するようでちょっと気になったので、触ってみた時のメモ。
Kumaとは
KumaはKongが中心となって開発されているService MeshのOSSで、CNCFのSandbox Projectにもなっている。
2022/5のCNCFの調査で「利用中、もしくは予定しているService Mesh製品は何か?」というアンケートではKumaの名前がなかったので、Service Mesh製品としてはマイナーな部類に入る。
アーキテクチャとしては以下のように複数のKubernetes/VMクラスタを跨いだマルチゾーン展開が出来、全体を見るControlPlaneが存在するようで、これがTanzu Service Meshにちょっと似ている。
(Overview of Kumaより引用)
なおKumaではKubernetesにMeshを導入するKubernetes Modeと、非Kubernetes環境でもMeshを実現するUniversal Modeが用意されており、どちらの環境でもMeshが利用できるようになっている。
また、各ゾーン内のMeshはControlPlaneとDataPlaneで構成されていて、DataplaneにはEnvoyが利用されている。
(Architectureより引用)
一般的なService MeshのSidecarパターンと同じと考えるとよさそう。
検証
事前準備
以下を用意して検証した。
- K8sクラスタ3台(1台はGlobal ControlPlane用、2台はZone用)
ちなみに最初はVMも含めた構成でUniversal Modeも検証しようとしたのだが、検証を進めた結果、どうもDataPlaneごとにVMが必要っぽいように見えて用意するのが大変なので断念した。
インストール
Deploy a multi-zone global control planeを参考にインストールを進めていく。
やりたいのは以下の構成となる。
Global ControlPlaneの構築
まずKubernetes上にGlobal ControlPlaneを構築する。
インストール方法は独自のCLIであるkumactlを使った方法と、Helmによるインストール方法が用意されているが、ここでは慣れたHelmで進める。
インストール時、controlPlane.mode
でglobal
を指定することで、Global ControlPlaneとしてKumaをデプロイ出来る。
Global ControlPlaneのUIに頻繁にアクセスするため、ここではServiceをtype: LoadBalancer
で公開してデプロイした。
helm repo add kuma https://kumahq.github.io/charts
helm upgrade -i --create-namespace --namespace kuma-system \
--set "controlPlane.mode=global" \
--set "controlPlane.service.type=LoadBalancer" \
kuma kuma/kuma
インストールが成功すると、ControlPlaneが展開される。
$ kubectl get pod -n kuma-system
NAME READY STATUS RESTARTS AGE
pod/kuma-control-plane-679574bbb-zk98x 1/1 Running 0 12s
ModeをGlobalにした場合にStandalone Modeと異なるのは、Serviceにkuma-global-zone-sync
が作成され、External-IPでIPが公開される点である。
このIPを別のクラスタ上にKuma ControlPlaneを展開する際にcontrolPlane.kdsGlobalAddress=<IP:5686>
で指定して、Global ControlPlaneと繋いでいく。
なお、通常DataPlaneはPodかNamespaceにkuma.io/sidecar-injection: enabled
というラベルを付与するとサイドカーとして自動的に付加されるが、Global ControlPlaneで展開したクラスタではkuma.io/sidecar-injection: enabled
をつけてもDataPlaneは展開されず、ControlPlane専用で動くようになっている。
マルチゾーン(クラスタ間通信)を利用するにはmTLSが必須なため、Global ControlPlaneのデプロイ後、以下を実行してdefaultのMesh設定を変更してmTLSを有効化する。
cat << EOF | kubectl apply -f -
apiVersion: kuma.io/v1alpha1
kind: Mesh
metadata:
name: default
spec:
routing:
zoneEgress: true
mtls:
enabledBackend: ca-1
backends:
- name: ca-1
type: builtin
dpCert:
rotation:
expiration: 1d
conf:
caCert:
RSAbits: 2048
expiration: 10y
EOF
K8s ZoneのControlPlaneの構築
Global ControlPlaneが提供するkuma-global-zone-sync
が公開しているIPを指定して、HelmでKubernetesクラスタに展開する。
GLOBAL_IP="10.220.35.73"
ZONE_NAME="tkgs-cluster-2"
helm install --create-namespace --namespace kuma-system \
--set "controlPlane.mode=zone" \
--set "controlPlane.zone=$ZONE_NAME" \
--set "ingress.enabled=true" \
--set "controlPlane.kdsGlobalAddress=grpcs://${GLOBAL_IP}:5685" \
--set "controlPlane.tls.kdsZoneClient.skipVerify=true" \
kuma kuma/kuma
Ingressを有効にすることで、type: LoadBalancer
でkuma-ingress
というServiceが作成され、外部から接続可能となる。
$ kubectl get svc -n kuma-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kuma-control-plane ClusterIP 10.97.3.51 <none> 5680/TCP,5681/TCP,5682/TCP,443/TCP,5676/TCP,5678/TCP 2d6h
kuma-ingress LoadBalancer 10.103.209.149 10.220.35.74 10001:30597/TCP 2d6h
なお、ModeをZoneにしているため、こちらではNamespaceかPodのラベルにkuma.io/sidecar-injection: enabled
があればDataPlaneがサイドカーとしてInjectされるので試してみる。
以下のサンプルのManifestを動かしてみる。
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
kuma.io/sidecar-injection: enabled
spec:
containers:
- image: nginx
name: nginx
EOF
確認する。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-67c9776b8b-bvqhs 2/2 Running 0 13s
コンテナ数が2となっており、サイドカー入りのPodが作成されることが確認できた。
次にもう1つのZone用クラスタにコンテキストを切り替え、同じように展開する。
なお、こちらでは動作確認用にEgressを有効にし、こちらのクラスタから先程のクラスタへの通信が行えるようにする。
ZONE_NAME="tkgs-cluster-3"
helm upgrade -i --create-namespace --namespace kuma-system \
--set "controlPlane.mode=zone" \
--set "controlPlane.zone=$ZONE_NAME" \
--set "ingress.enabled=true" \
--set "egress.enabled=true" \
--set "controlPlane.kdsGlobalAddress=grpcs://${GLOBAL_IP}:5685" \
--set "controlPlane.tls.kdsZoneClient.skipVerify=true" \
kuma kuma/kuma
展開後、Global ControlPlaneのServicekuma-control-plane
の5681ポートにブラウザで接続すると、それぞれのクラスタが確認できる。
動作確認
マルチゾーンでの通信確認のため、最初のK8sのZoneで立ち上げたnginxに対し、2番目のZoneから通信する。
最初のZoneのnginxのServiceを作成する。
kubectl expose deploy nginx --port 80
次に2番めのZoneでアクセス元となるPodを起動する。mTLSで通信しないと接続できないため、アクセス元の方もサイドカーをInjectionするようにラベルにkuma.io/sidecar-injection: enabled
を設定して起動する。
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: centos
name: centos
spec:
replicas: 1
selector:
matchLabels:
app: centos
template:
metadata:
labels:
app: centos
kuma.io/sidecar-injection: enabled
spec:
containers:
- command:
- sleep
- infinity
image: centos
name: centos
EOF
Podが起動したら、早速アクセスする。
アクセス先についてはkind: ServiceInsight
というリソースを確認することで確認できる。
$ kubectl get serviceinsight -o yaml all-services-default
apiVersion: kuma.io/v1alpha1
kind: ServiceInsight
mesh: default
:(省略)
nginx_default_svc_80:
dataplanes:
online: 1
issuedBackends:
ca-1: 1
status: online
ここだとnginx_default_svc_80
がアクセス先となる。
これに.mesh
をつけて、対応ポートを指定すればアクセスできる。
$ kubectl exec -it centos-6d7594d4c9-445rl -- curl nginx_default_svc_80.mesh:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
クラスタを跨いでアクセスすることが出来た。
なお、アクセス先はUIからも確認できる。
なお、メトリクスに関しては別途Prometheusなどをインストールする必要がある。
kumactlを使うことでKuma向けに設定されたPrometheus、Jaeger、Loki、Grafanaが簡単にインストール出来るようになっている。
kumactl install observability | kubectl apply -f -
ただ、インストールするだけではメトリクスが見えず、この辺などの設定を入れてメトリクスを公開する必要がある模様。
今回は時間の都合上断念した。
感想
簡単にクラスタ跨ぎのService Meshが作成でき、かつUIが最初から提供され、各クラスタの状態が確認できるのは便利だった。
一方で、TSMに慣れてるとそれでも導入が少し面倒と感じたり、UIもKialiみたいなネットワークトポロジーを表示する機能はなく、ダッシュボードも別途用意する必要がある点ではOOTBなTSMが流石だなと感じた。
Istioの面倒さとTSMの簡単さの中間にあるService Meshというところだろうか。
OSSとしては十分良かったので、お金を掛けず楽してService Meshを使いたい人は選択肢としてあっていいと思う。