为 GKE 配置以非公开方式使用的公共 IP 地址

本教程介绍如何将以非公开方式使用的公共 IP (PUPI) 地址应用于 Google Kubernetes Engine (GKE) Pod 地址块。IPv4 地址受限的服务使用方组织可以在服务提供方虚拟私有云 (VPC) 中将 PUPI 地址用作地址管理选项。

本文档适用于公司通过 Google Cloud 上的 GKE 基础架构提供代管式服务的网络架构师和 GKE 系统管理员。

简介

一些公司希望通过 Kubernetes 或 Google Cloud 上的 GKE 集群为客户提供代管式服务。但是,Kubernetes 可能需要多个 IP 地址才能使用其各种组件。对于一些组织来说,由于无法分配适当大小的 10.0.0.0/8172.16.0.0/12192.168.0.0/16 (RFC 1918) 无类别域间路由 (CIDR) 地址块,因此很难甚至无法满足此要求。

缓解地址耗尽的一种方法是使用 GKE Pod CIDR 地址块的以非公开方式使用的公共 IP (PUPI) 地址。PUPI 是指不归 Google 所有、客户可以在 Google Cloud 上以非公开方式使用的公共 IP 地址。客户不一定拥有这些地址。

下图显示了为客户(使用方)提供代管式服务的公司(提供方)。

GKE Pod CIDR 地址块的 PUPI 地址。

此设置涉及以下注意事项:

  • 主要 CIDR 地址块:用于节点和 ILB 且不能跨 VPC 重叠的非 PUPI CIDR 地址块。
  • 提供方次要 CIDR 地址块:用于 Pod 的 PUPI CIDR 地址块(例如 45.45.0.0/16)。
  • 使用方次要 CIDR 地址块:客户端的任何其他 PUPI CIDR 地址块(例如 5.5/16)。

公司代管式服务位于提供方 VPC (vpc-producer) 中,并在 GKE 部署上构建。公司 GKE 集群对 Pod 地址使用 PUPI 45.0.0.0/8 CIDR 地址块。客户应用位于使用方 VPC (vpc-consumer) 中。客户还安装了 GKE。使用方 VPC 中的 GKE 集群对 Pod 地址使用 PUPI 5.0.0.0/8 CIDR 地址块。这两个 VPC 彼此对等互连。这两个 VPC 都对节点、服务和负载平衡地址使用 RFC 1918 地址空间。

默认情况下,使用方 VPC (vpc-consumer) 将所有 RFC 1918 导出到提供方 VPC (vpc-producer)。与 RFC 1918 专用地址和扩展专用地址(CGN、Class E)不同,默认情况下不会自动将 PUPI 通告到 VPC 对等方。如果 vpc-consumer Pod 必须与 vpc-producer 通信,则使用方必须启用 VPC 对等互连连接来导出 PUPI 地址。同样,提供方必须配置提供方 VPC 以通过 VPC 对等互连连接导入 PUPI 路由。

导出到 vpc-producervpc-consumer 地址空间不得与 vpc-producer 中使用的任何 RFC 1918 或 PUPI 地址重叠。提供方必须向使用方告知代托管式服务使用的 PUPI CIDR 地址块,并确保使用方未在使用这些地址块。提供方和使用方还必须同意并分配未重叠的地址空间,以用于 vpc-producer 中的内部负载平衡 (ILB) 和节点地址。

在大多数情况下,vpc-consumer 中的资源通过提供方集群中的 ILB 地址与 vpc-producer 中的服务进行通信。如果需要提供方 Pod 直接启动与 vpc-consumer 中的资源的通信,并且 PUPI 寻址未重叠,则提供方必须配置提供方 VPC,以通过 VPC 对等互连连接导出 PUPI 路由。同样,使用方必须配置 VPC 对等互连连接以将路由导入 vpc-consumer。如果使用方 VPC 已使用 PUPI 地址,则提供方应配置 IP 地址伪装功能,并隐藏提供方节点 IP 地址后面的 Pod IP 地址。

下表显示了每个 VPC 的默认导入和导出设置。您可以使用 gcloud compute networks peerings update Cloud SDK 命令修改默认 VPC 对等互连设置。

PUPI 标志 导入 导出
提供方端(通过服务网络控制的标志)

要开启:--import-subnet-routes-with-public-ip(通过对等互连)

默认行为:已关闭

要关闭:--no-export-subnet-routes-with-public-ip(通过对等互连)

默认行为:已开启

使用方端(归客户所有,不需要通过服务网络进行修改) 已关闭(默认) 已开启(默认)

这些设置会产生以下结果:

  • 提供方 VPC 看到所有客户路由。
  • 使用方 VPC 未在提供方 VPC 的 Pod 子网上看到配置的 PUPI 路由。
  • 从提供方 Pod 到 vpc-consumer 网络的流量必须在提供方集群中的节点地址之后进行转换。

资格条件

  • 为 PUPI 选择的地址范围无法通过互联网访问,也无法成为 Google 拥有的地址。
  • 两个 VPC 之间的节点 IP 范围和主要范围不得重叠。
  • 如果客户 VPC 与代管式服务之间需要直接 Pod 到 Pod 通信,则必须在对应节点 IP 地址后面转换提供方 Pod IP 地址。

目标

  • 配置两个 VPC 网络。
  • 在每个 VPC 网络内配置一个子网。
  • 在每个子网的次要地址范围内配置 PUPI 地址范围。
  • 使用正确的导入和导出设置在两个 VPC 网络之间建立 VPC 对等互连关系。
  • 检查每个 VPC 内的路由。

费用

本教程使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用量来估算费用。 Google Cloud 新用户可能有资格申请免费试用

准备工作

  1. 在 Cloud Console 中,激活 Cloud Shell。

    激活 Cloud Shell

    您可以使用 HashiCorp 的 Terraform 和 Cloud SDK 从 Cloud Shell 终端完成本教程的大部分内容。

  2. 克隆 GitHub 代码库并切换到本地工作目录:

    git clone https://github.com/GoogleCloudPlatform/terraform-vpc-pupi $HOME/pupi
    

    该代码库包含完成本教程所需的所有文件。如需查看每个文件的完整说明,请参阅代码库中的 README.md 文件。

  3. 将所有 Shell 脚本设置为可执行脚本:

    sudo chmod 755 $HOME/pupi/*.sh
    

准备环境

在本部分中,您将安装并设置 Terraform,然后设置环境变量。

设置 Terraform

  1. 按照 HashiCorp 文档中的步骤安装 Terraform。
  2. 在 Cloud Shell 中,初始化 Terraform:

    cd $HOME/pupi
    terraform init
    

    输出类似于以下内容:

    ...
    Initializing provider plugins...
    The following providers do not have any version constraints in
    configuration, so the latest version was installed.
    ...
    Terraform has been successfully initialized!
    ...
    

    当 Terraform 初始化时,它会记录进度消息。在消息输出结束时,您会看到 Terraform 已成功初始化的消息。

设置环境变量

  1. 在 Cloud Shell 中,设置 TF_VAR_org_id 变量:

    export TF_VAR_org_id=$(gcloud organizations list | \
        awk '/YOUR_ORGANIZATION_NAME/ {print $2}')
    

    替换以下内容:

    • YOUR_ORGANIZATION_NAME:您要在本教程中使用的 Google Cloud 组织名称
  2. 验证是否已正确设置环境变量:

    echo $TF_VAR_org_id
    

    输出内容会以数字形式列出您的组织 ID,如下所示:

    ...
    123123123123
    ...
    
  3. 设置其余的环境变量:

    source $HOME/pupi/set_variables.sh
    

    此 Shell 脚本将 Google Cloud 地区、组织 ID 和项目 ID 等基本参数设置为 Shell 环境中的变量。Terraform 会使用这些变量来配置您的 Google Cloud 资源。您可以调整或更改 Shell 脚本中的参数,以适应您的环境。如需变量的完整列表,请查看 set_variables Shell 脚本。

  4. 验证是否已正确设置环境变量:

    env | grep TF_
    

    输出类似于以下内容:

    ...
    TF_VAR_billing_account=QQQQQQ-XAAAAA-E8769
    TF_VAR_org_id=406999999999
    TF_VAR_region1=us-west1
    TF_VAR_region2=us-west2
    TF_VAR_consumer_ilb_ip=10.129.0.200
    TF_VAR_user_account=user@example
    TF_VAR_pid=pupi-pid--999999999
    TF_VAR_zone2=us-west2-b
    TF_VAR_zone1=us-west1-b
    ...
    
  5. 创建环境变量文件:

    $HOME/pupi/saveVars.sh
    

    此命令会将您创建的环境变量重定向到名为 TF_ENV_VARS 的文件中。每个变量前面都会附加 export 命令。如果您的 Cloud Shell 会话终止,则可以使用此文件来重置变量。Terraform 脚本、Cloud Shell 脚本和 gcloud 命令行工具将使用这些变量。

    如果您稍后需要重新初始化这些变量,请运行以下命令:

    source $HOME/pupi/TF_ENV_VARS
    

部署辅助基础架构

  1. 在 Cloud Shell 中,部署 Terraform的辅助基础架构:

    terraform apply
    

    出现提示时,输入 yes 以应用任一配置。Terraform 可能需要几分钟来部署资源。

    terraform apply 命令指示 Terraform 部署此解决方案的所有组件。要了解如何以声明方式定义基础架构,请参阅 Terraform 清单(扩展名为 .tf 的文件)。

  2. 建立 VPC 对等互连关系。由于该功能处于 Alpha 版且不受 Terraform 支持,因此您可以使用 gcloud 命令来设置对等互连。

    gcloud alpha compute networks peerings create consumer \
        --project="$TF_VAR_pid" \
        --network=consumer \
        --peer-network=producer
    
    gcloud alpha compute networks peerings create producer \
        --project="$TF_VAR_pid" \
        --network=producer \
        --peer-network=consumer \
        --no-export-subnet-routes-with-public-ip \
        --import-subnet-routes-with-public-ip
    

    默认情况下,使用方 VPC 会导出 PUPI 地址。创建提供方 VPC 时,请使用以下参数将 VPC 配置为导入 PUPI 地址,但不导出地址:

    --no-export-subnet-routes-with-public-ip
    --import-subnet-routes-with-public-ip
    

检查辅助基础架构

现在,您可以通过在发送命令后检查资源是否响应,验证 Terraform 是否已成功创建资源。

验证项目

  1. 在 Cloud Shell 中,列出项目:

    gcloud projects list | grep pupi-pid
    

    输出类似于以下内容:

    ...
    pupi-pid--1234567899            pupi-test             777999333555
    ...
    

    在此输出中,pupi-test 是项目名称,pupi-pid- 是项目 ID 的前缀。

  2. 列出 API 状态:

    gcloud services list --project=$TF_VAR_pid \
        | grep -E "compute|container"
    

    输出类似于以下内容:

    ...
    compute.googleapis.com            Compute Engine API
    container.googleapis.com          Kubernetes Engine API
    containerregistry.googleapis.com  Container Registry API
    ...
    

    此输出显示 Compute Engine、GKE 和 Container Registry API 已启用。

验证网络和子网

  1. 在 Cloud Shell 中,验证提供方网络和子网:

    gcloud compute networks describe producer \
        --project=$TF_VAR_pid
    
    gcloud compute networks subnets describe producer-nodes \
        --project=$TF_VAR_pid \
        --region=$TF_VAR_region1
    

    输出类似于以下内容:

    ...
    kind: compute#network
    name: producer
    ...
    ipCidrRange: 10.128.0.0/24
    kind: compute#isubnetwork
    name: producer-nodes
    ...
    secondaryIpRanges:
    - ipCidrRange: 45.45.45.0/24
      rangeName: producer-pods
    - ipCidrRange: 172.16.45.0/24
      rangeName: producer-cluster
    ...
    

    此输出如下所示:

    • 该网络是使用 10.128.0.0/24 CIDR 地址块创建的。
    • 这两个子网是使用 45.45.45.0/24172.16.45.0/24 CIDR 地址块创建的。
  2. 验证使用方网络和子网:

    gcloud compute networks describe consumer \
        --project=$TF_VAR_pid
    
    gcloud compute networks subnets describe consumer-nodes \
        --project=$TF_VAR_pid \
        --region=$TF_VAR_region2
    

    输出类似于以下内容:

    ...
    kind: compute#network
    name: consumer
    ...
    ipCidrRange: 10.129.0.0/24
    kind: compute#isubnetwork
    name: consumer-nodes
    ...
    secondaryIpRanges:
    - ipCidrRange: 5.5.5.0/24
      rangeName: producer-pods
    - ipCidrRange: 172.16.5.0/24
      rangeName: consumer-cluster
    ...
    

    此输出如下所示:

    • 该网络是使用 10.129.0.0/24 CIDR 地址块创建的。
    • 两个子网是使用 5.5.5.0/24172.16.5.0/24 CIDR 地址块创建的。

验证 GKE 集群及其资源

  1. 在 Cloud Shell 中,获取集群凭据:

    gcloud container clusters get-credentials consumer-cluster \
        --project=$TF_VAR_pid \
        --zone=$TF_VAR_zone2
    

    输出类似于以下内容:

    ...
    Fetching cluster endpoint and auth data.
    kubeconfig entry generated for consumer-cluster.
    ...
    
  2. 验证集群:

    gcloud container clusters list \
        --project=$TF_VAR_pid \
        --zone=$TF_VAR_zone2
    

    输出类似于以下内容:

    NAME              LOCATION    MASTER_VERSION  MASTER_IP      MACHINE_TYPE   NODE_VERSION    NUM_NODES  STATUS
    consumer-cluster  us-west2-b  1.14.10-gke.17  35.236.104.74  n1-standard-1  1.14.10-gke.17  3          RUNNING
    

    此输出显示名为 consumer-cluster 的集群。

  3. 验证 Hello World 应用:

    kubectl get deployment my-app
    

    输出类似于以下内容:

    ...
    NAME     DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
    my-app   3         3         3            3           118m
    ...
    

    此输出显示名为 my-app 的部署。

  4. 验证内部负载平衡器服务:

    kubectl get service hello-server
    

    输出类似于以下内容:

    NAME           TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)          AGE
    hello-server   LoadBalancer   172.16.5.99   10.129.0.200   8080:31673/TCP   4d23h
    

    此输出显示名为 hello-server 的服务。

验证解决方案

  1. 在 Cloud Shell 中,验证是否已成功创建 VPC 对等互连:

    gcloud alpha compute networks peerings list
    

    输出类似于以下内容:

    NAME      NETWORK   PEER_PROJECT          PEER_NETWORK  IMPORT_CUSTOM_ROUTES  EXPORT_CUSTOM_ROUTES  STATE   STATE_DETAILS
    consumer  consumer  pupi-pid--1324732197  producer      False                 False                 ACTIVE  [2020-02-26T11:33:16.886-08:00]: Connected.
    producer  producer  pupi-pid--1324732197  consumer      False                 False                 ACTIVE  [2020-02-26T11:33:16.886-08:00]: Connected.
    

    此输出显示名为 consumerproducer 的对等互连。

  2. 验证使用方 VPC 是否导出 PUPI 路由:

    gcloud alpha compute networks peerings list-routes consumer \
        --direction=OUTGOING \
        --network=consumer \
        --region="$TF_VAR_region2"
    

    输出类似于以下内容:

    DEST_RANGE     TYPE                  NEXT_HOP_REGION  PRIORITY  STATUS
    10.129.0.0/24  SUBNET_PEERING_ROUTE  us-west2         1000      accepted by peer
    172.16.5.0/24  SUBNET_PEERING_ROUTE  us-west2         1000      accepted by peer
    5.5.5.0/24     SUBNET_PEERING_ROUTE  us-west2         1000      accepted by peer
    

    此输出显示所有三个使用方 CIDR 地址块。

  3. 验证提供方 VCP 导入的 PUPI 路由:

    gcloud alpha compute networks peerings list-routes producer \
        --direction=INCOMING \
        --network=producer \
        --region="$TF_VAR_region1"
    

    输出类似于以下内容:

    DEST_RANGE     TYPE                  NEXT_HOP_REGION  PRIORITY  STATUS
    10.129.0.0/24  SUBNET_PEERING_ROUTE  us-west2         1000      accepted
    172.16.5.0/24  SUBNET_PEERING_ROUTE  us-west2         1000      accepted
    5.5.5.0/24     SUBNET_PEERING_ROUTE  us-west2         1000      accepted
    

    此输出显示所有三个使用方 CIDR 地址块。

  4. 验证 GKE Pod 是否拥有 PUPI 地址:

    kubectl get pod -o wide
    

    输出类似于以下内容:

    NAME                      READY   STATUS    RESTARTS   AGE     IP         NODE                                              NOMINATED NODE   READINESS GATES
    my-app-594b56d7bc-642d8   1/1     Running   0          4d23h   5.5.5.21   gke-consumer-cluster-default-pool-cd302b68-tccf   <none>           <none>
    my-app-594b56d7bc-chnw8   1/1     Running   0          4d23h   5.5.5.38   gke-consumer-cluster-default-pool-cd302b68-h8v9   <none>           <none>
    my-app-594b56d7bc-fjvbz   1/1     Running   0          4d23h   5.5.5.20   gke-consumer-cluster-default-pool-cd302b68-tccf   <none>           <none>
    

    Pod 的 IP 地址在 5.5.5/24 范围内。

清理

为避免因本教程中使用的资源导致您的 Google Cloud 帐号产生费用,请执行以下操作:

销毁基础架构

  1. 在 Cloud Shell 中,销毁教程的所有组件:

    terraform destroy
    

    出现提示时,输入 yes 以销毁配置。

    您可能会看到以下 Terraform 错误:

    ...
    ∗ google_compute_network.ivpc (destroy): 1 error(s) occurred:
    ∗ google_compute_network.ivpc: Error waiting for Deleting Network: The network resource 'projects/pupi-pid--1324732197/global/networks/consumer-cluster' is already being used by 'projects/pupi-pid--1324732197/global/firewalls/k8s-05693142c93de80e-node-hc'
    ...
    

    如果该命令在销毁 GKE 防火墙规则之前试图销毁 VPC 网络,则会出现此错误。如果您收到此错误,请执行以下操作:

    1. 从 VPC 中移除非默认防火墙规则:

      $HOME/pupi/k8-fwr.sh
      

      输出显示要移除的防火墙规则。查看规则,并在出现提示时输入 yes

    2. 重新发出以下命令:

      cd $HOME/pupi
      terraform destroy
      

    出现提示时,输入 yes 以销毁配置。

  2. 移除 Git 代码库:

    rm -rf $HOME/pupi
    

后续步骤