mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 22:17:14 +00:00
Merge pull request #84356 from verb/pid-ga
Promote PodProcessNamespaceSharing feature to GA
This commit is contained in:
commit
c10d29ba88
2
api/openapi-spec/swagger.json
generated
2
api/openapi-spec/swagger.json
generated
@ -10086,7 +10086,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"shareProcessNamespace": {
|
||||
"description": "Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false. This field is beta-level and may be disabled with the PodShareProcessNamespace feature.",
|
||||
"description": "Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"subdomain": {
|
||||
|
@ -340,12 +340,6 @@ func dropDisabledFields(
|
||||
}
|
||||
}
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.PodShareProcessNamespace) && !shareProcessNamespaceInUse(oldPodSpec) {
|
||||
if podSpec.SecurityContext != nil {
|
||||
podSpec.SecurityContext.ShareProcessNamespace = nil
|
||||
}
|
||||
}
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.Sysctls) && !sysctlsInUse(oldPodSpec) {
|
||||
if podSpec.SecurityContext != nil {
|
||||
podSpec.SecurityContext.Sysctls = nil
|
||||
@ -633,16 +627,6 @@ func appArmorInUse(podAnnotations map[string]string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func shareProcessNamespaceInUse(podSpec *api.PodSpec) bool {
|
||||
if podSpec == nil {
|
||||
return false
|
||||
}
|
||||
if podSpec.SecurityContext != nil && podSpec.SecurityContext.ShareProcessNamespace != nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tokenRequestProjectionInUse(podSpec *api.PodSpec) bool {
|
||||
if podSpec == nil {
|
||||
return false
|
||||
|
@ -980,106 +980,6 @@ func TestDropEmptyDirSizeLimit(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropPodShareProcessNamespace(t *testing.T) {
|
||||
podWithShareProcessNamespace := func() *api.Pod {
|
||||
return &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
ShareProcessNamespace: &[]bool{true}[0],
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
podWithoutShareProcessNamespace := func() *api.Pod {
|
||||
return &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{},
|
||||
},
|
||||
}
|
||||
}
|
||||
podWithoutSecurityContext := func() *api.Pod {
|
||||
return &api.Pod{
|
||||
Spec: api.PodSpec{},
|
||||
}
|
||||
}
|
||||
|
||||
podInfo := []struct {
|
||||
description string
|
||||
hasShareProcessNamespace bool
|
||||
pod func() *api.Pod
|
||||
}{
|
||||
{
|
||||
description: "has ShareProcessNamespace",
|
||||
hasShareProcessNamespace: true,
|
||||
pod: podWithShareProcessNamespace,
|
||||
},
|
||||
{
|
||||
description: "does not have ShareProcessNamespace",
|
||||
hasShareProcessNamespace: false,
|
||||
pod: podWithoutShareProcessNamespace,
|
||||
},
|
||||
{
|
||||
description: "does not have SecurityContext",
|
||||
hasShareProcessNamespace: false,
|
||||
pod: podWithoutSecurityContext,
|
||||
},
|
||||
{
|
||||
description: "is nil",
|
||||
hasShareProcessNamespace: false,
|
||||
pod: func() *api.Pod { return nil },
|
||||
},
|
||||
}
|
||||
|
||||
for _, enabled := range []bool{true, false} {
|
||||
for _, oldPodInfo := range podInfo {
|
||||
for _, newPodInfo := range podInfo {
|
||||
oldPodHasShareProcessNamespace, oldPod := oldPodInfo.hasShareProcessNamespace, oldPodInfo.pod()
|
||||
newPodHasShareProcessNamespace, newPod := newPodInfo.hasShareProcessNamespace, newPodInfo.pod()
|
||||
if newPod == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodShareProcessNamespace, enabled)()
|
||||
|
||||
var oldPodSpec *api.PodSpec
|
||||
if oldPod != nil {
|
||||
oldPodSpec = &oldPod.Spec
|
||||
}
|
||||
dropDisabledFields(&newPod.Spec, nil, oldPodSpec, nil)
|
||||
|
||||
// old pod should never be changed
|
||||
if !reflect.DeepEqual(oldPod, oldPodInfo.pod()) {
|
||||
t.Errorf("old pod changed: %v", diff.ObjectReflectDiff(oldPod, oldPodInfo.pod()))
|
||||
}
|
||||
|
||||
switch {
|
||||
case enabled || oldPodHasShareProcessNamespace:
|
||||
// new pod should not be changed if the feature is enabled, or if the old pod had ShareProcessNamespace set
|
||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
||||
t.Errorf("new pod changed: %v", diff.ObjectReflectDiff(newPod, newPodInfo.pod()))
|
||||
}
|
||||
case newPodHasShareProcessNamespace:
|
||||
// new pod should be changed
|
||||
if reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
||||
t.Errorf("new pod was not changed")
|
||||
}
|
||||
// new pod should not have ShareProcessNamespace
|
||||
if !reflect.DeepEqual(newPod, podWithoutShareProcessNamespace()) {
|
||||
t.Errorf("new pod had ShareProcessNamespace: %v", diff.ObjectReflectDiff(newPod, podWithoutShareProcessNamespace()))
|
||||
}
|
||||
default:
|
||||
// new pod should not need to be changed
|
||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
||||
t.Errorf("new pod changed: %v", diff.ObjectReflectDiff(newPod, newPodInfo.pod()))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropAppArmor(t *testing.T) {
|
||||
podWithAppArmor := func() *api.Pod {
|
||||
return &api.Pod{
|
||||
|
@ -2812,7 +2812,6 @@ type PodSecurityContext struct {
|
||||
// in the same pod, and the first process in each container will not be assigned PID 1.
|
||||
// HostPID and ShareProcessNamespace cannot both be set.
|
||||
// Optional: Default to false.
|
||||
// This field is beta-level and may be disabled with the PodShareProcessNamespace feature.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
ShareProcessNamespace *bool
|
||||
|
@ -112,7 +112,9 @@ const (
|
||||
EphemeralContainers featuregate.Feature = "EphemeralContainers"
|
||||
|
||||
// owner: @verb
|
||||
// alpha: v1.10
|
||||
// beta: v1.12
|
||||
// GA: v1.17
|
||||
//
|
||||
// Allows all containers in a pod to share a process namespace.
|
||||
PodShareProcessNamespace featuregate.Feature = "PodShareProcessNamespace"
|
||||
@ -519,7 +521,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
LocalStorageCapacityIsolation: {Default: true, PreRelease: featuregate.Beta},
|
||||
Sysctls: {Default: true, PreRelease: featuregate.Beta},
|
||||
EphemeralContainers: {Default: false, PreRelease: featuregate.Alpha},
|
||||
PodShareProcessNamespace: {Default: true, PreRelease: featuregate.Beta},
|
||||
PodShareProcessNamespace: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.19
|
||||
PodPriority: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.18
|
||||
TaintNodesByCondition: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.18
|
||||
QOSReserved: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
@ -24,10 +24,8 @@ import (
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
)
|
||||
|
||||
@ -250,7 +248,7 @@ func pidNamespaceForPod(pod *v1.Pod) runtimeapi.NamespaceMode {
|
||||
if pod.Spec.HostPID {
|
||||
return runtimeapi.NamespaceMode_NODE
|
||||
}
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.PodShareProcessNamespace) && pod.Spec.ShareProcessNamespace != nil && *pod.Spec.ShareProcessNamespace {
|
||||
if pod.Spec.ShareProcessNamespace != nil && *pod.Spec.ShareProcessNamespace {
|
||||
return runtimeapi.NamespaceMode_POD
|
||||
}
|
||||
}
|
||||
|
@ -25,11 +25,8 @@ import (
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||
runtimetesting "k8s.io/cri-api/pkg/apis/testing"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
)
|
||||
|
||||
@ -285,8 +282,6 @@ func TestGetSeccompProfileFromAnnotations(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNamespacesForPod(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodShareProcessNamespace, true)()
|
||||
|
||||
for desc, test := range map[string]struct {
|
||||
input *v1.Pod
|
||||
expected *runtimeapi.NamespaceOption
|
||||
@ -350,48 +345,4 @@ func TestNamespacesForPod(t *testing.T) {
|
||||
actual := namespacesForPod(test.input)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
}
|
||||
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodShareProcessNamespace, false)()
|
||||
|
||||
for desc, test := range map[string]struct {
|
||||
input *v1.Pod
|
||||
expected *runtimeapi.NamespaceOption
|
||||
}{
|
||||
"v1.Pod default namespaces": {
|
||||
&v1.Pod{},
|
||||
&runtimeapi.NamespaceOption{
|
||||
Ipc: runtimeapi.NamespaceMode_POD,
|
||||
Network: runtimeapi.NamespaceMode_POD,
|
||||
Pid: runtimeapi.NamespaceMode_CONTAINER,
|
||||
},
|
||||
},
|
||||
"Shared Process Namespace (feature disabled)": {
|
||||
&v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
ShareProcessNamespace: &[]bool{true}[0],
|
||||
},
|
||||
},
|
||||
&runtimeapi.NamespaceOption{
|
||||
Ipc: runtimeapi.NamespaceMode_POD,
|
||||
Network: runtimeapi.NamespaceMode_POD,
|
||||
Pid: runtimeapi.NamespaceMode_CONTAINER,
|
||||
},
|
||||
},
|
||||
"Shared Process Namespace, redundant flag (feature disabled)": {
|
||||
&v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
ShareProcessNamespace: &[]bool{false}[0],
|
||||
},
|
||||
},
|
||||
&runtimeapi.NamespaceOption{
|
||||
Ipc: runtimeapi.NamespaceMode_POD,
|
||||
Network: runtimeapi.NamespaceMode_POD,
|
||||
Pid: runtimeapi.NamespaceMode_CONTAINER,
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Logf("TestCase: %s", desc)
|
||||
actual := namespacesForPod(test.input)
|
||||
assert.Equal(t, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
@ -3384,7 +3384,6 @@ message PodSpec {
|
||||
// in the same pod, and the first process in each container will not be assigned PID 1.
|
||||
// HostPID and ShareProcessNamespace cannot both be set.
|
||||
// Optional: Default to false.
|
||||
// This field is beta-level and may be disabled with the PodShareProcessNamespace feature.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
optional bool shareProcessNamespace = 27;
|
||||
|
@ -2940,7 +2940,6 @@ type PodSpec struct {
|
||||
// in the same pod, and the first process in each container will not be assigned PID 1.
|
||||
// HostPID and ShareProcessNamespace cannot both be set.
|
||||
// Optional: Default to false.
|
||||
// This field is beta-level and may be disabled with the PodShareProcessNamespace feature.
|
||||
// +k8s:conversion-gen=false
|
||||
// +optional
|
||||
ShareProcessNamespace *bool `json:"shareProcessNamespace,omitempty" protobuf:"varint,27,opt,name=shareProcessNamespace"`
|
||||
|
@ -1614,7 +1614,7 @@ var map_PodSpec = map[string]string{
|
||||
"hostNetwork": "Host networking requested for this pod. Use the host's network namespace. If this option is set, the ports that will be used must be specified. Default to false.",
|
||||
"hostPID": "Use the host's pid namespace. Optional: Default to false.",
|
||||
"hostIPC": "Use the host's ipc namespace. Optional: Default to false.",
|
||||
"shareProcessNamespace": "Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false. This field is beta-level and may be disabled with the PodShareProcessNamespace feature.",
|
||||
"shareProcessNamespace": "Share a single process namespace between all of the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false.",
|
||||
"securityContext": "SecurityContext holds pod-level security attributes and common container settings. Optional: Defaults to empty. See type description for default values of each field.",
|
||||
"imagePullSecrets": "ImagePullSecrets is an optional list of references to secrets in the same namespace to use for pulling any of the images used by this PodSpec. If specified, these secrets will be passed to individual puller implementations for them to use. For example, in the case of docker, only DockerConfig type secrets are honored. More info: https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod",
|
||||
"hostname": "Specifies the hostname of the Pod If not specified, the pod's hostname will be set to a system-defined value.",
|
||||
|
@ -181,7 +181,6 @@ go_test(
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//staging/src/k8s.io/client-go/tools/watch:go_default_library",
|
||||
"//staging/src/k8s.io/cri-api/pkg/apis:go_default_library",
|
||||
|
@ -26,8 +26,6 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/uuid"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
|
||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||
@ -79,10 +77,6 @@ var _ = framework.KubeDescribe("Security Context", func() {
|
||||
if !isEnabled {
|
||||
framework.Skipf("Skipped because shared PID namespace is not supported by this docker version.")
|
||||
}
|
||||
// It's not enough to set this flag in the kubelet because the apiserver needs it too
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.PodShareProcessNamespace) {
|
||||
framework.Skipf("run test with --feature-gates=PodShareProcessNamespace=true to test PID namespace sharing")
|
||||
}
|
||||
|
||||
ginkgo.By("Create a pod with shared PID namespace.")
|
||||
f.PodClient().CreateSync(&v1.Pod{
|
||||
|
Loading…
Reference in New Issue
Block a user