mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 23:15:14 +00:00
Implement mount propagation in kubelet
This commit is contained in:
parent
0c767355d8
commit
03b753daad
@ -43,6 +43,7 @@ go_library(
|
||||
"//pkg/fieldpath:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/kubelet/apis/cri:go_default_library",
|
||||
"//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig/v1alpha1:go_default_library",
|
||||
"//pkg/kubelet/cadvisor:go_default_library",
|
||||
@ -170,6 +171,7 @@ go_test(
|
||||
"//pkg/api/install:go_default_library",
|
||||
"//pkg/capabilities:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/kubelet/apis/cri/v1alpha1/runtime:go_default_library",
|
||||
"//pkg/kubelet/apis/kubeletconfig:go_default_library",
|
||||
"//pkg/kubelet/cadvisor/testing:go_default_library",
|
||||
"//pkg/kubelet/cm:go_default_library",
|
||||
@ -225,6 +227,7 @@ go_test(
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
|
@ -389,6 +389,8 @@ type Mount struct {
|
||||
ReadOnly bool
|
||||
// Whether the mount needs SELinux relabeling
|
||||
SELinuxRelabel bool
|
||||
// Requested propagation mode
|
||||
Propagation runtimeapi.MountPropagation
|
||||
}
|
||||
|
||||
type PortMapping struct {
|
||||
|
@ -41,6 +41,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
||||
@ -48,7 +49,9 @@ import (
|
||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||
"k8s.io/kubernetes/pkg/api/v1/resource"
|
||||
"k8s.io/kubernetes/pkg/api/v1/validation"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/fieldpath"
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
"k8s.io/kubernetes/pkg/kubelet/envvars"
|
||||
@ -188,12 +191,19 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h
|
||||
}
|
||||
}
|
||||
|
||||
propagation, err := translateMountPropagation(mount.MountPropagation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
glog.V(5).Infof("Pod %q container %q mount %q has propagation %q", format.Pod(pod), container.Name, mount.Name, propagation)
|
||||
|
||||
mounts = append(mounts, kubecontainer.Mount{
|
||||
Name: mount.Name,
|
||||
ContainerPath: containerPath,
|
||||
HostPath: hostPath,
|
||||
ReadOnly: mount.ReadOnly,
|
||||
SELinuxRelabel: relabelVolume,
|
||||
Propagation: propagation,
|
||||
})
|
||||
}
|
||||
if mountEtcHostsFile {
|
||||
@ -207,6 +217,26 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
// translateMountPropagation transforms v1.MountPropagationMode to
|
||||
// runtimeapi.MountPropagation.
|
||||
func translateMountPropagation(mountMode *v1.MountPropagationMode) (runtimeapi.MountPropagation, error) {
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.MountPropagation) {
|
||||
// mount propagation is disabled, use private as in the old versions
|
||||
return runtimeapi.MountPropagation_PROPAGATION_PRIVATE, nil
|
||||
}
|
||||
switch {
|
||||
case mountMode == nil:
|
||||
// HostToContainer is the default
|
||||
return runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, nil
|
||||
case *mountMode == v1.MountPropagationHostToContainer:
|
||||
return runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER, nil
|
||||
case *mountMode == v1.MountPropagationBidirectional:
|
||||
return runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid MountPropagation mode: %q", mountMode)
|
||||
}
|
||||
}
|
||||
|
||||
// makeHostsMount makes the mountpoint for the hosts file that the containers
|
||||
// in a pod are injected with.
|
||||
func makeHostsMount(podDir, podIP, hostName, hostDomainName string, hostAliases []v1.HostAlias, useHostNetwork bool) (*kubecontainer.Mount, error) {
|
||||
|
@ -35,6 +35,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
core "k8s.io/client-go/testing"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
@ -42,6 +43,7 @@ import (
|
||||
// api.Registry.GroupOrDie(v1.GroupName).GroupVersion.String() is changed
|
||||
// to "v1"?
|
||||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
||||
"k8s.io/kubernetes/pkg/kubelet/server/portforward"
|
||||
@ -49,6 +51,10 @@ import (
|
||||
)
|
||||
|
||||
func TestMakeMounts(t *testing.T) {
|
||||
bTrue := true
|
||||
propagationHostToContainer := v1.MountPropagationHostToContainer
|
||||
propagationBidirectional := v1.MountPropagationBidirectional
|
||||
|
||||
testCases := map[string]struct {
|
||||
container v1.Container
|
||||
podVolumes kubecontainer.VolumeMap
|
||||
@ -56,18 +62,20 @@ func TestMakeMounts(t *testing.T) {
|
||||
expectedErrMsg string
|
||||
expectedMounts []kubecontainer.Mount
|
||||
}{
|
||||
"valid mounts": {
|
||||
"valid mounts in unprivileged container": {
|
||||
podVolumes: kubecontainer.VolumeMap{
|
||||
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
|
||||
"disk4": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/host"}},
|
||||
"disk5": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/var/lib/kubelet/podID/volumes/empty/disk5"}},
|
||||
},
|
||||
container: v1.Container{
|
||||
Name: "container1",
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
MountPath: "/etc/hosts",
|
||||
Name: "disk",
|
||||
ReadOnly: false,
|
||||
MountPath: "/etc/hosts",
|
||||
Name: "disk",
|
||||
ReadOnly: false,
|
||||
MountPropagation: &propagationHostToContainer,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/path3",
|
||||
@ -93,6 +101,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
HostPath: "/mnt/disk",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER,
|
||||
},
|
||||
{
|
||||
Name: "disk",
|
||||
@ -100,6 +109,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
HostPath: "/mnt/disk",
|
||||
ReadOnly: true,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER,
|
||||
},
|
||||
{
|
||||
Name: "disk4",
|
||||
@ -107,6 +117,7 @@ func TestMakeMounts(t *testing.T) {
|
||||
HostPath: "/mnt/host",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER,
|
||||
},
|
||||
{
|
||||
Name: "disk5",
|
||||
@ -114,6 +125,66 @@ func TestMakeMounts(t *testing.T) {
|
||||
HostPath: "/var/lib/kubelet/podID/volumes/empty/disk5",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER,
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
"valid mounts in privileged container": {
|
||||
podVolumes: kubecontainer.VolumeMap{
|
||||
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
|
||||
"disk4": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/host"}},
|
||||
"disk5": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/var/lib/kubelet/podID/volumes/empty/disk5"}},
|
||||
},
|
||||
container: v1.Container{
|
||||
Name: "container1",
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
{
|
||||
MountPath: "/etc/hosts",
|
||||
Name: "disk",
|
||||
ReadOnly: false,
|
||||
MountPropagation: &propagationBidirectional,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/path3",
|
||||
Name: "disk",
|
||||
ReadOnly: true,
|
||||
MountPropagation: &propagationHostToContainer,
|
||||
},
|
||||
{
|
||||
MountPath: "/mnt/path4",
|
||||
Name: "disk4",
|
||||
ReadOnly: false,
|
||||
},
|
||||
},
|
||||
SecurityContext: &v1.SecurityContext{
|
||||
Privileged: &bTrue,
|
||||
},
|
||||
},
|
||||
expectedMounts: []kubecontainer.Mount{
|
||||
{
|
||||
Name: "disk",
|
||||
ContainerPath: "/etc/hosts",
|
||||
HostPath: "/mnt/disk",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_BIDIRECTIONAL,
|
||||
},
|
||||
{
|
||||
Name: "disk",
|
||||
ContainerPath: "/mnt/path3",
|
||||
HostPath: "/mnt/disk",
|
||||
ReadOnly: true,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER,
|
||||
},
|
||||
{
|
||||
Name: "disk4",
|
||||
ContainerPath: "/mnt/path4",
|
||||
HostPath: "/mnt/host",
|
||||
ReadOnly: false,
|
||||
SELinuxRelabel: false,
|
||||
Propagation: runtimeapi.MountPropagation_PROPAGATION_HOST_TO_CONTAINER,
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
@ -161,6 +232,12 @@ func TestMakeMounts(t *testing.T) {
|
||||
HostNetwork: true,
|
||||
},
|
||||
}
|
||||
// test makeMounts with enabled mount propagation
|
||||
err := utilfeature.DefaultFeatureGate.Set("MountPropagation=true")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to enable feature gate for MountPropagation: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
mounts, err := makeMounts(&pod, "/pod", &tc.container, "fakepodname", "", "", tc.podVolumes)
|
||||
|
||||
@ -178,6 +255,24 @@ func TestMakeMounts(t *testing.T) {
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.expectedMounts, mounts, "mounts of container %+v", tc.container)
|
||||
|
||||
// test makeMounts with disabled mount propagation
|
||||
err = utilfeature.DefaultFeatureGate.Set("MountPropagation=false")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to enable feature gate for MountPropagation: %v", err)
|
||||
return
|
||||
}
|
||||
mounts, err = makeMounts(&pod, "/pod", &tc.container, "fakepodname", "", "", tc.podVolumes)
|
||||
if !tc.expectErr {
|
||||
expectedPrivateMounts := []kubecontainer.Mount{}
|
||||
for _, mount := range tc.expectedMounts {
|
||||
// all mounts are expected to be private when mount
|
||||
// propagation is disabled
|
||||
mount.Propagation = runtimeapi.MountPropagation_PROPAGATION_PRIVATE
|
||||
expectedPrivateMounts = append(expectedPrivateMounts, mount)
|
||||
}
|
||||
assert.Equal(t, expectedPrivateMounts, mounts, "mounts of container %+v", tc.container)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -294,6 +294,7 @@ func (m *kubeGenericRuntimeManager) makeMounts(opts *kubecontainer.RunContainerO
|
||||
ContainerPath: v.ContainerPath,
|
||||
Readonly: v.ReadOnly,
|
||||
SelinuxRelabel: selinuxRelabel,
|
||||
Propagation: v.Propagation,
|
||||
}
|
||||
|
||||
volumeMounts = append(volumeMounts, mount)
|
||||
|
Loading…
Reference in New Issue
Block a user