はじめに
この記事ではIstioでサービスメッシュを実現する新たな仕組みである、Ambient Meshについて調べた内容を書いてみたいと思います。
Istioとは
Istioはオープンソースのサービスメッシュです。
Istioを利用することで、カナリアリリースなどの高度なルーティングやリクエストの再試行、フェイルオーバー、フォルトインジェクションによりトラフィックを細かく制御することが可能となります。
Istioにはその他にも多くの機能がありますので、詳細についてはIstioのドキュメントなどを参考としてください。
Kubernetes環境でIstioを利用する場合、各PodにサイドカーとしてEnvoy Proxyを実行し、トラフィックがサイドカーのEnvoy Proxyを経由することでサービスメッシュを構成します。
下記はIstioのブログから引用した図ですが、構成のイメージとしては下記です。
参考:https://istio.io/latest/blog/2022/introducing-ambient-mesh/
サイドカーのEnvoy Proxyを利用することで、アプリケーションを変更せずともサービスメッシュを導入することが可能です。
サイドカーパターンによる問題
サイドカーとしてEnvoy Proxyを利用することで、アプリケーションを変更せずともサービスメッシュを導入することが可能ではありますが、これによりいくつかの制限が発生するとのことです。
- サイドカーとしてEnvoy Proxyを注入する必要があるため、サイドカーのインストールやバージョンアップ時にアプリケーションのPodの再起動が必要となる。
- サイドカーは関連するワークロード専用であるため、それぞれのPodが利用する可能性のある量のCPU とメモリ リソースをプロビジョニングする必要がある。それによりクラスター全体でリソースが効率的に利用されない可能性がある。
- Istioのサイドカーで通常行われるトラフィックキャプチャとHTTP処理は、計算量が多く、HTTPの実装に準拠していない一部のアプリケーションを壊す可能性がある。
サイドカーには良い点があるものの、多くのサービスメッシュユーザーにとって、より負担の少ない、より簡単なオプションが必要であるとのことで、Ambient Meshという方法が考えられたようです。
Ambient Mesh について
Ambient Meshは上記のサイドカーを利用したパターンとは異なるアプローチを取っています。
Istioの機能を下記のように2つのレイヤーに分割し、Secure overlay Layer に記載されている機能は、各ワーカーノードで起動する共有のエージェント(ztunnel エージェント)が担当し、L7 Processing Layerの機能はwaypoint proxyというコンポーネントが担当する構成となります。
参考:https://istio.io/latest/blog/2022/introducing-ambient-mesh/#slicing-the-layers
Secure Overlay Layer
上記の Secure Overlay Layer に記載された Ambient Mesh の機能を Kubernetesで利用する場合、ztunnelをDaemonSetとしてデプロイすることで、各ワーカーノードでPodを1つ起動する構成とします。
構成のイメージとしては下記です。
参考: https://istio.io/latest/blog/2022/introducing-ambient-mesh/#building-an-ambient-mesh
L7 Processing Layer
L7 の機能を利用する場合、Ambient Mesh は Envoy ベースの waypoint proxy を経由する構成となります。
構成のイメージは下記です。
参考: https://istio.io/latest/blog/2022/introducing-ambient-mesh/#building-an-ambient-mesh
L7 の処理を必要とする場合、ztunnel 間の通信は、上記のように waypoint proxy を経由する構成となります。
Kubernetes 環境で利用する場合、waypoint proxy は通常のアプリケーションの Pod のように Deployment を利用して複数起動実行します。
トラフィックの量に応じて waypoint proxy の Pod をスケールアウトすることができますので、サイドカーとして Envoy を利用する場合よりも、リソースを効率良く利用できることが期待されます。
試してみる
実際に Ambient Mesh を試してみたいと思います。
下記のような設定ファイルをもとに kind を利用してローカルの環境で Kubernetes クラスターを作成します。
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: ambient
nodes:
- role: control-plane
- role: worker
- role: worker
Kubernetes クラスターを作成します。
$ kind create cluster --config=cluster.yaml
こちらのページ から ambient mesh をサポートしているプレビューバージョンの istioctl をダウンロードします。
ダウンロードした istioctl を利用して、作成した Kubernetes クラスターに istio をインストールします。
./istioctl install --set profile=ambient
インストールが完了すると、下記のコマンドで Istiod、ingress gateway、ztunnel、CNI plugin などが起動していることを確認できるかと思います。
$ kubectl get pod -n istio-system
istio をインストールしたクラスターに bookinfo アプリケーションをデプロイします。
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/bookinfo/platform/kube/bookinfo.yaml
上記のアプリケーションにアクセスするための Client 側のアプリケーションをデプロイします。
$ kubectl apply -f https://raw.githubusercontent.com/linsun/sample-apps/main/sleep/sleep.yaml
istio の Authorization Policy の機能を利用してアクセスの制限を試してみます。
下記のようなマニフェストファイルを作成します。
下記の例の場合、app: productpage ラベルが設定されたワークロードへのアクセスを制限します。
合わせて rules の設定により、sleep サービスアカウントからのアクセスを許可しています。
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: productpage-viewer
namespace: default
spec:
selector:
matchLabels:
app: productpage
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/sleep"]
上記のマニフェストをファイルを apply します。
$ kubectl apply -f authorization-policy.yaml
先ほどデプロイした Client の Pod からアクセスを試してみます。
Client の Pod は sleep サービスアカウントが設定されているため、アクセスすることが可能です。
$ kubectl describe deployment sleep
Name: sleep
Namespace: default
CreationTimestamp: Sun, 25 Dec 2022 15:55:40 +0900
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=sleep
Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=sleep
Service Account: sleep
Containers:
sleep:
Image: curlimages/curl
(略)
$ kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | head -n1
異なるサービスアカウントが設定された Pod からはアクセスができないことが確認できます。
$ kubectl apply -f https://raw.githubusercontent.com/linsun/sample-apps/main/sleep/notsleep.yaml
$ kubectl exec deploy/notsleep -- curl -s http://productpage:9080/ | head -n1
次に L7 の Authorization Policy の機能を試してみます。
上記の機能を利用するには waypoint proxy が必要となるため、下記のマニフェストをデプロイします。
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: productpage
annotations:
istio.io/service-account: bookinfo-productpage
spec:
gatewayClassName: istio-mesh
$ kubectl apply -f waypoint-proxy.yaml
私の環境の場合、下記のように bookinfo-productpage-waypoint-proxy-6f88c55d59-h26qt
という Pod が起動します。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
bookinfo-productpage-waypoint-proxy-6f88c55d59-h26qt 1/1 Running 0 142m
(略)
AuthorizationPolicy のマニフェストファイルを下記のように修正して apply します。
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: productpage-viewer
namespace: default
spec:
selector:
matchLabels:
app: productpage
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/sleep"]
to:
- operation:
methods: ["GET"]
GET メソッドのアクセスだけが許可されているため、sleep サービスアカウントが設定されている Pod からのアクセスであっても GET メソッド以外のアクセスは失敗することが確認できるかと思います。
$ kubectl exec deploy/sleep -- curl -s http://productpage:9080/ -X DELETE | head -n1
$ kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | head -n1
さいごに
確認が完了して、検証用の Kubernetes クラスタが不要になりましたら下記のコマンドでクラスタを削除してください。
$ kind delete cluster --name ambient
まとめ
簡単に試してみただけの内容となってしまいましたが、Ambient Mesh について調べた内容を書いてみました。
今回は動作の詳細などについては踏み込んで調査できませんでしたが、今後、機会があればより詳細について調査してみたいと思います。