使用golang监控K8S的Pod的CPU

### 概述
在Kubernetes(简称K8S)集群中,我们经常需要对运行的Pod进行监控,尤其是对它们的CPU使用情况进行监控。本文将介绍如何使用Golang编程语言监控K8S的Pod的CPU使用情况。

### 流程概览
下面是实现这个功能的整个流程概览:

| 步骤 | 操作 |
|------|------|
| 步骤一 | 连接K8S集群 |
| 步骤二 | 获取Pod列表 |
| 步骤三 | 遍历Pod列表,获取每个Pod的CPU使用情况 |

### 代码实现
下面是每一步的具体代码实现。

#### 步骤一:连接K8S集群
首先,我们需要连接到K8S集群。可以使用官方提供的client-go库来实现这一步。以下是实现该步骤的代码:

```golang
import (
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)

func ConnectToKubernetes() (*kubernetes.Clientset, error) {
// 使用default的kubeconfig路径,你也可以根据实际情况指定其他路径
config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
if err != nil {
return nil, err
}

// 创建一个kubernetes clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}

return clientset, nil
}
```

#### 步骤二:获取Pod列表
接下来,我们需要获取K8S集群中运行的所有Pod的列表。以下是实现该步骤的代码:

```golang
import (
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/watch"
)

func GetPods(clientset *kubernetes.Clientset) ([]corev1.Pod, error) {
// 创建一个Watcher来监视Pod的变化
watcher, err := clientset.CoreV1().Pods("").Watch(metav1.ListOptions{
FieldSelector: fields.OneTermEqualSelector("status.phase", string(corev1.PodRunning)).String(),
})
if err != nil {
return nil, err
}

pods := []corev1.Pod{}
for event := range watcher.ResultChan() {
switch event.Type {
case watch.Added:
pod := event.Object.(*corev1.Pod)
pods = append(pods, *pod)
case watch.Modified:
pod := event.Object.(*corev1.Pod)
pods = updatePod(pods, *pod) // 更新已有的Pod
case watch.Deleted:
pod := event.Object.(*corev1.Pod)
pods = deletePod(pods, *pod) // 从列表中删除Pod
}
}

return pods, nil
}

func updatePod(pods []corev1.Pod, pod corev1.Pod) []corev1.Pod {
// 更新存在的Pod
for i, p := range pods {
if p.Name == pod.Name {
pods[i] = pod
return pods
}
}

// 如果Pod不存在,则添加到列表中
pods = append(pods, pod)
return pods
}

func deletePod(pods []corev1.Pod, pod corev1.Pod) []corev1.Pod {
// 从列表中删除Pod
for i, p := range pods {
if p.Name == pod.Name {
pods = append(pods[:i], pods[i+1:]...)
return pods
}
}

return pods
}
```

#### 步骤三:遍历Pod列表,获取每个Pod的CPU使用情况
最后,我们需要遍历获取到的Pod列表,并获取每个Pod的CPU使用情况。以下是实现该步骤的代码:

```golang
import (
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
)

func GetPodCPUMetrics(clientset *kubernetes.Clientset, pods []corev1.Pod) error {
for _, pod := range pods {
// 获取Pod的CPU使用情况
podMetrics, err := clientset.MetricsV1beta1().PodMetricses(pod.Namespace).Get(pod.Name, metav1.GetOptions{})
if err != nil {
return err
}

for _, container := range podMetrics.Containers {
cpuUsage := container.Usage[corev1.ResourceCPU]
fmt.Printf("Pod: %s, Container: %s, CPU Usage: %s\n", pod.Name, container.Name, cpuUsage.String())
}
}

return nil
}
```

### 完整示例
下面是完整的示例代码,展示了如何连接K8S集群并获取每个Pod的CPU使用情况:

```golang
package main

import (
"fmt"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"os"
"path/filepath"
)

func main() {
clientset, err := ConnectToKubernetes()
if err != nil {
fmt.Printf("Failed to connect to Kubernetes: %v\n", err)
os.Exit(1)
}

pods, err := GetPods(clientset)
if err != nil {
fmt.Printf("Failed to get pods: %v\n", err)
os.Exit(1)
}

err = GetPodCPUMetrics(clientset, pods)
if err != nil {
fmt.Printf("Failed to get pod CPU metrics: %v\n", err)
os.Exit(1)
}
}

// 连接K8S集群
func ConnectToKubernetes() (*kubernetes.Clientset, error) {
// 使用default的kubeconfig路径
home := homeDir()
kubeconfig := filepath.Join(home, ".kube", "config")

// 根据kubeconfig文件获取到config
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
return nil, err
}

// 创建一个kubernetes clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}

return clientset, nil
}

func homeDir() string {
if h := os.Getenv("HOME"); h != "" {
return h
}
return os.Getenv("USERPROFILE") // for Windows
}

// 获取Pod列表
func GetPods(clientset *kubernetes.Clientset) ([]corev1.Pod, error) {
// 创建一个Watcher来监视Pod的变化
watcher, err := clientset.CoreV1().Pods("").Watch(metav1.ListOptions{
FieldSelector: fields.OneTermEqualSelector("status.phase", string(corev1.PodRunning)).String(),
})
if err != nil {
return nil, err
}

pods := []corev1.Pod{}
for event := range watcher.ResultChan() {
switch event.Type {
case watch.Added:
pod := event.Object.(*corev1.Pod)
pods = append(pods, *pod)
case watch.Modified:
pod := event.Object.(*corev1.Pod)
pods = updatePod(pods, *pod)
case watch.Deleted:
pod := event.Object.(*corev1.Pod)
pods = deletePod(pods, *pod)
}
}

return pods, nil
}

func updatePod(pods []corev1.Pod, pod corev1.Pod) []corev1.Pod {
for i, p := range pods {
if p.Name == pod.Name {
pods[i] = pod
return pods
}
}

pods = append(pods, pod)
return pods
}

func deletePod(pods []corev1.Pod, pod corev1.Pod) []corev1.Pod {
for i, p := range pods {
if p.Name == pod.Name {
pods = append(pods[:i], pods[i+1:]...)
return pods
}
}

return pods
}

// 获取Pod的CPU使用情况
func GetPodCPUMetrics(clientset *kubernetes.Clientset, pods []corev1.Pod) error {
for _, pod := range pods {
podMetrics, err := clientset.MetricsV1beta1().PodMetricses(pod.Namespace).Get(pod.Name, metav1.GetOptions{})
if err != nil {
return err
}

for _, container := range podMetrics.Containers {
cpuUsage := container.Usage[corev1.ResourceCPU]
fmt.Printf("Pod: %s, Container: %s, CPU Usage: %s\n", pod.Name, container.Name, cpuUsage.String())
}
}

return nil
}
```

### 总结
通过上述代码示例,我们学习了如何使用Golang监控K8S的Pod的CPU使用情况。首先我们连接到K8S集群,然后获取Pod列表,并遍历列表获取每个Pod的CPU使用情况。这样,我们就可以实时监控K8S集群中Pod的CPU使用情况了。希望这篇文章能够对你理解如何使用Golang来监控K8S集群中的Pod的CPU有所帮助。