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

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

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

    • 安装 :用于安装 TiDB Operator。

    • 完成 AWS eksctl 入门中所有操作。

      该教程包含以下内容:

      • 安装并配置 AWS 的命令行工具 awscli
      • 安装并配置创建 Kubernetes 集群的命令行工具 eksctl
      • 安装 Kubernetes 命令行工具 kubectl
    • AWS Access Key 至少具有 和创建 Linux 堡垒机所涉及的服务权限

    要验证 AWS CLI 的配置是否正确,请运行 命令。如果此命令的输出显示了 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。

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

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

      1. eksctl create cluster -f cluster_1.yaml

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

    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 命令操作每个集群。

      1. kubectl config get-contexts

      点击查看输出,其中的 `NAME` 项就是你需要使用的 context 。

      1. 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。

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

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

      1. eksctl get cluster ${cluster_1} --region ${region_1}

      点击查看示例输出,其中 `VPC` 项就是该集群所在 VPC 的 ID。

      1. 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。

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

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

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

    3. 按照,更新三个集群的路由表。

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

      每个路由项的 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,其文件内容如下:

      1. apiVersion: v1
      2. kind: Service
      3. metadata:
      4. labels:
      5. k8s-app: kube-dns
      6. name: across-cluster-dns-tcp
      7. namespace: kube-system
      8. annotations:
      9. service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
      10. service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
      11. service.beta.kubernetes.io/aws-load-balancer-internal: "true"
      12. spec:
      13. ports:
      14. port: 53
      15. protocol: TCP
      16. selector:
      17. k8s-app: kube-dns
      18. type: LoadBalancer
    2. 在每个集群中部署 Load Balancer Service。

    3. 获取各集群的负载均衡器的名字,并等待所有集群的负载均衡器变为 Active 状态。

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

      1. 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)
      2. 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)
      3. 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 状态。

      1. aws elbv2 describe-load-balancers --names ${lb_name_1} --region ${region_1} --query 'LoadBalancers[*].State' --output text
      2. aws elbv2 describe-load-balancers --names ${lb_name_2} --region ${region_2} --query 'LoadBalancers[*].State' --output text
      3. aws elbv2 describe-load-balancers --names ${lb_name_3} --region ${region_3} --query 'LoadBalancers[*].State' --output text

      点击查看期望输出

      1. active active active
    4. 查询各集群的负载均衡器关联的 IP 地址。

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

      1. aws ec2 describe-network-interfaces --region ${region_1} --filters Name=description,Values="ELB net/${lb_name_1}*" --query 'NetworkInterfaces[*].PrivateIpAddress' --output text

      点击查看期望输出

      1. 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 对应的 ConfigMap 来进行配置。如需了解更多配置项,参考 Customizing DNS Service

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

      1. 备份当前的 CoreDNS 配置:

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

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

        警告

        因为 EKS 集群无法修改集群的 cluster domain,因此我们需要使用 namespace 作为 DNS 请求转发的识别条件,所以 ${namespace_1}$ {namespace_2}${namespace_3} 必须不一样。

        1. apiVersion: v1
        2. kind: ConfigMap
        3. # ...
        4. data:
        5. Corefile: |
        6. .:53 {
        7. # ... 默认配置不修改
        8. }
        9. ${namespace_2}.svc.cluster.local:53 {
        10. errors
        11. cache 30
        12. forward . ${lb_ip_list_2} {
        13. force_tcp
        14. }
        15. }
        16. ${namespace_3}.svc.cluster.local:53 {
        17. errors
        18. cache 30
        19. forward . ${lb_ip_list_3} {
        20. force_tcp
        21. }
        22. }
      3. 等待 CoreDNS 重新加载配置,大约需要 30s 左右。

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

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

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

    第 3 步:验证网络连通性

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

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

      1. apiVersion: v1
      2. metadata:
      3. name: sample-nginx
      4. labels:
      5. app: sample-nginx
      6. spec:
      7. hostname: sample-nginx
      8. subdomain: sample-nginx-peer
      9. containers:
      10. - image: nginx:1.21.5
      11. imagePullPolicy: IfNotPresent
      12. name: nginx
      13. ports:
      14. - name: http
      15. containerPort: 80
      16. restartPolicy: Always
      17. ---
      18. apiVersion: v1
      19. kind: Service
      20. metadata:
      21. name: sample-nginx-peer
      22. spec:
      23. ports:
      24. - port: 80
      25. selector:
      26. app: sample-nginx
      27. clusterIP: None
    2. 在三个集群对应的命名空间下部署 NGINX 服务。

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

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

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

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

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

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

    每个集群的 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 部署到 一节中对应的 namespace 下,否则 TiDB 集群运行将会失败。
    • 各集群的 cluster domain 必须 设置为 “cluster.local”。

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

    1. apiVersion: pingcap.com/v1alpha1
    2. kind: TidbCluster
    3. metadata:
    4. name: ${tc_name_1}
    5. namespace: ${namespace_1}
    6. spec:
    7. # ...
    8. clusterDomain: "cluster.local"