IPv4 / IPv6 デュアルスタック ネットワーキング

Google Distributed Cloud は、IPv4 / IPv6 デュアルスタック ネットワーキングをサポートしています。つまり、クラスタは、インターネット プロトコル バージョン 4(IPv4)またはインターネット プロトコル バージョン 6(IPv6 など)を使用するデバイスからのトラフィックを受け入れることができます。

デュアルスタック ネットワーキングは、IPv4 と IPv6 の両方のアドレスを Pod とノードに割り当てます。Kubernetes Service は、IPv4 アドレス、IPv6 アドレス、またはその両方を持つことができます。

デュアル スタック クラスタはすべて、IPv6 にフラットモードを使用します。デフォルトでは、デュアルスタック クラスタは IPv4 にアイランド モードを使用しますが、IPv4 にフラットモードを使用するように構成することもできます。

デュアルスタック クラスタを作成するには、基盤となるネットワークでデュアルスタックが有効である必要があります。基盤となるネットワークがシングルスタック(IPv4 または IPv6)ネットワークの場合、デュアルスタック クラスタを起動できません。

始める前に

クラスタノードが RedHat Enterprise Linux を実行していて、SELinux が有効になっている場合は、各ノードで次の操作を行います。

  • /etc/firewalld/firewalld.confIPv6_rpfilter=no を設定します。

  • systemctl restart firewalld を実行します。

デュアルスタック クラスタの作成の概要

デュアルスタック ネットワーキングは新しいクラスタの作成時に有効にできます。既存のクラスタに対してデュアルスタック ネットワーキングを有効にすることはできません。

クラスタ作成に関するドキュメントの手順に沿って操作します。

構成ファイルに、次の項目に関するマニフェストを追加します。

  • Namespace リソース
  • クラスタ リソース
  • 1 つ以上の NodePool リソース
  • 1 つ以上の ClusterCIDRConfig リソース

シングルスタック クラスタの場合と同様に、Namespace マニフェストと NodePool マニフェストを設定します。

Cluster マニフェストの clusterNetwork.services.cidrBlocks で、IPv4 CIDR 範囲と IPv6 CIDR 範囲の両方を指定します。これは、デュアルスタック クラスタを有効にするための基準です。つまり、IPv4 と IPv6 の両方に Service CIDR 範囲を指定すると、クラスタはデュアルスタック ネットワークを使用します。

Cluster マニフェストの clusterNetwork.pods.cidrBlocks では、IPv4 CIDR 範囲を指定しますが、IPv6 CIDR 範囲は指定しません。Pod の IPv6 CIDR 範囲は ClusterCIDRConfig マニフェストで指定します。

バンドルされたロード バランシングを使用している場合は、Cluster マニフェストの loadBalancer.addressPools セクションに IPv4 アドレスと IPv6 アドレスの両方を指定します。

ClusterCIDRConfig リソースは、Pod の IPv4 と IPv6 の CIDR 範囲を指定するためのものです。1 つの ClusterCIDRConfig リソースでクラスタ全体の CIDR 範囲を指定できます。すべてのノードの IPv4 Pod アドレスは単一の CIDR 範囲から取得されます。また、すべてのノードの IPv6 Pod アドレスも単一の CIDR 範囲から取得されます。複数の ClusterCIDRConfig リソースを使用して、特定のノードプールまたは特定のノードに適用される CIDR 範囲を指定することもできます。

Pod IP アドレスのネットワーク到達性

デュアルスタック クラスタは、IPv6 ネットワーキングにフラットモードを使用します。このドキュメントの例は、IPv6 に静的フラットモード ネットワーキングを使用するクラスタを対象としています。このクラスタは Border Gateway Protocol(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 に、1 つの IPv4 CIDR 範囲を指定します。

  • clusterNetwork.services.cidrBlocks に、2 つの CIDR 範囲(IPv4 用と IPv6 用)を指定します。

  • loadBalancer.addressPools に、2 つのアドレス範囲(IPv4 用と IPv6 用)を指定します。LoadBalancer タイプの Service を作成すると、Service の外部 IP アドレスはこれらの範囲から選択されます。

次に、Cluster マニフェストに関連する部分の例を示します。

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

1 つの 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 に 1 つの 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 を作成する

Deployment のマニフェストは次のとおりです。

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 アドレスが Service に割り振られます。

  • ipFamilies フィールドでは、最初に IPv6 ファミリーを指定し、次に IPv4 ファミリーを指定します。つまり、Service の spec.ClusterIP が Cluster マニフェストの clusterNetwork.services.cidrBlocks から選択された IPv6 アドレスになります。

このマニフェストを my-cip-service.yaml という名前のファイルに保存して Service を作成します。

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

Service の詳細を一覧取得します。

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

Cluster マニフェストでは、LoadBalancer タイプの Service に使用する IPv6 アドレスの範囲と IPv4 アドレスの範囲を指定しました。

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

Service には、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: コントローラが 1 つのクラスタ IP アドレスを Service に割り振ります。これは、clusterNetwork.services.cidrBlocks に指定された Cluster マニフェストの最初の範囲から選択されます。

  • PreferDualStack: コントローラは、Service の IPv4 および IPv6 クラスタ IP アドレスを Cluster マニフェスト(clusterNetwork.services.cidrBlocks の下)に指定された範囲から選択して割り振ります。クラスタがデュアル スタック クラスタでない場合、動作は SingleStack の場合と同じです。

  • RequireDualStack: コントローラは、Service の IPv4 および IPv6 クラスタ IP アドレスを Cluster マニフェスト(clusterNetwork.services.cidrBlocks の下)に指定された範囲から選択して割り振ります。Service マニフェスト(ipFamilies の下)で指定された最初のアドレス ファミリーに基づいて spec.clusterIP の値が設定されます。

詳細

デュアルスタック サービスの作成方法については、新しい Service のデュアルスタック オプションをご覧ください。