繁体   English   中英

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

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

我是 golang 的新手,我有一个收集应用程序日志的任务,应用程序作为部署在 k8s 集群中运行,总共有 4 个 pod。 作为测试自动化的一部分,我需要在对应用程序执行一些操作并将日志写入文件的同时并行收集应用程序日志(仅在测试操作期间),然后转到下一个操作并执行相同的。

最后,我一个一个地遍历日志文件,过滤与我的操作相对应的某些关键字,并验证日志是否正确。


我正在考虑直接使用 kubectl 命令获取 pod 日志,而不是使用 go-sdk,因为我面临丢失的日志条目,我无法通过多次尝试对其进行分类。

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

我找到了一种使用 exec.Command 运行此命令的方法

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

现在我需要在 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}
}

您可以使用 Kube.netes go-client 从 pod 获取日志。 首先从 kub.netes 配置创建客户端。 您可以使用 InclusterConfig 或集群外配置。 我在这里使用了集群配置。

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")
    }

}

收集日志,需要先列大神。 然后从每个 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM