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

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

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

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

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

準備

クラスタノードが CentOS または RedHat Enterprise Linux を実行し、SELinux が有効化されている場合は、各ノードで:

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

  • systemctl restart firewalld を実行します。

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

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

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

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

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

シングルスタック クラスタの場合のように、Namespace マニフェストと 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 に静的フラットモード ネットワーキングを使用するクラスタを対象としています。つまり、クラスタは Border Gateway Protocol(BGP)を使用するように構成されていません。

静的フラットモード ネットワーキングを使用するクラスタの場合、すべて同じサブネットの一部であるノードと Pod の IP アドレスを指定する必要があります。これにより、クラスタ外のクライアントでクラスタノードと同じレイヤ 2(L2)ドメインに Pod の IP アドレスに直接パケットを送信できるようになります。

たとえば、クラスタノードと他のマシンがすべて同じ L2 ドメインにあるとします。次の方法でアドレス範囲を指定できます。

目的範囲アドレスの数
L2 ドメイン全体fd12::/1082^20
Podfd12::1:0/1122^16
ノードfd12::2:0/1122^16
その他のマシンfd12::3:0/1122^16
VIPfd12::4:0/1122^16

上の例で、次の点に注意してください。

  • すべてのノード、Pod、マシンのアドレスは、fd12::/108 の広い範囲にあります。

  • Pod IP アドレスが広い範囲のサブセット内にある。

  • ノードの IP アドレスが、広い範囲の異なるサブセットにある。

  • 他のマシンの IP アドレスは、広い範囲の異なるサブセットにあります。

  • すべてのサブセット範囲は互いに区別されています。

上記の例では、クラスタノードを含む L2 ドメイン内の各マシンに、広い範囲の転送ルールが必要です。次に例を示します。

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 アドレスはこうした範囲から選択されます。

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

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 の値は、それに対応して設定する必要があります。たとえば、ノードごとに 2^8 個のアドレスが必要な場合、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) = 2^16 個のアドレスが存在します。ノードあたりのマスクサイズは 24 であるため、各ノードに割り当てられるアドレスの数は 2^(32-24) = 2^8 です。

  • IPv6 Pod CIDR 範囲には、2^(128-112) = 2^16 個のアドレスが存在します。ノードあたりのマスクサイズは 120 であるため、各ノードに割り当てられるアドレスの数は 2^(128-120) = 2^8 です。

例: 構成ファイル

クラスタの作成を完了する

クラスタ作成のドキュメントの説明に沿って、クラスタの作成を完了します。

クラスタのノードと 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 は、"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 アドレスがサービスに割り振られます。

  • 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

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

クラスタ マニフェストでは、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 に指定されたクラスタ マニフェストの最初の範囲から選択されます。

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

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

詳細

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