构建多个网络互通的 AWS EKS 集群

本文以构建 3 个集群为例,介绍了如何构建多个 AWS EKS 集群,并配置集群之间的网络互通,为跨 Kubernetes 集群部署 TiDB 集群作准备。

如果仅需要部署 TiDB 集群到一个 AWS EKS 集群,请参考在 AWS EKS 上部署 TiDB 集群文档。

环境准备

部署前,请确认已完成以下环境准备:

要验证 AWS CLI 的配置是否正确,请运行 aws configure list 命令。如果此命令的输出显示了 access_keysecret_key 的值,则 AWS CLI 的配置是正确的。否则,你需要重新配置 AWS CLI。

第 1 步:启动 Kubernetes 集群

定义三个 EKS 集群的配置文件分别为 cluster_1.yamlcluster_2.yamlcluster_3.yaml,并使用 eksctl 命令创建三个 EKS 集群。

  1. 定义集群 1 的配置文件,并创建集群 1。

    将如下配置保存为 cluster_1.yaml 文件,其中 ${cluster_1} 为 EKS 集群的名字,${region_1} 为部署 EKS 集群到的 Region,${cidr_block_1} 为 EKS 集群所属的 VPC 的 CIDR block。

    apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ${cluster_1} region: ${region_1} # nodeGroups ... vpc: cidr: ${cidr_block_1}

    节点池 nodeGroups 字段的配置可以参考创建 EKS 集群和节点池一节。

    执行以下命令创建集群 1 :

    eksctl create cluster -f cluster_1.yaml

    执行上述命令后,等待 EKS 集群创建完成,以及节点组创建完成并加入进去,耗时约 5~20 分钟。可参考 eksctl 文档了解更多集群配置选项。

  2. 以集群 1 的配置文件为例,定义集群 2 与集群 3 的配置文件,并通过 eksctl 命令创建集群 2 与集群 3。

    需要注意,每个集群所属的 VPC 的 CIDR block 必须 与其他集群不重叠。

    后文中:

    • ${cluster_1}${cluster_2}${cluster_3} 分别代表三个集群的名字。
    • ${region_1}${region_2}${region_3} 分别代表三个集群所处的 Region。
    • ${cidr_block_1}${cidr_block_2}${cidr_block_3} 分别代表三个集群所属的 VPC 的 CIDR block。
  3. 在所有集群创建完毕后,你需要获取每个集群的 Kubernetes Context,以方便后续使用 kubectl 命令操作每个集群。

    kubectl config get-contexts
    点击查看输出,其中的 `NAME` 项就是你需要使用的 context 。
    CURRENT NAME CLUSTER AUTHINFO NAMESPACE * pingcap@tidb-1.us-west-1.eksctl.io tidb-1.us-west-1.eksctl.io pingcap@tidb-1.us-west-1.eksctl.io pingcap@tidb-2.us-west-2.eksctl.io tidb-2.us-west-2.eksctl.io pingcap@tidb-2.us-west-2.eksctl.io pingcap@tidb-3.us-east-1.eksctl.io tidb-3.us-east-1.eksctl.io pingcap@tidb-3.us-east-1.eksctl.io

    后文中,${context_1}${context_2}${context_3} 分别代表各个集群的 context。

第 2 步:配置网络

设置 VPC peering

为了联通三个集群的网络,你需要为每两个集群所在的 VPC 创建一个 VPC peering。关于 VPC peering,可以参考 AWS 官方文档

  1. 通过 eksctl 命令,得到每个集群所在的 VPC 的 ID。以集群 1 为例:

    eksctl get cluster ${cluster_1} --region ${region_1}
    点击查看示例输出,其中 `VPC` 项就是该集群所在 VPC 的 ID。
    NAME VERSION STATUS CREATED VPC SUBNETS SECURITYGROUPS tidb-1 1.20 ACTIVE 2021-11-22T06:40:20Z vpc-0b15ed35c02af5288 subnet-058777d55881c4095, subnet-06def2041b6fa3fa0,subnet-0869c7e73e09c3174,subnet-099d10845f6cbaf82,subnet-0a1a58db5cb087fed, subnet-0f68b302678c4d36b sg-0cb299e7ec153c595

    后文中,${vpc_id_1}${vpc_id_2}${vpc_id_3} 分别代表各个集群所在的 VPC 的 ID。

  2. 构建集群 1 与集群 2 的 VPC peering。

    1. 按照 AWS VPC peering 文档创建 VPC peering。${vpc_id_1} 作为 requester VPC,${vpc_id_2} 作为 accepter VPC 。

    2. 按照 AWS VPC Peering 文档完成 VPC peering 的构建。

  3. 以步骤 2 为例,构建集群 1 与集群 3 的 VPC peering,以及集群 2 与集群 3 的 VPC peering。

  4. 按照更新路由表文档,更新三个集群的路由表。

    你需要更新集群使用的所有 Subnet 的路由表。每个路由表需要添加两个路由项,以集群 1 的某个路由表为例:

    DestinationTargetStatusPropagated
    ${cidr_block_2}${vpc_peering_id_12}ActiveNo
    ${cidr_block_3}${vpc_peering_id_13}ActiveNo

    每个路由项的 Destination 为另一个集群的 CIDR block,Target 为这两个集群的 VPC peering ID。

更新实例的安全组

  1. 更新集群 1 的安全组:

    1. 进入 AWS Security Groups 控制台,找到集群 1 的安全组。安全组命名类似于 eksctl-${cluster_1}-cluster/ClusterSharedNodeSecurityGroup

    2. 在安全组中添加 Inbound rules,以允许来自集群 2 和集群 3 的流量:

      TypeProtocolPort rangeSourceDescription
      All trafficAllAllCustom ${cidr_block_2}Allow cluster 2 to communicate with cluster 1
      All trafficAllAllCustom ${cidr_block_3}Allow cluster 3 to communicate with cluster 1
  2. 按照步骤 1,更新集群 2 与集群 3 的安全组。

配置负载均衡器

每个集群的 CoreDNS 服务需要通过一个网络负载均衡器暴露给其他集群。本节介绍如何配置负载均衡器。

  1. 创建 Load Balancer Service 定义文件 dns-lb.yaml,其文件内容如下:

    apiVersion: v1 kind: Service metadata: labels: k8s-app: kube-dns name: across-cluster-dns-tcp namespace: kube-system annotations: service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true" service.beta.kubernetes.io/aws-load-balancer-type: "nlb" service.beta.kubernetes.io/aws-load-balancer-internal: "true" spec: ports: - name: dns port: 53 protocol: TCP targetPort: 53 selector: k8s-app: kube-dns type: LoadBalancer
  2. 在每个集群中部署 Load Balancer Service。

    kubectl --context ${context_1} apply -f dns-lb.yaml kubectl --context ${context_2} apply -f dns-lb.yaml kubectl --context ${context_3} apply -f dns-lb.yaml
  3. 获取各集群的负载均衡器的名字,并等待所有集群的负载均衡器变为 Active 状态。

    使用以下命令来查询三个集群的负载均衡器的名字。

    lb_name_1=$(kubectl --context ${context_1} -n kube-system get svc across-cluster-dns-tcp -o jsonpath="{.status.loadBalancer.ingress[0].hostname}" | cut -d - -f 1) lb_name_2=$(kubectl --context ${context_2} -n kube-system get svc across-cluster-dns-tcp -o jsonpath="{.status.loadBalancer.ingress[0].hostname}" | cut -d - -f 1) lb_name_3=$(kubectl --context ${context_3} -n kube-system get svc across-cluster-dns-tcp -o jsonpath="{.status.loadBalancer.ingress[0].hostname}" | cut -d - -f 1)

    执行以下命名来查看三个集群的负载均衡器的状态,所有的命令输出结果都为 "active" 时,表明负载均衡器为 Active 状态。

    aws elbv2 describe-load-balancers --names ${lb_name_1} --region ${region_1} --query 'LoadBalancers[*].State' --output text aws elbv2 describe-load-balancers --names ${lb_name_2} --region ${region_2} --query 'LoadBalancers[*].State' --output text aws elbv2 describe-load-balancers --names ${lb_name_3} --region ${region_3} --query 'LoadBalancers[*].State' --output text
    点击查看期望输出
    active active active
  4. 查询各集群的负载均衡器关联的 IP 地址。

    以集群 1 为例,执行下面命令查询集群 1 的负载均衡器关联的所有 IP 地址。

    aws ec2 describe-network-interfaces --region ${region_1} --filters Name=description,Values="ELB net/${lb_name_1}*" --query 'NetworkInterfaces[*].PrivateIpAddress' --output text
    点击查看期望输出
    10.1.175.233 10.1.144.196

    后文中,将各集群的负载均衡器关联 IP 地址称为 ${lb_ip_list_1}${lb_ip_list_2}${lb_ip_list_3}

    不同 Region 的负载均衡器可能有着不同数量的 IP 地址。例如上述示例中,${lb_ip_list_1} 就是 10.1.175.233 10.1.144.196

配置 CoreDNS

为了让集群中的 Pod 能够访问其他集群的 Service,你需要配置每个集群的 CoreDNS 服务,使其能够转发 DNS 请求给其他集群的 CoreDNS 服务。

你可以通过修改 CoreDNS 对应的 ConfigMap 来进行配置。如需了解更多配置项,参考 Customizing DNS Service

  1. 修改集群 1 的 CoreDNS 配置。

    1. 备份当前的 CoreDNS 配置:

      kubectl --context ${context_1} -n kube-system get configmap coredns -o yaml > ${cluster_1}-coredns.yaml.bk
    2. 修改 ConfigMap:

      kubectl --context ${context_1} -n kube-system edit configmap coredns

      修改 data.Corefile 字段如下,其中 ${namespace_2}${namespace_3} 分别为集群 2 和集群 3 将要部署的 TidbCluster 所在的 namespace。

      apiVersion: v1 kind: ConfigMap # ... data: Corefile: | .:53 { # ... 默认配置不修改 } ${namespace_2}.svc.cluster.local:53 { errors cache 30 forward . ${lb_ip_list_2} { force_tcp } } ${namespace_3}.svc.cluster.local:53 { errors cache 30 forward . ${lb_ip_list_3} { force_tcp } }
    3. 等待 CoreDNS 重新加载配置,大约需要 30s 左右。

  2. 以步骤 1 为例,修改集群 2 和集群 3 的 CoreDNS 配置。

    对于每个集群的 CoreDNS 配置,你需要将 ${namespace_2}${namespace_3} 修改为另外两个集群将要部署 TidbCluster 的 namespace,将配置中的 IP 地址配置为另外两个集群的 Load Balancer 的 IP 地址。

后文中,使用 ${namespace_1}${namespace_2}${namespace_3} 分别代表各个集群的将要部署的 TidbCluster 所在的 namespace。

第 3 步:验证网络连通性

在部署 TiDB 集群之前,你需要先验证多个集群之间的网络连通性。

  1. 将下面定义保存到 sample-nginx.yaml 文件。

    apiVersion: v1 kind: Pod metadata: name: sample-nginx labels: app: sample-nginx spec: hostname: sample-nginx subdomain: sample-nginx-peer containers: - image: nginx:1.21.5 imagePullPolicy: IfNotPresent name: nginx ports: - name: http containerPort: 80 restartPolicy: Always --- apiVersion: v1 kind: Service metadata: name: sample-nginx-peer spec: ports: - port: 80 selector: app: sample-nginx clusterIP: None
  2. 在三个集群对应的命名空间下部署 NGINX 服务。

    kubectl --context ${context_1} -n ${namespace_1} apply -f sample-nginx.yaml kubectl --context ${context_2} -n ${namespace_2} apply -f sample-nginx.yaml kubectl --context ${context_3} -n ${namespace_3} apply -f sample-nginx.yaml
  3. 访问其他集群的 NGINX 服务,验证网络是否连通。

    以验证集群 1 到集群 2 的网络连通性为例,执行以下命令。

    kubectl --context ${context_1} -n ${namespace_1} exec sample-nginx -- curl http://sample-nginx.sample-nginx-peer.${namespace_2}.svc.cluster.local:80

    如果输出为 NGINX 的欢迎页面,那么就表明网络是正常连通的。

  4. 验证完成后,执行以下命令删除 NGINX 服务。

    kubectl --context ${context_1} -n ${namespace_1} delete -f sample-nginx.yaml kubectl --context ${context_2} -n ${namespace_2} delete -f sample-nginx.yaml kubectl --context ${context_3} -n ${namespace_3} delete -f sample-nginx.yaml

第 4 步:部署 TiDB Operator

每个集群的 TidbCluster CR 由当前集群的 TiDB Operator 管理,因此每个集群都需要部署 TiDB Operator。

参考在 Kubernetes 上部署 TiDB Operator 部署 TiDB Operator 到每个 EKS 集群。区别在于,你需要通过命令 kubectl --context ${context}helm --kube-context ${context} 来为每个 EKS 集群部署 TiDB Operator。

第 5 步:部署 TiDB 集群

参考跨多个 Kubernetes 集群部署 TiDB 集群,为每个集群部署一个 TidbCluster CR。需要注意的是:

  • 必须将各集群的 TidbCluster 部署到配置 CoreDNS 一节中对应的 namespace 下,否则 TiDB 集群运行将会失败。
  • 各集群的 cluster domain 必须 设置为 "cluster.local"。

例如,部署初始集群的 TidbCluster CR 到集群 1 时,将 metadata.namespace 指定为 ${namespace_1}:

apiVersion: pingcap.com/v1alpha1 kind: TidbCluster metadata: name: ${tc_name_1} namespace: ${namespace_1} spec: # ... clusterDomain: "cluster.local" acrossK8s: true

探索更多

文档内容是否有帮助?