16 KiB
腾讯云跨账号流量统一接入与治理方案
需求场景
服务部署在不同腾讯云账号下,想统一在一个腾讯云账号下接入流量,部分流量可能会转发到其它腾讯云账号下的服务。
需求分析
多集群跨 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/v1alpha3
kind: Gateway
metadata:
name: cluster
namespace: istio-system
spec:
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: v1
kind: ConfigMap
metadata:
name: cluster1-conf
namespace: test
data:
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: v1
kind: Service
metadata:
name: cluster1
namespace: test
labels:
app: cluster1
spec:
type: ClusterIP
ports:
- port: 80
name: http
protocol: TCP
targetPort: 80
selector:
app: cluster1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster1
namespace: test
spec:
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 test
kubectl apply -f cluster1.yaml
等待部署成功:
第二个服务的 yaml (cluster2.yaml
):
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster2-conf
namespace: test
data:
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: v1
kind: Service
metadata:
name: cluster2
namespace: test
labels:
app: cluster2
spec:
type: ClusterIP
ports:
- port: 80
name: http
protocol: TCP
targetPort: 80
selector:
app: cluster2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster2
namespace: test
spec:
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 test
kubectl apply -f cluster2.yaml
类似的,第三个服务的 yaml (cluster3.yaml
):
apiVersion: v1
kind: ConfigMap
metadata:
name: cluster3-conf
namespace: test
data:
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: v1
kind: Service
metadata:
name: cluster3
namespace: test
labels:
app: cluster3
spec:
type: ClusterIP
ports:
- port: 80
name: http
protocol: TCP
targetPort: 80
selector:
app: cluster3
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster3
namespace: test
spec:
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 test
kubectl apply -f cluster3.yaml
配置 VirtualService 规则
可以在 TCM 控制台可视化操作,也可以用 apply yaml,这里示例使用 yaml。
首先,为三个不同服务创建对应的 VirtualService 并与 Gateway 关联:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: cluster1-imroc-cc
namespace: test
spec:
gateways:
- istio-system/cluster
hosts:
- 'cluster1.imroc.cc'
http:
- route:
- destination:
host: cluster1.test.svc.cluster.local
port:
number: 80
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: cluster2-imroc-cc
namespace: test
spec:
gateways:
- istio-system/cluster
hosts:
- 'cluster2.imroc.cc'
http:
- route:
- destination:
host: cluster2.test.svc.cluster.local
port:
number: 80
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: cluster3-imroc-cc
namespace: test
spec:
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 同时转发到不同集群,配置流量比例等。