mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-02 16:29:21 +00:00
Promote KEP-2681 to beta in 1.29
This commit is contained in:
parent
14ed7e8609
commit
33f2d487e2
@ -684,6 +684,7 @@ const (
|
|||||||
// owner: @wzshiming
|
// owner: @wzshiming
|
||||||
// kep: http://kep.k8s.io/2681
|
// kep: http://kep.k8s.io/2681
|
||||||
// alpha: v1.28
|
// alpha: v1.28
|
||||||
|
// beta: v1.29
|
||||||
//
|
//
|
||||||
// Adds pod.status.hostIPs and downward API
|
// Adds pod.status.hostIPs and downward API
|
||||||
PodHostIPs featuregate.Feature = "PodHostIPs"
|
PodHostIPs featuregate.Feature = "PodHostIPs"
|
||||||
@ -1134,7 +1135,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
|
|
||||||
PodReadyToStartContainersCondition: {Default: false, PreRelease: featuregate.Alpha},
|
PodReadyToStartContainersCondition: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
|
|
||||||
PodHostIPs: {Default: false, PreRelease: featuregate.Alpha},
|
PodHostIPs: {Default: true, PreRelease: featuregate.Beta},
|
||||||
|
|
||||||
PodSchedulingReadiness: {Default: true, PreRelease: featuregate.Beta},
|
PodSchedulingReadiness: {Default: true, PreRelease: featuregate.Beta},
|
||||||
|
|
||||||
|
@ -26,9 +26,8 @@ import (
|
|||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/uuid"
|
"k8s.io/apimachinery/pkg/util/uuid"
|
||||||
netutils "k8s.io/utils/net"
|
|
||||||
|
|
||||||
kubefeatures "k8s.io/kubernetes/pkg/features"
|
kubefeatures "k8s.io/kubernetes/pkg/features"
|
||||||
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
@ -38,9 +37,11 @@ import (
|
|||||||
e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"
|
e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"
|
||||||
"k8s.io/kubernetes/test/e2e/network/common"
|
"k8s.io/kubernetes/test/e2e/network/common"
|
||||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||||
|
netutils "k8s.io/utils/net"
|
||||||
|
"k8s.io/utils/ptr"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
var _ = common.SIGDescribe("DualStack Host IP [NodeFeature:PodHostIPs] [Feature:PodHostIPs]", func() {
|
||||||
f := framework.NewDefaultFramework("dualstack")
|
f := framework.NewDefaultFramework("dualstack")
|
||||||
|
|
||||||
ginkgo.Context("when creating a Pod, it has no PodHostIPs feature", func() {
|
ginkgo.Context("when creating a Pod, it has no PodHostIPs feature", func() {
|
||||||
@ -53,21 +54,7 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
|||||||
|
|
||||||
podName := "pod-dualstack-host-ips"
|
podName := "pod-dualstack-host-ips"
|
||||||
|
|
||||||
pod := &v1.Pod{
|
pod := genPodHostIPs(podName+string(uuid.NewUUID()), false)
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: podName,
|
|
||||||
Labels: map[string]string{"test": "dualstack-host-ips"},
|
|
||||||
},
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Containers: []v1.Container{
|
|
||||||
{
|
|
||||||
Name: "dualstack-host-ips",
|
|
||||||
Image: imageutils.GetE2EImage(imageutils.Agnhost),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ginkgo.By("submitting the pod to kubernetes")
|
ginkgo.By("submitting the pod to kubernetes")
|
||||||
podClient := e2epod.NewPodClient(f)
|
podClient := e2epod.NewPodClient(f)
|
||||||
p := podClient.CreateSync(ctx, pod)
|
p := podClient.CreateSync(ctx, pod)
|
||||||
@ -76,7 +63,7 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
|||||||
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil())
|
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil())
|
||||||
|
|
||||||
ginkgo.By("deleting the pod")
|
ginkgo.By("deleting the pod")
|
||||||
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
|
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
|
||||||
framework.ExpectNoError(err, "failed to delete pod")
|
framework.ExpectNoError(err, "failed to delete pod")
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -84,22 +71,7 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
|||||||
|
|
||||||
podName := "pod-dualstack-host-ips"
|
podName := "pod-dualstack-host-ips"
|
||||||
|
|
||||||
pod := &v1.Pod{
|
pod := genPodHostIPs(podName+string(uuid.NewUUID()), true)
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: podName,
|
|
||||||
Labels: map[string]string{"test": "dualstack-host-ips"},
|
|
||||||
},
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Containers: []v1.Container{
|
|
||||||
{
|
|
||||||
Name: "dualstack-host-ips",
|
|
||||||
Image: imageutils.GetE2EImage(imageutils.Agnhost),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
HostNetwork: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ginkgo.By("submitting the pod to kubernetes")
|
ginkgo.By("submitting the pod to kubernetes")
|
||||||
podClient := e2epod.NewPodClient(f)
|
podClient := e2epod.NewPodClient(f)
|
||||||
p := podClient.CreateSync(ctx, pod)
|
p := podClient.CreateSync(ctx, pod)
|
||||||
@ -108,7 +80,7 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
|||||||
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil())
|
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil())
|
||||||
|
|
||||||
ginkgo.By("deleting the pod")
|
ginkgo.By("deleting the pod")
|
||||||
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
|
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
|
||||||
framework.ExpectNoError(err, "failed to delete pod")
|
framework.ExpectNoError(err, "failed to delete pod")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -123,20 +95,7 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
|||||||
|
|
||||||
podName := "pod-dualstack-host-ips"
|
podName := "pod-dualstack-host-ips"
|
||||||
|
|
||||||
pod := &v1.Pod{
|
pod := genPodHostIPs(podName+string(uuid.NewUUID()), false)
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: podName,
|
|
||||||
Labels: map[string]string{"test": "dualstack-host-ips"},
|
|
||||||
},
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Containers: []v1.Container{
|
|
||||||
{
|
|
||||||
Name: "dualstack-host-ips",
|
|
||||||
Image: imageutils.GetE2EImage(imageutils.Agnhost),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ginkgo.By("submitting the pod to kubernetes")
|
ginkgo.By("submitting the pod to kubernetes")
|
||||||
podClient := e2epod.NewPodClient(f)
|
podClient := e2epod.NewPodClient(f)
|
||||||
@ -158,19 +117,26 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
|||||||
framework.ExpectNoError(err)
|
framework.ExpectNoError(err)
|
||||||
for _, node := range nodeList.Items {
|
for _, node := range nodeList.Items {
|
||||||
if node.Name == p.Spec.NodeName {
|
if node.Name == p.Spec.NodeName {
|
||||||
nodeIPs := []string{}
|
got := sets.New[string]()
|
||||||
|
for _, hostIP := range p.Status.HostIPs {
|
||||||
|
got.Insert(hostIP.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := sets.New[string]()
|
||||||
for _, address := range node.Status.Addresses {
|
for _, address := range node.Status.Addresses {
|
||||||
if address.Type == v1.NodeInternalIP {
|
if address.Type == v1.NodeInternalIP {
|
||||||
nodeIPs = append(nodeIPs, address.Address)
|
want.Insert(address.Address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gomega.Expect(p.Status.HostIPs).Should(gomega.Equal(nodeIPs))
|
if !got.Equal(want) {
|
||||||
|
framework.Failf("got %v, want %v", got, want)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ginkgo.By("deleting the pod")
|
ginkgo.By("deleting the pod")
|
||||||
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
|
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
|
||||||
framework.ExpectNoError(err, "failed to delete pod")
|
framework.ExpectNoError(err, "failed to delete pod")
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -178,21 +144,7 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
|||||||
|
|
||||||
podName := "pod-dualstack-host-ips"
|
podName := "pod-dualstack-host-ips"
|
||||||
|
|
||||||
pod := &v1.Pod{
|
pod := genPodHostIPs(podName+string(uuid.NewUUID()), true)
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: podName,
|
|
||||||
Labels: map[string]string{"test": "dualstack-host-ips"},
|
|
||||||
},
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Containers: []v1.Container{
|
|
||||||
{
|
|
||||||
Name: "dualstack-host-ips",
|
|
||||||
Image: imageutils.GetE2EImage(imageutils.Agnhost),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
HostNetwork: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
ginkgo.By("submitting the pod to kubernetes")
|
ginkgo.By("submitting the pod to kubernetes")
|
||||||
podClient := e2epod.NewPodClient(f)
|
podClient := e2epod.NewPodClient(f)
|
||||||
@ -214,19 +166,26 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
|||||||
framework.ExpectNoError(err)
|
framework.ExpectNoError(err)
|
||||||
for _, node := range nodeList.Items {
|
for _, node := range nodeList.Items {
|
||||||
if node.Name == p.Spec.NodeName {
|
if node.Name == p.Spec.NodeName {
|
||||||
nodeIPs := []string{}
|
got := sets.New[string]()
|
||||||
|
for _, hostIP := range p.Status.HostIPs {
|
||||||
|
got.Insert(hostIP.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := sets.New[string]()
|
||||||
for _, address := range node.Status.Addresses {
|
for _, address := range node.Status.Addresses {
|
||||||
if address.Type == v1.NodeInternalIP {
|
if address.Type == v1.NodeInternalIP {
|
||||||
nodeIPs = append(nodeIPs, address.Address)
|
want.Insert(address.Address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gomega.Expect(p.Status.HostIPs).Should(gomega.Equal(nodeIPs))
|
if !got.Equal(want) {
|
||||||
|
framework.Failf("got %v, want %v", got, want)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ginkgo.By("deleting the pod")
|
ginkgo.By("deleting the pod")
|
||||||
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
|
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
|
||||||
framework.ExpectNoError(err, "failed to delete pod")
|
framework.ExpectNoError(err, "failed to delete pod")
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -250,9 +209,90 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
|
|||||||
|
|
||||||
testDownwardAPI(ctx, f, podName, env, expectations)
|
testDownwardAPI(ctx, f, podName, env, expectations)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ginkgo.It("should able upgrade and rollback", func(ctx context.Context) {
|
||||||
|
podName := "pod-dualstack-host-ips"
|
||||||
|
|
||||||
|
pod := genPodHostIPs(podName+string(uuid.NewUUID()), false)
|
||||||
|
|
||||||
|
ginkgo.By("submitting the pod to kubernetes")
|
||||||
|
podClient := e2epod.NewPodClient(f)
|
||||||
|
p := podClient.CreateSync(ctx, pod)
|
||||||
|
|
||||||
|
gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil())
|
||||||
|
|
||||||
|
ginkgo.By("Disable PodHostIPs feature")
|
||||||
|
cfg, err := getCurrentKubeletConfig(ctx)
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
|
||||||
|
newCfg := cfg.DeepCopy()
|
||||||
|
newCfg.FeatureGates = map[string]bool{
|
||||||
|
string(kubefeatures.PodHostIPs): false,
|
||||||
|
}
|
||||||
|
|
||||||
|
updateKubeletConfig(ctx, f, newCfg, true)
|
||||||
|
|
||||||
|
gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil())
|
||||||
|
|
||||||
|
ginkgo.By("deleting the pod")
|
||||||
|
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
|
||||||
|
framework.ExpectNoError(err, "failed to delete pod")
|
||||||
|
|
||||||
|
ginkgo.By("recreate pod")
|
||||||
|
pod = genPodHostIPs(podName+string(uuid.NewUUID()), false)
|
||||||
|
p = podClient.CreateSync(ctx, pod)
|
||||||
|
// Feature PodHostIPs is disabled, HostIPs should be nil
|
||||||
|
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil())
|
||||||
|
|
||||||
|
newCfg.FeatureGates = map[string]bool{
|
||||||
|
string(kubefeatures.PodHostIPs): true,
|
||||||
|
}
|
||||||
|
|
||||||
|
updateKubeletConfig(ctx, f, newCfg, true)
|
||||||
|
|
||||||
|
p, err = podClient.Get(ctx, pod.Name, metav1.GetOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
// Feature PodHostIPs is enabled, HostIPs should not be nil
|
||||||
|
gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil())
|
||||||
|
|
||||||
|
ginkgo.By("deleting the pod")
|
||||||
|
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
|
||||||
|
framework.ExpectNoError(err, "failed to delete pod")
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
func genPodHostIPs(podName string, hostNetwork bool) *v1.Pod {
|
||||||
|
return &v1.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: podName,
|
||||||
|
Labels: map[string]string{"test": "dualstack-host-ips"},
|
||||||
|
},
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{
|
||||||
|
Name: "test-container",
|
||||||
|
Image: imageutils.GetE2EImage(imageutils.Agnhost),
|
||||||
|
SecurityContext: &v1.SecurityContext{
|
||||||
|
AllowPrivilegeEscalation: ptr.To(false),
|
||||||
|
Capabilities: &v1.Capabilities{
|
||||||
|
Drop: []v1.Capability{"ALL"},
|
||||||
|
},
|
||||||
|
RunAsNonRoot: ptr.To(true),
|
||||||
|
RunAsUser: ptr.To[int64](1000),
|
||||||
|
SeccompProfile: &v1.SeccompProfile{
|
||||||
|
Type: v1.SeccompProfileTypeRuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RestartPolicy: v1.RestartPolicyNever,
|
||||||
|
HostNetwork: hostNetwork,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testDownwardAPI(ctx context.Context, f *framework.Framework, podName string, env []v1.EnvVar, expectations []string) {
|
func testDownwardAPI(ctx context.Context, f *framework.Framework, podName string, env []v1.EnvVar, expectations []string) {
|
||||||
pod := &v1.Pod{
|
pod := &v1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
@ -276,6 +316,17 @@ func testDownwardAPI(ctx context.Context, f *framework.Framework, podName string
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Env: env,
|
Env: env,
|
||||||
|
SecurityContext: &v1.SecurityContext{
|
||||||
|
AllowPrivilegeEscalation: ptr.To(false),
|
||||||
|
Capabilities: &v1.Capabilities{
|
||||||
|
Drop: []v1.Capability{"ALL"},
|
||||||
|
},
|
||||||
|
RunAsNonRoot: ptr.To(true),
|
||||||
|
RunAsUser: ptr.To[int64](1000),
|
||||||
|
SeccompProfile: &v1.SeccompProfile{
|
||||||
|
Type: v1.SeccompProfileTypeRuntimeDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RestartPolicy: v1.RestartPolicyNever,
|
RestartPolicy: v1.RestartPolicyNever,
|
||||||
|
Loading…
Reference in New Issue
Block a user