多集群服务网格中的版本路由
在多集群服务网格中配置 Istio 路由规则。
如果您花时间研究 Istio,您可能已经注意到它包含许多功能,这些功能可以通过在单个 Kubernetes 集群上运行的简单任务和示例进行演示。由于大多数(如果不是全部)现实世界的云和基于微服务的应用程序并不那么简单,并且需要将服务分布并在多个位置运行,因此您可能想知道在您的真实生产环境中所有这些事情是否同样简单。
幸运的是,Istio 提供了几种方法来配置服务网格,以便应用程序或多或少地透明地成为网格的一部分,其中服务运行在多个集群中,即在多集群部署中。由于没有特殊的网络要求,因此设置多集群网格最简单的方法是使用复制的控制平面模型。在此配置中,每个为网格做出贡献的 Kubernetes 集群都有自己的控制平面,但每个控制平面都同步并在单个管理控制下运行。
在本文中,我们将了解 Istio 的一项功能,即流量管理,如何在具有专用控制平面拓扑的多集群网格中工作。我们将展示如何配置 Istio 路由规则以调用多集群服务网格中的远程服务,方法是部署Bookinfo 示例,其中版本v1
的reviews
服务运行在一个集群中,版本v2
和v3
运行在第二个集群中。
设置集群
首先,您需要两个 Kubernetes 集群,这两个集群都运行 Istio 的略微自定义配置。
按照复制控制平面说明设置具有两个 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 示例说明确定入口 IP 和端口,然后将浏览器指向
http://$GATEWAY_URL/productpage
。
您应该会看到带有评论的productpage
,但没有评分,因为只有reviews
服务的v1
正在cluster1
上运行,并且我们尚未配置对cluster2
的访问。
在cluster1
上为远程评论服务创建服务条目和目标规则
如设置说明中所述,远程服务使用.global
DNS 名称进行访问。在我们的例子中,它是reviews.default.global
,因此我们需要为此主机创建服务条目和目标规则。服务条目将使用cluster2
网关作为访问服务的端点地址。您可以使用网关的 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
)。一旦请求到达目标集群,将使用本地目标规则来识别与请求的子集相对应的实际 Pod 标签(version: v1
或version: v2
)。
在两个集群上为本地评论服务创建目标规则
从技术上讲,我们只需要定义每个集群中正在使用的本地服务的子集(即cluster1
中的v1
、cluster2
中的v2
和v3
),但为简单起见,我们将在两个集群中定义所有三个子集,因为定义实际上未部署的版本的子集没有任何问题。
$ 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
Pod(v1
),因为如果您查看源代码,您会发现productpage
实现只是对http://reviews:9080
(扩展为主机reviews.default.svc.cluster.local
)发出请求,即服务的本地版本。相应的远程服务名为reviews.default.global
,因此需要路由规则将请求重定向到全局主机。
应用以下虚拟服务,将用户jason
的流量引导到reviews
版本v2
和v3
(50/50),它们运行在cluster2
上。任何其他用户的流量都将转到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 路由规则在具有复制控制平面模型的多集群服务网格中跨集群分配服务的版本。在此示例中,我们手动配置了提供对一个远程服务reviews
的连接所需的.global
服务条目和目标规则。但是,一般来说,如果我们想启用任何服务在本地或远程运行,则需要为每个服务创建.global
资源。幸运的是,此过程可以自动化,并且可能会在将来的 Istio 版本中实现。