设置服务流量导向


本页面介绍如何为 Pod 设置服务流量导向。

如需了解服务流量导向的工作原理,请参阅服务流量导向的工作原理

要求

  • GKE 1.30 版或更高版本。

限制

  • 一个 ServiceFunctionChain 最多只能有一个服务功能。
  • 我们建议最多使用 100 个节点外加 10 个 ServiceFunctionChainTrafficSelector 对。
  • GKE 服务流量导向仅适用于运行 Container-Optimized OS 节点映像的节点。
  • GKE 服务流量导向仅支持出站流量和目标 IP 地址。
  • 服务流量导向不会处理在将具有相同前缀长度的多个流量选择器应用于同一主体时出现的冲突。为避免冲突,请主动设计具有不重叠 IP 地址范围和明确定义的选择条件的流量选择器。

实现服务流量导向

借助 GKE 服务流量导向,您可以自定义和控制集群内的网络流量流。本部分演示了如何使用 Web 网关示例实现服务流量导向。

请考虑一个应用场景,您希望创建一个 Web 网关来保护从最终用户客户端设备到互联网的流量。VPN 终止器使用安全隧道将流量引入托管式网关。最终用户流量会重定向到防火墙,然后再重定向到代理。代理会对流量执行来源网络地址转换 (SNAT),遮盖原始来源地址,然后将其向外发送到互联网。

如需实现 GKE 服务流量导向,请执行以下操作:

  1. 创建 MTU 为 8896 的 VPC。
  2. 创建 GKE 集群。
  3. 创建服务功能 Pod 和服务。
  4. 创建 ServiceFunctionChain
  5. 创建引用 ServiceFunctionChainTrafficSelector 资源。

准备工作

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

  • 启用 Google Kubernetes Engine API。
  • 启用 Google Kubernetes Engine API
  • 如果您要使用 Google Cloud CLI 执行此任务,请安装初始化 gcloud CLI。 如果您之前安装了 gcloud CLI,请运行 gcloud components update 以获取最新版本。

价格

只有启用了 GKE Enterprise 的项目中的集群支持以下 Network Function Optimizer (NFO) 功能:

如需了解启用 Google Kubernetes Engine (GKE) Enterprise 版本的相关费用,请参阅 GKE Enterprise 价格

准备 VPC

准备 VPC。服务流量导向使用封装将流量重定向到相应的服务功能。封装涉及向每个数据包添加额外标头,这会增加数据包大小。服务流量导向不需要在 VPC 中进行特殊配置。在准备 VPC 时,我们建议您在确定 MTU 大小时考虑封装开销。如需了解详情,请参阅具有指定 MTU 的 VPC 网络

以下命令会在您的 VPC 中设置 mtu 大小:

gcloud compute networks create VPC_NETWORK_NAME --mtu=8896

VPC_NETWORK_NAME 替换为包含子网的 VPC 网络的名称。

创建 GKE 集群

如需启用在 GKE 上实现服务流量导向所需的高级网络路由和 IP 地址管理功能,请create启用了 GKE Dataplane V2 的 GKE 集群,如下所示:

gcloud container clusters create CLUSTER_NAME \
    --network VPC_NAME \
    --release-channel RELEASE_CHANNEL \
    --cluster-version CLUSTER_VERSION \
    --enable-dataplane-v2 \
    --enable-ip-alias

替换以下内容:

  • CLUSTER_NAME:集群的名称。
  • VPC_NAME:要与集群关联的 VPC 的名称。
  • RELEASE_CHANNEL:发布渠道的名称。
  • VERSION:GKE 版本,必须为 1.30 或更高版本。您还可以使用 --release-channel 标志来选择发布渠道。发布渠道必须具有默认版本 1.30 或更高版本。

创建 ServiceFunction Pod

如需建立服务链,请在集群中部署 VPN 终止器 Pod 和所需服务功能 Pod。Pod 会封装执行网络功能的容器化应用。

VPN 终止器 Pod 通常是链中的第一个服务功能,它会终止通过 VPN 进入集群的流量。它随后会定向其他服务功能(例如防火墙和负载均衡)以进行进一步处理,然后再到达最终目标。

以下示例配置文件定义了以下三个组件,这些组件对于集群中的网络流量管理至关重要:

  • VPN Pod:在集群中建立虚拟专用网 (VPN) 端点,从而实现集群与外部网络之间的安全和加密通信。
  • 防火墙部署:部署防火墙 Pod 的多个副本,这些副本可提供安全性和负载均衡。
  • 代理 DaemonSet:在集群的每个节点上部署代理 Pod,以确保网络流量可以在转发到其他服务(如防火墙)之前在本地进行处理。

将以下示例清单保存为 service_function.yaml

apiVersion: v1
kind: Pod
  name: vpn
  namespace: vpn
  labels:
    app: vpn
spec:
  containers:
  -   name: vpn
    image: openvpn
    ports:
    -   containerPort: 51820
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: firewall
  namespace: firewall
spec:
  replicas: 3
  selector:
    matchLabels:
      app: firewall
  template:
    metadata:
      labels:
        app: firewall
    spec:
      containers:
      -   name: firewall
        image: firewall
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: proxy
  namespace: proxy
spec:
  selector:
    matchLabels:
      app: proxy
  template:
    metadata:
      labels:
        app: proxy
    spec:
      containers:
      -   name: proxy
        image: proxy

应用清单:

kubectl apply -f service_function.yaml

创建“ServiceFunctionChains

如需定义供流量遍历的一系列网络功能,请创建一个流水线,其中每个功能(如防火墙、代理和负载均衡器)都会先执行其特定任务,再将流量传递给下一个功能。

将以下示例清单保存为 ServiceFunctionChain.yaml

apiVersion: networking.gke.io/v1
kind: ServiceFunctionChain
metadata:
  name: firewall
spec:
  sessionAffinity:
    clientIpNoDestination:
      timeoutSeconds: 3600 # 1hr
  serviceFunctions:
  -   name: firewall
    namespace: firewall
    podSelector:
      matchLabels:
        app: firewall
---
apiVersion: networking.gke.io/v1
kind: ServiceFunctionChain
metadata:
  name: proxy
spec:
  sessionAffinity:
    clientIpNoDestination: {}
  serviceFunctions:
  -   name: proxy
    namespace: proxy
    podSelector:
      matchLabels:
        app: proxy

应用清单:

kubectl apply -f ServiceFunctionChain.yaml

服务功能使用 serviceFunctions 字段在 ServiceFunctionChain 中以内嵌方式定义。服务功能是一种端点选择器。

创建 TrafficSelector 资源

如需定义在哪里选择流量以及选择哪些流量进行服务流量导向,请创建引用 ServiceFunctionChains 以应用于所选流量的 TrafficSelector 资源。

将以下示例清单保存为 TrafficSelector.yaml

apiVersion: networking.gke.io/v1
kind: TrafficSelector
metadata:
  name: vpn-to-firewall
spec:
  serviceFunctionChain: firewall
  subject:
    pods:
      namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: vpn
      podSelector:
        matchLabels:
          app: vpn
  egress:
    to:
      ipBlock:
        cidr: 0.0.0.0/0
    ports:
    -   allPorts:
        protocol: UDP
    -   allPorts:
        protocol: TCP
---
apiVersion: networking.gke.io/v1
kind: TrafficSelector
metadata:
  name: firewall-to-proxy
spec:
  serviceFunctionChain: proxy
  subject:
    pods:
      namespaceSelector:
        kubernetes.io/metadata.name: firewall
      podSelector:
        app: firewall
  egress:
    to:
      ipBlock:
        cidr: 0.0.0.0/0
    ports:
    -   allPorts:
        protocol: UDP
    -   allPorts:
        protocol: TCP

应用清单:

kubectl apply -f TrafficSelector.yaml

排查服务流量导向问题

本部分介绍如何解决与 GKE 服务流量导向相关的问题。

网络流量不流动

您可以执行以下操作来调试此问题:

第 1 步:验证是否已在 ServiceFunctionChain 上设置 servicePathId

验证是否已在 ServiceFunctionChain 上设置 servicePathId。每个 ServiceFunctionChain 对象都分配有唯一的 servicePathId,如以下示例所示:

apiVersion: networking.gke.io/v1
kind: ServiceFunctionChain
metadata:
  name: firewall
spec:
  serviceFunctions:
  - name: firewall
    namespace: firewall
    podSelector:
      matchLabels:
        app: firewal
status:
  servicePathId: 1

第 2 步:验证是否对每个服务功能创建了 Kubernetes 服务

系统会自动为每个服务功能创建一个 ClusterIP 服务。您可以使用 kubectl 查看服务列表:

kubectl get svc -A -l networking.gke.io/managed-by=service-steering-controller.gke.io

第 3 步:验证对于每个服务功能,是否在每个节点上创建了一个 bpf 映射条目来存储服务 IP 地址

对于每个服务功能,系统会在每个节点上创建一个 bpf 映射条目来存储服务 IP 地址。

获取 anetd Pod 的名称:

kubectl get pods -n kube-system -o wide -l k8s-app=cilium

记录与 anetd 类似的 Pod 名称。

运行以下命令:

kubectl -n kube-system exec -it ANETD-POD-NAME -- cilium bpf sfcpath list

ANETD-POD-NAME 替换为 anetd Pod 的名称。

输出类似于以下内容:

PATH     SERVICE FUNCTION ADDRESS
(1, 1)   10.4.10.124

第 4 步:验证是否在 sfcselect 映射中创建了 bpf 映射条目

在节点上,如果 TrafficSelector 选择了 Pod,则 sfcselect 映射中会创建相应 bpf 映射条目。以下示例显示从端点 (Pod) 3783 的任何端口到目标 IP 地址 10.0.2.12 的 TCP/UDP 流量会导向到 ServiceFunctionChain

运行以下命令:

kubectl -n kube-system exec -it ANETD-POD-NAME -- cilium bpf sfcselect list

ANETD-POD-NAME 替换为集群中 anetd Pod 的实际名称。

输出类似于以下内容:

SELECTOR                            PATH
3783, egress, 0/TCP, 10.0.2.12/32   /32 (1, 1)
3783, egress, 0/UDP, 10.0.2.12/32   /32 (1, 1)

第 5 步:在端口 7081 上使用 tcpdump 捕获和分析网络流量

服务流量导向会在 UDP 端口 7081 上执行 Geneve 封装。您可以在相关节点上使用 tcpdump 来分析流量流并查明可能出现问题的位置。

后续步骤