-
Notifications
You must be signed in to change notification settings - Fork 11
/
node-restart.sh
executable file
·229 lines (216 loc) · 6.15 KB
/
node-restart.sh
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
#!/usr/bin/env bash
image='alpine:3.15'
nodesleep=20 #Time delay between node restarts - give pods time to start up
restartdeadline=300
kubeletdeadline=300
uncordondelay=0
force=false
dryrun=false
blue='\033[0;34m'
nocolor='\033[0m'
rebootcommand='touch /node-restart-flag && reboot'
function print_usage() {
echo "Usage: kubectl node-restart [<options>]"
echo ""
echo " all Restarts all nodes within the cluster"
echo ""
echo " --context context Specify the context (or use kubectx)"
echo " -l|--selector key=value Selector (label query) to target specific nodes"
echo " -f|--force Restart node(s) without first draining"
echo " -d|--dry-run Just print what to do; don't actually do it"
echo " -s|--sleep Sleep delay between restarting Nodes (default 20s)"
echo " -r|--registry Pull Alpine image from an alternate registry"
echo " -c|--command Pre-restart command to be executed"
echo " -ud|--uncordon-delay Sleep delay before uncordoning a node (default 0s)"
echo " -rd|--restart-deadline Deadline for the restart job to complete (default 300s)"
echo " -kd|--kubelet-deadline Deadling for kubelet to start up (default 300s)"
echo " -h|--help Print usage and exit"
}
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
all)
allnodes=true
shift
;;
--context)
cluster="$2"
echo -e "${blue}Targeting cluster $cluster${nocolor}"
context="--context $cluster"
shift
shift
;;
-l | --selector)
selector="$2"
shift
shift
;;
-f | --force)
force=true
shift
;;
-d | --dry-run)
dryrun=true
shift
;;
-s | --sleep)
nodesleep="$2"
shift
shift
;;
-r | --registry)
image="$2"
shift
shift
;;
-c | --command)
rebootcommand="$2 && touch /node-restart-flag && reboot"
shift
shift
;;
-ud | --uncordon-delay)
uncordondelay="$2"
shift
shift
;;
-rd | --restart-deadline)
restartdeadline="$2"
shift
shift
;;
-kd | --kubelet-deadline)
kubeletdeadline="$2"
shift
shift
;;
-h | --help)
print_usage
exit 0
;;
*)
print_usage
exit 1
;;
esac
done
function wait_for_job_completion() {
pod=$1
i=0
while [[ $i -lt $restartdeadline ]]; do
status=$(kubectl get job $pod -n kube-system -o "jsonpath={.status.succeeded}" $context 2> /dev/null)
if [[ $status -gt 0 ]]; then
echo "Restart complete after $i seconds"
break
else
i=$(($i + 10))
sleep 10
echo "$node - $i seconds"
fi
done
if [[ $i == $restartdeadline ]]; then
echo "Error: Restart job did not complete within $restartdeadline seconds"
exit 1
fi
}
function wait_for_status() {
node=$1
i=0
while [[ $i -lt $kubeletdeadline ]]; do
status=$(kubectl get node $node -o "jsonpath={.status.conditions[?(.reason==\"KubeletReady\")].type}" $context 2> /dev/null)
if [[ "$status" == "Ready" ]]; then
echo "KubeletReady after $i seconds"
break
else
i=$(($i + 10))
sleep 10
echo "$node NotReady - waited $i seconds"
fi
done
if [[ $i == $kubeletdeadline ]]; then
echo "Error: Did not reach KubeletReady state within $kubeletdeadline seconds"
exit 1
fi
}
if [ "$allnodes" == "true" ]; then
nodes=$(kubectl get nodes -o jsonpath={.items[*].metadata.name} $context)
echo -e "${blue}Targeting nodes:${nocolor}"
for node in $nodes; do
echo " $node"
done
elif [ ! -z "$selector" ]; then
nodes=$(kubectl get nodes --selector=$selector -o jsonpath={.items[*].metadata.name} $context)
echo -e "${blue}Targeting selective nodes:${nocolor}"
for node in $nodes; do
echo " $node"
done
else
print_usage
fi
for node in $nodes; do
if $force; then
echo -e "\nWARNING: --force specified, restarting node $node without draining first"
if $dryrun; then
echo "kubectl cordon $node $context"
else
kubectl $context cordon "$node"
fi
else
echo -e "\n${blue}Draining node $node...${nocolor}"
if $dryrun; then
echo "kubectl drain $node --ignore-daemonsets --delete-emptydir-data --force $context"
else
kubectl drain "$node" --ignore-daemonsets --delete-emptydir-data --force $context
fi
fi
echo -e "${blue}Initiating node restart job on $node...${nocolor}"
pod="node-restart-$(env LC_CTYPE=C LC_ALL=C tr -dc a-z0-9 < /dev/urandom | head -c 5)"
if $dryrun; then
echo "kubectl create job $pod $context"
else
kubectl apply $context -f- << EOT
apiVersion: batch/v1
kind: Job
metadata:
name: $pod
namespace: kube-system
spec:
backoffLimit: 3
ttlSecondsAfterFinished: 30
template:
spec:
nodeName: $node
hostPID: true
tolerations:
- effect: NoSchedule
operator: Exists
containers:
- name: $pod
image: $image
command: [ "nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--pid", "--", "bash", "-c" ]
args: [ "if [ -f /node-restart-flag ]; then rm /node-restart-flag && exit 0; else $rebootcommand && exit 1; fi" ]
securityContext:
privileged: true
restartPolicy: Never
EOT
fi
if ! $dryrun; then
echo -e "${blue}Waiting for restart job to complete on node $node...${nocolor}"
wait_for_job_completion $pod
wait_for_status $node KubeletReady
else
echo "Waiting $restartdeadline seconds for restart job completion."
echo "Waiting $kubeletdeadline seconds for kubelet initialization."
fi
if [[ $uncordondelay -gt 0 ]]; then
echo "Waiting $uncordondelay seconds before uncordoning."
fi
echo -e "${blue}Uncordoning node $node${nocolor}"
if $dryrun; then
echo "kubectl uncordon $node $context"
else
sleep $uncordondelay
kubectl uncordon "$node" $context
kubectl delete job $pod -n kube-system $context
[ "$node" != "${nodes##* }" ] && sleep $nodesleep
fi
done