简体   繁体   English

如何使用 Go 从 kube.netes 获取日志?

[英]How to get logs from kubernetes using Go?

I'm looking for the solution of how to get logs from a pod in Kube.netes cluster using Go. I've looked at "https://github.com/kube.netes/client-go" and "https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client", but couldn't understand how to use them for this purpose.我正在寻找如何使用 Go 从 Kube.netes 集群中的 pod 获取日志的解决方案。我查看了“https://github.com/kube.netes/client-go”和“https:/ /godoc.org/sigs.k8s.io/controller-runtime/pkg/client”,但无法理解如何将它们用于此目的。 I have no issues getting information of a pod or any other object in K8S except for logs.除了日志之外,我在 K8S 中获取 pod 或任何其他 object 的信息没有问题。

For example, I'm using Get() from "https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#example-Client--Get" to get K8S job info:例如,我使用来自“https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#example-Client--Get”的 Get() 来获取 K8S 作业信息:

found := &batchv1.Job{}
err = r.client.Get(context.TODO(), types.NamespacedName{Name: job.Name, Namespace: job.Namespace}, found)

Please share of how you get pod's logs nowadays.请分享您现在如何获取 Pod 的日志。 Any suggestions would be appreciated!任何建议,将不胜感激!

Update: The solution provided in Kube.netes go client api for log of a particular pod is out of date.更新: Kube.netes go 客户端 api 中针对特定 pod 的日志提供的解决方案已过时。 It have some tips, but it is not up to date with current libraries.它有一些提示,但不是最新的当前库。

Here is what we came up with eventually using client-go library:这是我们最终使用 client-go 库得出的结论:

func getPodLogs(pod corev1.Pod) string {
    podLogOpts := corev1.PodLogOptions{}
    config, err := rest.InClusterConfig()
    if err != nil {
        return "error in getting config"
    }
    // creates the clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        return "error in getting access to K8S"
    }
    req := clientset.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, &podLogOpts)
    podLogs, err := req.Stream()
    if err != nil {
        return "error in opening stream"
    }
    defer podLogs.Close()

    buf := new(bytes.Buffer)
    _, err = io.Copy(buf, podLogs)
    if err != nil {
        return "error in copy information from podLogs to buf"
    }
    str := buf.String()

    return str
}

I hope it will help someone.我希望它会帮助某人。 Please share your thoughts or solutions of how you get logs from pods in Kubernetes.请分享您对如何从 Kubernetes 中的 pod 获取日志的想法或解决方案。

And if you want read stream in client-go v11.0.0+ , the code is like this, feel free for create clientset by yourself:如果你想在client-go v11.0.0+读取流,代码是这样的,你可以自己创建client-go v11.0.0+

func GetPodLogs(namespace string, podName string, containerName string, follow bool) error {
    count := int64(100)
    podLogOptions := v1.PodLogOptions{
        Container: containerName,
        Follow:    follow,
        TailLines: &count,
    }

    podLogRequest := clientSet.CoreV1().
        Pods(namespace).
        GetLogs(podName, &podLogOptions)
    stream, err := podLogRequest.Stream(context.TODO())
    if err != nil {
        return err
    }
    defer stream.Close()

    for {
        buf := make([]byte, 2000)
        numBytes, err := stream.Read(buf)
        if numBytes == 0 {
            continue
        }
        if err == io.EOF {
            break
        }
        if err != nil {
            return err
        }
        message := string(buf[:numBytes])
        fmt.Print(message)
    }
    return nil
}

控制器运行时客户端库尚不支持 /status 以外的子资源,因此您必须使用 client-go,如另一个问题所示。

The answer by anon_coword got me interested, in getting logs in a bit more complicated case: anon_coword 的回答让我感兴趣,在更复杂的情况下获取日志:

  1. I want to preform the action multiple times, and check the logs multiple times.我想多次执行操作,并多次检查日志。
  2. I want to have many pods that will react the same way.我想要有许多会以相同方式做出反应的豆荚。

Here are a few examples: https://github.com/nwaizer/GetPodLogsEfficiently One example is:这里有几个例子: https://github.com/nwaizer/GetPodLogsEfficiently一个例子是:

package main

import (
    "GetPodLogsEfficiently/client"
    "GetPodLogsEfficiently/utils"
    "bufio"
    "context"
    "fmt"
    corev1 "k8s.io/api/core/v1"
    "time"
)

func GetPodLogs(cancelCtx context.Context, PodName string) {
    PodLogsConnection := client.Client.Pods(utils.Namespace).GetLogs(PodName, &corev1.PodLogOptions{
        Follow:    true,
        TailLines: &[]int64{int64(10)}[0],
    })
    LogStream, _ := PodLogsConnection.Stream(context.Background())
    defer LogStream.Close()

    reader := bufio.NewScanner(LogStream)
    var line string
    for {
        select {
        case <-cancelCtx.Done():
            break
        default:
            for reader.Scan() {
                line = reader.Text()
                fmt.Printf("Pod: %v line: %v\n", PodName, line)
            }
        }
    }
}
func main() {
    ctx := context.Background()
    cancelCtx, endGofunc := context.WithCancel(ctx)
    for _, pod := range utils.GetPods().Items {
        fmt.Println(pod.Name)
        go GetPodLogs(cancelCtx, pod.Name)
    }
    time.Sleep(10 * time.Second)
    endGofunc()
}

Combining some answers found elsewhere and here to stream (tailing) logs for all containers (init included):结合在其他地方和此处找到的一些答案,为所有容器(包括 init)流式传输(拖尾)日志:

func GetPodLogs(namespace string, podName string) {
    pod, err := clientSet.CoreV1().Pods(namespace).Get(ctx, podName, metav1.GetOptions{})
    if err != nil {
        return err
    }
    wg := &sync.WaitGroup{}
    functionList := []func(){}
    for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) {
        podLogOpts := v1.PodLogOptions{}
        podLogOpts.Follow = true
        podLogOpts.TailLines = &[]int64{int64(100)}[0]
        podLogOpts.Container = container.Name
        podLogs, err := clientSet.CoreV1().Pods(namespace).GetLogs(podName, &podLogOpts).Stream(ctx)
        if err != nil {
            return err
        }
        defer podLogs.Close()
        functionList = append(functionList, func() {
            defer wg.Done()
            reader := bufio.NewScanner(podLogs)
            for reader.Scan() {
                select {
                case <-ctx.Done():
                    return
                default:
                    line := reader.Text()
                    fmt.Println(worker+"/"+podLogOpts.Container, line)
                }
            }
            log.Printf("INFO log EOF " + reader.Err().Error() + ": " + worker + "/" + podLogOpts.Container)
        })
    }

    wg.Add(len(functionList))
    for _, f := range functionList {
        go f()
    }
    wg.Wait()
    return nil
}

My env has RBAC, I had to add the following role to enable your code. 我的环境有RBAC,我必须添加以下角色来启用您的代码。 Thanks, it works great! 谢谢,效果很好!

  • apiGroups: apiGroups:
    • "" resources: “”资源:
    • pods/log verbs: 广告连播/日志动词:
    • '*' '*'

@Emixam23 @Emixam23

I believe you will find this snippet useful.我相信你会发现这个片段很有用。

How to get the dynamic name of a pod?如何获取pod的动态名称?

import  metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

    labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{<LABEL_KEY>: <LABEL_VALUE>}}
    listOptions := metav1.ListOptions{
        LabelSelector: labels.Set(labelSelector.MatchLabels).String(),
    }
    pod, err := k8sClient.CoreV1().Pods(<NAMESPACE>).List(listOptions)
    podName := pod.Items[0].ObjectMeta.Name

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

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