· cloud · 工具

Kubernetes调试利器Nsenter

在 k8s 云环境中,我们需要在容器内抓包进行 Debug, 但通常大多容器都没有安装 tcpdump 以及其他网络工具;在托管 k8s 中我们想登录 node,不是没权限就是步骤太麻烦。本文的主角nsenter正是很擅长解决这些问题,nsenter可以进入指定namespace的工具,一般用来在容器环境中进行调试。

调试容器网络

通过nsenter可以轻松在宿主机进入容器的网络命令空间,命令如下:

# 设置containerid
containerid=xxx
# 获取容器主进程
pid=$(docker inspect -f {{.State.Pid}} $containerid)
# 进入容器networker namespace
nsenter -n --target $pid

之后便可以使用宿主机各种工具tcpdump, netstat等命令

登录 k8s 节点

如果只有Apiserver权限,登录 k8s 节点也可以使用nsenter

临时登录某个节点可以使用如下脚本:

前提是需要拥有一些特殊权限privilededhostPID

node=xxx
cmd='[ "nsenter", "--target", "1", "--mount", "--uts", "--ipc", "--net", "--pid", "--"]'
overrides="$(
cat <<EOT
{
  "spec": {
    "nodeName": "$node",
    "hostPID": true,
    "hostNetwork": true,
    "containers": [
      {
        "securityContext": {
          "privileged": true
        },
        "image": "alpine",
        "name": "nsenter",
        "stdin": true,
        "stdinOnce": true,
        "tty": true,
        "command": $cmd
      }
    ],
    "tolerations": [
      {
        "operator": "Exists"
      }
    ]
  }
}
EOT
)"
pod="kube-nodeshell-$(env LC_ALL=C tr -dc a-z0-9 </dev/urandom | head -c 6)"
kubectl run --image=alpine --restart=Never --rm --overrides="$overrides" -it $pod

原理是通过共享 pid 方式hostPID=true,在容器中看到宿主机的所有进程,然后使用nsenter进入宿主机 1 号进程(宿主机根进程)的mount、uts、ipc、net、pid等 namespace,从而可以获取类似宿主机的 shell。

如果需要经常使用,可以部署个DaemonSet,使用时登录对应节点的 pod 即可(建议只在测试环境使用,具有一定风险)

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-nodehsell
  labels:
    app: kube-nodehsell
spec:
  selector:
    matchLabels:
      app: kube-nodehsell
  template:
    metadata:
      labels:
        app: kube-nodehsell
    spec:
      tolerations:
        - operator: 'Exists'
      containers:
        - name: kube-nodehsell
          image: alpine
          command:
            - nsenter
            - --target
            - '1'
            - --mount
            - --uts
            - --ipc
            - --net
            - --pid
            - --
            - sleep
            - infinity
          securityContext:
            privileged: true
      hostIPC: true
      hostPID: true
      hostNetwork: true
      priorityClassName: system-node-critical

本文所有文件见kube-nodeshell

临时容器

kubernetes 1.18 之后启用了临时容器,用户可以通过kubectl debug命令来添加临时容器到 pod,也可以登录到 node shell,一些简单的调试工作可以使用这种方法, 见调试运行中的 Pod

对比nsenter方法,kubectl debug通过 shell 登录节点时只是共享了pidhostNetworknsenter则更灵活可以使用宿主机的相关工具以及执行特权操作。

参考