Skip to content

Commit 2b06409

Browse files
committed
Introduced an entrypoint script to autotune the number of worker processes
The script is a no-op bye default, you would need to enable its logic by setting an NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE variable to any value. The script then tries to get the following values: - getconf _NPROCESSORS_ONLN - the amount of cpus from cpuset cgroupv1 - the quotas from cpu/cpuacct cgroupv1 - the amount of cpus from cgroupv2 - the quotas from cgroupv2 The lowest of all five is then applied to nginx.conf. Fixes #472
1 parent 2f28591 commit 2b06409

19 files changed

+1756
-0
lines changed

Dockerfile-alpine.template

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ RUN set -x \
105105
COPY docker-entrypoint.sh /
106106
COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d
107107
COPY 20-envsubst-on-templates.sh /docker-entrypoint.d
108+
COPY 30-tune-worker-processes.sh /docker-entrypoint.d
108109
ENTRYPOINT ["/docker-entrypoint.sh"]
109110

110111
EXPOSE 80

Dockerfile-debian.template

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ RUN set -x \
9696
COPY docker-entrypoint.sh /
9797
COPY 10-listen-on-ipv6-by-default.sh /docker-entrypoint.d
9898
COPY 20-envsubst-on-templates.sh /docker-entrypoint.d
99+
COPY 30-tune-worker-processes.sh /docker-entrypoint.d
99100
ENTRYPOINT ["/docker-entrypoint.sh"]
100101

101102
EXPOSE 80
+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
#!/bin/sh
2+
# vim:sw=2:ts=2:sts=2:et
3+
4+
set -eu
5+
6+
LC_ALL=C
7+
ME=$( basename "$0" )
8+
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
9+
10+
[ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0
11+
12+
touch /etc/nginx/nginx.conf 2>/dev/null || { echo >&2 "$ME: error: can not modify /etc/nginx/nginx.conf (read-only file system?)"; exit 0; }
13+
14+
ceildiv() {
15+
num=$1
16+
div=$2
17+
echo $(( (num + div - 1) / div ))
18+
}
19+
20+
get_cpuset() {
21+
cpusetroot=$1
22+
cpusetfile=$2
23+
ncpu=0
24+
[ -f "$cpusetroot/$cpusetfile" ] || return
25+
for token in $( tr ',' ' ' < "$cpusetroot/$cpusetfile" ); do
26+
case "$token" in
27+
*-*)
28+
count=$( seq $(echo "$token" | tr '-' ' ') | wc -l )
29+
ncpu=$(( ncpu+count ))
30+
;;
31+
*)
32+
ncpu=$(( ncpu+1 ))
33+
;;
34+
esac
35+
done
36+
echo "$ncpu"
37+
}
38+
39+
get_quota() {
40+
cpuroot=$1
41+
ncpu=0
42+
[ -f "$cpuroot/cpu.cfs_quota_us" ] || return
43+
[ -f "$cpuroot/cpu.cfs_period_us" ] || return
44+
cfs_quota=$( cat "$cpuroot/cpu.cfs_quota_us" )
45+
cfs_period=$( cat "$cpuroot/cpu.cfs_period_us" )
46+
[ "$cfs_quota" = "-1" ] && return
47+
[ "$cfs_period" = "0" ] && return
48+
ncpu=$( ceildiv "$cfs_quota" "$cfs_period" )
49+
[ "$ncpu" -gt 0 ] || return
50+
echo "$ncpu"
51+
}
52+
53+
get_quota_v2() {
54+
cpuroot=$1
55+
ncpu=0
56+
[ -f "$cpuroot/cpu.max" ] || return
57+
cfs_quota=$( cut -d' ' -f 1 < "$cpuroot/cpu.max" )
58+
cfs_period=$( cut -d' ' -f 2 < "$cpuroot/cpu.max" )
59+
[ "$cfs_quota" = "max" ] && return
60+
[ "$cfs_period" = "0" ] && return
61+
ncpu=$( ceildiv "$cfs_quota" "$cfs_period" )
62+
[ "$ncpu" -gt 0 ] || return
63+
echo "$ncpu"
64+
}
65+
66+
get_cgroup_v1_path() {
67+
needle=$1
68+
found=
69+
foundroot=
70+
mountpoint=
71+
72+
[ -r "/proc/self/mountinfo" ] || return
73+
[ -r "/proc/self/cgroup" ] || return
74+
75+
while IFS= read -r line; do
76+
case "$needle" in
77+
"cpuset")
78+
case "$line" in
79+
*cpuset*)
80+
found=$( echo "$line" | cut -d ' ' -f 4,5 )
81+
;;
82+
esac
83+
;;
84+
"cpu")
85+
case "$line" in
86+
*cpuset*)
87+
;;
88+
*cpu,cpuacct*|*cpuacct,cpu|*cpuacct*|*cpu*)
89+
found=$( echo "$line" | cut -d ' ' -f 4,5 )
90+
;;
91+
esac
92+
esac
93+
done << __EOF__
94+
$( grep -F -- '- cgroup ' /proc/self/mountinfo )
95+
__EOF__
96+
97+
while IFS= read -r line; do
98+
controller=$( echo "$line" | cut -d: -f 2 )
99+
case "$needle" in
100+
"cpuset")
101+
case "$controller" in
102+
cpuset)
103+
mountpoint=$( echo "$line" | cut -d: -f 3 )
104+
;;
105+
esac
106+
;;
107+
"cpu")
108+
case "$controller" in
109+
cpu,cpuacct|cpuacct,cpu|cpuacct|cpu)
110+
mountpoint=$( echo "$line" | cut -d: -f 3 )
111+
;;
112+
esac
113+
;;
114+
esac
115+
done << __EOF__
116+
$( grep -F -- 'cpu' /proc/self/cgroup )
117+
__EOF__
118+
119+
case "${found%% *}" in
120+
"/")
121+
foundroot="${found##* }$mountpoint"
122+
;;
123+
"$mountpoint")
124+
foundroot="${found##* }"
125+
;;
126+
esac
127+
echo "$foundroot"
128+
}
129+
130+
get_cgroup_v2_path() {
131+
found=
132+
foundroot=
133+
mountpoint=
134+
135+
[ -r "/proc/self/mountinfo" ] || return
136+
[ -r "/proc/self/cgroup" ] || return
137+
138+
while IFS= read -r line; do
139+
found=$( echo "$line" | cut -d ' ' -f 4,5 )
140+
done << __EOF__
141+
$( grep -F -- '- cgroup2 ' /proc/self/mountinfo )
142+
__EOF__
143+
144+
while IFS= read -r line; do
145+
mountpoint=$( echo "$line" | cut -d: -f 3 )
146+
done << __EOF__
147+
$( grep -F -- '0::' /proc/self/cgroup )
148+
__EOF__
149+
150+
case "${found%% *}" in
151+
"")
152+
return
153+
;;
154+
"/")
155+
foundroot="${found##* }$mountpoint"
156+
;;
157+
"$mountpoint")
158+
foundroot="${found##* }"
159+
;;
160+
esac
161+
echo "$foundroot"
162+
}
163+
164+
ncpu_online=$( getconf _NPROCESSORS_ONLN )
165+
ncpu_cpuset=
166+
ncpu_quota=
167+
ncpu_cpuset_v2=
168+
ncpu_quota_v2=
169+
170+
cpuset=$( get_cgroup_v1_path "cpuset" )
171+
[ "$cpuset" ] && ncpu_cpuset=$( get_cpuset "$cpuset" "cpuset.effective_cpus" )
172+
[ "$ncpu_cpuset" ] || ncpu_cpuset=$ncpu_online
173+
174+
cpu=$( get_cgroup_v1_path "cpu" )
175+
[ "$cpu" ] && ncpu_quota=$( get_quota "$cpu" )
176+
[ "$ncpu_quota" ] || ncpu_quota=$ncpu_online
177+
178+
cgroup_v2=$( get_cgroup_v2_path )
179+
[ "$cgroup_v2" ] && ncpu_cpuset_v2=$( get_cpuset "$cgroup_v2" "cpuset.cpus.effective" )
180+
[ "$ncpu_cpuset_v2" ] || ncpu_cpuset_v2=$ncpu_online
181+
182+
[ "$cgroup_v2" ] && ncpu_quota_v2=$( get_quota_v2 "$cgroup_v2" )
183+
[ "$ncpu_quota_v2" ] || ncpu_quota_v2=$ncpu_online
184+
185+
ncpu=$( printf "%s\n%s\n%s\n%s\n%s\n" \
186+
"$ncpu_online" \
187+
"$ncpu_cpuset" \
188+
"$ncpu_quota" \
189+
"$ncpu_cpuset_v2" \
190+
"$ncpu_quota_v2" \
191+
| sort -n \
192+
| head -n 1 )
193+
194+
sed -i.bak -r 's/^(worker_processes)(.*)$/# Commented out by '"$ME"' on '"$(date)"'\n#\1\2\n\1 '"$ncpu"';/' /etc/nginx/nginx.conf

0 commit comments

Comments
 (0)