IPv4/IPv6 雙重堆疊網路

Google Distributed Cloud 支援 IPv4/IPv6 雙重堆疊網路。也就是說,叢集可以接受來自外部裝置的流量,這些裝置使用網際網路通訊協定第 4 版 (IPv4) 或網際網路通訊協定第 6 版 (IPv6)。

雙重堆疊網路會為 Pod 和節點指派 IPv4 和 IPv6 位址。 Kubernetes Service 可以同時擁有 IPv4 和 IPv6 位址。

所有雙堆疊叢集都使用 IPv6 的扁平模式。根據預設,雙堆疊叢集會使用 IPv4 的島嶼模式,但您可以設定使用 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 類型服務的 IPv4 位址集區
  • 用於 LoadBalancer 類型服務的 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 類型的雙堆疊服務

以下是部署的資訊清單:

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」,表示系統會為服務分配 IPv6 和 IPv4 ClusterIP 位址。

  • ipFamilies 欄位會先指定 IPv6 系列,再指定 IPv4 系列。也就是說,系統會從叢集資訊清單的 clusterNetwork.services.cidrBlocks 中,為服務選擇 IPv6 位址 spec.ClusterIP

將資訊清單儲存到名為 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 類型的雙堆疊服務

以下是 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 類型的服務:

  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 位址,指派給您的服務。

列出服務的詳細資料:

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:控制器會為 Service 分配叢集 IP 位址,該位址是從叢集資訊清單中 clusterNetwork.services.cidrBlocks 下方指定的第一個範圍中選取。

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

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

更多資訊

如要進一步瞭解如何建立雙堆疊服務,請參閱新服務的雙堆疊選項