-
Notifications
You must be signed in to change notification settings - Fork 169
/
Copy pathstart-dockerd
executable file
·201 lines (176 loc) · 5.13 KB
/
start-dockerd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env bash
set -euo pipefail
# constants
SUPERVISORD_LOG='/tmp/supervisord.log'
DOCKERD_LOG='/tmp/dockerd.log'
DEFAULT_TIMEOUT=60
ERR_INSUFFICIENT_PRIVILEGES=101
ERR_DOCKERD_FAILED=102
ERR_INVALID_ARGS=103
ERR_SUPERVISORD_FAILED=104
# options
verbose=false
quiet=false
logs=false
timeout=${DEFAULT_TIMEOUT}
# functions
is_true() {
[[ ${1} = true ]]
}
is_verbose() {
is_true ${verbose}
}
is_quiet() {
is_true ${quiet}
}
say() {
echo "${@}" >&2
}
say_verbose() {
if is_verbose; then
say "${@}"
fi
}
check_privileged_mode_or_die() {
mkdir /mnt/_tmp
if ! mount -t tmpfs none /mnt/_tmp 2> /dev/null; then
say 'docker privileged mode required'
rm -r /mnt/_tmp
exit ${ERR_INSUFFICIENT_PRIVILEGES}
fi
umount /mnt/_tmp
rm -r /mnt/_tmp
}
start_restart_dockerd() {
if supervisorctl pid > /dev/null; then
say_verbose "restarting dockerd"
supervisorctl stop dockerd > /dev/null
if [[ -f ${DOCKERD_LOG} ]]; then
rm ${DOCKERD_LOG}
fi
supervisorctl start dockerd > /dev/null
echo 'restarted'
else
local ctl_status=${?}
# LSBInitExitStatuses.NOT_RUNNING = 7
if [[ ${ctl_status} -eq 7 ]]; then
say_verbose "starting dockerd"
supervisord -c /etc/supervisord.conf
echo 'started'
else
say "supervisorctl exited with status ${ctl_status}"
if ! is_quiet && [[ -f ${SUPERVISORD_LOG} ]]; then
cat ${SUPERVISORD_LOG} >&2
fi
exit ${ERR_SUPERVISORD_FAILED}
fi
fi
}
move_processes_to_separate_cgroup() {
# Move processes to a separate cgroup to prevent the root cgroup from becoming
# threaded -- "Once you have a threaded controller you can not create cgroups
# below it that reference non-threaded controllers like the memory controller".
# "A domain cgroup is turned into a threaded domain when [...] threaded controllers
# are enabled in the “cgroup.subtree_control” file while there are processes
# in the cgroup."
# Fixes "cannot enter cgroupv2 "/sys/fs/cgroup/docker" with domain controllers --
# it is in threaded mode" when starting containers with resource constraints,
# see https://github.com/dstackai/dstack/issues/1854
# Based on https://github.com/moby/moby/blob/65cfcc2/hack/dind#L59 and
# https://github.com/earthly/earthly/blob/08b0d1f/buildkitd/dockerd-wrapper.sh#L63
if [[ -f /sys/fs/cgroup/cgroup.controllers ]]; then
local group=/sys/fs/cgroup/dind
mkdir -p ${group}
xargs -rn1 < /sys/fs/cgroup/cgroup.procs > ${group}/cgroup.procs || true
fi
}
wait_dockerd_started() {
local counter=1
while true; do
if grep -qs 'API listen on' ${DOCKERD_LOG}; then
return 0
fi
if [[ ${counter} -gt ${timeout} ]]; then
break
fi
say_verbose "waiting for dockerd to start (${counter}/${timeout})"
((counter++))
sleep 1
done
return 1
}
stop_dockerd_and_die() {
supervisorctl stop dockerd > /dev/null
say 'failed to start dockerd'
if ! is_quiet; then
cat ${DOCKERD_LOG} >&2
fi
exit ${ERR_DOCKERD_FAILED}
}
usage() {
echo 'usage: start-dockerd [-v|-q] [-l] [-t SECONDS]'
echo ' -v, --verbose get more output, mutually exclusive with -q'
echo ' -q, --quiet get less output, mutually exclusive with -v'
echo ' -l, --logs follow dockerd log output'
echo ' -t, --timeout SECONDS wait for dockerd to start the specified amount'
echo ' of seconds before failing with error, '
echo " ${DEFAULT_TIMEOUT} seconds by default"
}
# main
check_privileged_mode_or_die
while [[ ${#} -gt 0 ]]; do
option=${1}
shift
case ${option} in
--verbose|-v)
verbose=true
;;
--quiet|-q)
quiet=true
;;
--logs|-l)
logs=true
;;
--timeout|-t)
if [[ ${#} -eq 0 ]]; then
say "${option}: value expected"
exit ${ERR_INVALID_ARGS}
fi
timeout=${1}
shift
# single brackets are intentional, compare to:
# set -u; [[ "foo" -gt 0 ]]
# bash: foo: unbound variable
if ! [ "${timeout}" -gt 0 ] 2> /dev/null; then
say "${option}: invalid value"
exit ${ERR_INVALID_ARGS}
fi
;;
--help|-h)
usage
exit 0
;;
*)
say "${option}: invalid option"
usage
exit ${ERR_INVALID_ARGS}
;;
esac
done
if is_verbose && is_quiet; then
say '--verbose and --quiet are mutually exclusive'
exit ${ERR_INVALID_ARGS}
fi
event=$(start_restart_dockerd)
if ! wait_dockerd_started; then
stop_dockerd_and_die
fi
if [[ ${event} = 'started' ]]; then
move_processes_to_separate_cgroup
fi
if ! is_quiet; then
say "dockerd ${event}"
fi
if is_true ${logs}; then
tail -f ${DOCKERD_LOG}
fi