分享一个连接k8snode节点的脚本,github大佬写的
原理就是利用容器特权用户和hostpath来实现的
#!/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
以下(deepseek生成)是对脚本中每条命令的逐行详细解释:
1. 脚本初始设置
#!/usr/bin/env bash
- 作用:指定使用 Bash 解释器执行此脚本。
set -e
- 作用:开启“错误即退出”模式,任何命令执行失败(返回非零状态码)时立即终止脚本。
2. ssh_node()
函数
参数处理与节点选择
node=$1
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
- 关键命令:
kubectl get node -o name
:获取所有节点的名称(格式为node/<NAME>
)。sed 's/node\///'
:删除node/
前缀,仅保留节点名。tr '\n' ' '
:将换行符替换为空格,合并节点名为一行。node=${node::-1}
:删除最后一个字符(多余的空格)。[[ "$node" =~ " " ]]
:检查节点名是否包含空格,判断是否为多节点集群。
创建临时 Pod
pod=$(
kubectl create -o name -f - <<EOF
...
EOF
)
- 关键命令:
kubectl create -o name -f -
:从标准输入(-
)读取 YAML 并创建资源,返回资源名称(如pod/ssh-node-xxxx
)。- YAML 配置详解:
command: ["chroot", "/host"] # 切换到宿主机的根文件系统 securityContext: privileged # 赋予特权权限(类似 root) volumeMounts: /host # 挂载宿主机的根目录到容器内 hostNetwork/IPC/PID: true # 共享节点的网络、IPC 和 PID 命名空间
Pod 清理逻辑
deletePod() {
kubectl delete $pod --wait=false
}
trap deletePod EXIT
- 关键命令:
trap deletePod EXIT
:注册deletePod
函数,在脚本退出(无论正常或异常)时调用。kubectl delete --wait=false
:异步删除 Pod,避免阻塞脚本退出。
等待 Pod 就绪并连接
kubectl wait --for=condition=Ready $pod >/dev/null
kubectl attach -it $pod -c ssh-node
- 关键命令:
kubectl wait
:阻塞直到 Pod 状态为Ready
。kubectl attach -it
:附加到容器的标准输入/输出,进入交互式会话。
3. ssh_pod()
函数
kubectl exec -it "$@" bash || (
echo "Running bash in pod failed; trying with sh"
kubectl exec -it "$@" sh
)
- 关键命令:
kubectl exec -it "$@" bash
:在 Pod 中执行bash
。||
:如果bash
失败(如容器中无bash
),尝试执行sh
。
4. 参数解析与分发
if [[ "$1" == node/* ]]; then
ssh_node ${1:5}
elif [ "$1" == "node" ]; then
ssh_node $2
elif [[ "$1" == pod/* ]]; then
ssh_pod "$@"
elif [ "$1" == "pod" ]; then
shift
ssh_pod "$@"
else
print_usage
fi
- 关键逻辑:
node/<NAME>
或pod/<NAME>
格式直接提取名称。shift
:移除第一个参数(pod
),将剩余参数传递给ssh_pod
。
5. 辅助函数 print_usage()
echo "Provider-agnostic way of opening a remote shell..."
- 作用:输出使用说明文档,解释脚本的功能和示例。
关键设计总结
-
节点访问机制:
- 通过创建特权 Pod 并挂载宿主机的根目录,绕过 SSH 直接访问节点。
- 使用
chroot /host
让容器进程直接操作节点的文件系统。
-
多节点集群处理:
- 自动检测单节点集群,多节点需显式指定节点名。
-
安全性:
- 依赖 Kubernetes RBAC 控制,需
cluster-admin
权限。 - 特权 Pod 可能带来安全风险,需谨慎使用。
- 依赖 Kubernetes RBAC 控制,需
-
兼容性:
- 通过回退到
sh
处理容器中无bash
的情况。
- 通过回退到
完整流程示例
-
连接到节点:
kubectl ssh node my-node
- 创建临时 Pod → 等待就绪 → 附加到 Pod → 退出时删除 Pod。
-
连接到容器:
kubectl ssh pod my-pod -n my-namespace
- 直接调用
kubectl exec
,优先使用bash
,失败后使用sh
。
- 直接调用
此脚本提供了一种云环境无关的 Kubernetes 调试方式,但需注意其权限和安全影响。