Validate IPv4/IPv6 dual-stack

This document shares how to validate IPv4/IPv6 dual-stack enabled Kubernetes clusters.

Before you begin

  • Provider support for dual-stack networking (Cloud provider or otherwise must be able to provide Kubernetes nodes with routable IPv4/IPv6 network interfaces)
  • A network plugin that supports dual-stack (such as Kubenet or Calico)
  • Dual-stack enabled cluster

Your Kubernetes server must be version v1.20. To check the version, enter kubectl version.

Validate addressing

Validate node addressing

Each dual-stack Node should have a single IPv4 block and a single IPv6 block allocated. Validate that IPv4/IPv6 Pod address ranges are configured by running the following command. Replace the sample node name with a valid dual-stack Node from your cluster. In this example, the Node’s name is k8s-linuxpool1-34450317-0:

  1. kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template='{{range .spec.podCIDRs}}{{printf "%s\n" .}}{{end}}'
  1. 10.244.1.0/24
  2. a00:100::/24

There should be one IPv4 block and one IPv6 block allocated.

Validate that the node has an IPv4 and IPv6 interface detected (replace node name with a valid node from the cluster. In this example the node name is k8s-linuxpool1-34450317-0):

  1. kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template='{{range .status.addresses}}{{printf "%s: %s \n" .type .address}}{{end}}'
  1. Hostname: k8s-linuxpool1-34450317-0
  2. InternalIP: 10.240.0.5
  3. InternalIP: 2001:1234:5678:9abc::5

Validate Pod addressing

Validate that a Pod has an IPv4 and IPv6 address assigned. (replace the Pod name with a valid Pod in your cluster. In this example the Pod name is pod01)

  1. kubectl get pods pod01 -o go-template --template='{{range .status.podIPs}}{{printf "%s \n" .ip}}{{end}}'
  1. 10.244.1.4
  2. a00:100::4

You can also validate Pod IPs using the Downward API via the status.podIPs fieldPath. The following snippet demonstrates how you can expose the Pod IPs via an environment variable called MY_POD_IPS within a container.

  1. env:
  2. - name: MY_POD_IPS
  3. valueFrom:
  4. fieldRef:
  5. fieldPath: status.podIPs

The following command prints the value of the MY_POD_IPS environment variable from within a container. The value is a comma separated list that corresponds to the Pod’s IPv4 and IPv6 addresses.

  1. kubectl exec -it pod01 -- set | grep MY_POD_IPS
  1. MY_POD_IPS=10.244.1.4,a00:100::4

The Pod’s IP addresses will also be written to /etc/hosts within a container. The following command executes a cat on /etc/hosts on a dual stack Pod. From the output you can verify both the IPv4 and IPv6 IP address for the Pod.

  1. kubectl exec -it pod01 -- cat /etc/hosts
  1. # Kubernetes-managed hosts file.
  2. 127.0.0.1 localhost
  3. ::1 localhost ip6-localhost ip6-loopback
  4. fe00::0 ip6-localnet
  5. fe00::0 ip6-mcastprefix
  6. fe00::1 ip6-allnodes
  7. fe00::2 ip6-allrouters
  8. 10.244.1.4 pod01
  9. a00:100::4 pod01

Validate Services

Create the following Service that does not explicitly define .spec.ipFamilyPolicy. Kubernetes will assign a cluster IP for the Service from the first configured service-cluster-ip-range and set the .spec.ipFamilyPolicy to SingleStack.

service/networking/dual-stack-default-svc.yaml Validate IPv4/IPv6 dual-stack - 图1

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: my-service
  5. labels:
  6. app: MyApp
  7. spec:
  8. selector:
  9. app: MyApp
  10. ports:
  11. - protocol: TCP
  12. port: 80

Use kubectl to view the YAML for the Service.

  1. kubectl get svc my-service -o yaml

The Service has .spec.ipFamilyPolicy set to SingleStack and .spec.clusterIP set to an IPv4 address from the first configured range set via --service-cluster-ip-range flag on kube-controller-manager.

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: my-service
  5. namespace: default
  6. spec:
  7. clusterIP: 10.0.217.164
  8. clusterIPs:
  9. - 10.0.217.164
  10. ipFamilies:
  11. - IPv4
  12. ipFamilyPolicy: SingleStack
  13. ports:
  14. - port: 80
  15. protocol: TCP
  16. targetPort: 9376
  17. selector:
  18. app: MyApp
  19. sessionAffinity: None
  20. type: ClusterIP
  21. status:
  22. loadBalancer: {}

Create the following Service that explicitly defines IPv6 as the first array element in .spec.ipFamilies. Kubernetes will assign a cluster IP for the Service from the IPv6 range configured service-cluster-ip-range and set the .spec.ipFamilyPolicy to SingleStack.

service/networking/dual-stack-ipfamilies-ipv6.yaml Validate IPv4/IPv6 dual-stack - 图2

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: my-service
  5. labels:
  6. app: MyApp
  7. spec:
  8. ipFamilies:
  9. - IPv6
  10. selector:
  11. app: MyApp
  12. ports:
  13. - protocol: TCP
  14. port: 80

Use kubectl to view the YAML for the Service.

  1. kubectl get svc my-service -o yaml

The Service has .spec.ipFamilyPolicy set to SingleStack and .spec.clusterIP set to an IPv6 address from the IPv6 range set via --service-cluster-ip-range flag on kube-controller-manager.

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. labels:
  5. app: MyApp
  6. name: my-service
  7. spec:
  8. clusterIP: fd00::5118
  9. clusterIPs:
  10. - fd00::5118
  11. ipFamilies:
  12. - IPv6
  13. ipFamilyPolicy: SingleStack
  14. ports:
  15. - port: 80
  16. protocol: TCP
  17. targetPort: 80
  18. selector:
  19. app: MyApp
  20. sessionAffinity: None
  21. type: ClusterIP
  22. status:
  23. loadBalancer: {}

Create the following Service that explicitly defines PreferDualStack in .spec.ipFamilyPolicy. Kubernetes will assign both IPv4 and IPv6 addresses (as this cluster has dual-stack enabled) and select the .spec.ClusterIP from the list of .spec.ClusterIPs based on the address family of the first element in the .spec.ipFamilies array.

service/networking/dual-stack-preferred-svc.yaml Validate IPv4/IPv6 dual-stack - 图3

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: my-service
  5. labels:
  6. app: MyApp
  7. spec:
  8. ipFamilyPolicy: PreferDualStack
  9. selector:
  10. app: MyApp
  11. ports:
  12. - protocol: TCP
  13. port: 80

Note:

The kubectl get svc command will only show the primary IP in the CLUSTER-IP field.

  1. kubectl get svc -l app=MyApp
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. my-service ClusterIP 10.0.216.242 <none> 80/TCP 5s

Validate that the Service gets cluster IPs from the IPv4 and IPv6 address blocks using kubectl describe. You may then validate access to the service via the IPs and ports.

  1. kubectl describe svc -l app=MyApp
  1. Name: my-service
  2. Namespace: default
  3. Labels: app=MyApp
  4. Annotations: <none>
  5. Selector: app=MyApp
  6. Type: ClusterIP
  7. IP Family Policy: PreferDualStack
  8. IP Families: IPv4,IPv6
  9. IP: 10.0.216.242
  10. IPs: 10.0.216.242,fd00::af55
  11. Port: <unset> 80/TCP
  12. TargetPort: 9376/TCP
  13. Endpoints: <none>
  14. Session Affinity: None
  15. Events: <none>

Create a dual-stack load balanced Service

If the cloud provider supports the provisioning of IPv6 enabled external load balancers, create the following Service with PreferDualStack in .spec.ipFamilyPolicy, IPv6 as the first element of the .spec.ipFamilies array and the type field set to LoadBalancer.

service/networking/dual-stack-prefer-ipv6-lb-svc.yaml Validate IPv4/IPv6 dual-stack - 图4

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: my-service
  5. labels:
  6. app: MyApp
  7. spec:
  8. ipFamilyPolicy: PreferDualStack
  9. ipFamilies:
  10. - IPv6
  11. type: LoadBalancer
  12. selector:
  13. app: MyApp
  14. ports:
  15. - protocol: TCP
  16. port: 80

Check the Service:

  1. kubectl get svc -l app=MyApp

Validate that the Service receives a CLUSTER-IP address from the IPv6 address block along with an EXTERNAL-IP. You may then validate access to the service via the IP and port.

  1. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  2. my-service LoadBalancer fd00::7ebc 2603:1030:805::5 80:30790/TCP 35s