/【腾讯云原生】腾讯云跨账号流量统一接入与治理方案

【腾讯云原生】腾讯云跨账号流量统一接入与治理方案

导语 | 本文推选自腾讯云开发者社区-【技思广益 · 腾讯技术人原创集】专栏。该专栏是腾讯云开发者社区为腾讯技术人与广泛开发者打造的分享交流窗口。栏目邀约腾讯技术人分享原创的技术积淀,与广泛开发者互启迪共成长。本文作者是腾讯云原生架构师imroc。


本文主要探析腾讯云跨账号流量统一接入与治理的相关方案,由浅入深,层层深入,希望本文能对此方面感兴趣的开发者们提供一些经验和帮助。

需求场景

服务部署在不同腾讯云账号下,想统一在一个腾讯云账号下接入流量,部分流量可能会转发到其它腾讯云账号下的服务。

需求分析

多集群跨VPC流量管理,可以通过腾讯云服务网格(TCM) + 云联网(CCN) 来实现,自动对多个容器集群进行服务发现(Pod IP),利用isito ingressgateway统一接入流量,然后直接转发到后端服务的Pod IP:

但这里需求关键点是跨账号,虽然跨账号网络也可以用云联网打通,但是TCM是无法直接管理其它账号下的集群的,原因很明显,关联集群时只能选择本账号下的集群,没有权限关联其它账号下的集群:

幸运的是,我们可以利用云原生分布式云中心(TDCC) 来管理其它账号的集群 (TDCC目前还在内测中,需提交内核申请进行开通),将其它账号的集群注册到TDCC中,然后在TCM里添加TDCC中注册的集群,TCM通过关联 TDCC注册集群来间接对其它账号的集群进行服务发现,以实现多账号下的集群流量统一纳管:

注意事项: 其它账号尽量使用独立集群

istio注入sidecar时需要集群apiserver调用TCM控制面webhook:

如果使用托管集群(TKE托管集群或EKS集群),apiserver是用户不可见的,使用169开头的IP,这个IP只在VPC内可用。


所以如果将账号B的托管集群注册到账号A的TDCC中,账号B的托管集群 apiserver也无法调用到账号A的TCM控制面,就会导致无法注入 sidecar,而独立集群没这个问题,因为apiserver是部署在用户CVM上,使用CVM的IP,打通云联网后网络就可以互通,所以推荐其它账号下的集群使用TKE独立集群。


当然如果能保证完全没有sidecar自动注入的需求,不需要账号B的服务通过网格的服务发现主动调用账号A的服务,这种情况使用托管集群也可以。

操作步骤

(一)准备集群

在账号A下(用于接入流量的账号),准备好一个或多个TKE/EKS集群,在其它账号准备好TKE独立集群。

注意,一定保证所有集群使用的网段互不冲突。

(二)使用云联网打通网络

登录账号A,进入云联网控制台里,新建一个云联网,然后点击【新增实例】,将需要账号A下需要打通网络的VPC全部关联进来:

登录其它账号,进入VPC控制台,点击进入需要与账号A打通网络的VPC,点【立即关联】:

选择【其它账号】,输入账号A的ID以及前面创建的云联网的ID以申请加入账号A创建的云联网:

然后再登录账号A,点进前面创建的云联网,同意其它账号VPC加入云联网的申请:

不出意外,不同账号不同VPC成功通过云联网打通网络:

如果你使用了TKE集群的Global Router网络模式,在集群基本信息页面,将容器网络注册到云联网的开关打开,以便让Global Router网络模式的容器IP通过云联网下发给所有其它VPC:

(三)开通TDCC

登录账号A,进入TDCC控制台,首次进入需要按流程进行开通操作。

首先会提示为TDCC进行授权:

点击【同意授权】:

选择要开通的TDCC所在地域以及VPC与子网:

需要注意的是:


  • TDCC是多集群的控制面,可以同时管理多个地域的集群,尽量将TDCC所在地域选在服务部署的地域,如果服务分散在多个地域,或者TDCC还不支持服务所在地域,可以尽量选择离服务近一点的地域,尽量降低TDCC控制面到集群之间的时延。

  • TDCC与集群如果跨地域,仅仅增加一点控制面之间的时延,不影响数据面。数据面之间的转发时延只取决于集群之间的距离,与TDCC无关,比如,集群都在成都地域,但TDCC不支持成都,可以将TDCC选择广州。

  • 可以将TDCC所在VPC也加入到云联网,这样其它账号注册集群到TDCC时就可以使用内网方式,网络稳定性更有保障。

等待TDCC的Hub集群创建完成:

完成后,在TDCC集群列表页面,点击【注册已有集群】:

虽然其它账号使用的TKE独立集群,但这里一定要选择【非TKE集群】:

因为如果选【TKE集群】,只能选到本账号的,其它账号的选不了。

选择其它账号集群实际所在地域,然后点【完成】,回到集群列表页面,点击【查看注册命令】:

可以看到自动生成的yaml,将其下载下来,保存成agent.yaml:

然后kubectl的context切换到其它账号中要注册到TDCC的集群,使用kubectl将yaml apply进去:

kubectl apply -f agent.yaml

不出意外,TDCC集群列表页面可以看到注册集群状态变为了运行中,即将其它账号下的集群成功注册到TDCC:

(四)创建服务网格

登录账号A,进入TCM控制台,点【新建】来创建一个服务网格:

推荐选择最高版本istio,托管网格:

服务发现就是关联集群,可以在创建网格时就关联,也可以等创建完再关联。

如果将TDCC中的注册集群关联进TCM?在关联集群时,选择TDCC所在地域和注册集群类型,然后就可以下拉选择其它账号下注册进来的集群了:

不出意外,账号A和其它账号的集群都关联到同一个服务网格了:

(五)创建Ingress Gateway

进入账号A创建的网格,在基本信息页面里创建Ingress Gateway:

配置一下Ingress Gateway,接入集群选要统一接入流量的集群:

创建好后,点进去:

可以看到创建出来的CLB IP地址以及对应的CLB ID:

如有需要,创建Ingress Gateway时也可以选择已有CLB。

Ingress Gateway组件创建好了,再创建一个Gateway对象与之关联:

也可以直接用yaml创建。

apiVersion: networking.istio.io/v1alpha3kind: Gatewaymetadata:  name: cluster  namespace: istio-systemspec:  selector:    app: istio-ingressgateway    istio: ingressgateway  servers:  - port:      number: 80      name: HTTP-80      protocol: HTTP    hosts:    - "*.imroc.cc"

(六)配置DNS解析

将三个不同的域名都解析到前面创建的Ingress Gateway的CLB IP:


验证一下是否都正确解析到了同一个IP:

(七)部署测试服务


分别在几个集群部署服务,这里给出一个示例,将3个不同服务分别部署在不同集群中,其中一个集群在其它账号下:

  • 3个服务使用不同域名,但DNS都指向同一个ingressgateway,统一接入流量。

  • 根据不同域名转发给不同的服务。

服务部署使用prism,模拟不同服务的返回不同,访问根路径分别返回字符串cluster1、cluster2与cluster3。

第一个服务的yaml (cluster1.yaml):

apiVersion: v1kind: ConfigMapmetadata:  name: cluster1-conf  namespace: testdata:  mock.yaml: |    openapi: 3.0.3    info:      title: MockServer      description: MockServer      version: 1.0.0    paths:      '/':        get:          responses:            '200':              content:                'text/plain':                  schema:                    type: string                    example: cluster1---apiVersion: v1kind: Servicemetadata:  name: cluster1  namespace: test  labels:    app: cluster1spec:  type: ClusterIP  ports:  - port: 80    name: http    protocol: TCP    targetPort: 80  selector:    app: cluster1
---apiVersion: apps/v1kind: Deploymentmetadata: name: cluster1 namespace: testspec: replicas: 1 selector: matchLabels: app: cluster1 version: v1 template: metadata: labels: app: cluster1 version: v1 spec: containers: - name: cluster1 image: stoplight/prism:4 args: - mock - -h - 0.0.0.0 - -p - "80" - /etc/prism/mock.yaml volumeMounts: - mountPath: /etc/prism name: config volumes: - name: config configMap: name: cluster1-conf

将其apply到账号A的集群1:

kubectl create ns testkubectl apply -f cluster1.yaml

等待部署成功:

第二个服务的yaml (cluster2.yaml):

apiVersion: v1kind: ConfigMapmetadata:  name: cluster2-conf  namespace: testdata:  mock.yaml: |    openapi: 3.0.3    info:      title: MockServer      description: MockServer      version: 1.0.0    paths:      '/':        get:          responses:            '200':              content:                'text/plain':                  schema:                    type: string                    example: cluster2---apiVersion: v1kind: Servicemetadata:  name: cluster2  namespace: test  labels:    app: cluster2spec:  type: ClusterIP  ports:  - port: 80    name: http    protocol: TCP    targetPort: 80  selector:    app: cluster2
---apiVersion: apps/v1kind: Deploymentmetadata: name: cluster2 namespace: testspec: replicas: 1 selector: matchLabels: app: cluster2 version: v1 template: metadata: labels: app: cluster2 version: v1 spec: containers: - name: cluster2 image: stoplight/prism:4 args: - mock - -h - 0.0.0.0 - -p - "80" - /etc/prism/mock.yaml volumeMounts: - mountPath: /etc/prism name: config volumes: - name: config configMap: name: cluster2-conf

将其apply到账号A的集群2:

kubectl create ns testkubectl apply -f cluster2.yaml

类似的,第三个服务的yaml (cluster3.yaml):

apiVersion: v1kind: ConfigMapmetadata:  name: cluster3-conf  namespace: testdata:  mock.yaml: |    openapi: 3.0.3    info:      title: MockServer      description: MockServer      version: 1.0.0    paths:      '/':        get:          responses:            '200':              content:                'text/plain':                  schema:                    type: string                    example: cluster3---apiVersion: v1kind: Servicemetadata:  name: cluster3  namespace: test  labels:    app: cluster3spec:  type: ClusterIP  ports:  - port: 80    name: http    protocol: TCP    targetPort: 80  selector:    app: cluster3
---apiVersion: apps/v1kind: Deploymentmetadata: name: cluster3 namespace: testspec: replicas: 1 selector: matchLabels: app: cluster3 version: v1 template: metadata: labels: app: cluster3 version: v1 spec: containers: - name: cluster3 image: stoplight/prism:4 args: - mock - -h - 0.0.0.0 - -p - "80" - /etc/prism/mock.yaml volumeMounts: - mountPath: /etc/prism name: config volumes: - name: config configMap: name: cluster3-conf

将其apply到另一个账号的集群:

kubectl create ns testkubectl apply -f cluster3.yaml

(八)配置VirtualService规则

可以在TCM控制台可视化操作,也可以用apply yaml,这里示例使用 yaml。

首先,为三个不同服务创建对应的VirtualService并与Gateway关联:

apiVersion: networking.istio.io/v1beta1kind: VirtualServicemetadata:  name: cluster1-imroc-cc  namespace: testspec:  gateways:  - istio-system/cluster  hosts:  - 'cluster1.imroc.cc'  http:  - route:    - destination:        host: cluster1.test.svc.cluster.local        port:          number: 80---apiVersion: networking.istio.io/v1beta1kind: VirtualServicemetadata:  name: cluster2-imroc-cc  namespace: testspec:  gateways:  - istio-system/cluster  hosts:  - 'cluster2.imroc.cc'  http:  - route:    - destination:        host: cluster2.test.svc.cluster.local        port:          number: 80---apiVersion: networking.istio.io/v1beta1kind: VirtualServicemetadata:  name: cluster3-imroc-cc  namespace: testspec:  gateways:  - istio-system/cluster  hosts:  - cluster3.imroc.cc  http:  - route:    - destination:        host: cluster3.test.svc.cluster.local        port:          number: 80

(九)测试效果


使用curl请求不同服务的域名,可以看到将请求均正确转发到了对应的集群,并响应了对应不同的结果:

总结

本文给出了在腾讯云上利用TCM+CCN+TDCC实现跨账号多集群流量统一接入和治理的方案,示例中的功能相对简单,如有需要,还可以自行配置istio规则实现更细粒度的流量治理,比如根据不同url路径转发到不同集群的服务,甚至相同url同时转发到不同集群,配置流量比例等。

 作者简介


imroc

腾讯云开发者社区【技思广益·腾讯技术人原创集】作者


腾讯云原生架构师,负责腾讯云原生产品解决方案与售后的技术支持,根据客户需求输出合理技术方案与最佳实践,为客户业务保驾护航。

 推荐阅读

地产行业,如何跑赢「黑铁时代」?

深入浅出webpack的最佳实践!

基于腾讯云自建高可用DNS方案实践

Kubernetes原理与架构初探


👇点击「阅读原文」注册成为社区创作者,认识大咖,打造你的技术影响力!

本文来自微信公众号“腾讯云开发者”(ID:QcloudCommunity)。大作社经授权转载,该文观点仅代表作者本人,大作社平台仅提供信息存储空间服务。