Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

GKEでIstio Ambient Meshを導入・活用する方法

By Alfred TommyMar 19, 20248 min read

このページはEnglishDeutschEspañolFrançaisItalianoPortuguêsでもご覧いただけます。

本記事は、Istio Ambient Meshに対する筆者の見解と、従来のサイドカー型データプレーンモデルとの比較を述べた前回のブログ記事の続編です。

今回は、Google Cloud Platform上に構築したGoogle Kubernetes Engineクラスターに、Istio Ambient Meshを導入して活用する手順を解説します。

注:Istio Ambient Meshは現在アルファ版です。一般提供(GA)に到達するまでは本番環境での利用は避けてください。

前提条件

  • クラスターはサポート対象バージョンのKubernetes(1.25、1.26、1.27、1.28、1.29)で稼働している必要があります。
  • クラスターでCNI(Container Network Interface)が有効化されている必要があります。GKEクラスターではGKE CNIがデフォルトで有効化されています。Dataplane v2は現在サポートされていません。
  • 最低3ノード、各ノードに4vCPU以上が必要です。各z-tunnelは500mCPUと2Giのメモリを予約しますが、これは他のコンポーネントを含まない値のため、十分なvCPUとメモリを確保しておくことを推奨します。
  • プラットフォームの前提条件
  • GKE固有の前提条件

注:GKE AutopilotクラスターではDataplane v2を無効化できないため、本手順は動作しません。ただし NET_ADMINおよびNET_RAW capabilityの有効化 は可能です。

重要:DataPlane v2との互換性問題

Istio Ambient Meshには、Istio CNIプラグインのインストールが必須です。このプラグインは、istio-initコンテナ(NET_ADMIN およびNET_RAW capabilityを必要とする)の役割を引き継ぎ、デプロイを行うユーザーに特権コンテナをプロビジョニングするための高い権限を持つRBACを付与しなくても利用できるようにします。

Istio CNIのドキュメントには次のような注意書きがあります。

注:Istio CNIプラグインはチェーン型CNIプラグインとして動作し、PTPCalicoなどの他のCNIプラグインと組み合わせて使うように設計されています。詳細は他のCNIプラグインとの互換性を参照してください。

ここから話が少しややこしくなります。従来のGKEデータプレーン(現在のデフォルト)はGKE CNI(ネットワークポリシーが有効な場合はCalico CNI)を採用し、kube-proxyとiptablesを使ってクラスター内のトラフィックをルーティングします。

一方、比較的新しいGKE Data Plane v2(将来的にデフォルトかつデファクトスタンダードとなる予定)は、本質的にはCilium CNIのマネージド版で、kube-proxyを最新のeBPFプログラムに置き換えたeBPFデータプレーンにより、より高度なネットワーキングを実現します。

Solo.ioによるこちらの記事では、Istioを壊さずにCilium CNIを構成する方法が解説されています。ただし、これはあくまでIstioのサイドカーモデルに対する手法であり、Dataplane V2はGCPのマネージドコンポーネントで設定変更ができないため、いずれにせよ適用できません。

DataPlane V2もvethデバイスを利用してはいるものの、おそらくeBPFプログラム同士に互換性がないのだと思われます。理由をご存じの方は、ぜひコメントで教えてください。

そのため、Istio CNIコンポーネントを正常にインストールするには、構成上Dataplane v2を無効化する必要があります。

Dataplane v2は近い将来GKEクラスターのデフォルトとなる見込みのため、いずれサポートされることを期待しています。

クラスターのセットアップ

本例では、プライベートノードとパブリックなマスターエンドポイントを備えたシンプルなGKEクラスターを作成します。

以下は、デフォルトのVPCネットワークにクラスターをデプロイするためのコマンドです。変数は自由に調整して構いませんが、Dataplane v2が無効化されていることは必ず確認してください。

本番環境で活用する場合は、ノードあたりのPod数を多く確保できる大きめのノードを使うとより効果的です。

export PROJECT_ID=`gcloud config get-value project` && \
export M_TYPE=e2-standard-4 && \
export ZONE=us-central1-a && \
export CLUSTER_NAME=ambient-mesh-cluster && \
gcloud services enable container.googleapis.com && \
gcloud container clusters create $CLUSTER_NAME \
--project $PROJECT_ID \
--cluster-version "latest" \
--release-channel "regular" \
--location $ZONE \
--machine-type $M_TYPE \
--image-type "COS_CONTAINERD" \
--num-nodes "3" \
--enable-private-nodes \
--master-ipv4-cidr "172.16.0.0/28" \
--enable-ip-alias \
--no-enable-master-authorized-networks \
--network "projects/$PROJECT_ID/global/networks/default" \
--subnetwork "projects/$PROJECT_ID/regions/us-central1/subnetworks/default"

クラスターが作成されると、コントロールプレーンのマスターがノードと通信できるよう、GCPが自動的にファイアウォールルールを作成してくれます。

TCPポート443(HTTPS)と10250(Kubelet)は許可されていることが分かりますが、このルールではPilot(Istioコントロールプレーンのコンポーネント)のディスカバリ検証Webhookが必要とするポート15017は開放されていません。

プライベートGKEクラスターを使う場合(本例もこれに該当)は、ポート15017でマスターからのトラフィックを許可するファイアウォールルールを追加で作成する必要があります。まずはマスターのソースIPレンジと、ファイアウォールルールのネットワークタグを取得します。

gcloud compute firewall-rules list --filter="name~gke-${CLUSTER_NAME}-[0-9a-z]*-master" --format="table(targetTags, sourceRanges.list())"

続いて、上記コマンドの出力で得たソースIPレンジとネットワークタグを使い、TCPポート15017でマスターからのトラフィックを許可する新しいファイアウォールルールを作成します。

gcloud compute firewall-rules create <firewall-rule-name> --network <VPC-name> --source-ranges=<CIDR_RANGE> --direction=INGRESS --target-tags=<TAG> --allow tcp:15017

また、プライベートGKEノード上のPodがインターネットにアクセスできるよう、クラスターをデプロイしたVPCにCloud NATが構成されていることも確認しておいてください。

IstioをAmbientモードでダウンロード・インストールする

最新版のIstioをダウンロードします。

curl -L https://istio.io/downloadIstio | sh -

Istioのディレクトリに移動し、IstioctlクライアントをPATHに追加します。

cd istio-1.20.3/
export PATH=$PWD/bin:$PATH

GKEクラスターに認証・接続します(クラスターへの接続およびデプロイに必要なIAM権限があることを事前に確認してください)。

gcloud container clusters get-credentials ${CLUSTER_NAME} --zone ${ZONE} --project ${PROJECT_ID}

Kubernetes Gateway CRDをインストールします。

$ kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
  { kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd/experimental?ref=v1.0.0" | kubectl apply -f -; }

Istioをambientモードでインストールします。

istioctl install --set profile=ambient --set "components.ingressGateways[0].enabled=true" --set "components.ingressGateways[0].name=istio-ingressgateway" --skip-confirmation

以下5つのコンポーネント、特にCNIとz-tunnelが正常にインストールされていることが確認できるはずです。

istio-system名前空間のPodおよびDaemonSetを確認し、各コンポーネントがインストールされ、稼働可能な状態になっていることをチェックします。

kubectl get pod -n istio-system

kubectl get ds -n istio-system

kubectl get ds -n kube-system

Istio Ambient Meshへのアプリケーションのデプロイ

Istioの優れた点の1つは、アプリケーション側に手を加える必要がないことです。ここでは定番のサンプルであるIstioのbookinfoアプリをそのままデプロイし、デプロイ後にメッシュへ追加していきます。

bookinfoアプリのコードは、Istioをインストールしたディレクトリと同じ場所にあります。

kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

次に、メッシュ環境へのトラフィックをシミュレートするためのアプリケーション(curlクライアント)をさらに2つデプロイします。

kubectl apply -f samples/sleep/sleep.yaml
kubectl apply -f samples/sleep/notsleep.yaml

インターネットからBookinfoアプリにアクセスできるよう、Ingressゲートウェイをデプロイします。

kubectl apply -export GATEWAY_HOST=$(kubectl get service/istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}' -n istio-system)l

istio-ingressgatewayサービスの内部および外部のエンドポイントを取得します。両方のエンドポイントにトラフィックを送ることで、メッシュ内部のトラフィックとクラスター外部からのトラフィックの双方を確認できます。

export GATEWAY_HOST_EXT=$(kubectl get service/istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}' -n istio-system)
export GATEWAY_HOST_INT=istio-ingressgateway.istio-system

ブラウザから表示した場合の様子

メッシュの動作を確認する

トラフィックの監視と可視化を行うため、PrometheusとKialiのサンプル構成をそれぞれデプロイします。

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/prometheus.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/kiali.yaml

ブラウザから閲覧できるよう、Kialiのサービス定義を変更してインターネットに公開します。

kubectl patch svc kiali -n istio-system -p '{"spec": {"type": "LoadBalancer"}}'

Kialiサービスに外部IPが割り当てられたら、ブラウザからアクセスしてみましょう。現時点ではアプリケーションがまだメッシュに含まれていないため、表示されるデータはごく限定的です。

default名前空間にラベルを付与することで、その中のBookinfoアプリケーションをAmbient Meshへ追加します。

kubectl label namespace default istio.io/dataplane-mode=ambient

これで、アプリケーションは無停止のままシームレスにメッシュの一部となりました。それでは、curlクライアントから各アプリケーションにトラフィックを送って、メッシュの動作を確認してみましょう。

curl http://$GATEWAY_HOST_EXT/productpage
#ユーザーから外部ゲートウェイエンドポイントへのトラフィック
kubectl exec deploy/sleep -- curl -s "http://$GATEWAY_HOST_INT/productpage"
#Podから内部ゲートウェイエンドポイントへのトラフィック
kubectl exec deploy/sleep -- curl -s http://productpage:9080/
#Podからsvcへのトラフィック(直接)
kubectl exec deploy/notsleep -- curl -s http://productpage:9080/
#Podからsvcへのトラフィック(直接)

もう一度Kialiのグラフを確認してみてください。今度はmTLSで保護された通信や、その他の有用なテレメトリーデータが表示されているはずです。

L7認可ポリシーの適用

セキュアオーバーレイが整ったので、通常のIstioと同じ感覚でL4認可ポリシーを簡単に適用できます。

ただし、このセキュアオーバーレイだけではL7フィルタリングは行えません。L7フィルタリングを使うには、productpageサービス向けにEnvoyベースのwaypointプロキシをデプロイする必要があります。

プロキシはサービスアカウント単位で適用されるため、productpageサービスの場合はbookinfo-productpageというサービスアカウントが対象になります。

productpageサービス用のwaypointプロキシをデプロイします。

istioctl x waypoint apply --service-account bookinfo-productpage

これにより、bookinfo-productpageサービスアカウントを使用するすべてのサービスに対してwaypointプロキシがデプロイされます。

これ以降、productpageサービス宛てのトラフィックは、利用状況に応じて自動でスケールするL7プロキシを必ず経由するようになります。

続いて、L7のAuthorizationPolicyを作成し、sleepとゲートウェイの各サービスアカウントにはproductpageサービスへのGETのみを明示的に許可し、その他の操作はすべて拒否する設定を行ってみましょう。

export GATEWAY_SERVICE_ACCOUNT=ns/istio-system/sa/istio-ingressgateway-service-account
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: productpage-viewer
  namespace: default
spec:
  targetRef:
    kind: Gateway
    group: gateway.networking.k8s.io
    name: bookinfo-productpage
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - cluster.local/ns/default/sa/sleep
        - cluster.local/$GATEWAY_SERVICE_ACCOUNT
    to:
    - operation:
        methods: ["GET"]
EOF

ポリシーの動作をテストします。

# GET操作ではないため、RBACエラーで失敗するはずです
kubectl exec deploy/sleep -- curl -s "http://$GATEWAY_HOST/productpage" -X DELETE
# 出力は 'RBAC: access denied' となるはずです
# 許可されていないIDからのアクセスのため、RBACエラーで失敗するはずです
kubectl exec deploy/notsleep -- curl -s http://productpage:9080/
# 出力は 'RBAC: access denied' となるはずです
# これは引き続き正常に動作するはずです
kubectl exec deploy/sleep -- curl -s http://productpage:9080/ | grep -o "<title>.*</title>"
# 出力は '<title>Simple Bookstore App</title>' となるはずです

クリーンアップ

以下のコマンドを実行して、Istioと関連コンポーネントをアンインストールします。

istioctl x waypoint delete --all
istioctl uninstall -y --purge
kubectl delete namespace istio-system

GKEクラスターを削除します。

gcloud container clusters delete $CLUSTER_NAME --zone $ZONE

L4とL7の機能が、柔軟性と効率性を両立させる形でモジュール化されている点は非常に興味深いところです。

個人的には大規模環境でどれほどのメリットを発揮するかに強い関心があり、本番環境で稼働するAmbient Meshをぜひ見てみたいと思っています。

本記事が皆さまのお役に立てば幸いです。ご意見やご感想がありましたら、お気軽にコメントでお寄せください。

参考資料