如何在没有 ssh 的情况下从主节点访问 k8s 工作节点?

How can i access a k8s worker node from a master node without ssh?

我想构建一个 python 脚本来访问 kubernetes 工作节点,列出网络接口并捕获所选接口的流量(例如使用 tcpdump),然后将 pcap 文件存储在主节点。

我想知道是否可以在没有 ssh 的情况下从我的主节点访问工作节点? (也许直接调用 k8s-apiserver ?) 如果 ssh 是访问工作节点的唯一方式,我如何在不输入工作人员密码(用于身份验证)的情况下建立连接。

或者也许还有其他方法可以做到这一点?

连接节点的一种方法,当 SSH 不是一个选项时,将启动一些特权容器,它将访问您的节点文件系统,禁用 pid 命名空间隔离。

假设我有一些节点“infra1”

$> kubectl get nodes
infra1     Ready         infra         728d   v1.21.6

我可以使用:

$ kubectl debug node/infra1 -it --image=busybox
Creating debugging pod node-debugger-infra1-s46g6 with container debugger on node infra1.
If you don't see a command prompt, try pressing enter.
/ #
/ # chroot /host
root@infra1:/# 
root@infra1:/# crictl ps | head -2
CONTAINER           IMAGE               CREATED             STATE               
NAME                       ATTEMPT             POD ID
a36863efe2a2e       3fb5cabb64693       4 minutes ago       Running             

/host 是一个“卷”,与该调试容器共享我的主机文件系统。使用 chroot,您现在可以在节点运行时工作。

$ k get pods 
NAME                                      READY   STATUS    RESTARTS   AGE
node-debugger-infra1-g5nwg                0/1     Error     0          71s
node-debugger-infra1-s46g6                1/1     Running   0          55s

实际上,创建一个 Pod 就完成了,如下所示:

apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubernetes.io/psp: hostaccess
  name: node-debugger-infra1-s46g6
  namespace: default
spec:
  containers:
  - image: busybox
    ...
    volumeMounts:
    - mountPath: /host
      name: host-root
      ...
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  hostIPC: true
  hostNetwork: true
  hostPID: true
  nodeName: infra1
  nodeSelector:
    kubernetes.io/os: linux
  preemptionPolicy: PreemptLowerPriority
  priority: 0
  restartPolicy: Never
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - operator: Exists
  volumes:
  - hostPath:
      path: /
      type: ""
    name: host-root
  ...

回答您的 follow-up 问题,关于 caliXXX 接口。这些是特定于 calico SDN 的,尽管相同的评论可能适用于其他实现:没有简单的方法来解析来自那些的 pods IP。

但是我们可以检查 pods 配置,找出它们使用的接口:

# crictl pods
...
b693b9ff6487c       3 hours ago         Ready               controller-6b78bff7d9-5b7vr                 metallb-system          2                   (default)

# crictl inspectp b693b9ff6487c | jq '.info.cniResult'
{
  "Interfaces": {
    "cali488d4aeb0e6": {
      "IPConfigs": null,
      "Mac": "",
      "Sandbox": ""
    },
    "eth0": {
      "IPConfigs": [
        {
          "IP": "10.233.105.55",
          "Gateway": ""
        }
      ],
      "Mac": "",
      "Sandbox": ""
    },
    "lo": {
      "IPConfigs": [
        {
          "IP": "127.0.0.1",
          "Gateway": ""
        },
        {
          "IP": "::1",
          "Gateway": ""
        }
      ],
      "Mac": "00:00:00:00:00:00",
      "Sandbox": "/var/run/netns/cni-55322514-e37a-2913-022a-9f7488df8ca5"
    }
  },
  "DNS": [
    {},
    {}
  ],
  "Routes": null
}

然后,解析给定 IP 的接口名称,我们可以这样:

# MATCH_IP="10\.233\.105\.55"
# crictl pods | awk '/Ready/{print }' | while read pod
    do
        crictl inspectp $pod | grep $MATCH_IP >/dev/null 2>&1 || continue
        echo found pod $pod
        crictl inspectp $pod \
           | jq '.info.cniResult.Interfaces | with_entries(select(.key|match("cali"))) | to_entries[] | .key'
        break
    done
found pod b693b9ff6487c
"cali488d4aeb0e6"