データプレーン@Istio アンビエント¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. アンビエントモードのデータプレーンの仕組み¶

アンビエントモードは、データプレーンとコントロールプレーンから構成される。データプレーンでは、各 Node の ztunnel と必要に応じて配置する waypoint-proxy を使用して、サービスメッシュを実装する。
マイクロサービスアーキテクチャ固有のインフラ領域の問題 (例:サービス検出の必要性、パケットのアプリケーションデータの暗号化、テレメトリー作成など) を解決する責務を持つ。
L7 トラフィック管理が必要な通信は、ztunnel Pod から waypoint-proxy Pod に中継される。L4 トラフィック管理のみの場合、waypoint-proxy Pod は経由しない。
サイドカーモードを将来的に廃止するということはなく、好きなほうを選べるようにするらしい。
ztunnel Pod 間、または ztunnel Pod と waypoint-proxy Pod の間では、HBONE トンネル内で L4/L7 トラフィックを送受信する。
ハードウェアリソース消費量の少ない L4 プロトコルと、消費量の多い L7 プロトコルでは処理の責務が分離されているため、サイドカーモードと比較して、L4 プロトコルのみを処理する場合、Node のハードウェアリソース消費量を節約できる。
Istio Ingress Gateway からサービスメッシュ内へのリクエストは、通常、宛先側の ztunnel に中継される。Namespace の istio.io/ingress-use-waypoint ラベルと Istiod の ENABLE_INGRESS_WAYPOINT_ROUTING を有効にした場合は、waypoint-proxy を経由する。waypoint-proxy を経由する場合の経路は以下の通りである。
パブリックネットワーク
⬇⬆️︎
Istio Ingress Gateway
⬇⬆️︎
⬇⬆️︎ # HBONE
⬇⬆️︎
# L7 ロードバランサー
waypoint-proxy Pod (L7) # Deployment 配下の Pod なので、任意の Node にいる
⬇⬆️︎
⬇⬆️︎ # HBONE
⬇⬆️︎
# L4 ロードバランサー
ztunnel Pod (L4) # DaemonSet 配下の Pod なので、Node ごとにいる
⬇⬆️︎
マイクロサービスのPod
サービスメッシュ内のリクエストの経路は以下の通りである。
マイクロサービスのPod # 送信元
⬇⬆️︎
# L4 ロードバランサー
ztunnel Pod (L4) # DaemonSet 配下の Pod なので、Node ごとにいる
⬇⬆️︎
⬇⬆️︎ # HBONE
⬇⬆️︎
# L7 ロードバランサー
waypoint-proxy Pod (L7) # Deployment 配下の Pod なので、任意の Node にいる
⬇⬆️︎
⬇⬆️︎ # HBONE
⬇⬆️︎
# L4 ロードバランサー
ztunnel Pod (L4) # DaemonSet 配下の Pod なので、Node ごとにいる
⬇⬆️︎
マイクロサービスのPod # 宛先
サービスメッシュ外へのリクエストの経路は以下の通りである。
パブリックネットワーク
⬆️⬇
# L7 ロードバランサー
waypoint-proxy Pod (L7) # Deployment 配下なので、任意の Node にいる
⬆️⬇
⬆️⬇ # HBONE
⬆️⬇
# L4 ロードバランサー
ztunnel Pod (L4) # DaemonSet 配下なので、Node ごとにいる
⬆️⬇
リダイレクト
⬆️⬇
マイクロサービスのPod
- Istio / Introducing Ambient Mesh
- Istio / Get Started with Istio Ambient Mesh
- istio/manifests/charts/istio-control/istio-discovery/files/waypoint.yaml at experimental-ambient · istio/istio · GitHub
- Istio's ambient mode - SoByte
- 译文:重磅消息 - Istio 引入 Ambient Mesh 模式 | 赵化冰的博客 | Zhaohuabing Blog
- Istio Ambient is not a "Node Proxy" | howardjohn's blog
02. データプレーンの要素¶
istio-cni¶
▼ istio-cni とは¶
実体は、DaemonSet として稼働する。
kube-system の Namespace におき、PriorityClass を system-node-critical とすることが推奨である。
istio-cni は、/var/run/ztunnel/ztunnel.sock ファイル経由で ztunnel から接続される。
そのため、istio-cni は ztunnel と同じ Node 上に作成する必要がある (Namespace は違っていてもよい) 。
▼ 仕組み¶
マイクロサービスの Pod 内の iptables のルーティングルールを書き換え、インバウンド通信とアウトバウンド通信を ztunnel へリダイレクトできるようにする。
また、ztunnel が受信ポートを公開するように、通知する。
注意点として、Cilium は iptable の代わりに eBPF を使用する。
- Istio Ambient Mesh の inpod redirection 試してみた | sreake.com | 株式会社スリーシェイク
- Traffic in ambient mesh: Istio CNI and node configuration | Solo.io
- RFC 8926: Geneve: Generic Network Virtualization Encapsulation
- https://www.reddit.com/r/kubernetes/comments/1cygujm/comment/l59qh64/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
▼ Google Cloud Mesh について¶
Google Cloud Mesh では、istio-cni のロジックが GKE に統合されており、istio-cni が存在しない。
代わりに、NEG などを使用する。
ztunnel¶
▼ ztunnel とは¶
サービスメッシュ内の L4 トラフィックを管理する。
実体は DaemonSet 配下の Pod であり、Node ごとにスケジューリングされている。
ztunnel Pod は、/var/run/ztunnel/ztunnel.sock ファイル経由で istio-cni に接続する。
そのため、ztunnel Pod は istio-cni と同じ Node 上に作成する必要がある (Namespace は違っていてもよい) 。
▼ 新しい仕組み (inpod redirection)¶
ztunnel へのリダイレクトの仕組みは一度リプレイスされている。
新しい仕組みでは、サイドカーパターンでマイクロサービスからの通信が istio-proxy にリダイレクトされるのと同じような仕組みになっている。

アウトバウンド通信の仕組みは以下の通りである。
- Pod 内マイクロサービスが
L4アウトバウンド通信を送信する。 - Pod 内 iptables が通信を ztunnel Pod にリダイレクトする。
- ztunnel Pod は通信を宛先に送信する。
一方で、インバウンド通信の仕組みは以下の通りである。
- Pod 宛ての
L4インバウンド通信が到着する。 - Pod 内 iptables が通信を ztunnel Pod にリダイレクトする。
- ztunnel Pod が Pod 内マイクロサービスへ
L4インバウンド通信を中継する。

▼ 古い仕組み¶
ztunnel へのリダイレクトの仕組みは一度リプレイスされている。
新しい仕組みは『inpod redirection』と呼ばれている。
waypoint-proxy¶
▼ waypoint-proxy とは¶
サービスメッシュ内の L7 トラフィックを管理する。
実体は、Gateway-API で作成された istio-proxy を含む Pod である。
$ istioctl experimental waypoint generate
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: foo
spec:
gatewayClassName: istio-waypoint
listeners:
- name: mesh
port: 15008
protocol: HBONE
apiVersion: v1
kind: Pod
metadata:
labels:
istio.io/waypoint-for: service
name: istio-waypoint
namespace: app
spec:
containers:
- args:
- proxy
- waypoint
- --domain
- $(POD_NAMESPACE).svc.cluster.local
- --serviceCluster
- istio-waypoint.$(POD_NAMESPACE)
- --proxyLogLevel
- warning
- --proxyComponentLogLevel
- misc:error
- --log_output_level
- default:info
env:
- name: ISTIO_META_SERVICE_ACCOUNT
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.serviceAccountName
- name: ISTIO_META_NODE_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.nodeName
- name: PILOT_CERT_PROVIDER
value: istiod
- name: CA_ADDR
value: istiod-1-24-2.istio-system.svc:15012
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: INSTANCE_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: SERVICE_ACCOUNT
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: spec.serviceAccountName
- name: HOST_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.hostIP
- name: ISTIO_CPU_LIMIT
valueFrom:
resourceFieldRef:
divisor: "0"
resource: limits.cpu
- name: PROXY_CONFIG
value: |
{"discoveryAddress":"istiod-1-24-2.istio-system.svc:15012","holdApplicationUntilProxyStarts":true}
- name: GOMEMLIMIT
valueFrom:
resourceFieldRef:
divisor: "0"
resource: limits.memory
- name: GOMAXPROCS
valueFrom:
resourceFieldRef:
divisor: "0"
resource: limits.cpu
- name: ISTIO_META_CLUSTER_ID
value: Kubernetes
- name: ISTIO_META_INTERCEPTION_MODE
value: REDIRECT
- name: ISTIO_META_WORKLOAD_NAME
value: istio-waypoint
- name: ISTIO_META_OWNER
value: kubernetes://apis/apps/v1/namespaces/app/deployments/istio-waypoint
- name: ISTIO_META_MESH_ID
value: cluster.local
image: docker.io/istio/proxyv2:1.24.2
imagePullPolicy: IfNotPresent
# istio-proxy
name: istio-proxy
ports:
- containerPort: 15020
name: metrics
protocol: TCP
- containerPort: 15021
name: status-port
protocol: TCP
- containerPort: 15090
name: http-envoy-prom
protocol: TCP
readinessProbe:
failureThreshold: 4
httpGet:
path: /healthz/ready
port: 15021
scheme: HTTP
periodSeconds: 15
successThreshold: 1
timeoutSeconds: 1
resources:
limits:
cpu: "2"
memory: 1Gi
requests:
cpu: 100m
memory: 128Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
readOnlyRootFilesystem: true
runAsGroup: 1337
runAsNonRoot: true
runAsUser: 1337
startupProbe:
failureThreshold: 30
httpGet:
path: /healthz/ready
port: 15021
scheme: HTTP
initialDelaySeconds: 1
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/workload-spiffe-uds
name: workload-socket
- mountPath: /var/run/secrets/istio
name: istiod-ca-cert
- mountPath: /var/lib/istio/data
name: istio-data
- mountPath: /etc/istio/proxy
name: istio-envoy
- mountPath: /var/run/secrets/tokens
name: istio-token
- mountPath: /etc/istio/pod
name: istio-podinfo
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-rttpm
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: foo-m06
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: istio-waypoint
serviceAccountName: istio-waypoint
terminationGracePeriodSeconds: 2
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- emptyDir: {}
name: workload-socket
- emptyDir:
medium: Memory
name: istio-envoy
- emptyDir:
medium: Memory
name: go-proxy-envoy
- emptyDir: {}
name: istio-data
- emptyDir: {}
name: go-proxy-data
- downwardAPI:
defaultMode: 420
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.labels
path: labels
- fieldRef:
apiVersion: v1
fieldPath: metadata.annotations
path: annotations
name: istio-podinfo
- name: istio-token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
audience: istio-ca
expirationSeconds: 43200
path: istio-token
- configMap:
defaultMode: 420
name: istio-ca-root-cert
name: istiod-ca-cert
- name: kube-api-access-rttpm
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
▼ 仕組み¶
送信元 ztunnel から L7 トラフィックを HBONE を経由して受信し、宛先側の ztunnel に中継する。
waypoint-proxy は、サービス検出により宛先情報を取得し、証明書を管理する。

▼ Namespace のリバースプロキシとして¶
waypoint-proxy は、Namespace のリバースプロキシである。
アウトバウンド通信には関与せず、宛先リバースプロキシとしてのみ機能する。
マイクロサービス Pod がいる Namespace 単位で waypoint-proxy を作成するとよい。

03. 各機能の仕組み¶
分散トレース¶
アンビエントメッシュでは、waypoint-proxy Pod がスパンを作成する。
送信元からリクエストを受信した waypoint-proxy Pod は、宛先へのリクエスト送信からレスポンス受信までの処理時間を計測する。
waypoint-proxy Pod 上で記録したタイムスタンプを集計し、A-C (トレースに相当) 、A-B (スパンに相当) 、B-C (スパンに相当) の処理時間を計測する。
サイドカーモードとアンビエントモードでも、マイクロサービスから最初のプロキシまでの通信時間を計測できない問題はある。
ただし、サイドカーモードの「送信元マイクロサービスコンテナ ⇄ 送信元 istio-proxy」とアンビエントモードの「送信元マイクロサービスの Pod ⇄ waypoint-proxy Pod」を比較して、サイドカーモードのほうが通信時間の欠損が無視できるほど短く、より適していると言えそう。
マイクロサービスAのPod
⬇⬆︎
ztunnel (L4)
⬇⬆︎
⬇⬆︎ # HBONE
⬇⬆︎
waypoint-proxy Pod (L7) # タイムスタンプ
⬇⬆︎
⬇⬆︎ # HBONE
⬇⬆︎
ztunnel (L4)
⬇⬆︎
マイクロサービスBのPod
⬇⬆︎
ztunnel (L4)
⬇⬆︎
⬇⬆︎ # HBONE
⬇⬆︎
waypoint-proxy (L7) # タイムスタンプ
⬇⬆︎
⬇⬆︎ # HBONE
⬇⬆︎
ztunnel (L4)
⬇⬆︎
マイクロサービスCのPod