简体   繁体   English

如何仅在一段时间内使用 golang 并行收集 k8s pod 日志

[英]How to collect k8s pods logs in parallel using golang only for a duration of time

I am new to golang, I have a task to collect the application logs, application is running as deployment in k8s cluster, there are 4 pods in total.我是 golang 的新手,我有一个收集应用程序日志的任务,应用程序作为部署在 k8s 集群中运行,总共有 4 个 pod。 As part of test automation, I need to collect the application logs (only for the duration of my test operation) in parallel while I perform some operations on the application and write the logs to a file, and move to the next operation and do the same.作为测试自动化的一部分,我需要在对应用程序执行一些操作并将日志写入文件的同时并行收集应用程序日志(仅在测试操作期间),然后转到下一个操作并执行相同的。

Finally I iterate through the log files one-by-one and filter for certain keywords corresponding to my operation and validate the logs are correct/not.最后,我一个一个地遍历日志文件,过滤与我的操作相对应的某些关键字,并验证日志是否正确。


I am thinking to get the pod logs using kubectl command directly, instead of using the go-sdk as I am facing missing log entries which I couldn't triage with many attempts.我正在考虑直接使用 kubectl 命令获取 pod 日志,而不是使用 go-sdk,因为我面临丢失的日志条目,我无法通过多次尝试对其进行分类。

kubectl logs -f -l app=my-app -n dev > /usr/mylogs.txt

I found a way to run this command using exec.Command我找到了一种使用 exec.Command 运行此命令的方法

command := exec.Command("/bin/sh", "-c", "kubectl logs -f -l app=my-app -n dev > /usr/mylogs.txt")
    err := command.Start()

Now I need to do this in golang,现在我需要在 golang 中做这个,

func myTest(t *testing.T){
  go collectApplicationLogs("test1")
  
  // do application operation 
   // run test
  
  stopLogsCollection ()   -------> how to achieve this?
}

func collectApplicationLogs(fileName string){
   // command to collect the logs to a file
  // kubectl logs -f -l app=my-app -n dev > /usr/{fileName}
}

You can use Kube.netes go-client to get logs from the pods.您可以使用 Kube.netes go-client 从 pod 获取日志。 At first create the clientset from kub.netes config.首先从 kub.netes 配置创建客户端。 You can use InclusterConfig or Out of cluster config.您可以使用 InclusterConfig 或集群外配置。 I have used out of cluster config here.我在这里使用了集群配置。

const (
    // set namespace and label
    namespace = "dev"
    label     = "app=my-app"
)

func main() {
    // parse the .kubeconfig file
    var kubeconfig *string
    if home := homedir.HomeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    flag.Parse()

    // use the current context in kubeconfig
    ctx := context.TODO()
    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        log.Println(err, "Failed to build config from flags")
        return
    }

    err = collectApplicationLogs(ctx, config, "/usr/mylogs.txt")
    if err != nil {
        log.Println(err, "Failed to collect logs")
    }

}

To collect logs, you need to list the gods first.收集日志,需要先列大神。 Then get logs from each of those pods and append them to the file concurrently.然后从每个 pod 中获取日志并将它们 append 同时写入文件。

func collectApplicationLogs(ctx context.Context, config *rest.Config, filename string) error {
    // create the clientset
    clientSet, err := kubernetes.NewForConfig(config)
    if err != nil {
        log.Println("Failed to create clientset from the given config")
        return err
    }
    // get the pods as ListItems
    pods, err := clientSet.CoreV1().Pods(namespace).List(ctx, metav1.ListOptions{
        LabelSelector: label,
    })
    if err != nil {
        log.Println(err, "Failed to get pods")
        return err
    }
    // If the file doesn't exist, create it or append to the file
    file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
    if err != nil {
        return err
    }
    defer file.Close()
    // get the pod lists first
    // then get the podLogs from each of the pods
    // write to files concurrently
    // use channel for blocking reasons
    ch := make(chan bool)
    podItems := pods.Items
    for i := 0; i < len(podItems); i++ {
        podLogs, err := clientSet.CoreV1().Pods(namespace).GetLogs(podItems[i].Name, &v1.PodLogOptions{
            Follow: true,
        }).Stream(ctx)
        if err != nil {
            return err
        }
        buffer := bufio.NewReader(podLogs)
        go writeLogs(buffer, file, ch)
    }
    <-ch
    return nil
}

func writeLogs(buffer *bufio.Reader, file *os.File, ch chan bool) {
    defer func() {
        ch <- true
    }()
    for {
        str, readErr := buffer.ReadString('\n')
        if readErr == io.EOF {
            break
        }
        _, err := file.Write([]byte(str))
        if err != nil {
            return
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 k8s 中复制的 pod 中拥有只执行一次的逻辑(一段代码)? - How to have a logic (piece of code) that executes only once inside pods which are replicated in k8s? 使用 Golang k8s 客户端在 GKE k8s 集群中部署服务 - Deploying services in GKE k8s cluster using Golang k8s client 如何在 k8s golang 客户端上应用 HorizontalPodAutoscalers - How to apply HorizontalPodAutoscalers with k8s golang client 如何在不杀死原始Pod的情况下改变k8s的Pod倾斜度? - How to change k8s's pods limts without killing the original pod? 使用 k8s rest api 从特定节点获取 Pod - Get Pods from a Particular node using k8s rest api k8s 使用 ownerRef 获取集群中的所有 pod 层次结构 - k8s get all pods hierarchy in cluster with ownerRef's k8s中如何获取StatefulSet的最新变化时间 - How to get the latest change time of StatefulSet in k8s 通过操作员框架对K8s Pod进行负载平衡 - Load balancing K8s Pods with operator-framework 使用 Kubernetes 集群 k8s 中的 SRV 记录在 Golang 中通过 DNS 实现对等发现逻辑 - implement peer discovery logic through DNS in Golang using SRV records in Kubernetes cluster k8s golang k8s 客户端中的 Pod 重新部署触发器 - Pod redeploy trigger in golang k8s client
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM