如何DEBUG一个正在运行的POD

参考文档
https://kubernetes.io/zh-cn/docs/tasks/debug/debug-application/debug-running-pod/

原理
K8S会使用debug镜像在POD里起一个EphemeralContainer,和目标container共享linux namespace,但是注意他们不共享rootfs和mountfs,两者的文件系统是独立的。

想访问目标container的文件系统,需要在EphemeralContainer先cd /proc/1/root/,然后才能看到对方的文件系统,如图访问es的/tmp:

开启方法:
注:K8S1.22以下需要手动开启,1.23默认开启

step1:在master node的/etc/kubernetes/manifests/kube-apiserver.yaml

  • –feature-gates=RemoveSelfLink=false,EphemeralContainers=true

step2: 在slave node上

sed -i ‘s/“/ --feature-gates=EphemeralContainers=true”/2’ /var/lib/kubelet/kubeadm-flags.env

systemctl restart kubelet

使用命令进入交互界面:
kubectl debug -it --image= -n --target=
以测试POD为例:

kubectl debug -it function-test-testdaily-XXXX --image=harbor.tsingj.local/re_release/test_debug:v2.4.0rc14-1131-gf2d8127c0 -n chenwei1 --target=function-test
操作举例:

  1. 抓包/监控流量:网络操作必须使用root用户,用test_debug可以su root, 输入密码qwer1234.

iftop

tcpdump

2)jstack等jdk工具

镜像必须和被debug的container里的用户相同:privpy,然后镜像里的jdk最好与产品版本一致。

高权限调试方法
有些命令例如strace/ptrace需要更高系统权限,因此用上面的kubectl debug命令没用办法使用(目前kubectl debug命令还不支持设置securitycontext),所以可以使用下面的办法

方法1:起一个POD共享k8s node的namespace
Step1: 查找你需要debug的POD所在node,例如:
开发 > Debug a running pod > image2023-4-10_17-55-20.png

Step2: 使用我们的test_debug镜像在这个node上起一个pod然后exec -it进入这个pod,su root,找到你想debug的进程号再使用strace:
kubectl apply -f node_pod.yaml -n chenwei1
kubectl exec -it -n chenwei1 node-debugger – /bin/bash
su root
ps -efH | grep privpy
使用的yaml文件如下,需要改下nodeName为step1中所查得node

apiVersion: v1
kind: Pod
metadata:
  name: node-debugger
spec:
  containers:
  - image: harbor.tsingj.local/re_release/test_debug:v2.4.0rc14-1131-gf2d8127c0
    imagePullPolicy: IfNotPresent
    name: debugger
    resources: {}
    stdin: true
    tty: true
    command: [ "/bin/bash", "-c", "sleep 6000s" ]
    securityContext:
      privileged: true
      allowPrivilegeEscalation: true
    volumeMounts:
    - mountPath: /host
      name: host-root
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: kube-api-access-97p2b
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  hostIPC: true
  hostNetwork: true
  hostPID: true
  nodeName: k8sdeploy-node315
  preemptionPolicy: PreemptLowerPriority
  priority: 1
  priorityClassName: low-priority
  restartPolicy: Never
  schedulerName: default-scheduler
  securityContext: {}
  serviceAccount: default
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - hostPath:
      path: /
      type: ""
    name: host-root
  - name: kube-api-access-97p2b
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace

方法2: 由于kubectl debug不支持加上securityContext,可以使用go 脚本来加上securityContext,代码如下,但是还没有调通,可能是目前的k8s版本还不支持。

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
)

func main() {
    logger := log.New(os.Stdout, "[Debug] - ", log.Lshortfile)
    if len(os.Args) != 4 {
       panic("expected three args")
    }
    podNamespace := os.Args[1]
    podName := os.Args[2]
    kubeconfigPath := os.Args[3]

    // Create the client
    client, err := getKubernetesClients(kubeconfigPath)
    if err != nil {
       panic(fmt.Errorf("could not create client: %w", err))
    }
    ctx := context.Background()

    // Get the Pod
    pod, err := client.CoreV1().Pods(podNamespace).Get(ctx, podName, metav1.GetOptions{})
    logger.Println(pod.Name)
    logger.Println(pod.Spec)

    if err != nil {
       panic(fmt.Errorf("could not get pod: %w", err))
    }

    // Add a new ephemeral container
    trueValue := true
    ephemeralContainer := corev1.EphemeralContainer{
       TargetContainerName: "demo",
       EphemeralContainerCommon: corev1.EphemeralContainerCommon{
          Name:  "debug",
          Image: "quay.io/iovisor/bpftrace:latest",
          TTY:   true,
          SecurityContext: &corev1.SecurityContext{
             Privileged:               &trueValue,
             AllowPrivilegeEscalation: &trueValue,
          },
       },
    }
    pod.Spec.EphemeralContainers = append(pod.Spec.EphemeralContainers, ephemeralContainer)

    pod, err = client.CoreV1().Pods(pod.Namespace).UpdateEphemeralContainers(ctx, pod.Name, pod, metav1.UpdateOptions{})
    if err != nil {
       panic(fmt.Errorf("could not add ephemeral container: %w", err))
    }
}

func getKubernetesClients(path string) (kubernetes.Interface, error) {
    cfg, err := clientcmd.BuildConfigFromFlags("", path)
    if err != nil {
       return nil, err
    }
    client, err := kubernetes.NewForConfig(cfg)
    if err != nil {
       return nil, err
    }
    return client, nil
}
  • 25
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值