通过pod登录k8s节点

分享一个连接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..."
  • 作用:输出使用说明文档,解释脚本的功能和示例。

关键设计总结

  1. 节点访问机制

    • 通过创建特权 Pod 并挂载宿主机的根目录,绕过 SSH 直接访问节点。
    • 使用 chroot /host 让容器进程直接操作节点的文件系统。
  2. 多节点集群处理

    • 自动检测单节点集群,多节点需显式指定节点名。
  3. 安全性

    • 依赖 Kubernetes RBAC 控制,需 cluster-admin 权限。
    • 特权 Pod 可能带来安全风险,需谨慎使用。
  4. 兼容性

    • 通过回退到 sh 处理容器中无 bash 的情况。

完整流程示例

  1. 连接到节点

    kubectl ssh node my-node
    
    • 创建临时 Pod → 等待就绪 → 附加到 Pod → 退出时删除 Pod。
  2. 连接到容器

    kubectl ssh pod my-pod -n my-namespace
    
    • 直接调用 kubectl exec,优先使用 bash,失败后使用 sh

此脚本提供了一种云环境无关的 Kubernetes 调试方式,但需注意其权限和安全影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值