英文:
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")
// 执行应用程序操作
// 运行测试
stopLogsCollection () -------> 如何实现这一点?
}
func collectApplicationLogs(fileName string){
// 收集日志到文件的命令
// kubectl logs -f -l app=my-app -n dev > /usr/{fileName}
}
英文:
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.
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 logs -f -l app=my-app -n dev > /usr/mylogs.txt
I found a way to run this command using 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,
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}
}
答案1
得分: 4
你可以使用Kubernetes go-client从Pod中获取日志。首先从Kubernetes配置中创建clientset。你可以使用InclusterConfig或Out of cluster config。这里我使用的是Out of cluster config。
const (
// 设置命名空间和标签
namespace = "dev"
label = "app=my-app"
)
func main() {
// 解析.kubeconfig文件
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()
// 使用当前上下文的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")
}
}
要收集日志,首先需要列出Pods。然后并发地从每个Pod获取日志,并将其追加到文件中。
func collectApplicationLogs(ctx context.Context, config *rest.Config, filename string) error {
// 创建clientset
clientSet, err := kubernetes.NewForConfig(config)
if err != nil {
log.Println("Failed to create clientset from the given config")
return err
}
// 获取Pods作为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
}
// 如果文件不存在,则创建文件或追加到文件
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
return err
}
defer file.Close()
// 首先获取Pod列表
// 然后从每个Pod获取PodLogs
// 并发地写入文件
// 使用通道进行阻塞
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
}
}
}
英文:
You can use Kubernetes go-client to get logs from the pods. At first create the clientset from kubenetes config. You can use InclusterConfig or Out of cluster config. 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.
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
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论