作为业内首个全托管Istio兼容的阿里云服务网格产品ASM,一开始从架构上就保持了与社区、业界趋势的一致性,控制平面的组件托管在阿里云侧,与数据面侧的用户集群独立。ASM产品是基于社区Istio定制实现的,在托管的控制面侧提供了用于支撑精细化的流量管理和安全管理的组件能力。通过托管模式,解耦了Istio组件与所管理的K8s集群的生命周期管理,使得架构更加灵活,提升了系统的可伸缩性。从2022年4月1日起,阿里云服务网格ASM正式推出商业化版本, 提供了更丰富的能力、更大的规模支持及更完善的技术保障,更好地满足客户的不同需求场景,详情可进入阿里云官方网站 - 搜索服务网格ASM。
网格拓扑是一个服务网格可观测性工具,提供查看相关服务拓扑的可视化界面。阿里云服务网格ASM从1.7.5.25版本开始支持内置网格拓扑。
在默认情况下,网格拓扑服务部署在客户的数据面集群之中,并查询与客户数据面集群关联的Prometheus实例,这样可以显著降低客户操作集成服务网格、网格拓扑与Prometheus的操作成本。在这种模式下,每个客户集群都拥有自己的网格拓扑服务实例、并分别显示各自集群中的服务拓扑可视化情况。
如果客户的ASM实例管理了多个集群,且集群之间互相有流量访问,那么在一个网格拓扑服务中同时观测多个集群中的流量拓扑情况显然是不错的主意。那么可不可以做到这个效果呢?
通过配置ASM网格拓扑来对接阿里云ARMS Prometheus的聚合实例,我们就可以做到让ASM网格拓扑同时查询并展示多个集群的流量拓扑情况。让我们看看怎么做吧!
配置ASM网格拓扑连接阿里云Prometheus全局聚合实例
我们可以配置ASM网格拓扑来对接阿里云ARMS Prometheus的聚合实例,这样就可以同时查询聚合实例中提供的多个集群服务的指标信息,进而形成跨集群的网格拓扑。
前提条件
步骤一:将ACK集群加入ASM实例并打开监控指标
-
所有集群加入ASM实例后,我们需要打开ASM的监控指标能力,来启用Sidecar代理上报监控指标。
-
在 网格管理 页面,单击目标实例名称,然后在左侧导航栏,选择 可观测管理中心 > 监控指标 。
-
点选 集成自建Prometheus实现监控, 确认已按照对应文档完成相关参数配置 ,然后点击开 启监控指标生成与采集 。
如果勾选使用ARMS Prometheus采集监控指标并开启监控指标能力,ASM会默认为每个集群关联的ARMS Prometheus开启与服务网格的集成,同时将集群关联的ARMS Prometheus HTTP API 地址作为默认的Prometheus连接地址。
由于我们这里想要通过Prometheus全局聚合实例来查询多集群全局网格拓扑,因此这里我们选择集成自建Prometheus实现监控这个自由度更高的选项, 然后手动为ARMS Prometheus开启服务网格的集成。
做完以上步骤,每个集群关联的ARMS Prometheus实例应该就可以读到本集群内Sidecar代理上报的指标了。接下来我们需要用一个全局聚合实例来将这些指标聚合起来。
步骤二:创建一个阿里云Prometheus全局聚合实例
我们可以参考这篇文档来为本地域下的多个集群Prometheus实例创建一个聚合实例:Prometheus实例 for GlobalView。
-
访问Endpoint 需要选择一个和ACK集群相同的地域,因为我们需要让集群中的ASM网格拓扑服务通过内网端点访问这个全局聚合实例。
-
在 选择要聚合的实例 这一栏选中所有加入ASM的ACK集群所关联的Prometheus实例,这样网格拓扑就可以读取所有集群中Sidecar代理上报的指标了。
这一步做完之后,我们已经有了一个可以查看ASM中所有集群的全局大盘的Prometheus聚合实例,接下来我们只需要配置一下让ASM网格拓扑对接这个实例就可以了。
步骤三:开启ASM网格拓扑,对接Prometheus全局聚合实例
-
我们需要首先记录一下我们刚刚创建的Prometheus全局聚合实例的HTTP API地址。这可以在这个实例的设置页面中找到:
-
在 网格管理 页面,单击目标实例名称,然后在左侧导航栏,选择 可观测管理中心 > 网格拓扑 , 在启用ASM网格拓扑区域,输入我们上面拿到的Prometheus全局聚合实例的HTTP API内网地址,然后单击开始启用 。
如果一切顺利的话,到这里我们就已经可以在任意一个ASM网格拓扑服务中观测到全局的网格拓扑图了。随意部署一个多集群场景下的应用到我们的多集群中,我们将可以看到流量在多集群中的流动情况。
一点小建议,可以调整一下ASM网格拓扑的显示信息:
-
打开流量分布、流量请求速率和流量动画:将为拓扑图中的边提供更多有效的信息
-
关闭命名空间分框:可以凸显集群分框,更明确地区分出不同集群中的服务及集群间的流量
-
可以考虑关闭服务节点,并将拓扑图视角改为工作负载视角,以减少拓扑图中的冗余信息
最终效果:我们将可以看到一张多集群架构下的全局流量拓扑图,其中每个灰色的分框代表一个集群,我们可以清楚地看到流量在多集群的不同工作负载之间流动
实战:利用服务网格ASM实现多可用区的多集群容灾,并使用ASM网格拓扑观测流量变化
提到多集群的使用场景,容灾和故障转移无疑是其中重要的一部分。比如,我们可以set up以下的一个场景:
我们在两个可用区分别创建一个集群,并在其中部署相同的应用和服务,一个做主、一个做备。网关可以自由指定向两个集群中的服务发送流量的比例(比如,主机群发送80%流量、备集群发送20%流量)。
当所有服务处于正常状态时,服务间的流量访问遵循“同可用区优先”的原则,此时两个集群内的服务都只会访问本集群内的工作负载。
如果集群中的某个服务出现了故障,此时依赖故障服务的工作负载可以将请求发往另一个集群中的相同服务,来实现容灾的逻辑。
一、使用服务网格ASM实现多可用区多集群容灾
我们首先需要创建两个位于同vpc不同可用区的集群,并配置好两个集群之间的互访连通性,然后将两个集群加入ASM,布置好应用部署环境。我们可以参考在多集群管理模式下部署应用示例来完成环境的设置。
拥有一个加入两个集群的ASM实例后,我们就可以开始部署示例应用了。我们这里使用一个经典的bookinfo来作为应用的例子。bookinfo是一个经典的多语言微服务应用,由最前端的productpage服务提供前端页面,productpage服务则依赖details和reviews服务。
我们在服务网格中创建一个叫demo的全局命名空间,并给这个命名空间打开Sidecar注入,然后创建一个名称为默认的ingressgateway的ASM入口网关做访问入口,打开80端口。
接着在集群1中部署以下应用:
##################################################################################################
# Details service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: details
namespace: demo
labels:
app: details
service: details
spec:
ports:
- port: 9080
name: http
selector:
app: details
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-details
namespace: demo
labels:
account: details
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: details-cluster1
namespace: demo
labels:
app: details
cluster: cluster1
spec:
replicas: 1
selector:
matchLabels:
app: details
cluster: cluster1
template:
metadata:
labels:
app: details
cluster: cluster1
spec:
serviceAccountName: bookinfo-details
containers:
- name: details
image: docker.io/istio/examples-bookinfo-details-v1:1.16.4
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
securityContext:
runAsUser: 1000
---
##################################################################################################
# Reviews service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: reviews
namespace: demo
labels:
app: reviews
service: reviews
spec:
ports:
- port: 9080
name: http
selector:
app: reviews
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-reviews
namespace: demo
labels:
account: reviews
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: reviews-cluster1
namespace: demo
labels:
app: reviews
cluster: cluster1
spec:
replicas: 1
selector:
matchLabels:
app: reviews
cluster: cluster1
template:
metadata:
labels:
app: reviews
cluster: cluster1
spec:
serviceAccountName: bookinfo-reviews
containers:
- name: reviews
image: docker.io/istio/examples-bookinfo-reviews-v1:1.16.4
imagePullPolicy: IfNotPresent
env:
- name: LOG_DIR
value: "/tmp/logs"
ports:
- containerPort: 9080
volumeMounts:
- name: tmp
mountPath: /tmp
- name: wlp-output
mountPath: /opt/ibm/wlp/output
securityContext:
runAsUser: 1000
volumes:
- name: wlp-output
emptyDir: {}
- name: tmp
emptyDir: {}
---
##################################################################################################
# Productpage services
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: productpage
namespace: demo
labels:
app: productpage
service: productpage
spec:
ports:
- port: 9080
name: http
selector:
app: productpage
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-productpage
namespace: demo
labels:
account: productpage
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: productpage-cluster1
namespace: demo
labels:
app: productpage
cluster: cluster1
spec:
replicas: 1
selector:
matchLabels:
app: productpage
cluster: cluster1
template:
metadata:
labels:
app: productpage
cluster: cluster1
spec:
serviceAccountName: bookinfo-productpage
containers:
- name: productpage
image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.4
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
volumeMounts:
- name: tmp
mountPath: /tmp
securityContext:
runAsUser: 1000
volumes:
- name: tmp
emptyDir: {}
在多集群场景下,这个例子为工作负载的名称和标签加入了一个cluster1的标识,以识别不同集群中的工作负载。
在集群2中同理,只是将上例中工作负载名称和标签中的cluster1和cluster2。
然后用kubectl连接ASM实例,部署以下规则:
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: bookinfo-gateway
namespace: demo
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*'
port:
name: http
number: 80
protocol: HTTP
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: productpage-destination
namespace: demo
spec:
host: productpage.demo.svc.cluster.local
subsets:
- labels:
cluster: ack
name: ack
- labels:
cluster: distro
name: distro
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: bookinfo
namespace: demo
spec:
gateways:
- bookinfo-gateway
hosts:
- '*'
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
subset: ack
weight: 80
- destination:
host: productpage
port:
number: 9080
subset: distro
weight: 20
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: details-failover
namespace: demo
spec:
host: details.demo.svc.cluster.local
trafficPolicy:
connectionPool:
http:
maxRequestsPerConnection: 1
loadBalancer:
localityLbSetting:
enabled: true
simple: ROUND_ROBIN
outlierDetection:
baseEjectionTime: 1m
consecutive5xxErrors: 1
interval: 1s
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: ratings-failover
namespace: demo
spec:
host: ratings.demo.svc.cluster.local
trafficPolicy:
connectionPool:
http:
maxRequestsPerConnection: 1
loadBalancer:
localityLbSetting:
enabled: true
simple: ROUND_ROBIN
outlierDetection:
baseEjectionTime: 1m
consecutive5xxErrors: 1
interval: 1s
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: reviews-failover
namespace: demo
spec:
host: reviews.demo.svc.cluster.local
trafficPolicy:
connectionPool:
http:
maxRequestsPerConnection: 1
loadBalancer:
localityLbSetting:
enabled: true
simple: ROUND_ROBIN
outlierDetection:
baseEjectionTime: 1m
consecutive5xxErrors: 1
interval: 1s
这里的重点是我们为每个服务都制定了一个localityLbSetting的负载均衡设定,以提供同可用区优先的路由策略。
访问http://{ASM网关ip地址}/productpage,已经可以看到bookinfo应用可以正常访问了。
二、使用ASM网格拓扑观测流量变化
使用文章开头提到的方法,我们就将能够在ASM网格拓扑中观察到两个集群下的流量拓扑情况,可以看到两个集群中部署了完全相同的应用,其中约有80%的流量打向集群1,20%的流量打向集群2 。
接下来模拟reviews服务故障的场景,我们可以直接将reviews服务在集群1中的工作负载缩容到0,随后将在ASM网格拓扑中观察到流量的走向发生了变化,集群1中的productpage服务开始将流量打向集群2中的reviews服务。
此时继续访问bookinfo应用的地址,我们可以发现服务没有中断,reviews服务的提供者被fail over到集群2中的工作负载上。