From fb6c78c90b4a8f436066ac4a528eb03f1102968e Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Wed, 8 May 2024 16:07:31 +0300 Subject: [PATCH] Use tmpfs noswap if supported use the tmpfs noswap option in order to mount memory-backed volumes if it's supported. Signed-off-by: Itamar Holder --- pkg/kubelet/util/swap/swap_util.go | 73 ++++++++++++++++++++++++++++++ pkg/volume/emptydir/empty_dir.go | 20 ++++++-- 2 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 pkg/kubelet/util/swap/swap_util.go diff --git a/pkg/kubelet/util/swap/swap_util.go b/pkg/kubelet/util/swap/swap_util.go new file mode 100644 index 00000000000..025c36c35ff --- /dev/null +++ b/pkg/kubelet/util/swap/swap_util.go @@ -0,0 +1,73 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package swap + +import ( + "os" + sysruntime "runtime" + "sync" + + "k8s.io/klog/v2" + "k8s.io/mount-utils" +) + +var ( + tmpfsNoswapOptionSupported bool + tmpfsNoswapOptionAvailabilityOnce sync.Once +) + +const TmpfsNoswapOption = "noswap" + +func IsTmpfsNoswapOptionSupported(mounter mount.Interface) bool { + isTmpfsNoswapOptionSupportedHelper := func() bool { + if sysruntime.GOOS == "windows" { + return false + } + + mountDir, err := os.MkdirTemp("", "tmpfs-noswap-test-") + if err != nil { + klog.InfoS("error creating dir to test if tmpfs noswap is enabled. Assuming not supported", "mount path", mountDir, "error", err) + return false + } + + defer func() { + err = os.RemoveAll(mountDir) + if err != nil { + klog.ErrorS(err, "error removing test tmpfs dir", "mount path", mountDir) + } + }() + + err = mounter.MountSensitiveWithoutSystemd("tmpfs", mountDir, "tmpfs", []string{TmpfsNoswapOption}, nil) + if err != nil { + klog.InfoS("error mounting tmpfs with the noswap option. Assuming not supported", "error", err) + return false + } + + err = mounter.Unmount(mountDir) + if err != nil { + klog.ErrorS(err, "error unmounting test tmpfs dir", "mount path", mountDir) + } + + return true + } + + tmpfsNoswapOptionAvailabilityOnce.Do(func() { + tmpfsNoswapOptionSupported = isTmpfsNoswapOptionSupportedHelper() + }) + + return tmpfsNoswapOptionSupported +} diff --git a/pkg/volume/emptydir/empty_dir.go b/pkg/volume/emptydir/empty_dir.go index d98a46197db..d4f281a9cab 100644 --- a/pkg/volume/emptydir/empty_dir.go +++ b/pkg/volume/emptydir/empty_dir.go @@ -18,6 +18,7 @@ package emptydir import ( "fmt" + "k8s.io/kubernetes/pkg/kubelet/util/swap" "os" "path/filepath" @@ -327,11 +328,7 @@ func (ed *emptyDir) setupTmpfs(dir string) error { return nil } - var options []string - // Linux system default is 50% of capacity. - if ed.sizeLimit != nil && ed.sizeLimit.Value() > 0 { - options = []string{fmt.Sprintf("size=%d", ed.sizeLimit.Value())} - } + options := ed.generateTmpfsMountOptions(swap.IsTmpfsNoswapOptionSupported(ed.mounter)) klog.V(3).Infof("pod %v: mounting tmpfs for volume %v", ed.pod.UID, ed.volName) return ed.mounter.MountSensitiveWithoutSystemd("tmpfs", dir, "tmpfs", options, nil) @@ -555,3 +552,16 @@ func getVolumeSource(spec *volume.Spec) (*v1.EmptyDirVolumeSource, bool) { return volumeSource, readOnly } + +func (ed *emptyDir) generateTmpfsMountOptions(noswapSupported bool) (options []string) { + // Linux system default is 50% of capacity. + if ed.sizeLimit != nil && ed.sizeLimit.Value() > 0 { + options = append(options, fmt.Sprintf("size=%d", ed.sizeLimit.Value())) + } + + if noswapSupported { + options = append(options, swap.TmpfsNoswapOption) + } + + return options +}