From 29535c0463d7bc44900b479df5e08c5465604584 Mon Sep 17 00:00:00 2001 From: Itamar Holder Date: Wed, 8 May 2024 17:33:47 +0300 Subject: [PATCH] Warn of swap is enabled on the OS and tmpfs noswap is not supported When --fail-swap-on=false kubelet CLI argument is provided, but tmpfs noswap is not supported by the kernel, warn about the risks of memory-backed volumes being swapped into disk Signed-off-by: Itamar Holder --- pkg/kubelet/cm/container_manager_linux.go | 32 +++++++++------------- pkg/kubelet/util/swap/swap_util.go | 33 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/pkg/kubelet/cm/container_manager_linux.go b/pkg/kubelet/cm/container_manager_linux.go index fb666a8333f..b8c54120776 100644 --- a/pkg/kubelet/cm/container_manager_linux.go +++ b/pkg/kubelet/cm/container_manager_linux.go @@ -20,12 +20,10 @@ limitations under the License. package cm import ( - "bytes" "context" "fmt" "os" "path" - "strings" "sync" "time" @@ -64,6 +62,7 @@ import ( "k8s.io/kubernetes/pkg/kubelet/stats/pidlimit" "k8s.io/kubernetes/pkg/kubelet/status" "k8s.io/kubernetes/pkg/kubelet/userns/inuserns" + "k8s.io/kubernetes/pkg/kubelet/util/swap" schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework" "k8s.io/kubernetes/pkg/util/oom" ) @@ -204,25 +203,18 @@ func NewContainerManager(mountUtil mount.Interface, cadvisorInterface cadvisor.I return nil, fmt.Errorf("failed to get mounted cgroup subsystems: %v", err) } - if failSwapOn { - // Check whether swap is enabled. The Kubelet does not support running with swap enabled. - swapFile := "/proc/swaps" - swapData, err := os.ReadFile(swapFile) - if err != nil { - if os.IsNotExist(err) { - klog.InfoS("File does not exist, assuming that swap is disabled", "path", swapFile) - } else { - return nil, err - } - } else { - swapData = bytes.TrimSpace(swapData) // extra trailing \n - swapLines := strings.Split(string(swapData), "\n") + isSwapOn, err := swap.IsSwapOn() + if err != nil { + return nil, fmt.Errorf("failed to determine if swap is on: %w", err) + } - // If there is more than one line (table headers) in /proc/swaps, swap is enabled and we should - // error out unless --fail-swap-on is set to false. - if len(swapLines) > 1 { - return nil, fmt.Errorf("running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false. /proc/swaps contained: %v", swapLines) - } + if isSwapOn { + if failSwapOn { + return nil, fmt.Errorf("running with swap on is not supported, please disable swap or set --fail-swap-on flag to false") + } + + if !swap.IsTmpfsNoswapOptionSupported(mountUtil) { + klog.InfoS("tmpfs noswap option is not supported, hence memory-backed volumes (e.g. secrets, emptyDirs) might be swapped to disk") } } diff --git a/pkg/kubelet/util/swap/swap_util.go b/pkg/kubelet/util/swap/swap_util.go index db7fdc9fcc9..626e30ebd01 100644 --- a/pkg/kubelet/util/swap/swap_util.go +++ b/pkg/kubelet/util/swap/swap_util.go @@ -32,6 +32,9 @@ import ( var ( tmpfsNoswapOptionSupported bool tmpfsNoswapOptionAvailabilityOnce sync.Once + swapOn bool + swapOnErr error + swapOnOnce sync.Once ) const TmpfsNoswapOption = "noswap" @@ -96,3 +99,33 @@ func isSwapOnAccordingToProcSwaps(procSwapsContent []byte) bool { klog.InfoS("Swap is on", "/proc/swaps contents", procSwapsStr) return len(procSwapsLines) > 1 } + +// IsSwapOn detects whether swap in enabled on the system by inspecting +// /proc/swaps. If the file does not exist, an os.NotFound error will be returned. +// If running on windows, swap is assumed to always be false. +func IsSwapOn() (bool, error) { + isSwapOnHelper := func() (bool, error) { + if sysruntime.GOOS == "windows" { + return false, nil + } + + const swapFilePath = "/proc/swaps" + procSwapsContent, err := os.ReadFile(swapFilePath) + if err != nil { + if os.IsNotExist(err) { + klog.InfoS("File does not exist, assuming that swap is disabled", "path", swapFilePath) + return false, nil + } + + return false, err + } + + return isSwapOnAccordingToProcSwaps(procSwapsContent), nil + } + + swapOnOnce.Do(func() { + swapOn, swapOnErr = isSwapOnHelper() + }) + + return swapOn, swapOnErr +}