Skip to content

Commit

Permalink
Read container memory limit from cgroup (v1 and v2)
Browse files Browse the repository at this point in the history
Uses memory.high if available (recommended way of setting a functioning soft limit), then first falls back to memory.max (e.g. from 'docker run -m'), then to memory.low (e.g. from 'docker run --memory-reservation'), and finally to memory.min.

Falls back to direct reading of '/sys/fs/cgroup/memory/memory.limit_in_bytes' for cases where that exists, but no full cgroupfs is mounted (e.g. on Heroku).

Limit enforcement (now to 8 TB) is still in place this way - a Docker v1 value will be read, and run into the limit for unrestricted containers, without hitting the fallback and getting returned.

GUS-W-16052317
  • Loading branch information
dzuelke committed Jul 1, 2024
1 parent ce0a915 commit 7604313
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Added Yarn version 4.3.1.
- Added Yarn version 3.8.3.
- Support reading container memory limits from cgroups (v1 and v2)

## [v255] - 2024-06-21

Expand Down
9 changes: 8 additions & 1 deletion lib/environment.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,14 @@ write_profile() {
local bp_dir="$1"
local build_dir="$2"
mkdir -p "$build_dir/.profile.d"
cp "$bp_dir"/profile/* "$build_dir/.profile.d/"
cp "$bp_dir"/profile/nodejs.sh "$build_dir/.profile.d/"
write_web_concurrency "$bp_dir" "$build_dir/.profile.d/WEB_CONCURRENCY.sh"
}

write_web_concurrency() {
local bp_dir="$1"
# concatenate these two together
cat "$bp_dir"/etc/cgroups.sh "$bp_dir"/profile/WEB_CONCURRENCY.sh > "$2"
}

write_ci_profile() {
Expand Down
19 changes: 15 additions & 4 deletions profile/WEB_CONCURRENCY.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,28 @@ log_concurrency() {
detect_memory() {
local default=$1

if [ -e /sys/fs/cgroup/memory/memory.limit_in_bytes ]; then
echo $(($(cat /sys/fs/cgroup/memory/memory.limit_in_bytes) / 1048576))
local memory_limit
memory_limit=$(cgroup_util_read_cgroup_memory_limit_with_fallback) && {
echo $(( memory_limit / 1024 / 1024 ))
return
}

if (($? == 99)); then
dne_memory
else
echo "$default"
fi
fi
}

dne_memory() {
echo "129024"
}

bound_memory() {
local detected=$1
# Memory is bound to the maximum memory of known dyno types: ~126 GB
local max_detected_memory=129024
local max_detected_memory
max_detected_memory=$(dne_memory)
if (( detected > max_detected_memory )); then
echo "$max_detected_memory"
else
Expand Down
42 changes: 33 additions & 9 deletions test/run
Original file line number Diff line number Diff line change
Expand Up @@ -557,35 +557,55 @@ testBuildWithUserCacheDirectoriesCamel() {
}

testConcurrency1X() {
LOG_CONCURRENCY=true MEMORY_AVAILABLE=512 capture "$(pwd)"/profile/WEB_CONCURRENCY.sh
# write_web_concurrency concatenates a vendored library file and our own logic into one file
WEB_CONCURRENCY_SH=$(mktemp)
chmod u+x "$WEB_CONCURRENCY_SH"
write_web_concurrency "$(pwd)" "$WEB_CONCURRENCY_SH"
LOG_CONCURRENCY=true MEMORY_AVAILABLE=512 capture "$WEB_CONCURRENCY_SH"
assertCaptured "Detected 512 MB available memory, 512 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=1"
assertCapturedSuccess
}

testConcurrency2X() {
LOG_CONCURRENCY=true MEMORY_AVAILABLE=1024 capture "$(pwd)"/profile/WEB_CONCURRENCY.sh
# write_web_concurrency concatenates a vendored library file and our own logic into one file
WEB_CONCURRENCY_SH=$(mktemp)
chmod u+x "$WEB_CONCURRENCY_SH"
write_web_concurrency "$(pwd)" "$WEB_CONCURRENCY_SH"
LOG_CONCURRENCY=true MEMORY_AVAILABLE=1024 capture "$WEB_CONCURRENCY_SH"
assertCaptured "Detected 1024 MB available memory, 512 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=2"
assertCapturedSuccess
}

testConcurrencyPerformanceM() {
LOG_CONCURRENCY=true MEMORY_AVAILABLE=2560 capture "$(pwd)"/profile/WEB_CONCURRENCY.sh
# write_web_concurrency concatenates a vendored library file and our own logic into one file
WEB_CONCURRENCY_SH=$(mktemp)
chmod u+x "$WEB_CONCURRENCY_SH"
write_web_concurrency "$(pwd)" "$WEB_CONCURRENCY_SH"
LOG_CONCURRENCY=true MEMORY_AVAILABLE=2560 capture "$WEB_CONCURRENCY_SH"
assertCaptured "Detected 2560 MB available memory, 512 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=5"
assertCapturedSuccess
}

testConcurrencyPerformanceL() {
LOG_CONCURRENCY=true MEMORY_AVAILABLE=14336 capture "$(pwd)"/profile/WEB_CONCURRENCY.sh
assertCaptured "Detected 14336 MB available memory, 512 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=28"
assertCapturedSuccess
# write_web_concurrency concatenates a vendored library file and our own logic into one file
WEB_CONCURRENCY_SH=$(mktemp)
chmod u+x "$WEB_CONCURRENCY_SH"
write_web_concurrency "$(pwd)" "$WEB_CONCURRENCY_SH"
LOG_CONCURRENCY=true MEMORY_AVAILABLE=14336 capture "$WEB_CONCURRENCY_SH"
assertCaptured "Detected 14336 MB available memory, 512 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=28"
assertCapturedSuccess
}

testConcurrencyCustomLimit() {
LOG_CONCURRENCY=true MEMORY_AVAILABLE=1024 WEB_MEMORY=256 capture "$(pwd)"/profile/WEB_CONCURRENCY.sh
# write_web_concurrency concatenates a vendored library file and our own logic into one file
WEB_CONCURRENCY_SH=$(mktemp)
chmod u+x "$WEB_CONCURRENCY_SH"
write_web_concurrency "$(pwd)" "$WEB_CONCURRENCY_SH"
LOG_CONCURRENCY=true MEMORY_AVAILABLE=1024 WEB_MEMORY=256 capture "$WEB_CONCURRENCY_SH"
assertCaptured "Detected 1024 MB available memory, 256 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=4"
assertCapturedSuccess
Expand All @@ -594,7 +614,11 @@ testConcurrencyCustomLimit() {
# When /sys/fs/cgroup/memory/memory.limit_in_bytes lies and gives a ridiculous value
# This happens on Dokku for example
testConcurrencyTooHigh() {
LOG_CONCURRENCY=true MEMORY_AVAILABLE=10000000000 capture "$(pwd)"/profile/WEB_CONCURRENCY.sh
# write_web_concurrency concatenates a vendored library file and our own logic into one file
WEB_CONCURRENCY_SH=$(mktemp)
chmod u+x "$WEB_CONCURRENCY_SH"
write_web_concurrency "$(pwd)" "$WEB_CONCURRENCY_SH"
LOG_CONCURRENCY=true MEMORY_AVAILABLE=10000000000 capture "$WEB_CONCURRENCY_SH"
assertCaptured "Could not determine a reasonable value for WEB_CONCURRENCY"
assertCaptured "Recommending WEB_CONCURRENCY=1"
assertCapturedSuccess
Expand Down

0 comments on commit 7604313

Please sign in to comment.