-
Notifications
You must be signed in to change notification settings - Fork 75
/
kubectl-ssh
executable file
·146 lines (133 loc) · 3.37 KB
/
kubectl-ssh
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
#!/usr/bin/env bash
set -e
ssh_node() {
node=$1
image=${KUBECTL_SSH_IMAGE:-busybox}
shift
if [ "$node" = "" ]; then
node=$(kubectl get node -o name "$@" | sed 's/node\///' | tr '\n' ' ')
node=${node::-1}
if [[ "$node" =~ " " ]]; then
echo "Node name must be specified. Choose one of: [$node]"
exit 1
else
echo "Single-node cluster detected. Defaulting to node $node"
fi
fi
if [ $# -eq 1 ]; then
command="$1"
shift
fi
ns=default
pod=$(
kubectl create -n "$ns" -o name "$@" -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
generateName: ssh-node-
labels:
plugin: ssh-node
spec:
nodeName: $node
containers:
- name: ssh-node
image: $image
imagePullPolicy: IfNotPresent
command: ["chroot", "/host"]
tty: true
stdin: true
stdinOnce: true
securityContext:
privileged: true
volumeMounts:
- name: host
mountPath: /host
volumes:
- name: host
hostPath:
path: /
hostNetwork: true
hostIPC: true
hostPID: true
restartPolicy: Never
tolerations:
- operator: "Exists"
EOF
)
deletePod() {
kubectl delete -n "$ns" "$pod" "$@" --wait=false
}
trap deletePod EXIT
echo "Created $pod"
echo "Waiting for container to start..."
kubectl wait -n "$ns" --for=condition=Ready --timeout 120s "$pod" "$@" >/dev/null
if [ -z "$command" ]; then
kubectl attach -n "$ns" -it "$pod" -c ssh-node "$@"
else
kubectl exec -n "$ns" -it "$pod" ssh-node -- "$command"
fi
}
ssh_pod() {
# TODO: improve this
if [ "$1" == "" ]; then
echo "Pod name must be specified."
exit 1
fi
# Use sh as a default and switch to bash if it's available
# shellcheck disable=SC2016
kubectl exec -it "$@" -- sh -c 'exec "$( command -v bash || echo sh )"'
}
print_usage() {
echo "Provider-agnostic way of opening a remote shell to a Kubernetes node."
echo
echo "Enables you to access a node even when it doesn't run an SSH server or"
echo "when you don't have the required credentials. Also, the way you log in"
echo "is always the same, regardless of what provides the Kubernetes cluster"
echo "(e.g. Minikube, Kind, Docker Desktop, GKE, AKS, EKS, ...)"
echo
echo "You must have cluster-admin rights to use this plugin."
echo
echo "The primary focus of this plugin is to provide access to nodes, but it"
echo "also provides a quick way of running a shell inside a pod."
echo
echo "Examples: "
echo " # Open a shell to node of a single-node cluster (e.g. Docker Desktop)"
echo " kubectl ssh node"
echo
echo " # Open a shell to node of a multi-node cluster (e.g. GKE)"
echo " kubectl ssh node my-worker-node-1"
echo
echo " # Execute the command ls on a node my-worker-node-1"
echo " kubectl ssh node my-worker-node-1 ls"
echo
echo " # Open a shell to a pod"
echo " kubectl ssh pod my-pod"
echo
echo "Usage:"
echo " kubectl ssh node [nodeName [command]]"
echo " kubectl ssh pod [podName] [-n namespace] [-c container]"
exit 0
}
if [ "$1" == "--help" ]; then
print_usage
fi
if [[ "$1" == node/* ]]; then
nodeName=${1:5}
shift
ssh_node "$nodeName" "$@"
elif [ "$1" == "node" ]; then
shift
case "$1" in
-*) nodeName="";;
"") ;;
*) nodeName="$1"; shift ;;
esac
ssh_node "$nodeName" "$@"
elif [[ "$1" == pod/* ]]; then
ssh_pod "$@"
elif [ "$1" == "pod" ]; then
shift
ssh_pod "$@"
else
print_usage
fi