Skip to content

Commit

Permalink
Merge pull request kubernetes#81163 from jsafrane/skip-unused-volumes
Browse files Browse the repository at this point in the history
Skip unused volumes in VolumeManager
  • Loading branch information
k8s-ci-robot authored Aug 17, 2019
2 parents d5173ef + 2c79ffe commit e319abf
Show file tree
Hide file tree
Showing 13 changed files with 560 additions and 93 deletions.
4 changes: 3 additions & 1 deletion pkg/kubelet/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ import (
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/csi"
"k8s.io/kubernetes/pkg/volume/util/subpath"
"k8s.io/kubernetes/pkg/volume/util/volumepathhandler"
utilexec "k8s.io/utils/exec"
"k8s.io/utils/integer"
)
Expand Down Expand Up @@ -819,7 +820,8 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
klet.getPodsDir(),
kubeDeps.Recorder,
experimentalCheckNodeCapabilitiesBeforeMount,
keepTerminatedPodVolumes)
keepTerminatedPodVolumes,
volumepathhandler.NewBlockVolumePathHandler())

klet.reasonCache = NewReasonCache()
klet.workQueue = queue.NewBasicWorkQueue(klet.clock)
Expand Down
3 changes: 2 additions & 1 deletion pkg/kubelet/kubelet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,8 @@ func newTestKubeletWithImageList(
kubelet.getPodsDir(),
kubelet.recorder,
false, /* experimentalCheckNodeCapabilitiesBeforeMount*/
false /* keepTerminatedPodVolumes */)
false, /* keepTerminatedPodVolumes */
volumetest.NewBlockVolumePathHandler())

kubelet.pluginManager = pluginmanager.NewPluginManager(
kubelet.getPluginsRegistrationDir(), /* sockDir */
Expand Down
95 changes: 93 additions & 2 deletions pkg/kubelet/kubelet_volumes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
Expand All @@ -37,6 +37,21 @@ func TestListVolumesForPod(t *testing.T) {
kubelet := testKubelet.kubelet

pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Containers: []v1.Container{
{
Name: "container1",
VolumeMounts: []v1.VolumeMount{
{
Name: "vol1",
MountPath: "/mnt/vol1",
},
{
Name: "vol2",
MountPath: "/mnt/vol2",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "vol1",
Expand Down Expand Up @@ -74,7 +89,6 @@ func TestListVolumesForPod(t *testing.T) {

outerVolumeSpecName2 := "vol2"
assert.NotNil(t, volumesToReturn[outerVolumeSpecName2], "key %s", outerVolumeSpecName2)

}

func TestPodVolumesExist(t *testing.T) {
Expand All @@ -89,6 +103,17 @@ func TestPodVolumesExist(t *testing.T) {
UID: "pod1uid",
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "container1",
VolumeMounts: []v1.VolumeMount{
{
Name: "vol1",
MountPath: "/mnt/vol1",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "vol1",
Expand All @@ -107,6 +132,17 @@ func TestPodVolumesExist(t *testing.T) {
UID: "pod2uid",
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "container2",
VolumeMounts: []v1.VolumeMount{
{
Name: "vol2",
MountPath: "/mnt/vol2",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "vol2",
Expand All @@ -125,6 +161,17 @@ func TestPodVolumesExist(t *testing.T) {
UID: "pod3uid",
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "container3",
VolumeMounts: []v1.VolumeMount{
{
Name: "vol3",
MountPath: "/mnt/vol3",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "vol3",
Expand Down Expand Up @@ -160,6 +207,17 @@ func TestVolumeAttachAndMountControllerDisabled(t *testing.T) {
kubelet := testKubelet.kubelet

pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Containers: []v1.Container{
{
Name: "container1",
VolumeMounts: []v1.VolumeMount{
{
Name: "vol1",
MountPath: "/mnt/vol1",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "vol1",
Expand Down Expand Up @@ -204,6 +262,17 @@ func TestVolumeUnmountAndDetachControllerDisabled(t *testing.T) {
kubelet := testKubelet.kubelet

pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Containers: []v1.Container{
{
Name: "container1",
VolumeMounts: []v1.VolumeMount{
{
Name: "vol1",
MountPath: "/mnt/vol1",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "vol1",
Expand Down Expand Up @@ -290,6 +359,17 @@ func TestVolumeAttachAndMountControllerEnabled(t *testing.T) {
})

pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Containers: []v1.Container{
{
Name: "container1",
VolumeMounts: []v1.VolumeMount{
{
Name: "vol1",
MountPath: "/mnt/vol1",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "vol1",
Expand Down Expand Up @@ -356,6 +436,17 @@ func TestVolumeUnmountAndDetachControllerEnabled(t *testing.T) {
})

pod := podWithUIDNameNsSpec("12345678", "foo", "test", v1.PodSpec{
Containers: []v1.Container{
{
Name: "container1",
VolumeMounts: []v1.VolumeMount{
{
Name: "vol1",
MountPath: "/mnt/vol1",
},
},
},
},
Volumes: []v1.Volume{
{
Name: "vol1",
Expand Down
5 changes: 3 additions & 2 deletions pkg/kubelet/runonce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (

cadvisorapi "github.com/google/cadvisor/info/v1"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/clock"
Expand Down Expand Up @@ -108,7 +108,8 @@ func TestRunOnce(t *testing.T) {
kb.getPodsDir(),
kb.recorder,
false, /* experimentalCheckNodeCapabilitiesBeforeMount */
false /* keepTerminatedPodVolumes */)
false, /* keepTerminatedPodVolumes */
volumetest.NewBlockVolumePathHandler())

// TODO: Factor out "StatsProvider" from Kubelet so we don't have a cyclic dependency
volumeStatsAggPeriod := time.Second * 10
Expand Down
3 changes: 3 additions & 0 deletions pkg/kubelet/volumemanager/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ go_test(
srcs = ["volume_manager_test.go"],
embed = [":go_default_library"],
deps = [
"//pkg/features:go_default_library",
"//pkg/kubelet/config:go_default_library",
"//pkg/kubelet/configmap:go_default_library",
"//pkg/kubelet/container/testing:go_default_library",
Expand All @@ -62,10 +63,12 @@ go_test(
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait: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/kubernetes/fake:go_default_library",
"//staging/src/k8s.io/client-go/tools/record:go_default_library",
"//staging/src/k8s.io/client-go/util/testing:go_default_library",
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,18 @@ func (dswp *desiredStateOfWorldPopulator) processPodVolumes(
}

allVolumesAdded := true
mountsMap, devicesMap := dswp.makeVolumeMap(pod.Spec.Containers)
mounts, devices := util.GetPodVolumeNames(pod)

// Process volume spec for each volume defined in pod
for _, podVolume := range pod.Spec.Volumes {
if !mounts.Has(podVolume.Name) && !devices.Has(podVolume.Name) {
// Volume is not used in the pod, ignore it.
klog.V(4).Infof("Skipping unused volume %q for pod %q", podVolume.Name, format.Pod(pod))
continue
}

pvc, volumeSpec, volumeGidValue, err :=
dswp.createVolumeSpec(podVolume, pod.Name, pod.Namespace, mountsMap, devicesMap)
dswp.createVolumeSpec(podVolume, pod.Name, pod.Namespace, mounts, devices)
if err != nil {
klog.Errorf(
"Error processing volume %q for pod %q: %v",
Expand Down Expand Up @@ -481,11 +487,11 @@ func (dswp *desiredStateOfWorldPopulator) deleteProcessedPod(
delete(dswp.pods.processedPods, podName)
}

// createVolumeSpec creates and returns a mutatable volume.Spec object for the
// createVolumeSpec creates and returns a mutable volume.Spec object for the
// specified volume. It dereference any PVC to get PV objects, if needed.
// Returns an error if unable to obtain the volume at this time.
func (dswp *desiredStateOfWorldPopulator) createVolumeSpec(
podVolume v1.Volume, podName string, podNamespace string, mountsMap map[string]bool, devicesMap map[string]bool) (*v1.PersistentVolumeClaim, *volume.Spec, string, error) {
podVolume v1.Volume, podName string, podNamespace string, mounts, devices sets.String) (*v1.PersistentVolumeClaim, *volume.Spec, string, error) {
if pvcSource :=
podVolume.VolumeSource.PersistentVolumeClaim; pvcSource != nil {
klog.V(5).Infof(
Expand Down Expand Up @@ -538,14 +544,14 @@ func (dswp *desiredStateOfWorldPopulator) createVolumeSpec(
return nil, nil, "", err
}
// Error if a container has volumeMounts but the volumeMode of PVC isn't Filesystem
if mountsMap[podVolume.Name] && volumeMode != v1.PersistentVolumeFilesystem {
if mounts.Has(podVolume.Name) && volumeMode != v1.PersistentVolumeFilesystem {
return nil, nil, "", fmt.Errorf(
"volume %s has volumeMode %s, but is specified in volumeMounts",
podVolume.Name,
volumeMode)
}
// Error if a container has volumeDevices but the volumeMode of PVC isn't Block
if devicesMap[podVolume.Name] && volumeMode != v1.PersistentVolumeBlock {
if devices.Has(podVolume.Name) && volumeMode != v1.PersistentVolumeBlock {
return nil, nil, "", fmt.Errorf(
"volume %s has volumeMode %s, but is specified in volumeDevices",
podVolume.Name,
Expand Down Expand Up @@ -628,28 +634,6 @@ func (dswp *desiredStateOfWorldPopulator) getPVSpec(
return volume.NewSpecFromPersistentVolume(pv, pvcReadOnly), volumeGidValue, nil
}

func (dswp *desiredStateOfWorldPopulator) makeVolumeMap(containers []v1.Container) (map[string]bool, map[string]bool) {
volumeDevicesMap := make(map[string]bool)
volumeMountsMap := make(map[string]bool)

for _, container := range containers {
if container.VolumeMounts != nil {
for _, mount := range container.VolumeMounts {
volumeMountsMap[mount.Name] = true
}
}
// TODO: remove feature gate check after no longer needed
if utilfeature.DefaultFeatureGate.Enabled(features.BlockVolume) &&
container.VolumeDevices != nil {
for _, device := range container.VolumeDevices {
volumeDevicesMap[device.Name] = true
}
}
}

return volumeMountsMap, volumeDevicesMap
}

func getPVVolumeGidAnnotationValue(pv *v1.PersistentVolume) string {
if volumeGid, ok := pv.Annotations[util.VolumeGidAnnotationKey]; ok {
return volumeGid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (

"fmt"

"k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -410,7 +410,7 @@ func TestCreateVolumeSpec_Valid_File_VolumeMounts(t *testing.T) {
pod := createPodWithVolume("dswp-test-pod", "dswp-test-volume-name", "file-bound", containers)

fakePodManager.AddPod(pod)
mountsMap, devicesMap := dswp.makeVolumeMap(pod.Spec.Containers)
mountsMap, devicesMap := util.GetPodVolumeNames(pod)
_, volumeSpec, _, err :=
dswp.createVolumeSpec(pod.Spec.Volumes[0], pod.Name, pod.Namespace, mountsMap, devicesMap)

Expand Down Expand Up @@ -459,7 +459,7 @@ func TestCreateVolumeSpec_Valid_Block_VolumeDevices(t *testing.T) {
pod := createPodWithVolume("dswp-test-pod", "dswp-test-volume-name", "block-bound", containers)

fakePodManager.AddPod(pod)
mountsMap, devicesMap := dswp.makeVolumeMap(pod.Spec.Containers)
mountsMap, devicesMap := util.GetPodVolumeNames(pod)
_, volumeSpec, _, err :=
dswp.createVolumeSpec(pod.Spec.Volumes[0], pod.Name, pod.Namespace, mountsMap, devicesMap)

Expand Down Expand Up @@ -508,7 +508,7 @@ func TestCreateVolumeSpec_Invalid_File_VolumeDevices(t *testing.T) {
pod := createPodWithVolume("dswp-test-pod", "dswp-test-volume-name", "file-bound", containers)

fakePodManager.AddPod(pod)
mountsMap, devicesMap := dswp.makeVolumeMap(pod.Spec.Containers)
mountsMap, devicesMap := util.GetPodVolumeNames(pod)
_, volumeSpec, _, err :=
dswp.createVolumeSpec(pod.Spec.Volumes[0], pod.Name, pod.Namespace, mountsMap, devicesMap)

Expand Down Expand Up @@ -557,7 +557,7 @@ func TestCreateVolumeSpec_Invalid_Block_VolumeMounts(t *testing.T) {
pod := createPodWithVolume("dswp-test-pod", "dswp-test-volume-name", "block-bound", containers)

fakePodManager.AddPod(pod)
mountsMap, devicesMap := dswp.makeVolumeMap(pod.Spec.Containers)
mountsMap, devicesMap := util.GetPodVolumeNames(pod)
_, volumeSpec, _, err :=
dswp.createVolumeSpec(pod.Spec.Volumes[0], pod.Name, pod.Namespace, mountsMap, devicesMap)

Expand Down
14 changes: 5 additions & 9 deletions pkg/kubelet/volumemanager/volume_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ func NewVolumeManager(
kubeletPodsDir string,
recorder record.EventRecorder,
checkNodeCapabilitiesBeforeMount bool,
keepTerminatedPodVolumes bool) VolumeManager {
keepTerminatedPodVolumes bool,
blockVolumePathHandler volumepathhandler.BlockVolumePathHandler) VolumeManager {

vm := &volumeManager{
kubeClient: kubeClient,
Expand All @@ -169,7 +170,7 @@ func NewVolumeManager(
volumePluginMgr,
recorder,
checkNodeCapabilitiesBeforeMount,
volumepathhandler.NewBlockVolumePathHandler())),
blockVolumePathHandler)),
}

vm.desiredStateOfWorldPopulator = populator.NewDesiredStateOfWorldPopulator(
Expand Down Expand Up @@ -435,13 +436,8 @@ func filterUnmountedVolumes(mountedVolumes sets.String, expectedVolumes []string
// getExpectedVolumes returns a list of volumes that must be mounted in order to
// consider the volume setup step for this pod satisfied.
func getExpectedVolumes(pod *v1.Pod) []string {
expectedVolumes := []string{}

for _, podVolume := range pod.Spec.Volumes {
expectedVolumes = append(expectedVolumes, podVolume.Name)
}

return expectedVolumes
mounts, devices := util.GetPodVolumeNames(pod)
return mounts.Union(devices).UnsortedList()
}

// getExtraSupplementalGid returns the value of an extra supplemental GID as
Expand Down
Loading

0 comments on commit e319abf

Please sign in to comment.