多集群网关(Multi-cluster Gateways)是ACK One为多云、多集群环境提供的云原生网关,通过托管MSE Ingress并使用Ingress API以管理七层南北向流量。多集群网关支持同城自动容灾和基于Header的灰度发布,可以帮您简化多集群应用的运维和节省成本,结合ACK One GitOps的能力,您可以快速构建同城多活或主备容灾系统(不包含数据容灾)。
容灾概述
目前云上容灾主要分为以下三类:
同城跨AZ容灾
同城容灾包含多活容灾和主备容灾,同城中心之间物理距离较近,网络延迟低,可防范AZ级别性质的灾难损害,例如火灾、断网或断电等。
跨地域多活容灾
跨地域多活容灾对于网络延迟相对较高,但可以防范地域性质的灾难损害,例如地震、水灾等。
两地三中心
两地三中心将同城双中心和跨地域灾备结合起来,兼具两者的优点,适用于应用与数据连续性和可用性要求高的场景。
而从实际情况考虑,同城容灾相比于跨地域容灾,在数据容灾方面更容易实现,所以同城容灾仍然具有非常重要的意义。
功能优势
基于多集群网关的容灾方案与基于DNS流量分发的容灾方案对比优势如下:
基于DNS流量分发的容灾方案需要多个LB IP(每个集群1个),而基于多集群网关的容灾方案在地域级别仅需要1个LB IP,且默认提供同地域多可用区的高可用性。
基于多集群网关的容灾支持七层路由转发能力,而基于DNS流量分发的容灾不支持七层路由转发。
基于DNS流量分发的容灾方案在IP切换时,通常会有客户端缓存而造成服务短暂不可用,而基于多集群网关的容灾方案则可以平滑地将流量Fallback到另一个集群的服务后端。
多集群网关是地域级别的,所以所有操作都仅需在Fleet实例中操作(创建网关、Ingress资源等),无需在每个ACK集群中都安装Ingress Controller和创建Ingress资源,提供地域级全局流量管理能力的同时,还能减少多集群管理成本。
方案架构
ACK One多集群网关通过托管MSE Ingress来实现,结合ACK One GitOps的应用多集群分发能力,可以帮助您快速实现应用的同城容灾系统。本文将通过GitOps部署示例应用到中国(香港)地域的两个不同可用区的ACK集群(Cluster 1、Cluster 2)为例,介绍如何实现同城多活容灾和同城主备容灾。
本文示例应用为Web应用,包含Deployment、Service资源,通过多集群网关实现同城容灾的方案架构如下图所示。
在ACK One Fleet中通过MseIngressConfig资源来创建MSE网关。
在同一个地域的两个不同可用区AZ 1和AZ 2中,分别创建一个ACK集群Cluster 1和Cluster 2。
通过ACK One GitOps将应用分发到已创建的Cluster 1和Cluster 2集群中。
创建多集群网关后,通过设置流量规则可以实现按权重路由流量、根据Header将流量路由到指定集群的能力,当其中一个集群异常时,流量将自动路由到另一个集群中。
前提条件
已开启舰队管理功能。具体操作,请参见开启舰队管理功能。
ACK One Fleet已关联2个与Fleet实例相同VPC的ACK集群。具体操作,请参见添加关联集群。
已从ACK One控制台获取Fleet实例的KubeConfig,并通过kubectl连接至Fleet实例。
- 说明
关于多集群网关计费的更多信息,请参见计费规则。
已在ACK One Fleet实例中创建Namespace,该Namespace与关联集群中部署应用的Namespace一致(本文示例的Namespace为
gateway-demo
)
步骤一:使用GitOps部署应用到多个集群
通过ArgoCD UI部署
登录ACK One控制台,在左侧导航栏选择 。
在GitOps页面,单击GitOps控制台跳转至GitOps页面。
说明若ACK One舰队的Fleet实例未开启GitOps,请先单击开启GitOps,才能登录GitOps控制台。
如需通过公网访问GitOps,请开通公网访问GitOps。
添加应用仓库。
在ArgoCD UI左侧导航栏选择Settings,然后选择
。在弹出的面板中配置以下信息,然后单击CONNECT添加连接。
区域
参数
参数值
Choose your connection method
VIA HTTPS
CONNECT REPO USING HTTPS
Type
git
Project
default
Repository URL
https://github.com/AliyunContainerService/gitops-demo.git
Skip server verification
勾选
连接添加成功后会显示Git的CONNECTION STATUS为Successful。
创建应用。
在ArgoCD的Applications页面中,单击+ NEW APP,进行如下参数配置。
区域
参数
说明
GENERAL
Application Name
自定义应用名称。
Project Name
default
SYNC POLICY
可根据实际情况选择同步策略。取值:
Manual:当Git端有变更时,需手动执行同步动作将其部署至目标集群。
Automatic:ArgoCD Server每隔3分钟自动检测Git端的变更并将其自动部署至目标集群。
SYNC OPTIONS
勾选
AUTO-CREATE NAMESPACE
。SOURCE
Repository URL
在下拉列表选择已有Git Repo,此处选择上一步已添加的
https://github.com/AliyunContainerService/gitops-demo.git
。Revision
选择Branches:
gateway-demo
。Path
manifests/helm/web-demo
DESTINATION
Cluster URL
选择集群1或集群2的URL。
也可以单击右侧的
URL
,切换为根据CLUSTER NAME
字段选择。Namespace
本示例使用
gateway-demo
。表示应用资源(Service、Deployment)将被创建在此Namespace下。Helm
Parameters
envCluster
值设置为cluster-demo-1
或cluster-demo-2
,用于区分请求由哪个集群的后端处理。
通过ArgoCD CLI部署
在ACK One Fleet实例中开启GitOps。具体操作,请参见在ACK One Fleet实例中开启GitOps。
访问ArgoCD。具体操作,请参见通过ArgoCD CLI方式访问ArgoCD。
创建并发布应用。
执行以下命令,添加Git Repo。
argocd repo add https://github.com/AliyunContainerService/gitops-demo.git --name ackone-gitops-demos
预期输出:
Repository 'https://github.com/AliyunContainerService/gitops-demo.git' added
执行以下命令,查看已添加的Git Repo列表。
argocd repo list
预期输出:
TYPE NAME REPO INSECURE OCI LFS CREDS STATUS MESSAGE PROJECT git https://github.com/AliyunContainerService/gitops-demo.git false false false false Successful default
执行以下命令,查看Clusters列表。
argocd cluster list
预期输出:
SERVER NAME VERSION STATUS MESSAGE PROJECT https://1.1.XX.XX:6443 c83f3cbc90a****-temp01 1.22+ Successful https://2.2.XX.XX:6443 c83f3cbc90a****-temp02 1.22+ Successful https://kubernetes.default.svc in-cluster Unknown Cluster has no applications and is not being monitored.
使用Application方式创建并发布Demo应用到目标集群。
使用以下内容,创建apps-web-demo.yaml文件。
其中
repoURL
需替换为您实际的仓库地址。执行以下命令,部署应用。
kubectl apply -f apps-web-demo.yaml
执行以下命令,查看应用列表。
argocd app list
预期输出:
# app list NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET argocd/web-demo-cluster1 https://10.1.XX.XX:6443 default Synced Healthy Auto <none> https://github.com/AliyunContainerService/gitops-demo.git manifests/helm/web-demo main argocd/web-demo-cluster2 https://10.1.XX.XX:6443 default Synced Healthy Auto <none> https://github.com/AliyunContainerService/gitops-demo.git manifests/helm/web-demo main
步骤二:在Fleet实例中通过kubectl创建多集群网关
通过在ACK One Fleet中创建MseIngressConfig对象来创建一个多集群网关,并将关联集群添加至多集群网关。
获取ACK One Fleet实例的虚拟交换机ID并记录。具体操作,请参见获取交换机ID。
使用以下内容,创建gateway.yaml文件。
说明请将
${vsw-id}
替换为您上一步获取的交换机ID,${cluster1}
、${cluster2}
替换为您待添加的关联集群ID。子集群
${cluster1}
、${cluster2}
的安全组的入方向需要允许该交换机网段的IP和所有端口通过。
apiVersion: mse.alibabacloud.com/v1alpha1 kind: MseIngressConfig metadata: annotations: mse.alibabacloud.com/remote-clusters: ${cluster1},${cluster2} name: ackone-gateway-hongkong spec: common: instance: replicas: 3 spec: 2c4g network: vSwitches: - ${vsw-id} ingress: local: ingressClass: mse name: mse-ingress
参数
说明
mse.alibabacloud.com/remote-clusters
表示待添加到多集群网关的集群。此处所填的是已经关联到Fleet实例的集群ID。
spec.name
网关实例名称。
spec.common.instance.spec
可选,网关实例规格。默认为
4c8g
。spec.common.instance.replicas
可选,网关实例副本数。默认为3个。
spec.ingress.local.ingressClass
可选,待监听的ingressClass name,表示监听Fleet实例中所有
ingressClass
字段设置为mse
的Ingress。执行以下命令,部署多集群网关。
kubectl apply -f gateway.yaml
执行以下命令,验证多集群网关是否创建成功并处于监听状态。
kubectl get mseingressconfig ackone-gateway-hongkong
预期输出:
NAME STATUS AGE ackone-gateway-hongkong Listening 3m15s
预期输出中网关状态为
Listening
,表明云原生网关创建成功处于运行状态,并自动监听集群中IngressClass为mse
的Ingress资源。通过MseIngressConfig创建的多集群网关会按照Pending、Running、Listening的状态依次变化。各状态说明如下:
Pending:表明云原生网关正在创建中,需等待3分钟左右。
Running:表明云原生网关创建成功,并处于运行状态。
Listening:表明云原生网关处于运行状态,并监听集群中Ingress资源。
Failed:表明云原生网关处于非法状态,可以查看Status字段中Message来进一步明确原因。
执行以下命令,确认关联集群是否添加成功。
kubectl get mseingressconfig ackone-gateway-hongkong -ojsonpath="{.status.remoteClusters}"
预期输出:
[{"clusterId":"c7fb82****"},{"clusterId":"cd3007****"}]
预期输出中已包含指定的Cluster ID,并且无Failed信息,表明关联集群已成功添加至多集群网关。
步骤三:使用Ingress实现同城容灾
多集群网关通过Ingress对多集群流量进行管理,您可以在ACK One Fleet实例中创建Ingress对象来实现同城多活容灾和同城主备容灾。
确认您已经在Fleet实例中创建Namespacegateway-demo
,此处创建的Ingress需要和上一步部署的Demo应用中Service的Namespace保持一致为gateway-demo
。
同城多活容灾
创建Ingress实现同城多活容灾
在ACK One Fleet实例中创建以下Ingress对象,可以实现同城多活容灾。
默认将流量负载均衡到已添加到多集群网关的两个集群的同名服务后端的每个副本中,如果其中的Cluster 1后端异常,网关自动将流量全都路由到Cluster 2。Cluster 1和Cluster 2的副本数比为9:1,所以默认90%流量被路由到Cluster 1, 10%流量被路由到Cluster 2,在Cluster 1后端全部异常后,100%流量自动被路由到Cluster 2。拓扑如下所示:
使用以下内容,创建ingress-demo.yaml文件。
以下代码中,通过域名
example.com
下的/svc1
路由规则暴露后端服务service1
。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-demo spec: ingressClassName: mse rules: - host: example.com http: paths: - path: /svc1 pathType: Exact backend: service: name: service1 port: number: 80
执行以下命令,在ACK One Fleet实例中部署Ingress。
kubectl apply -f ingress-demo.yaml -n gateway-demo
实现灰度发布验证
在多活容灾场景下,不影响业务的前提下,您可以通过以下方式对应用进行灰度发布验证。
在已有集群中新建应用,仅将Service和Deployment的name
和selector
与原应用进行区分,之后基于Header在新建的应用上进行验证。
使用以下内容,在Cluster 1中新建new-app.yaml文件。仅Service和Deployment与原应用有差异,其他均一致。
apiVersion: v1 kind: Service metadata: name: service1-canary-1 namespace: gateway-demo spec: ports: - port: 80 protocol: TCP targetPort: 8080 selector: app: web-demo-canary-1 sessionAffinity: None type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: web-demo-canary-1 namespace: gateway-demo spec: replicas: 1 selector: matchLabels: app: web-demo-canary-1 template: metadata: labels: app: web-demo-canary-1 spec: containers: - env: - name: ENV_NAME value: cluster-demo-1-canary image: 'registry-cn-hangzhou.ack.aliyuncs.com/acs/web-demo:0.6.0' imagePullPolicy: Always name: web-demo
执行以下命令,在Cluster 1中部署新的应用。
kubectl apply -f new-app.yaml
使用以下内容,创建new-ingress.yaml文件。
在Fleet实例中创建基于Header的Ingress。通过添加Annotations开启Canary,并指定Header,在请求中使用Header:
canary-dest: cluster1
来将流量路由到灰度版本进行验证。nginx.ingress.kubernetes.io/canary
:设置为"true"
,表示开启灰度发布能力。nginx.ingress.kubernetes.io/canary-by-header
:请求到该集群的header key。nginx.ingress.kubernetes.io/canary-by-header-value
:请求到该集群的header value。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web-demo-canary-1 namespace: gateway-demo annotations: nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: "canary-dest" nginx.ingress.kubernetes.io/canary-by-header-value: "cluster1" spec: ingressClassName: mse rules: - host: example.com http: paths: - path: /svc1 pathType: Exact backend: service: name: service1-canary-1 port: number: 80
执行以下命令,在Fleet实例中部署基于Header的Ingress。
kubectl apply -f new-ingress.yaml
验证同城多活容灾实现效果
修改部署到Cluster 1的副本数为9,Cluster 2的副本数为1,即期望默认流量按照9:1路由到Cluster 1和Cluster 2,并且在Cluster1异常后,自动将所有流量路由到Cluster 2。
执行以下命令,获取多集群网关的对外IP。
kubectl get ingress web-demo -n gateway-demo -ojsonpath="{.status.loadBalancer}"
默认流量按比例路由到两个集群
执行以下命令,查看流量的路由情况。
替换以下
XX.XX.XX.XX
为上一步获取的多集群网关的对外IP。for i in {1..100}; do curl -H "host: example.com" XX.XX.XX.XX done
预期输出:预期输出表明,流量被负载均衡到了Cluster 1和Cluster 2,到Cluster 1和Cluster 2的流量比为9:1。
Cluster 1异常后流量全部容灾到Cluster 2
如果将Cluster 1的Deployment的
replica
缩为0时,得到的输出结果如下,表明流量已被自动容灾到Cluster 2。通过Header将请求路由到灰度版本
执行以下命令,查看流量的路由情况。
替换以下
XX.XX.XX.XX
为实现灰度发布验证中的应用和Ingress部署完成后查询到的IP。for i in {1..100}; do curl -H "host: example.com" -H "canary-dest: cluster1" xx.xx.xx.xx/svc1; sleep 1; done
预期输出:预期输出表明,添加了header:
canary-dest: cluster1
的请求都被路由到了Cluster 1中的灰度版本。
同城主备容灾
在ACK One Fleet实例中创建以下Ingress对象,可以实现同城主备容灾。
当两个集群后端都正常时,流量仅路由到Cluster 1的服务后端;如果其中一个Cluster 1后端异常,网关会自动将流量路由到Cluster 2。拓扑如下所示:
创建Ingress实现同城主备容灾
使用以下内容,创建ingress-demo-cluster-one.yaml文件。
以下Ingress对象的YAML文件中,通过添加两个Annotations
mse.ingress.kubernetes.io/service-subset
、mse.ingress.kubernetes.io/subset-labels
以实现域名example.com
下的/service1
路由规则暴露后端服务service1
。关于MSE Ingress支持的Annotations详情,请参见MSE Ingress支持的Annotation。mse.ingress.kubernetes.io/service-subset
:服务的子版本名称。建议定义为与目标集群相关且可读性强的值。mse.ingress.kubernetes.io/subset-labels
:指定目标集群的ID。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: mse.ingress.kubernetes.io/service-subset: cluster-demo-1 mse.ingress.kubernetes.io/subset-labels: | topology.istio.io/cluster ${cluster1-id} name: web-demo-cluster-one spec: ingressClassName: mse rules: - host: example.com http: paths: - path: /service1 pathType: Exact backend: service: name: service1 port: number: 80
执行以下命令,在ACK One Fleet实例中部署Ingress。
kubectl apply -f ingress-demo-cluster-one.yaml -ngateway-demo
实现集群级别灰度发布
多集群网关支持创建基于Header的Ingress以实现将请求路由到指定集群,基于该能力与创建Ingress实现同城主备容灾中Ingress对象实现的全副本负载均衡的能力,可以实现基于Header的灰度发布。
已创建Ingress实现同城主备容灾中的Ingress。
在ACK One Fleet实例中创建包含Header相关Annotation的Ingress,实现集群级别的灰度发布。请求的Header与Ingress中的配置相匹配时,请求将被路由给灰度版本的后端。
使用以下内容,创建ingress-demo-cluster-gray.yaml文件。
以下Ingress对象的YAML文件中,替换YAML中的
${cluster1-id}
为目标集群ID。除了mse.ingress.kubernetes.io/service-subset
和mse.ingress.kubernetes.io/subset-labels
两个Annotation之外,您还需要添加以下Annotation以实现域名example.com
下的/service1
路由规则暴露后端服务service1
nginx.ingress.kubernetes.io/canary
:设置为"true"
,表示开启灰度发布能力。nginx.ingress.kubernetes.io/canary-by-header
:表示请求到该集群的header key。nginx.ingress.kubernetes.io/canary-by-header-value
:表示请求到该集群的header value。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: mse.ingress.kubernetes.io/service-subset: cluster-demo-2 mse.ingress.kubernetes.io/subset-labels: | topology.istio.io/cluster ${cluster2-id} nginx.ingress.kubernetes.io/canary: "true" nginx.ingress.kubernetes.io/canary-by-header: "app-web-demo-version" nginx.ingress.kubernetes.io/canary-by-header-value: "gray" name: web-demo-cluster-gray name: web-demo spec: ingressClassName: mse rules: - host: example.com http: paths: - path: /service1 pathType: Exact backend: service: name: service1 port: number: 80
执行以下命令,在ACK One Fleet实例中部署Ingress。
kubectl apply -f ingress-demo-cluster-gray.yaml -n gateway-demo
验证同城主备容灾实现效果
为便于验证,修改部署到Cluster 1和Cluster 2的副本数都为1,期望默认流量只被路由到Cluster 1,加灰度Header的流量被路由到Cluster 2,当Cluster 1应用异常后,默认流量也被路由到Cluster 2。
执行以下命令,获取多集群网关的对外IP。
kubectl get ingress web-demo -n gateway-demo -ojsonpath="{.status.loadBalancer}"
默认流量路由到Cluster 1
执行以下命令,查看默认流量是否被路由到Cluster 1。
替换以下
XX.XX.XX.XX
为上一步获取的多集群网关的对外IP。for i in {1..100}; do curl -H "host: example.com" xx.xx.xx.xx/service1; sleep 1; done
预期输出:预期输出表明,默认流量全都被路由到Cluster 1了。
通过header将请求路由到灰度版本
执行以下命令,查看Header的请求是否被路由到灰度版本。
替换以下
XX.XX.XX.XX
为上一步获取的多集群网关的对外IP。for i in {1..50}; do curl -H "host: example.com" -H "app-web-demo-version: gray" xx.xx.xx.xx/service1; sleep 1; done
预期输出:预期输出表明,添加了Header:
app-web-demo-version: gray
的请求都被路由到了Cluster 2(灰度版本)。Cluster 1异常后流量被容灾到Cluster 2
如果将Cluster 1的Deployment的
replica
缩为0时,得到的输出结果如下,表明流量已被自动容灾到Cluster 2。
相关文档
如需了解ACK One多集群网关的南北流量管理能力,请参见使用多集群网关管理南北流量。
关于ACK One GitOps应用分发的相关操作,请参见GitOps快速入门。