IPv4/IPv6 雙重堆疊網路

Google Distributed Cloud 的雙重堆疊網路可讓叢集接受使用 IPv4 或 IPv6 的外部裝置流量。Pod 和節點會同時取得 IPv4 和 IPv6 位址,而 Kubernetes Service 可以有 IPv4 位址、IPv6 位址,或兩者皆有。

雙堆疊叢集一律會對 IPv6 使用扁平模式。如果是 IPv4,雙堆疊叢集預設會使用孤島模式,但您也可以改為設定平面模式。如要建立雙重堆疊叢集,基礎網路必須啟用雙重堆疊。您無法在單一堆疊 IPv4 或 IPv6 網路上啟動雙重堆疊叢集。

事前準備

如果叢集節點執行 RedHat Enterprise Linux,且已啟用 SELinux,請在每個節點上執行下列操作:

  • 在 /etc/firewalld/firewalld.conf 中,設定 IPv6_rpfilter=no。

  • 執行 systemctl restart firewalld。

建立雙重堆疊叢集總覽

您可以在建立新叢集時啟用雙重堆疊網路,但無法為現有叢集啟用雙重堆疊網路。

請按照其中一份叢集建立文件中的指示操作。

在設定檔中,加入下列項目的資訊清單:

  • 命名空間資源
  • 叢集資源
  • 一或多項 NodePool 資源
  • 一或多個 ClusterCIDRConfig 資源

填寫命名空間資訊清單和 NodePool 資訊清單,就像為單一堆疊叢集填寫一樣。

在叢集資訊清單的 clusterNetwork.services.cidrBlocks 下方,同時指定 IPv4 CIDR 範圍和 IPv6 CIDR 範圍。這是雙堆疊叢集的啟用條件。也就是說,如果您同時為 IPv4 和 IPv6 提供 Service CIDR 範圍,叢集就會有雙重堆疊網路。

在叢集資訊清單的 clusterNetwork.pods.cidrBlocks 下方,指定 IPv4 CIDR 範圍,但不要指定 IPv6 CIDR 範圍。Pod 的 IPv6 CIDR 範圍是在 ClusterCIDRConfig 資訊清單中指定。

如果您使用套裝組合負載平衡,請在叢集資訊清單的 loadBalancer.addressPools 區段中,同時提供 IPv4 和 IPv6 位址。

ClusterCIDRConfig 資源用於指定 Pod 的 IPv4 和 IPv6 CIDR 範圍。您可以使用單一 ClusterCIDRConfig 資源,指定叢集範圍的 CIDR 範圍。也就是說,所有節點的 IPv4 Pod 位址都來自單一 CIDR 範圍,所有節點的 IPv6 Pod 位址也來自單一 CIDR 範圍。您也可以使用多個 ClusterCIDRConfig 資源,指定適用於特定節點集區或特定節點的 CIDR 範圍。

Pod IP 位址的可連性

雙堆疊叢集會針對 IPv6 網路使用平面模式。本文中的範例適用於使用 IPv6 靜態平面模式網路的叢集。也就是說,叢集未設定為使用邊界閘道通訊協定 (BGP)。

如果叢集使用靜態平面模式網路,您必須指定節點和 Pod IP 位址,且這些位址都屬於同一個子網路。這項設定可讓叢集外的用戶端 (但與叢集節點位於相同的第 2 層網域) 直接將封包傳送至 Pod IP 位址。

舉例來說,假設叢集節點和其他一些機器都位於同一個第 2 層網域。以下是指定位址範圍的一種方式:

目的範圍地址數量
整個第 2 層網域fd12::/108220
Podfd12::1:0/112216
節點fd12::2:0/112216
其他機器fd12::3:0/112216
VIPfd12::4:0/112216

在上述範例中,請務必瞭解以下重點:

  • 所有節點、Pod 和機器位址都位於較大的範圍:fd12::/108。

  • Pod IP 位址位於大範圍的子集中。

  • 節點 IP 位址則位於大範圍的不同子集中。

  • 其他機器的 IP 位址則位於大範圍的不同子集中。

  • 所有子集範圍彼此不重複。

在上述範例中,第 2 層網域中的每部機器 (包括叢集節點) 都必須有大範圍的轉送規則。例如:

inet fd12::/108 scope global eth0

範例:建立雙重堆疊叢集

建立雙堆疊叢集時,您有多種選項。例如,您可以設定叢集層級的 CIDR 範圍,或適用於特定節點集區的 CIDR 範圍。您可以將 IPv6 平面網路與 IPv4 孤島模式網路結合。或者,IPv4 和 IPv6 網路可能都是扁平網路。您可以使用隨附的負載平衡功能,或手動負載平衡。

本節提供建立雙堆疊叢集的範例。本範例中的叢集具有下列特性:

  • 孤島模式的 IPv4 網路
  • 扁平模式的 IPv6 網路
  • Pod 的全叢集 IPv4 CIDR 範圍
  • Pod 的全叢集 IPv6 CIDR 範圍
  • Service 的全叢集 IPv4 CIDR 範圍
  • Service 的全叢集 IPv6 CIDR 範圍
  • 用於 LoadBalancer 類型 Service 的 IPv4 位址集區
  • 用於 LoadBalancer 類型 Service 的 IPv6 位址集區
  • 套裝組合負載平衡

如需其他設定範例,請參閱「使用 ClusterCIDRConfig 的變化版本」。

填寫設定檔

請按照其中一份叢集建立文件中的指示操作。

在設定檔的 Cluster 資訊清單中:

  • 在 clusterNetwork.pods.cidrBlocks 部分,提供單一 IPv4 CIDR 範圍。

  • 針對 clusterNetwork.services.cidrBlocks,請提供兩個 CIDR 範圍:一個用於 IPv4,另一個用於 IPv6。

  • 針對 loadBalancer.addressPools,請提供兩個位址範圍:一個用於 IPv4,另一個用於 IPv6。建立LoadBalancer 類型的 Service 時,系統會從這些範圍中選擇 Service 的外部 IP 位址。

以下範例顯示叢集資訊清單的相關部分:

apiVersion: baremetal.cluster.gke.io/v1
kind: Cluster
metadata:
  name: "dual-stack"
  namespace: "cluster-dual-stack"

spec:
  clusterNetwork:
    pods:
      cidrBlocks:
      - "192.168.0.0/16"
    services
      cidrBlocks:
       - "172.16.0.0/20"
       - "fd12::5:0/116"
...
  loadBalancer:
    mode: "bundled"
    ...
    addressPools:
    - name: "pool-1"
      addresses:
       - "10.2.0.212-10.2.0.221"
       - "fd12::4:101-fd12::4:110"

在同一個設定檔中,加入 ClusterCIDRConfig 的資訊清單。

  • 將 ipv4.cidr 設為您在 Cluster 資訊清單中提供的相同 CIDR 範圍。如果 IPv4 處於孤島模式,則必須執行這項操作。

  • 將 namespace 設為您在 Cluster 資訊清單中提供的值。

  • 將 ipv6.cidr 設為 Pod 的 IPv6 CIDR 範圍。

  • 請為每個 CIDR 範圍提供 perNodeMaskSize 的值,指定要指派給每個節點的 Pod 位址數量。指派給每個節點的 IPv4 位址數量,必須與指派給每個節點的 IPv6 位址數量相同。您必須據此設定 perNodeMaskSize 的值。舉例來說,如果您希望每個節點有 28 個位址,請按照下列方式設定 perNodeMaskSize 值:

    • ipv4.perNodeMaskSize: 24 # (32 - 8 = 24)
    • ipv6.perNodeMaskSize: 120 # (128 - 8 = 120)

以下是 ClusterCIDRConfig 資訊清單範例:

apiVersion: baremetal.cluster.gke.io/v1alpha1
kind: ClusterCIDRConfig
metadata:
  name: "cluster-wide-ranges"
  namespace: "cluster-dual-stack"  # Must be the same as the Cluster namespace.
spec:
  ipv4:
    cidr: "192.168.0.0/16"  #  For island mode, must be the same as the Cluster CIDR.
    perNodeMaskSize: 24
  ipv6:
    cidr: "fd12::1:0/112"
    perNodeMaskSize: 120

在上述範例中:

  • IPv4 Pod CIDR 範圍有 2(32-16) = 216 個位址。每個節點的遮罩大小為 24,因此指派給每個節點的位址數量為 2(32-24) = 28。

  • IPv6 Pod CIDR 範圍有 2(128-112) = 216 個位址。每個節點的遮罩大小為 120,因此指派給每個節點的位址數量為 2(128-120) = 28。

設定檔範例

完成叢集建立作業

按照叢集建立文件中的說明,完成叢集建立作業。

查看叢集節點和 Pod

列出叢集節點:

kubectl --kubeconfig CLUSTER_KUBECONFIG get nodes --output yaml

將 CLUSTER_KUBECONFIG 替換為叢集 kubeconfig 檔案的路徑。

在輸出內容中,您可以看到每個節點的 IPv4 和 IPv6 位址。您也可以查看節點上 Pod 的 IPv4 和 IPv6 位址範圍。例如:

- apiVersion: v1
  kind: Node
  ...
  spec:
    podCIDR: 192.168.1.0/24
    podCIDRs:
    - 192.168.1.0/24
    - fd12::1:100/120
    providerID: baremetal://10.2.0.5
  status:
    addresses:
    - address: 10.2.0.5
      type: InternalIP
    - address: fd12::2:5
      type: InternalIP

在叢集中列出 Pod:

kubectl --kubeconfig CLUSTER_KUBECONFIG get pods --all-namespaces

選擇一個 Pod,並列出詳細資料。例如:

kubectl --kubeconfig CLUSTER_KUBECONFIG get pod gke-metrics-agent-b9qrv \
  --namespace kube-system \
  -- output yaml

在輸出內容中,您可以看到 Pod 的 IPv4 和 IPv6 位址。例如:

apiVersion: v1
kind: Pod
metadata:
  ...
  name: gke-metrics-agent-b9qrv
  namespace: kube-system
...
status:
  ...
  podIPs:
  - ip: 192.168.1.146
  - ip: fd12::1:11a

使用 ClusterCIDRConfig 的變化版本

上述範例使用 ClusterCIDRConfig 物件指定叢集層級的 Pod CIDR 範圍。也就是說,叢集中的所有 Pod 都會使用單一 IPv4 CIDR 範圍。叢集中的所有 Pod 則使用單一 IPv6 CIDR 範圍。

在某些情況下,您可能不希望叢集中的所有 Pod 都使用單一 CIDR 範圍。例如,您可能想為每個節點集區指定不同的 CIDR 範圍,或為每個節點指定不同的 CIDR 範圍。如要進一步瞭解 ClusterCIDRConfig 和使用範例,請參閱「瞭解 ClusterCIDRConfig 自訂資源」。

舉例來說,下列 ClusterCIDRConfig 會為名為 "workers" 的節點集區指定 CIDR 範圍。

apiVersion: baremetal.cluster.gke.io/v1alpha1
kind: ClusterCIDRConfig
metadata:
  name: "worker-pool-ccc"
  namespace: "cluster-dual-stack"
spec:
  ipv4:
    cidr: "192.168.0.0/16"
    perNodeMaskSize: 24
  ipv6:
    cidr: "fd12::1:0/112"
    perNodeMaskSize: 120
  nodeSelector:
    matchLabels:
      baremetal.cluster.gke.io/node-pool: "workers"

下列 ClusterCIDRConfig 會為 IP 位址為 10.2.0.5 的單一節點指定 CIDR 範圍:

apiVersion: baremetal.cluster.gke.io/v1alpha1
kind: ClusterCIDRConfig
metadata:
  name: "range-node1"
  namespace: "cluster-dual-stack"
spec:
  ipv4:
    cidr: "192.168.1.0/24"
    perNodeMaskSize: 24
  ipv6:
    cidr: "fd12::1:0/120"
    perNodeMaskSize: 120
  nodeSelector:
    matchLabels:
      baremetal.cluster.gke.io/k8s-ip: "10.2.0.5"

建立 ClusterIP 類型的雙堆疊 Service

以下是部署的資訊清單:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: "my-deployment"
spec:
  selector:
    matchLabels:
      app: "try-dual-stack"
  replicas: 3
  template:
    metadata:
      labels:
        app: "try-dual-stack"
    spec:
      containers:
      - name: "hello"
        image: "us-docker.pkg.dev/google-samples/containers/gke/hello-app:2.0"

將資訊清單儲存至名為 my-deployment.yaml 的檔案,然後建立 Deployment:

kubectl --kubeconfig CLUSTER_KUBECONFIG apply -f my-deployment.yaml

將 CLUSTER_KUBECONFIG 替換為叢集 kubeconfig 檔案的路徑。

以下是 ClusterIP 類型 Service 的資訊清單:

apiVersion: v1
kind: Service
metadata:
  name: "my-service"
spec:
  selector:
    app: "try-dual-stack"
  type: "ClusterIP"
  ipFamilyPolicy: "RequireDualStack"
  ipFamilies:
  - "IPv6"
  - "IPv4"
  ports:
  - port: 80
    targetPort: 8080

在本練習中,請務必瞭解上述 Service 資訊清單的下列重點:

  • ipFamilyPolicy 欄位設為 RequireDualStack,表示系統會為 Service 分配 IPv6 和 IPv4 ClusterIP 位址。

  • ipFamilies 欄位會先指定 IPv6 系列,再指定 IPv4 系列。這表示 Service 的 spec.ClusterIP 會是從叢集資訊清單中的 clusterNetwork.services.cidrBlocks 選擇的 IPv6 位址。

將資訊清單儲存至名為 my-cip-service.yaml 的檔案,然後建立 Service:

kubectl --kubeconfig CLUSTER_KUBECONFIG apply -f my-cip-service.yaml

列出服務的詳細資料:

kubectl --kubeconfig CLUSTER_KUBECONFIG get service my-service --output yaml

在輸出內容中,您可以看到 Service 的叢集 IP 位址。例如:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  …
spec:
  clusterIP: fd12::5:9af
  clusterIPs:
  - fd12::5:9af
  - 172.16.12.197

在叢集節點上呼叫 Service:

curl IPV4_CLUSTER_IP
curl IPV6_CLUSTER_IP

輸出內容會顯示「Hello world」訊息:

Hello, world!
Version: 2.0.0
Hostname: my-deployment-xxx

建立 LoadBalancer 類型的雙堆疊 Service

以下是 LoadBalancer 類型 Service 的資訊清單:

apiVersion: v1
kind: Service
metadata:
  name: "my-lb-service"
spec:
  selector:
    app: "try-dual-stack"
  type: "LoadBalancer"
  ipFamilyPolicy: "RequireDualStack"
  ipFamilies:
  - "IPv6"
  - "IPv4"
  ports:
  - port: 80
    targetPort: 8080

將資訊清單儲存至名為 my-lb-service.yaml 的檔案,然後建立 Service:

kubectl --kubeconfig CLUSTER_KUBECONFIG apply -f my-lb-service.yaml

回想一下,您在叢集資訊清單中指定了 IPv6 位址範圍和 IPv4 位址範圍,用於 LoadBalancer 類型的 Service:

  loadBalancer:
    mode: "bundled"
    ...
    addressPools:
    - name: "pool-1"
      addresses:
      - "10.2.0.112-10.2.0.221"
      - "fd12::4:101-fd12::4:110"

系統會從 IPv4 範圍中選擇一個外部 IPv4 位址,並從 IPv6 範圍中選擇一個外部 IPv6 位址,指派給您的 Service。

列出服務的詳細資料:

kubectl --kubeconfig CLUSTER_KUBECONFIG get service my-lb-service --output yaml

在輸出內容中,您可以看到 Service 的外部位址。例如:

apiVersion: v1
kind: Service
metadata:
  name: my-lb-service
...
status:
  loadBalancer:
    ingress:
    - ip: 10.2.0.213
    - ip: fd12::4:101

ipFamilyPolicy 的可能值

建立雙堆疊 Service 時,您可以將 ipFamilyPolicy 設為下列其中一個值:

  • SingleStack:控制器會從叢集資訊清單中 clusterNetwork.services.cidrBlocks 下方指定的第一個範圍,為 Service 分配叢集 IP 位址。

  • PreferDualStack:控制器會從叢集資訊清單中 clusterNetwork.services.cidrBlocks 指定的範圍,為 Service 分配 IPv4 和 IPv6 叢集 IP 位址。如果叢集不是雙堆疊叢集,則行為與 SingleStack 相同。

  • RequireDualStack:控制器會從叢集資訊清單中 clusterNetwork.services.cidrBlocks 指定的範圍,為 Service 分配 IPv4 和 IPv6 叢集 IP 位址。系統會根據 Service 資訊清單中 ipFamilies 下方指定的第一個位址系列,設定 spec.clusterIP 的值。

更多資訊

如要進一步瞭解如何建立雙堆疊 Service,請參閱「新 Service 的雙堆疊選項」。