マルチクラスタサービスメッシュにおけるバージョンルーティング
マルチクラスタサービスメッシュでのIstioルートルールの設定。
Istioを少しでも調べたことがある方は、単純なタスクや単一のKubernetesクラスタで実行されるサンプルでデモできる多くの機能が含まれていることに気づいたでしょう。ほとんどすべての実世界のクラウドおよびマイクロサービスベースのアプリケーションはそれほど単純ではなく、サービスを複数の場所に分散して実行する必要があるため、これらのことが実際のプロダクション環境でも同じようにシンプルになるのか疑問に思われるかもしれません。
幸いなことに、Istioには、アプリケーションが、複数のクラスタ、つまりマルチクラスタデプロイメントでサービスが実行されているメッシュの一部として、ほぼ透過的に動作するようにサービスメッシュを構成するいくつかの方法が用意されています。特別なネットワーク要件がないため、マルチクラスタメッシュを設定する最も簡単な方法は、レプリケートされたコントロールプレーンモデルを使用することです。この構成では、メッシュに参加する各Kubernetesクラスタは独自のコントロールプレーンを持っていますが、各コントロールプレーンは同期され、単一の管理制御下で実行されます。
この記事では、Istioの機能の1つであるトラフィック管理が、専用コントロールプレーントポロジを持つマルチクラスタメッシュでどのように機能するかを見ていきます。reviewsサービスのバージョンv1を1つのクラスタで、バージョンv2とv3を2番目のクラスタで実行するBookinfoサンプルをデプロイすることで、マルチクラスタサービスメッシュでリモートサービスを呼び出すためのIstioルートルールの設定方法を示します。
クラスタの設定
まず、Istioの構成を少しカスタマイズした2つのKubernetesクラスタが必要です。
レプリケートされたコントロールプレーンの手順に従って、2つのIstioクラスタを持つマルチクラスタ環境をセットアップします。
kubectlコマンドは、--contextフラグを使用して両方のクラスタにアクセスするために使用されます。次のコマンドを使用してコンテキストをリストします$ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * cluster1 cluster1 user@foo.com default cluster2 cluster2 user@foo.com default構成のコンテキスト名を持つ次の環境変数をエクスポートします
$ export CTX_CLUSTER1=<cluster1 context name> $ export CTX_CLUSTER2=<cluster2 context name>
cluster1にbookinfoアプリケーションのバージョンv1をデプロイします
cluster1でproductpageおよびdetailsサービスと、reviewsサービスのバージョンv1を実行します
$ kubectl label --context=$CTX_CLUSTER1 namespace default istio-injection=enabled
$ kubectl apply --context=$CTX_CLUSTER1 -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: productpage
labels:
app: productpage
spec:
ports:
- port: 9080
name: http
selector:
app: productpage
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: productpage-v1
spec:
replicas: 1
template:
metadata:
labels:
app: productpage
version: v1
spec:
containers:
- name: productpage
image: istio/examples-bookinfo-productpage-v1:1.10.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
apiVersion: v1
kind: Service
metadata:
name: details
labels:
app: details
spec:
ports:
- port: 9080
name: http
selector:
app: details
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: details-v1
spec:
replicas: 1
template:
metadata:
labels:
app: details
version: v1
spec:
containers:
- name: details
image: istio/examples-bookinfo-details-v1:1.10.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
apiVersion: v1
kind: Service
metadata:
name: reviews
labels:
app: reviews
spec:
ports:
- port: 9080
name: http
selector:
app: reviews
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: reviews-v1
spec:
replicas: 1
template:
metadata:
labels:
app: reviews
version: v1
spec:
containers:
- name: reviews
image: istio/examples-bookinfo-reviews-v1:1.10.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
EOF
cluster2にbookinfo v2およびv3サービスをデプロイします
cluster2でratingsサービスと、reviewsサービスのバージョンv2およびv3を実行します
$ kubectl label --context=$CTX_CLUSTER2 namespace default istio-injection=enabled
$ kubectl apply --context=$CTX_CLUSTER2 -f - <<EOF
apiVersion: v1
kind: Service
metadata:
name: ratings
labels:
app: ratings
spec:
ports:
- port: 9080
name: http
selector:
app: ratings
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: ratings-v1
spec:
replicas: 1
template:
metadata:
labels:
app: ratings
version: v1
spec:
containers:
- name: ratings
image: istio/examples-bookinfo-ratings-v1:1.10.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
apiVersion: v1
kind: Service
metadata:
name: reviews
labels:
app: reviews
spec:
ports:
- port: 9080
name: http
selector:
app: reviews
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: reviews-v2
spec:
replicas: 1
template:
metadata:
labels:
app: reviews
version: v2
spec:
containers:
- name: reviews
image: istio/examples-bookinfo-reviews-v2:1.10.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: reviews-v3
spec:
replicas: 1
template:
metadata:
labels:
app: reviews
version: v3
spec:
containers:
- name: reviews
image: istio/examples-bookinfo-reviews-v3:1.10.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
EOF
bookinfoアプリケーションへのアクセス
他のアプリケーションと同様に、Istioゲートウェイを使用してbookinfoアプリケーションにアクセスします。
cluster1にbookinfoゲートウェイを作成します$ kubectl apply --context=$CTX_CLUSTER1 -f @samples/bookinfo/networking/bookinfo-gateway.yaml@Bookinfoサンプルの手順に従って、ingress IPとポートを決定し、ブラウザを
http://$GATEWAY_URL/productpageに向けてください。
reviewsサービスのv1のみがcluster1で実行されており、cluster2へのアクセスをまだ構成していないため、レビューが表示されたproductpageが表示されますが、評価は表示されません。
リモートreviewsサービス用にcluster1にサービスエントリと宛先ルールを作成します
設定手順で説明されているように、リモートサービスには.global DNS名を使用してアクセスします。この場合、reviews.default.globalなので、そのホストのサービスエントリと宛先ルールを作成する必要があります。サービスエントリは、サービスにアクセスするためのエンドポイントアドレスとしてcluster2ゲートウェイを使用します。ゲートウェイにDNS名がある場合はDNS名を使用するか、次のようにパブリックIPを使用できます。
$ export CLUSTER2_GW_ADDR=$(kubectl get --context=$CTX_CLUSTER2 svc --selector=app=istio-ingressgateway \
-n istio-system -o jsonpath="{.items[0].status.loadBalancer.ingress[0].ip}")
次のコマンドを使用して、サービスエントリと宛先ルールを作成します
$ kubectl apply --context=$CTX_CLUSTER1 -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: reviews-default
spec:
hosts:
- reviews.default.global
location: MESH_INTERNAL
ports:
- name: http1
number: 9080
protocol: http
resolution: DNS
addresses:
- 240.0.0.3
endpoints:
- address: ${CLUSTER2_GW_ADDR}
labels:
cluster: cluster2
ports:
http1: 15443 # Do not change this port value
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews-global
spec:
host: reviews.default.global
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
subsets:
- name: v2
labels:
cluster: cluster2
- name: v3
labels:
cluster: cluster2
EOF
サービスエントリのアドレス240.0.0.3は、任意の未割り当てのIPにすることができます。クラスEアドレス範囲240.0.0.0/4のIPを使用するのが良い選択です。詳細については、ゲートウェイ接続マルチクラスタの例を参照してください。
宛先ルールのサブセットのラベルが、cluster2ゲートウェイに対応するサービスエントリエンドポイントラベル(cluster: cluster2)にマップされることに注意してください。リクエストが宛先クラスタに到達すると、ローカル宛先ルールが、要求されたサブセットに対応する実際のポッドラベル(version: v1またはversion: v2)を識別するために使用されます。
ローカルreviewsサービス用に両方のクラスタに宛先ルールを作成します
技術的には、各クラスタで使用されているローカルサービスのサブセット(つまり、cluster1のv1、cluster2のv2とv3)のみを定義する必要がありますが、簡単にするために、実際にデプロイされていないバージョンのサブセットを定義しても問題ないため、両方のクラスタですべての3つのサブセットを定義します。
$ kubectl apply --context=$CTX_CLUSTER1 -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews.default.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
EOF
$ kubectl apply --context=$CTX_CLUSTER2 -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews.default.svc.cluster.local
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
EOF
reviewsサービストラフィックをルーティングするための仮想サービスを作成します
この時点で、reviewsサービスへのすべての呼び出しは、ローカルのreviewsポッド(v1)に送られます。これは、ソースコードを見ると、productpageの実装が単にhttp://reviews:9080(ホストreviews.default.svc.cluster.localに展開される)へのリクエストを行っているため、ローカルバージョンのサービスです。対応するリモートサービスはreviews.default.globalという名前なので、グローバルホストにリクエストをリダイレクトするにはルートルールが必要です。
次の仮想サービスを適用して、ユーザーjasonのトラフィックをcluster2で実行されているreviewsバージョンv2とv3(50/50)に転送します。他のユーザーのトラフィックはreviewsバージョンv1に送られます。
$ kubectl apply --context=$CTX_CLUSTER1 -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews.default.svc.cluster.local
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews.default.global
subset: v2
weight: 50
- destination:
host: reviews.default.global
subset: v3
weight: 50
- route:
- destination:
host: reviews.default.svc.cluster.local
subset: v1
EOF
ブラウザに戻り、ユーザーjasonとしてログインします。ページを数回リフレッシュすると、評価の星が黒と赤(v2とv3)で交互に表示されるはずです。ログアウトすると、評価なしのレビュー(v1)のみが表示されます。
まとめ
この記事では、レプリケートされたコントロールプレーンモデルを持つマルチクラスタサービスメッシュで、Istioルートルールを使用してサービスバージョンをクラスタ間で分散する方法を見てきました。この例では、1つのリモートサービスreviewsへの接続を提供するために必要な.globalサービスエントリと宛先ルールを手動で構成しました。ただし、一般に、サービスがローカルまたはリモートで実行できるようにするには、すべてのサービスに対して.globalリソースを作成する必要があります。幸いなことに、このプロセスは自動化でき、おそらく将来のIstioリリースで実現されるでしょう。