设置节点内可见性

本指南介绍了如何在 Google Kubernetes Engine (GKE) 集群中设置节点内可见性

节点内可见性在集群中的每个节点上配置网络,以便从一个 Pod 发送到另一个 Pod 的流量由集群的 Virtual Private Cloud (VPC) 网络处理,即使这些 Pod 位于同一节点上也是如此。

默认情况下,节点内可见性在标准集群中处于停用状态,而在 Autopilot 集群中处于启用状态。

架构

节点内可见性可确保在 Pod 之间发送的数据包始终由 VPC 网络处理,从而确保防火墙规则、路由、流日志和数据包镜像配置应用于数据包。

当一个 Pod 向同一节点上的另一个 Pod 发送数据包时,数据包将离开该节点并由 Google Cloud 网络处理。然后,数据包会立即发送回同一个节点并转发到目标 Pod。

节点内可见性会部署 netd DaemonSet。

优势

节点内可见性具有以下优势:

  • 查看 Pod 之间所有流量(包括同一节点上 Pod 之间的流量)的流日志
  • 创建应用于 Pod 之间所有流量(包括同一节点上 Pod 之间的流量)的防火墙规则
  • 使用数据包镜像克隆流量(包括同一节点上 Pod 之间的流量),并将其转发以供检查。

要求和限制

节点内可见性有以下要求和限制:

  • 您的集群必须为 GKE 1.15 或更高版本。
  • Windows Server 节点池不支持节点内可见性。
  • 如果您希望集群使用最大传输单元 (MTU) 为 1500 个字节的 VPC 网络,则需要节点内可见性。如需了解详情,请参阅最大传输单元
  • 如果您启用了节点内可见性,并使用了配置有 nonMasqueradeCIDRs 参数的 ip-masq-agent,则必须在 nonMasqueradeCIDRs 中添加 Pod CIDR 范围,以避免遇到节点内连接问题。
  • 启用节点内可见性后,如果客户端 Pod 和 kube-dns Pod 位于同一节点上,则可能会频繁出现 DNS 超时。如需了解详情,请参阅 DNS 超时
  • 如果启用节点内可见性和网络政策,则可能会遇到Pod 到 Pod 流量的重置

防火墙规则

启用节点内可见性后,VPC 网络会处理在 Pod 之间发送的所有数据包,包括在同一节点上的 Pod 之间发送的数据包。这意味着无论 Pod 位置如何,Pod 到 Pod 的通信都施行一致的 VPC 防火墙规则和分层防火墙政策。

如果您为集群内的通信配置自定义防火墙规则,请仔细评估集群的网络需求,以确定一组出站和入站许可规则。您可以使用连接测试来确保合法流量不受阻碍。例如,网络政策正常运行需要 Pod 到 Pod 的通信。

准备工作

在开始之前,请确保您已执行以下任务:

使用以下任一方法设定默认的 gcloud 设置:

  • 使用 gcloud init(如果您想要在系统引导下完成默认设置)。
  • 使用 gcloud config(如果您想单独设置项目 ID、区域和地区)。

使用 gcloud init

如果您收到 One of [--zone, --region] must be supplied: Please specify location 错误,请完成本部分。

  1. 运行 gcloud init 并按照说明操作:

    gcloud init

    如果您要在远程服务器上使用 SSH,请使用 --console-only 标志来防止命令启动浏览器:

    gcloud init --console-only
  2. 按照说明授权 gcloud 使用您的 Google Cloud 帐号。
  3. 创建新配置或选择现有配置。
  4. 选择 Google Cloud 项目。
  5. 为可用区级集群选择默认 Compute Engine 可用区,或为区域级集群或 Autopilot 集群选择区域。

使用 gcloud config

  • 设置默认项目 ID
    gcloud config set project PROJECT_ID
  • 如果您使用的是可用区级集群,请设置默认计算可用区
    gcloud config set compute/zone COMPUTE_ZONE
  • 如果您使用的是 Autopilot 集群或区域级集群,请设置默认计算区域
    gcloud config set compute/region COMPUTE_REGION
  • gcloud 更新到最新版本:
    gcloud components update

在新集群上启用节点内可见性

您可以使用 gcloud 工具或 Google Cloud Console 创建一个启用了节点内可见性的集群。

gcloud

如需创建一个启用了节点内可见性的单节点集群,请使用 --enable-intra-node-visibility 标志:

gcloud container clusters create CLUSTER_NAME \
    --region=COMPUTE_REGION \
    --enable-intra-node-visibility

替换以下内容:

  • CLUSTER_NAME:新集群的名称。
  • COMPUTE_REGION:集群的 计算区域

控制台

如需创建一个启用了节点内可见性的单节点集群,请执行以下步骤:

  1. 转到 Cloud Console 中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 点击 创建

  3. 输入集群的名称

  4. 配置集群对话框中,点击 GKE 标准旁边的配置

  5. 根据需要配置集群。

  6. 在导航窗格的集群下,点击网络

  7. 选中启用节点内可见性复选框。

  8. 点击创建

在现有集群上启用节点内可见性

您可以使用 gcloud 工具或 Google Cloud Console 在现有集群上启用节点内可见性。

如果您为现有集群启用节点内可见性,则 GKE 会重启控制层面和工作器节点中的组件。

gcloud

如需在现有集群上启用节点内可见性,请使用 --enable-intra-node-visibility 标志:

gcloud container clusters update CLUSTER_NAME \
    --enable-intra-node-visibility

CLUSTER_NAME 替换为您的集群名称。

控制台

如需在现有集群上启用节点内可见性,请执行以下步骤:

  1. 转到 Cloud Console 中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 在集群列表中,点击您要修改的集群的名称。

  3. 网络下,点击 修改节点内可见性

  4. 选中启用节点内可见性复选框。

  5. 点击保存更改

停用节点内可见性

您可以使用 gcloud 工具或 Google Cloud Console 停用集群上的节点内可见性。

如果您停用现有集群的节点内可见性,则 GKE 会重启控制层面和工作器节点中的组件。

gcloud

如需停用节点内可见性,请使用 --no-enable-intra-node-visibility 标志:

gcloud container clusters update CLUSTER_NAME \
    --no-enable-intra-node-visibility

CLUSTER_NAME 替换为您的集群名称。

控制台

如需停用节点内可见性,请执行以下步骤:

  1. 转到 Cloud Console 中的 Google Kubernetes Engine 页面。

    转到 Google Kubernetes Engine

  2. 在集群列表中,点击您要修改的集群的名称。

  3. 网络下,点击 修改节点内可见性

  4. 清除启用节点内可见性复选框。

  5. 点击保存更改

练习:验证节点内可见性

本练习展示了启用节点内可见性并确认其适用于您的集群所需的步骤。

在本练习中,您将执行以下步骤:

  1. us-central1 区域中的默认子网启用流日志。
  2. us-central1-a 可用区中创建一个启用了节点内可见性的单节点集群。
  3. 在集群中创建两个 Pod。
  4. 从一个 Pod 向另一个 Pod 发送 HTTP 请求。
  5. 查看 Pod 到 Pod 请求的流日志条目。

启用流日志

  1. 为默认子网启用流日志:

    gcloud compute networks subnets update default \
        --region=us-central1 \
        --enable-flow-logs
    
  2. 验证默认子网是否已启用流日志:

    gcloud compute networks subnets describe default \
        --region=us-central1
    

    输出结果会显示已启用流日志,如下所示:

    ...
    enableFlowLogs: true
    ...
    

创建集群

  1. 创建一个启用了节点内可见性的单节点集群:

    gcloud container clusters create flow-log-test \
        --zone=us-central1-a \
        --num-nodes=1 \
        --enable-intra-node-visibility
    
  2. 获取集群的凭据:

    gcloud container clusters get-credentials flow-log-test \
        --zone=us-central1-a
    

创建两个 Pod

  1. 创建一个 Pod。

    将以下清单保存到名为 pod-1.yaml 的文件中:

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-1
    spec:
      containers:
      - name: container-1
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
    
  2. 将清单应用到您的集群:

    kubectl apply -f pod-1.yaml
    
  3. 创建另一个 Pod。

    将以下清单保存到名为 pod-2.yaml 的文件中:

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-2
    spec:
      containers:
      - name: container-2
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0
    
  4. 将清单应用到您的集群:

    kubectl apply -f pod-2.yaml
    
  5. 查看 Pod:

    kubectl get pod pod-1 pod-2 --output wide
    

    输出结果会显示 Pod 的 IP 地址,如下所示:

    NAME      READY     STATUS    RESTARTS   AGE       IP           ...
    pod-1     1/1       Running   0          1d        10.52.0.13   ...
    pod-2     1/1       Running   0          1d        10.52.0.14   ...
    

    记下 pod-1pod-2 的 IP 地址。

发送请求

  1. 获取连接至 pod-1 中容器的 shell:

    kubectl exec -it pod-1 -- sh
    
  2. 在您的 shell 中,向 pod-2 发送请求:

    wget -qO- POD_2_IP_ADDRESS:8080
    

    POD_2_IP_ADDRESS 替换为 pod-2 的 IP 地址。

    输出结果会显示 pod-2 中运行的容器返回的响应。

    Hello, world!
    Version: 2.0.0
    Hostname: pod-2
    
  3. 输入 exit 以离开 shell 并返回到主命令行环境。

查看流日志条目

如需查看流日志条目,请使用以下命令:

gcloud logging read \
    'logName="projects/PROJECT_ID/logs/compute.googleapis.com%2Fvpc_flows" AND jsonPayload.connection.src_ip="POD_1_IP_ADDRESS" AND jsonPayload.connection.dest_ip="POD_2_IP_ADDRESS"'

替换以下内容:

  • PROJECT_ID:您的项目 ID。
  • POD_1_IP_ADDRESSpod-1 的 IP 地址。
  • POD_2_IP_ADDRESSpod-2 的 IP 地址。

输出显示与从 pod-1pod-2 发送的请求相关的流日志条目。在本示例中,pod-1 的 IP 地址为 10.56.0.13,而 pod-2 的 IP 地址为 10.56.0.14

...
jsonPayload:
  bytes_sent: '0'
  connection:
    dest_ip: 10.56.0.14
    dest_port: 8080
    protocol: 6
    src_ip: 10.56.0.13
    src_port: 35414
...

清理

为避免您的帐号产生不必要的费用,请执行以下步骤来移除您创建的资源:

  1. 删除集群:

    gcloud container clusters delete -q flow-log-test
    
  2. 停用默认子网的流日志:

    gcloud compute networks subnets update default --no-enable-flow-logs
    

已知问题

连接重置

如果您在集群上同时启用节点内可见性和网络政策,则可能会看到同一节点上 Pod 之间的流量连接重置。

此问题会影响以下 GKE 版本的集群:

  • 1.19.9-gke.1900 到 1.19.12-gke.500
  • 1.20.5-gke.2000 到 1.20.8-gke.600
  • 1.21.0-gke.400 到 1.21.2-gke.500

如需解决此问题,请将集群升级到以下某个 GKE 版本:

  • 1.19.12-gke.700 或更高版本
  • 1.20.8-gke.700 或更高版本
  • 1.21.2-gke.600 或更高版本

DNS 超时

启用节点内可见性后,如果客户端 Pod 和 kube-dns Pod 位于同一节点上,则可能会出现 DNS 超时。

此问题会影响以下 GKE 版本的集群:

  • 1.18.16-gke.300 及更高版本
  • 1.19.7-gke.1500 及更高版本
  • 1.20.2-gke.1500 及更高版本

此问题主要影响基于 Alpine 的工作负载,但也可能影响使用 glibc 2.9 的基于 Debian 的 Pod。外部名称(如 metadata.internalgoogleapis.com 超时)的 DNS 请求。使用完全限定域名 (FQDN) 的集群内的 DNS 查询不会受影响。

为了缓解这一问题,请使用以下解决方法之一:

  • 启用 NodeLocal DNSCache

  • 停用节点内可见性

  • 通过向 Pod 清单添加 single-requestsingle-request-reopen 字段来序列化 DNS 查找:

    dnsConfig:
      options:
        - name: single-request
    

    此解决方法仅适用于非 Alpine Pod。您必须将此更改应用于每个 Pod。

  • 将 Pod 清单中的 ndots 选项设置为较低值(例如 2),以缩小搜索路径扩展范围:

    dnsConfig:
      options:
        - name: ndots
          value: "2"
    

    您还可以将 ndots 设置为 0,以避免进行搜索路径扩展。如果您停用搜索路径扩展,则 Pod 会按 FQDN 对所有服务名称执行查找。与 kubernetes.default 类似的查找不起作用。您必须使用类似于 kubernetes.default.svc.cluster.local 的 FQDN。

后续步骤