From a20b2088ace71ca06a5063c962081cba079094a9 Mon Sep 17 00:00:00 2001 From: Antonio Ojea Date: Mon, 29 Nov 2021 15:10:54 +0100 Subject: [PATCH 1/2] set secondary address on host-network pods host-network pods IPs are obtained from the reported kubelet nodeIPs. Historically, host-network podIPs are immutable once set, but when we've added dual-stack support, we didn't consider that the secondary IP address may not be present at the same time that the primary nodeIP. If a secondary IP address is added to a node after the host-network pods IPs are set, we can add the secondary host-network pod IP address maintaining the current behavior of not updating the current podIPs on host-network pods. --- pkg/kubelet/kubelet_pods.go | 14 ++-- pkg/kubelet/kubelet_pods_test.go | 113 +++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 4 deletions(-) diff --git a/pkg/kubelet/kubelet_pods.go b/pkg/kubelet/kubelet_pods.go index ba0ab34b5c7..1530815214e 100644 --- a/pkg/kubelet/kubelet_pods.go +++ b/pkg/kubelet/kubelet_pods.go @@ -1520,10 +1520,16 @@ func (kl *Kubelet) generateAPIPodStatus(pod *v1.Pod, podStatus *kubecontainer.Po klog.V(4).InfoS("Cannot get host IPs", "err", err) } else { s.HostIP = hostIPs[0].String() - if kubecontainer.IsHostNetworkPod(pod) && s.PodIP == "" { - s.PodIP = hostIPs[0].String() - s.PodIPs = []v1.PodIP{{IP: s.PodIP}} - if len(hostIPs) == 2 { + // HostNetwork Pods inherit the node IPs as PodIPs. They are immutable once set, + // other than that if the node becomes dual-stack, we add the secondary IP. + if kubecontainer.IsHostNetworkPod(pod) { + // Primary IP is not set + if s.PodIP == "" { + s.PodIP = hostIPs[0].String() + s.PodIPs = []v1.PodIP{{IP: s.PodIP}} + } + // Secondary IP is not set #105320 + if len(hostIPs) == 2 && len(s.PodIPs) == 1 { s.PodIPs = append(s.PodIPs, v1.PodIP{IP: hostIPs[1].String()}) } } diff --git a/pkg/kubelet/kubelet_pods_test.go b/pkg/kubelet/kubelet_pods_test.go index 495434bca8f..78263de16e9 100644 --- a/pkg/kubelet/kubelet_pods_test.go +++ b/pkg/kubelet/kubelet_pods_test.go @@ -3349,6 +3349,119 @@ func TestGenerateAPIPodStatusHostNetworkPodIPs(t *testing.T) { } } +func TestNodeAddressUpdatesGenerateAPIPodStatusHostNetworkPodIPs(t *testing.T) { + testcases := []struct { + name string + nodeIPs []string + nodeAddresses []v1.NodeAddress + expectedPodIPs []v1.PodIP + }{ + + { + name: "Immutable after update node addresses single-stack", + nodeIPs: []string{"10.0.0.1"}, + nodeAddresses: []v1.NodeAddress{ + {Type: v1.NodeInternalIP, Address: "1.1.1.1"}, + }, + expectedPodIPs: []v1.PodIP{ + {IP: "10.0.0.1"}, + }, + }, + { + name: "Immutable after update node addresses dual-stack - primary address", + nodeIPs: []string{"10.0.0.1", "2001:db8::2"}, + nodeAddresses: []v1.NodeAddress{ + {Type: v1.NodeInternalIP, Address: "1.1.1.1"}, + {Type: v1.NodeInternalIP, Address: "2001:db8::2"}, + }, + expectedPodIPs: []v1.PodIP{ + {IP: "10.0.0.1"}, + {IP: "2001:db8::2"}, + }, + }, + { + name: "Immutable after update node addresses dual-stack - secondary address", + nodeIPs: []string{"10.0.0.1", "2001:db8::2"}, + nodeAddresses: []v1.NodeAddress{ + {Type: v1.NodeInternalIP, Address: "10.0.0.1"}, + {Type: v1.NodeInternalIP, Address: "2001:db8:1:2:3::2"}, + }, + expectedPodIPs: []v1.PodIP{ + {IP: "10.0.0.1"}, + {IP: "2001:db8::2"}, + }, + }, + { + name: "Immutable after update node addresses dual-stack - primary and secondary address", + nodeIPs: []string{"10.0.0.1", "2001:db8::2"}, + nodeAddresses: []v1.NodeAddress{ + {Type: v1.NodeInternalIP, Address: "1.1.1.1"}, + {Type: v1.NodeInternalIP, Address: "2001:db8:1:2:3::2"}, + }, + expectedPodIPs: []v1.PodIP{ + {IP: "10.0.0.1"}, + {IP: "2001:db8::2"}, + }, + }, + { + name: "Update secondary after new secondary address dual-stack", + nodeIPs: []string{"10.0.0.1"}, + nodeAddresses: []v1.NodeAddress{ + {Type: v1.NodeInternalIP, Address: "10.0.0.1"}, + {Type: v1.NodeInternalIP, Address: "2001:db8::2"}, + }, + expectedPodIPs: []v1.PodIP{ + {IP: "10.0.0.1"}, + {IP: "2001:db8::2"}, + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */) + defer testKubelet.Cleanup() + kl := testKubelet.kubelet + for _, ip := range tc.nodeIPs { + kl.nodeIPs = append(kl.nodeIPs, netutils.ParseIPSloppy(ip)) + } + kl.nodeLister = testNodeLister{nodes: []*v1.Node{ + { + ObjectMeta: metav1.ObjectMeta{Name: string(kl.nodeName)}, + Status: v1.NodeStatus{ + Addresses: tc.nodeAddresses, + }, + }, + }} + + pod := podWithUIDNameNs("12345", "test-pod", "test-namespace") + pod.Spec.HostNetwork = true + for _, ip := range tc.nodeIPs { + pod.Status.PodIPs = append(pod.Status.PodIPs, v1.PodIP{IP: ip}) + } + if len(pod.Status.PodIPs) > 0 { + pod.Status.PodIP = pod.Status.PodIPs[0].IP + } + + // set old status + podStatus := &kubecontainer.PodStatus{ + ID: pod.UID, + Name: pod.Name, + Namespace: pod.Namespace, + } + podStatus.IPs = tc.nodeIPs + + status := kl.generateAPIPodStatus(pod, podStatus) + if !reflect.DeepEqual(status.PodIPs, tc.expectedPodIPs) { + t.Fatalf("Expected PodIPs %#v, got %#v", tc.expectedPodIPs, status.PodIPs) + } + if kl.nodeIPs[0].String() != status.PodIPs[0].IP { + t.Fatalf("Expected HostIP %q to equal PodIPs[0].IP %q", status.HostIP, status.PodIPs[0].IP) + } + }) + } +} + func TestGenerateAPIPodStatusPodIPs(t *testing.T) { testcases := []struct { name string From bc8e7ac1a0daca13b8c464f14ace7e3d5c610ce8 Mon Sep 17 00:00:00 2001 From: Antonio Ojea Date: Mon, 29 Nov 2021 16:07:18 +0100 Subject: [PATCH 2/2] ignore CRI PodSandboxNetworkStatus for host network pods --- pkg/kubelet/kubelet_pods_test.go | 1 + staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.pb.go | 1 + staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.proto | 1 + staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.pb.go | 1 + staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.proto | 1 + 5 files changed, 5 insertions(+) diff --git a/pkg/kubelet/kubelet_pods_test.go b/pkg/kubelet/kubelet_pods_test.go index 78263de16e9..02006e51a92 100644 --- a/pkg/kubelet/kubelet_pods_test.go +++ b/pkg/kubelet/kubelet_pods_test.go @@ -3284,6 +3284,7 @@ func TestGenerateAPIPodStatusHostNetworkPodIPs(t *testing.T) { criPodIPs: []string{"192.168.0.1"}, podIPs: []v1.PodIP{ {IP: "192.168.0.1"}, + {IP: "fd01::1234"}, }, }, { diff --git a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.pb.go b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.pb.go index f8762ae63a0..998673fc923 100644 --- a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.pb.go +++ b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.pb.go @@ -1608,6 +1608,7 @@ func (m *PodIP) GetIp() string { } // PodSandboxNetworkStatus is the status of the network for a PodSandbox. +// Currently ignored for pods sharing the host networking namespace. type PodSandboxNetworkStatus struct { // IP address of the PodSandbox. Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"` diff --git a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.proto b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.proto index 8f96c97ebc6..43bca464dab 100644 --- a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.proto +++ b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1/api.proto @@ -445,6 +445,7 @@ message PodIP{ string ip = 1; } // PodSandboxNetworkStatus is the status of the network for a PodSandbox. +// Currently ignored for pods sharing the host networking namespace. message PodSandboxNetworkStatus { // IP address of the PodSandbox. string ip = 1; diff --git a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.pb.go b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.pb.go index dd1d1d84e93..c333e73c9d5 100644 --- a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.pb.go +++ b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.pb.go @@ -1613,6 +1613,7 @@ func (m *PodIP) GetIp() string { } // PodSandboxNetworkStatus is the status of the network for a PodSandbox. +// Currently ignored for pods sharing the host networking namespace. type PodSandboxNetworkStatus struct { // IP address of the PodSandbox. Ip string `protobuf:"bytes,1,opt,name=ip,proto3" json:"ip,omitempty"` diff --git a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.proto b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.proto index ba3230d183b..19ec2e7871c 100644 --- a/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.proto +++ b/staging/src/k8s.io/cri-api/pkg/apis/runtime/v1alpha2/api.proto @@ -449,6 +449,7 @@ message PodIP{ string ip = 1; } // PodSandboxNetworkStatus is the status of the network for a PodSandbox. +// Currently ignored for pods sharing the host networking namespace. message PodSandboxNetworkStatus { // IP address of the PodSandbox. string ip = 1;