This document shares how to validate IPv4/IPv6 dual-stack enabled Kubernetes clusters.
kubectl version
. 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
:
kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template='{{range .spec.podCIDRs}}{{printf "%s\n" .}}{{end}}'
10.244.1.0/24
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
:
kubectl get nodes k8s-linuxpool1-34450317-0 -o go-template --template='{{range .status.addresses}}{{printf "%s: %s\n" .type .address}}{{end}}'
Hostname: k8s-linuxpool1-34450317-0
InternalIP: 10.240.0.5
InternalIP: 2001:1234:5678:9abc::5
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
:
kubectl get pods pod01 -o go-template --template='{{range .status.podIPs}}{{printf "%s\n" .ip}}{{end}}'
10.244.1.4
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.
env:
- name: MY_POD_IPS
valueFrom:
fieldRef:
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.
kubectl exec -it pod01 -- set | grep MY_POD_IPS
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.
kubectl exec -it pod01 -- cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
fe00::0 ip6-mcastprefix
fe00::1 ip6-allnodes
fe00::2 ip6-allrouters
10.244.1.4 pod01
a00:100::4 pod01
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
Use kubectl
to view the YAML for the Service.
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.
apiVersion: v1 kind: Service metadata: name: my-service namespace: default spec: clusterIP: 10.0.217.164 clusterIPs: - 10.0.217.164 ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - port: 80 protocol: TCP targetPort: 9376 selector: app: MyApp sessionAffinity: None type: ClusterIP status: 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
Use kubectl
to view the YAML for the Service.
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.
apiVersion: v1 kind: Service metadata: labels: app: MyApp name: my-service spec: clusterIP: fd00::5118 clusterIPs: - fd00::5118 ipFamilies: - IPv6 ipFamilyPolicy: SingleStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: MyApp sessionAffinity: None type: ClusterIP status: 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
The kubectl get svc
command will only show the primary IP in the CLUSTER-IP
field.
kubectl get svc -l app=MyApp NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE 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.
kubectl describe svc -l app=MyApp
Name: my-service
Namespace: default
Labels: app=MyApp
Annotations: <none>
Selector: app=MyApp
Type: ClusterIP
IP Family Policy: PreferDualStack
IP Families: IPv4,IPv6
IP: 10.0.216.242
IPs: 10.0.216.242,fd00::af55
Port: <unset> 80/TCP
TargetPort: 9376/TCP
Endpoints: <none>
Session Affinity: None
Events: <none>
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
Check the Service:
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.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-service LoadBalancer fd00::7ebc 2603:1030:805::5 80:30790/TCP 35s
© 2022 The Kubernetes Authors
Documentation Distributed under CC BY 4.0.
https://kubernetes.io/docs/tasks/network/validate-dual-stack