mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 17:30:00 +00:00
Add namespace targeting to the kubelet
This commit is contained in:
parent
89714227ff
commit
9a6d50cb2a
@ -41,7 +41,9 @@ import (
|
|||||||
kubetypes "k8s.io/apimachinery/pkg/types"
|
kubetypes "k8s.io/apimachinery/pkg/types"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/events"
|
"k8s.io/kubernetes/pkg/kubelet/events"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/types"
|
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||||
@ -86,13 +88,52 @@ func (m *kubeGenericRuntimeManager) recordContainerEvent(pod *v1.Pod, container
|
|||||||
m.recorder.Event(ref, eventType, reason, eventMessage)
|
m.recorder.Event(ref, eventType, reason, eventMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// startSpec wraps the spec required to start a container, either a regular/init container
|
||||||
|
// or an ephemeral container. Ephemeral containers contain all the fields of regular/init
|
||||||
|
// containers, plus some additional fields. In both cases startSpec.container will be set.
|
||||||
|
type startSpec struct {
|
||||||
|
container *v1.Container
|
||||||
|
ephemeralContainer *v1.EphemeralContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
func containerStartSpec(c *v1.Container) *startSpec {
|
||||||
|
return &startSpec{container: c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ephemeralContainerStartSpec(ec *v1.EphemeralContainer) *startSpec {
|
||||||
|
return &startSpec{
|
||||||
|
container: (*v1.Container)(&ec.EphemeralContainerCommon),
|
||||||
|
ephemeralContainer: ec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTargetID returns the kubecontainer.ContainerID for ephemeral container namespace
|
||||||
|
// targeting. The target is stored as EphemeralContainer.TargetContainerName, which must be
|
||||||
|
// resolved to a ContainerID using podStatus. The target container must already exist, which
|
||||||
|
// usually isn't a problem since ephemeral containers aren't allowed at pod creation time.
|
||||||
|
// This always returns nil when the EphemeralContainers feature is disabled.
|
||||||
|
func (s *startSpec) getTargetID(podStatus *kubecontainer.PodStatus) (*kubecontainer.ContainerID, error) {
|
||||||
|
if s.ephemeralContainer == nil || s.ephemeralContainer.TargetContainerName == "" || !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
targetStatus := podStatus.FindContainerStatusByName(s.ephemeralContainer.TargetContainerName)
|
||||||
|
if targetStatus == nil {
|
||||||
|
return nil, fmt.Errorf("unable to find target container %v", s.ephemeralContainer.TargetContainerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &targetStatus.ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
// startContainer starts a container and returns a message indicates why it is failed on error.
|
// startContainer starts a container and returns a message indicates why it is failed on error.
|
||||||
// It starts the container through the following steps:
|
// It starts the container through the following steps:
|
||||||
// * pull the image
|
// * pull the image
|
||||||
// * create the container
|
// * create the container
|
||||||
// * start the container
|
// * start the container
|
||||||
// * run the post start lifecycle hooks (if applicable)
|
// * run the post start lifecycle hooks (if applicable)
|
||||||
func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandboxConfig *runtimeapi.PodSandboxConfig, container *v1.Container, pod *v1.Pod, podStatus *kubecontainer.PodStatus, pullSecrets []v1.Secret, podIP string, podIPs []string) (string, error) {
|
func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandboxConfig *runtimeapi.PodSandboxConfig, spec *startSpec, pod *v1.Pod, podStatus *kubecontainer.PodStatus, pullSecrets []v1.Secret, podIP string, podIPs []string) (string, error) {
|
||||||
|
container := spec.container
|
||||||
|
|
||||||
// Step 1: pull the image.
|
// Step 1: pull the image.
|
||||||
imageRef, msg, err := m.imagePuller.EnsureImageExists(pod, container, pullSecrets, podSandboxConfig)
|
imageRef, msg, err := m.imagePuller.EnsureImageExists(pod, container, pullSecrets, podSandboxConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -115,7 +156,14 @@ func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandb
|
|||||||
restartCount = containerStatus.RestartCount + 1
|
restartCount = containerStatus.RestartCount + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
containerConfig, cleanupAction, err := m.generateContainerConfig(container, pod, restartCount, podIP, imageRef, podIPs)
|
target, err := spec.getTargetID(podStatus)
|
||||||
|
if err != nil {
|
||||||
|
s, _ := grpcstatus.FromError(err)
|
||||||
|
m.recordContainerEvent(pod, container, "", v1.EventTypeWarning, events.FailedToCreateContainer, "Error: %v", s.Message())
|
||||||
|
return s.Message(), ErrCreateContainerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
containerConfig, cleanupAction, err := m.generateContainerConfig(container, pod, restartCount, podIP, imageRef, podIPs, target)
|
||||||
if cleanupAction != nil {
|
if cleanupAction != nil {
|
||||||
defer cleanupAction()
|
defer cleanupAction()
|
||||||
}
|
}
|
||||||
@ -195,7 +243,7 @@ func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandb
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generateContainerConfig generates container config for kubelet runtime v1.
|
// generateContainerConfig generates container config for kubelet runtime v1.
|
||||||
func (m *kubeGenericRuntimeManager) generateContainerConfig(container *v1.Container, pod *v1.Pod, restartCount int, podIP, imageRef string, podIPs []string) (*runtimeapi.ContainerConfig, func(), error) {
|
func (m *kubeGenericRuntimeManager) generateContainerConfig(container *v1.Container, pod *v1.Pod, restartCount int, podIP, imageRef string, podIPs []string, nsTarget *kubecontainer.ContainerID) (*runtimeapi.ContainerConfig, func(), error) {
|
||||||
opts, cleanupAction, err := m.runtimeHelper.GenerateRunContainerOptions(pod, container, podIP, podIPs)
|
opts, cleanupAction, err := m.runtimeHelper.GenerateRunContainerOptions(pod, container, podIP, podIPs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -239,7 +287,7 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(container *v1.Contai
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set platform specific configurations.
|
// set platform specific configurations.
|
||||||
if err := m.applyPlatformSpecificContainerConfig(config, container, pod, uid, username); err != nil {
|
if err := m.applyPlatformSpecificContainerConfig(config, container, pod, uid, username, nsTarget); err != nil {
|
||||||
return nil, cleanupAction, err
|
return nil, cleanupAction, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,22 +28,28 @@ import (
|
|||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
|
||||||
kubefeatures "k8s.io/kubernetes/pkg/features"
|
kubefeatures "k8s.io/kubernetes/pkg/features"
|
||||||
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||||
)
|
)
|
||||||
|
|
||||||
// applyPlatformSpecificContainerConfig applies platform specific configurations to runtimeapi.ContainerConfig.
|
// applyPlatformSpecificContainerConfig applies platform specific configurations to runtimeapi.ContainerConfig.
|
||||||
func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config *runtimeapi.ContainerConfig, container *v1.Container, pod *v1.Pod, uid *int64, username string) error {
|
func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config *runtimeapi.ContainerConfig, container *v1.Container, pod *v1.Pod, uid *int64, username string, nsTarget *kubecontainer.ContainerID) error {
|
||||||
config.Linux = m.generateLinuxContainerConfig(container, pod, uid, username)
|
config.Linux = m.generateLinuxContainerConfig(container, pod, uid, username, nsTarget)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateLinuxContainerConfig generates linux container config for kubelet runtime v1.
|
// generateLinuxContainerConfig generates linux container config for kubelet runtime v1.
|
||||||
func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *v1.Container, pod *v1.Pod, uid *int64, username string) *runtimeapi.LinuxContainerConfig {
|
func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *v1.Container, pod *v1.Pod, uid *int64, username string, nsTarget *kubecontainer.ContainerID) *runtimeapi.LinuxContainerConfig {
|
||||||
lc := &runtimeapi.LinuxContainerConfig{
|
lc := &runtimeapi.LinuxContainerConfig{
|
||||||
Resources: &runtimeapi.LinuxContainerResources{},
|
Resources: &runtimeapi.LinuxContainerResources{},
|
||||||
SecurityContext: m.determineEffectiveSecurityContext(pod, container, uid, username),
|
SecurityContext: m.determineEffectiveSecurityContext(pod, container, uid, username),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if nsTarget != nil && lc.SecurityContext.NamespaceOptions.Pid == runtimeapi.NamespaceMode_CONTAINER {
|
||||||
|
lc.SecurityContext.NamespaceOptions.Pid = runtimeapi.NamespaceMode_TARGET
|
||||||
|
lc.SecurityContext.NamespaceOptions.TargetId = nsTarget.ID
|
||||||
|
}
|
||||||
|
|
||||||
// set linux container resources
|
// set linux container resources
|
||||||
var cpuShares int64
|
var cpuShares int64
|
||||||
cpuRequest := container.Resources.Requests.Cpu()
|
cpuRequest := container.Resources.Requests.Cpu()
|
||||||
|
@ -22,13 +22,17 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
|
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"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeExpectedConfig(m *kubeGenericRuntimeManager, pod *v1.Pod, containerIndex int) *runtimeapi.ContainerConfig {
|
func makeExpectedConfig(m *kubeGenericRuntimeManager, pod *v1.Pod, containerIndex int) *runtimeapi.ContainerConfig {
|
||||||
@ -57,7 +61,7 @@ func makeExpectedConfig(m *kubeGenericRuntimeManager, pod *v1.Pod, containerInde
|
|||||||
Stdin: container.Stdin,
|
Stdin: container.Stdin,
|
||||||
StdinOnce: container.StdinOnce,
|
StdinOnce: container.StdinOnce,
|
||||||
Tty: container.TTY,
|
Tty: container.TTY,
|
||||||
Linux: m.generateLinuxContainerConfig(container, pod, new(int64), ""),
|
Linux: m.generateLinuxContainerConfig(container, pod, new(int64), "", nil),
|
||||||
Envs: envs,
|
Envs: envs,
|
||||||
}
|
}
|
||||||
return expectedConfig
|
return expectedConfig
|
||||||
@ -93,7 +97,7 @@ func TestGenerateContainerConfig(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expectedConfig := makeExpectedConfig(m, pod, 0)
|
expectedConfig := makeExpectedConfig(m, pod, 0)
|
||||||
containerConfig, _, err := m.generateContainerConfig(&pod.Spec.Containers[0], pod, 0, "", pod.Spec.Containers[0].Image, []string{})
|
containerConfig, _, err := m.generateContainerConfig(&pod.Spec.Containers[0], pod, 0, "", pod.Spec.Containers[0].Image, []string{}, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expectedConfig, containerConfig, "generate container config for kubelet runtime v1.")
|
assert.Equal(t, expectedConfig, containerConfig, "generate container config for kubelet runtime v1.")
|
||||||
assert.Equal(t, runAsUser, containerConfig.GetLinux().GetSecurityContext().GetRunAsUser().GetValue(), "RunAsUser should be set")
|
assert.Equal(t, runAsUser, containerConfig.GetLinux().GetSecurityContext().GetRunAsUser().GetValue(), "RunAsUser should be set")
|
||||||
@ -124,7 +128,7 @@ func TestGenerateContainerConfig(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = m.generateContainerConfig(&podWithContainerSecurityContext.Spec.Containers[0], podWithContainerSecurityContext, 0, "", podWithContainerSecurityContext.Spec.Containers[0].Image, []string{})
|
_, _, err = m.generateContainerConfig(&podWithContainerSecurityContext.Spec.Containers[0], podWithContainerSecurityContext, 0, "", podWithContainerSecurityContext.Spec.Containers[0].Image, []string{}, nil)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
imageID, _ := imageService.PullImage(&runtimeapi.ImageSpec{Image: "busybox"}, nil, nil)
|
imageID, _ := imageService.PullImage(&runtimeapi.ImageSpec{Image: "busybox"}, nil, nil)
|
||||||
@ -136,7 +140,7 @@ func TestGenerateContainerConfig(t *testing.T) {
|
|||||||
podWithContainerSecurityContext.Spec.Containers[0].SecurityContext.RunAsUser = nil
|
podWithContainerSecurityContext.Spec.Containers[0].SecurityContext.RunAsUser = nil
|
||||||
podWithContainerSecurityContext.Spec.Containers[0].SecurityContext.RunAsNonRoot = &runAsNonRootTrue
|
podWithContainerSecurityContext.Spec.Containers[0].SecurityContext.RunAsNonRoot = &runAsNonRootTrue
|
||||||
|
|
||||||
_, _, err = m.generateContainerConfig(&podWithContainerSecurityContext.Spec.Containers[0], podWithContainerSecurityContext, 0, "", podWithContainerSecurityContext.Spec.Containers[0].Image, []string{})
|
_, _, err = m.generateContainerConfig(&podWithContainerSecurityContext.Spec.Containers[0], podWithContainerSecurityContext, 0, "", podWithContainerSecurityContext.Spec.Containers[0].Image, []string{}, nil)
|
||||||
assert.Error(t, err, "RunAsNonRoot should fail for non-numeric username")
|
assert.Error(t, err, "RunAsNonRoot should fail for non-numeric username")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,3 +300,70 @@ func TestGetHugepageLimitsFromResources(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenerateLinuxContainerConfigNamespaces(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
|
||||||
|
_, _, m, err := createTestRuntimeManager()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error creating test RuntimeManager: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
pod *v1.Pod
|
||||||
|
target *kubecontainer.ContainerID
|
||||||
|
want *runtimeapi.NamespaceOption
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"Default namespaces",
|
||||||
|
&v1.Pod{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{Name: "test"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
&runtimeapi.NamespaceOption{
|
||||||
|
Pid: runtimeapi.NamespaceMode_CONTAINER,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PID Namespace POD",
|
||||||
|
&v1.Pod{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{Name: "test"},
|
||||||
|
},
|
||||||
|
ShareProcessNamespace: &[]bool{true}[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
&runtimeapi.NamespaceOption{
|
||||||
|
Pid: runtimeapi.NamespaceMode_POD,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PID Namespace TARGET",
|
||||||
|
&v1.Pod{
|
||||||
|
Spec: v1.PodSpec{
|
||||||
|
Containers: []v1.Container{
|
||||||
|
{Name: "test"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&kubecontainer.ContainerID{Type: "docker", ID: "really-long-id-string"},
|
||||||
|
&runtimeapi.NamespaceOption{
|
||||||
|
Pid: runtimeapi.NamespaceMode_TARGET,
|
||||||
|
TargetId: "really-long-id-string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
got := m.generateLinuxContainerConfig(&tc.pod.Spec.Containers[0], tc.pod, nil, "", tc.target)
|
||||||
|
if diff := cmp.Diff(tc.want, got.SecurityContext.NamespaceOptions); diff != "" {
|
||||||
|
t.Errorf("%v: diff (-want +got):\n%v", t.Name(), diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,17 +17,22 @@ limitations under the License.
|
|||||||
package kuberuntime
|
package kuberuntime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
|
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
||||||
@ -325,7 +330,7 @@ func TestLifeCycleHook(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now try to create a container, which should in turn invoke PostStart Hook
|
// Now try to create a container, which should in turn invoke PostStart Hook
|
||||||
_, err := m.startContainer(fakeSandBox.Id, fakeSandBoxConfig, testContainer, testPod, fakePodStatus, nil, "", []string{})
|
_, err := m.startContainer(fakeSandBox.Id, fakeSandBoxConfig, containerStartSpec(testContainer), testPod, fakePodStatus, nil, "", []string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("startContainer error =%v", err)
|
t.Errorf("startContainer error =%v", err)
|
||||||
}
|
}
|
||||||
@ -334,3 +339,72 @@ func TestLifeCycleHook(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStartSpec(t *testing.T) {
|
||||||
|
podStatus := &kubecontainer.PodStatus{
|
||||||
|
ContainerStatuses: []*kubecontainer.ContainerStatus{
|
||||||
|
{
|
||||||
|
ID: kubecontainer.ContainerID{
|
||||||
|
Type: "docker",
|
||||||
|
ID: "docker-something-something",
|
||||||
|
},
|
||||||
|
Name: "target",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
spec *startSpec
|
||||||
|
want *kubecontainer.ContainerID
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"Regular Container",
|
||||||
|
containerStartSpec(&v1.Container{
|
||||||
|
Name: "test",
|
||||||
|
}),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Ephemeral Container w/o Target",
|
||||||
|
ephemeralContainerStartSpec(&v1.EphemeralContainer{
|
||||||
|
EphemeralContainerCommon: v1.EphemeralContainerCommon{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Ephemeral Container w/ Target",
|
||||||
|
ephemeralContainerStartSpec(&v1.EphemeralContainer{
|
||||||
|
EphemeralContainerCommon: v1.EphemeralContainerCommon{
|
||||||
|
Name: "test",
|
||||||
|
},
|
||||||
|
TargetContainerName: "target",
|
||||||
|
}),
|
||||||
|
&kubecontainer.ContainerID{
|
||||||
|
Type: "docker",
|
||||||
|
ID: "docker-something-something",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, true)()
|
||||||
|
if got, err := tc.spec.getTargetID(podStatus); err != nil {
|
||||||
|
t.Fatalf("%v: getTargetID got unexpected error: %v", t.Name(), err)
|
||||||
|
} else if diff := cmp.Diff(tc.want, got); diff != "" {
|
||||||
|
t.Errorf("%v: getTargetID got unexpected result. diff:\n%v", t.Name(), diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test with feature disabled in self-contained section which can be removed when feature flag is removed.
|
||||||
|
t.Run(fmt.Sprintf("%s (disabled)", tc.name), func(t *testing.T) {
|
||||||
|
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.EphemeralContainers, false)()
|
||||||
|
if got, err := tc.spec.getTargetID(podStatus); err != nil {
|
||||||
|
t.Fatalf("%v: getTargetID got unexpected error: %v", t.Name(), err)
|
||||||
|
} else if got != nil {
|
||||||
|
t.Errorf("%v: getTargetID got: %v, wanted nil", t.Name(), got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,9 +21,10 @@ package kuberuntime
|
|||||||
import (
|
import (
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// applyPlatformSpecificContainerConfig applies platform specific configurations to runtimeapi.ContainerConfig.
|
// applyPlatformSpecificContainerConfig applies platform specific configurations to runtimeapi.ContainerConfig.
|
||||||
func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config *runtimeapi.ContainerConfig, container *v1.Container, pod *v1.Pod, uid *int64, username string) error {
|
func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config *runtimeapi.ContainerConfig, container *v1.Container, pod *v1.Pod, uid *int64, username string, nsTarget *kubecontainer.ContainerID) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ package kuberuntime
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/sysinfo"
|
"github.com/docker/docker/pkg/sysinfo"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
@ -27,11 +28,12 @@ import (
|
|||||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
|
||||||
kubefeatures "k8s.io/kubernetes/pkg/features"
|
kubefeatures "k8s.io/kubernetes/pkg/features"
|
||||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||||
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/securitycontext"
|
"k8s.io/kubernetes/pkg/securitycontext"
|
||||||
)
|
)
|
||||||
|
|
||||||
// applyPlatformSpecificContainerConfig applies platform specific configurations to runtimeapi.ContainerConfig.
|
// applyPlatformSpecificContainerConfig applies platform specific configurations to runtimeapi.ContainerConfig.
|
||||||
func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config *runtimeapi.ContainerConfig, container *v1.Container, pod *v1.Pod, uid *int64, username string) error {
|
func (m *kubeGenericRuntimeManager) applyPlatformSpecificContainerConfig(config *runtimeapi.ContainerConfig, container *v1.Container, pod *v1.Pod, uid *int64, username string, _ *kubecontainer.ContainerID) error {
|
||||||
windowsConfig, err := m.generateWindowsContainerConfig(container, pod, uid, username)
|
windowsConfig, err := m.generateWindowsContainerConfig(container, pod, uid, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -777,20 +777,20 @@ func (m *kubeGenericRuntimeManager) SyncPod(pod *v1.Pod, podStatus *kubecontaine
|
|||||||
// Helper containing boilerplate common to starting all types of containers.
|
// Helper containing boilerplate common to starting all types of containers.
|
||||||
// typeName is a label used to describe this type of container in log messages,
|
// typeName is a label used to describe this type of container in log messages,
|
||||||
// currently: "container", "init container" or "ephemeral container"
|
// currently: "container", "init container" or "ephemeral container"
|
||||||
start := func(typeName string, container *v1.Container) error {
|
start := func(typeName string, spec *startSpec) error {
|
||||||
startContainerResult := kubecontainer.NewSyncResult(kubecontainer.StartContainer, container.Name)
|
startContainerResult := kubecontainer.NewSyncResult(kubecontainer.StartContainer, spec.container.Name)
|
||||||
result.AddSyncResult(startContainerResult)
|
result.AddSyncResult(startContainerResult)
|
||||||
|
|
||||||
isInBackOff, msg, err := m.doBackOff(pod, container, podStatus, backOff)
|
isInBackOff, msg, err := m.doBackOff(pod, spec.container, podStatus, backOff)
|
||||||
if isInBackOff {
|
if isInBackOff {
|
||||||
startContainerResult.Fail(err, msg)
|
startContainerResult.Fail(err, msg)
|
||||||
klog.V(4).Infof("Backing Off restarting %v %+v in pod %v", typeName, container, format.Pod(pod))
|
klog.V(4).Infof("Backing Off restarting %v %+v in pod %v", typeName, spec.container, format.Pod(pod))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
klog.V(4).Infof("Creating %v %+v in pod %v", typeName, container, format.Pod(pod))
|
klog.V(4).Infof("Creating %v %+v in pod %v", typeName, spec.container, format.Pod(pod))
|
||||||
// NOTE (aramase) podIPs are populated for single stack and dual stack clusters. Send only podIPs.
|
// NOTE (aramase) podIPs are populated for single stack and dual stack clusters. Send only podIPs.
|
||||||
if msg, err := m.startContainer(podSandboxID, podSandboxConfig, container, pod, podStatus, pullSecrets, podIP, podIPs); err != nil {
|
if msg, err := m.startContainer(podSandboxID, podSandboxConfig, spec, pod, podStatus, pullSecrets, podIP, podIPs); err != nil {
|
||||||
startContainerResult.Fail(err, msg)
|
startContainerResult.Fail(err, msg)
|
||||||
// known errors that are logged in other places are logged at higher levels here to avoid
|
// known errors that are logged in other places are logged at higher levels here to avoid
|
||||||
// repetitive log spam
|
// repetitive log spam
|
||||||
@ -812,15 +812,14 @@ func (m *kubeGenericRuntimeManager) SyncPod(pod *v1.Pod, podStatus *kubecontaine
|
|||||||
// containers cannot be specified on pod creation.
|
// containers cannot be specified on pod creation.
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
|
if utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) {
|
||||||
for _, idx := range podContainerChanges.EphemeralContainersToStart {
|
for _, idx := range podContainerChanges.EphemeralContainersToStart {
|
||||||
c := (*v1.Container)(&pod.Spec.EphemeralContainers[idx].EphemeralContainerCommon)
|
start("ephemeral container", ephemeralContainerStartSpec(&pod.Spec.EphemeralContainers[idx]))
|
||||||
start("ephemeral container", c)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 6: start the init container.
|
// Step 6: start the init container.
|
||||||
if container := podContainerChanges.NextInitContainerToStart; container != nil {
|
if container := podContainerChanges.NextInitContainerToStart; container != nil {
|
||||||
// Start the next init container.
|
// Start the next init container.
|
||||||
if err := start("init container", container); err != nil {
|
if err := start("init container", containerStartSpec(container)); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -830,7 +829,7 @@ func (m *kubeGenericRuntimeManager) SyncPod(pod *v1.Pod, podStatus *kubecontaine
|
|||||||
|
|
||||||
// Step 7: start containers in podContainerChanges.ContainersToStart.
|
// Step 7: start containers in podContainerChanges.ContainersToStart.
|
||||||
for _, idx := range podContainerChanges.ContainersToStart {
|
for _, idx := range podContainerChanges.ContainersToStart {
|
||||||
start("container", &pod.Spec.Containers[idx])
|
start("container", containerStartSpec(&pod.Spec.Containers[idx]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
@ -157,7 +157,7 @@ func makeFakeContainer(t *testing.T, m *kubeGenericRuntimeManager, template cont
|
|||||||
sandboxConfig, err := m.generatePodSandboxConfig(template.pod, template.sandboxAttempt)
|
sandboxConfig, err := m.generatePodSandboxConfig(template.pod, template.sandboxAttempt)
|
||||||
assert.NoError(t, err, "generatePodSandboxConfig for container template %+v", template)
|
assert.NoError(t, err, "generatePodSandboxConfig for container template %+v", template)
|
||||||
|
|
||||||
containerConfig, _, err := m.generateContainerConfig(template.container, template.pod, template.attempt, "", template.container.Image, []string{})
|
containerConfig, _, err := m.generateContainerConfig(template.container, template.pod, template.attempt, "", template.container.Image, []string{}, nil)
|
||||||
assert.NoError(t, err, "generateContainerConfig for container template %+v", template)
|
assert.NoError(t, err, "generateContainerConfig for container template %+v", template)
|
||||||
|
|
||||||
podSandboxID := apitest.BuildSandboxName(sandboxConfig.Metadata)
|
podSandboxID := apitest.BuildSandboxName(sandboxConfig.Metadata)
|
||||||
|
@ -216,6 +216,13 @@ enum NamespaceMode {
|
|||||||
// For example, a container with a PID namespace of NODE expects to view
|
// For example, a container with a PID namespace of NODE expects to view
|
||||||
// all of the processes on the host running the kubelet.
|
// all of the processes on the host running the kubelet.
|
||||||
NODE = 2;
|
NODE = 2;
|
||||||
|
// TARGET targets the namespace of another container. When this is specified,
|
||||||
|
// a target_id must be specified in NamespaceOption and refer to a container
|
||||||
|
// previously created with NamespaceMode CONTAINER. This containers namespace
|
||||||
|
// will be made to match that of container target_id.
|
||||||
|
// For example, a container with a PID namespace of TARGET expects to view
|
||||||
|
// all of the processes that container target_id can view.
|
||||||
|
TARGET = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NamespaceOption provides options for Linux namespaces.
|
// NamespaceOption provides options for Linux namespaces.
|
||||||
@ -227,12 +234,16 @@ message NamespaceOption {
|
|||||||
// PID namespace for this container/sandbox.
|
// PID namespace for this container/sandbox.
|
||||||
// Note: The CRI default is POD, but the v1.PodSpec default is CONTAINER.
|
// Note: The CRI default is POD, but the v1.PodSpec default is CONTAINER.
|
||||||
// The kubelet's runtime manager will set this to CONTAINER explicitly for v1 pods.
|
// The kubelet's runtime manager will set this to CONTAINER explicitly for v1 pods.
|
||||||
// Namespaces currently set by the kubelet: POD, CONTAINER, NODE
|
// Namespaces currently set by the kubelet: POD, CONTAINER, NODE, TARGET
|
||||||
NamespaceMode pid = 2;
|
NamespaceMode pid = 2;
|
||||||
// IPC namespace for this container/sandbox.
|
// IPC namespace for this container/sandbox.
|
||||||
// Note: There is currently no way to set CONTAINER scoped IPC in the Kubernetes API.
|
// Note: There is currently no way to set CONTAINER scoped IPC in the Kubernetes API.
|
||||||
// Namespaces currently set by the kubelet: POD, NODE
|
// Namespaces currently set by the kubelet: POD, NODE
|
||||||
NamespaceMode ipc = 3;
|
NamespaceMode ipc = 3;
|
||||||
|
// Target Container ID for NamespaceMode of TARGET. This container must have been
|
||||||
|
// previously created in the same pod. It is not possible to specify different targets
|
||||||
|
// for each namespace.
|
||||||
|
string target_id = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int64Value is the wrapper of int64.
|
// Int64Value is the wrapper of int64.
|
||||||
|
Loading…
Reference in New Issue
Block a user