diff --git a/.changelog/17625.txt b/.changelog/17625.txt new file mode 100644 index 000000000..df5ea63b9 --- /dev/null +++ b/.changelog/17625.txt @@ -0,0 +1,3 @@ +```release-note:bug +client: Fixed a bug where Nomad incorrectly wrote to memory swappiness cgroup on old kernels +``` diff --git a/client/lib/cgutil/cgutil_linux.go b/client/lib/cgutil/cgutil_linux.go index 7727b2a43..ffb3f4c18 100644 --- a/client/lib/cgutil/cgutil_linux.go +++ b/client/lib/cgutil/cgutil_linux.go @@ -11,6 +11,7 @@ import ( "path/filepath" "github.com/hashicorp/go-hclog" + "github.com/hashicorp/nomad/helper/pointer" "github.com/hashicorp/nomad/helper/uuid" "github.com/opencontainers/runc/libcontainer/cgroups" lcc "github.com/opencontainers/runc/libcontainer/configs" @@ -148,3 +149,26 @@ func CopyCpuset(source, destination string) error { return nil } + +// MaybeDisableMemorySwappiness will disable memory swappiness, if that controller +// is available. Always the case for cgroups v2, but is not always the case on +// very old kernels with cgroups v1. +func MaybeDisableMemorySwappiness() *uint64 { + bypass := (*uint64)(nil) + zero := pointer.Of[uint64](0) + + // cgroups v2 always set zero + if UseV2 { + return zero + } + + // cgroups v1 detect if swappiness is supported by attempting to write to + // the nomad parent cgroup swappiness interface + e := &editor{fromRoot: "memory/nomad"} + err := e.write("memory.swappiness", "0") + if err != nil { + return bypass + } + + return zero +} diff --git a/client/lib/cgutil/cgutil_linux_test.go b/client/lib/cgutil/cgutil_linux_test.go index 8047b5ccc..9c51e3ef3 100644 --- a/client/lib/cgutil/cgutil_linux_test.go +++ b/client/lib/cgutil/cgutil_linux_test.go @@ -130,3 +130,12 @@ func TestUtil_CopyCpuset(t *testing.T) { require.Equal(t, "0-1", strings.TrimSpace(value)) }) } + +func TestUtil_MaybeDisableMemorySwappiness(t *testing.T) { + ci.Parallel(t) + + // will return 0 on any reasonable kernel (both cgroups v1 and v2) + value := MaybeDisableMemorySwappiness() + must.NotNil(t, value) + must.Eq(t, 0, *value) +} diff --git a/drivers/shared/executor/executor_linux.go b/drivers/shared/executor/executor_linux.go index 1d9b352fb..d0c4a743b 100644 --- a/drivers/shared/executor/executor_linux.go +++ b/drivers/shared/executor/executor_linux.go @@ -689,9 +689,8 @@ func configureCgroups(cfg *lconfigs.Config, command *ExecCommand) error { cfg.Cgroups.Resources.Memory = memHard * 1024 * 1024 cfg.Cgroups.Resources.MemoryReservation = memSoft * 1024 * 1024 - // Disable swap to avoid issues on the machine - var memSwappiness uint64 - cfg.Cgroups.Resources.MemorySwappiness = &memSwappiness + // Disable swap if possible, to avoid issues on the machine + cfg.Cgroups.Resources.MemorySwappiness = cgutil.MaybeDisableMemorySwappiness() } cpuShares := res.Cpu.CpuShares