LinuCエヴァンジェリストの鯨井貴博@opensourcetechです。
はじめに
Dual Stack環境のkubernetes(v1.26.0)におけるServiceの挙動(IPv4とIPv6のどっちが有効になるの?)に関するメモです。
なお、Dual Stack環境のkubernetesクラスターはこちらで構築したものを使っています。
やってみること
以下のようにkubernetes上にnginxのDeploymentsがあるので、
それを公開(Service)して挙動を確かめます。
※kubectl create deployments nginx --image=nginx:1.23.2
kubeuser@master01:~$ kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME master01 Ready control-plane 158m v1.26.0 192.168.1.41 <none> Ubuntu 22.04.2 LTS 5.15.0-67-generic containerd://1.6.18 worker01 Ready <none> 155m v1.26.0 192.168.1.45 <none> Ubuntu 22.04.2 LTS 5.15.0-67-generic containerd://1.6.18 worker02 Ready <none> 155m v1.26.0 192.168.1.46 <none> Ubuntu 22.04.2 LTS 5.15.0-67-generic containerd://1.6.18
kubeuser@master01:~$ kubectl get deployments.apps NAME READY UP-TO-DATE AVAILABLE AGE nginx 1/1 1 1 147m kubeuser@master01:~$ kubectl get deployments.apps nginx -o yaml apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: "1" creationTimestamp: "2023-03-14T13:50:35Z" generation: 1 labels: app: nginx name: nginx namespace: default resourceVersion: "1156" uid: 9083fb18-721d-4102-ae2d-100ebae18536 spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: creationTimestamp: null labels: app: nginx spec: containers: - image: nginx:1.23.2 imagePullPolicy: IfNotPresent name: nginx resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 status: availableReplicas: 1 conditions: - lastTransitionTime: "2023-03-14T13:50:59Z" lastUpdateTime: "2023-03-14T13:50:59Z" message: Deployment has minimum availability. reason: MinimumReplicasAvailable status: "True" type: Available - lastTransitionTime: "2023-03-14T13:50:35Z" lastUpdateTime: "2023-03-14T13:50:59Z" message: ReplicaSet "nginx-759fd59899" has successfully progressed. reason: NewReplicaSetAvailable status: "True" type: Progressing observedGeneration: 1 readyReplicas: 1 replicas: 1 updatedReplicas: 1 kubeuser@master01:~$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-759fd59899-59sgs 1/1 Running 0 147m 10.0.30.65 worker02 <none> <none> kubeuser@master01:~$ kubectl get pods nginx-759fd59899-59sgs -o go-template --template='{{range .status.podIPs}}{{printf "%s\n" .ip}}{{end}}' 10.0.30.65 fd12:b5e0:383e:0:7bf:50a7:b256:1e40 kubeuser@master01:~$ curl http://[fd12:b5e0:383e:0:7bf:50a7:b256:1e40] <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
ipFamilies(IPv4/IPv6)指定なし
まずは、以下のService用のマニュフェストを使います。
特に、どのipFamilies(IPv4/IPv6)を指定していません。
kubeuser@master01:~$ cat svc_nginx_ipv4.yaml apiVersion: v1 kind: Service metadata: labels: app: nginx name: nginx spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx
結果:IPv4がアサインされる
kubeuser@master01:~$ kubectl apply -f svc_nginx_ipv4.yaml service/nginx configured kubeuser@master01:~$ kubectl get svc nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP 10.1.179.244 <none> 80/TCP 158m kubeuser@master01:~$ kubectl get svc nginx -o yaml apiVersion: v1 kind: Service metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx","namespace":"default"},"spec":{"ports":[{"port":80,"protocol":"TCP","targetPort":80}],"selector":{"app":"nginx"}}} creationTimestamp: "2023-03-14T13:55:35Z" labels: app: nginx name: nginx namespace: default resourceVersion: "15706" uid: 97bbff5e-a1ad-4410-a9cb-267defd83fc3 spec: clusterIP: 10.1.179.244 clusterIPs: - 10.1.179.244 - fd12:b5e0:383f::2261 internalTrafficPolicy: Cluster ipFamilies: - IPv4 - IPv6 ipFamilyPolicy: PreferDualStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx sessionAffinity: None type: ClusterIP status: loadBalancer: {}
ipFamilies(IPv6指定) & ipFamilyPolicy: SingleStack
まずは、以下のService用のマニュフェストを使います。
ipFamiliesでIPv6を指定します。
kubeuser@master01:~$ cat svc_nginx_ipv6.yaml apiVersion: v1 kind: Service metadata: labels: app: nginx name: nginx spec: ipFamilies: - IPv6 ipFamilyPolicy: SingleStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx
結果:IPv6がアサインされる
kubeuser@master01:~$ kubectl apply -f svc_nginx_ipv6.yaml service/nginx created kubeuser@master01:~$ kubectl get svc nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP fd12:b5e0:383f::f75b <none> 80/TCP 5s kubeuser@master01:~$ kubectl get svc nginx -o yaml apiVersion: v1 kind: Service metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx","namespace":"default"},"spec":{"ipFamilies":["IPv6"],"ipFamilyPolicy":"SingleStack","ports":[{"port":80,"protocol":"TCP","targetPort":80}],"selector":{"app":"nginx"}}} creationTimestamp: "2023-03-14T16:37:41Z" labels: app: nginx name: nginx namespace: default resourceVersion: "16046" uid: 9b2b69ec-fc71-4873-813b-9ab59fbdcc95 spec: clusterIP: fd12:b5e0:383f::f75b clusterIPs: - fd12:b5e0:383f::f75b internalTrafficPolicy: Cluster ipFamilies: - IPv6 ipFamilyPolicy: SingleStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx sessionAffinity: None type: ClusterIP status: loadBalancer: {}
ipFamilies(IPv4/IPv6指定) & ipFamilyPolicy: PreferDualStack
まずは、以下のService用のマニュフェストを使います。
ipFamiliesでIPv4/IPv6を指定します。
また、ipFamilyPolicy: PreferDualStackとしています。
kubeuser@master01:~$ cat svc_nginx_dual_prefer.yaml apiVersion: v1 kind: Service metadata: labels: app: nginx name: nginx spec: ipFamilies: - IPv4 - IPv6 ipFamilyPolicy: PreferDualStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx
結果:IPv4/IPv6(Dual Stack)となる
kubeuser@master01:~$ kubectl apply -f svc_nginx_dual_prefer.yaml service/nginx created kubeuser@master01:~$ kubectl get svc nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP 10.1.49.119 <none> 80/TCP 5s kubeuser@master01:~$ kubectl get svc nginx -o yaml apiVersion: v1 kind: Service metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx","namespace":"default"},"spec":{"ipFamilies":["IPv4","IPv6"],"ipFamilyPolicy":"PreferDualStack","ports":[{"port":80,"protocol":"TCP","targetPort":80}],"selector":{"app":"nginx"}}} creationTimestamp: "2023-03-14T16:41:24Z" labels: app: nginx name: nginx namespace: default resourceVersion: "16387" uid: 164a6826-54ea-41f2-8820-75a6ca0fb1c1 spec: clusterIP: 10.1.49.119 clusterIPs: - 10.1.49.119 - fd12:b5e0:383f::f2e2 internalTrafficPolicy: Cluster ipFamilies: - IPv4 - IPv6 ipFamilyPolicy: PreferDualStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx sessionAffinity: None type: ClusterIP status: loadBalancer: {}
ipFamilies(IPv4/IPv6指定) & ipFamilyPolicy: RequireDualStack
まずは、以下のService用のマニュフェストを使います。
ipFamiliesでIPv4/IPv6を指定します。
また、ipFamilyPolicy: RequireDualStackとしています。
kubeuser@master01:~$ cat svc_nginx_dual_reequire.yaml apiVersion: v1 kind: Service metadata: labels: app: nginx name: nginx spec: ipFamilies: - IPv4 - IPv6 ipFamilyPolicy: RequireDualStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx
結果:IPv4/IPv6(Dual Stack)となる
kubeuser@master01:~$ kubectl apply -f svc_nginx_dual_reequire.yaml service/nginx created kubeuser@master01:~$ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 3h12m nginx ClusterIP 10.1.223.177 <none> 80/TCP 5s kubeuser@master01:~$ kubectl get svc -o yaml apiVersion: v1 items: - apiVersion: v1 kind: Service metadata: creationTimestamp: "2023-03-14T13:45:53Z" labels: component: apiserver provider: kubernetes name: kubernetes namespace: default resourceVersion: "199" uid: 55782f7e-062c-4cfb-acca-4e4a0d8177a3 spec: clusterIP: 10.1.0.1 clusterIPs: - 10.1.0.1 internalTrafficPolicy: Cluster ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - name: https port: 443 protocol: TCP targetPort: 6443 sessionAffinity: None type: ClusterIP status: loadBalancer: {} - apiVersion: v1 kind: Service metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx","namespace":"default"},"spec":{"ipFamilies":["IPv4","IPv6"],"ipFamilyPolicy":"RequireDualStack","ports":[{"port":80,"protocol":"TCP","targetPort":80}],"selector":{"app":"nginx"}}} creationTimestamp: "2023-03-14T16:58:24Z" labels: app: nginx name: nginx namespace: default resourceVersion: "17914" uid: 699a5e0f-bf6d-4941-85c9-ca0a1eade1b5 spec: clusterIP: 10.1.223.177 clusterIPs: - 10.1.223.177 - fd12:b5e0:383f::e44e internalTrafficPolicy: Cluster ipFamilies: - IPv4 - IPv6 ipFamilyPolicy: RequireDualStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx sessionAffinity: None type: ClusterIP status: loadBalancer: {} kind: List metadata: resourceVersion: ""
ServiceのipFamilyPolicyとipFamiliesについて
ipFamilyPolicy
・SingleStack:IPv4 or IPv6のどちらか
・PreferDualStack:DualStack or SingleStackのどちらか
・RequireDualStack:DualStack(それ以外は失敗する)
ipFamilies
・IPv4/IPv6のどちらか、もしくは両方の指定が可能
・IPv4/IPv6のどれが適用されるかは、クラスターの構成とipFamilyPolicyで決定される
kubeuser@master01:~$ kubectl explain svc.spec.ipFamilyPolicy KIND: Service VERSION: v1 FIELD: ipFamilyPolicy <string> DESCRIPTION: IPFamilyPolicy represents the dual-stack-ness requested or required by this Service. If there is no value provided, then this field will be set to SingleStack. Services can be "SingleStack" (a single IP family), "PreferDualStack" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or "RequireDualStack" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the value of this field. This field will be wiped when updating a service to type ExternalName. kubeuser@master01:~$ kubectl explain svc.spec.ipFamilies KIND: Service VERSION: v1 FIELD: ipFamilies <[]string> DESCRIPTION: IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this service. This field is usually assigned automatically based on cluster configuration and the ipFamilyPolicy field. If this field is specified manually, the requested family is available in the cluster, and ipFamilyPolicy allows it, it will be used; otherwise creation of the service will fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not allow changing the primary IP family of the Service. Valid values are "IPv4" and "IPv6". This field only applies to Services of types ClusterIP, NodePort, and LoadBalancer, and does apply to "headless" services. This field will be wiped when updating a Service to type ExternalName. This field may hold a maximum of two entries (dual-stack families, in either order). These families must correspond to the values of the clusterIPs field, if specified. Both clusterIPs and ipFamilies are governed by the ipFamilyPolicy field.