mirror of
https://github.com/bcicen/ctop.git
synced 2025-12-06 15:16:41 +08:00
Added draft for collector metrics of k8s
This commit is contained in:
committed by
Bradley Cicenas
parent
187adf0540
commit
7f6ff0b599
@@ -1,16 +1,21 @@
|
|||||||
package collector
|
package collector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/metrics/pkg/client/clientset_generated/clientset"
|
||||||
|
|
||||||
"github.com/bcicen/ctop/config"
|
"github.com/bcicen/ctop/config"
|
||||||
"github.com/bcicen/ctop/models"
|
"github.com/bcicen/ctop/models"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Kubernetes collector
|
// Kubernetes collector
|
||||||
type Kubernetes struct {
|
type Kubernetes struct {
|
||||||
models.Metrics
|
models.Metrics
|
||||||
name string
|
name string
|
||||||
client *kubernetes.Clientset
|
client clientset.Interface
|
||||||
|
clientset *kubernetes.Clientset
|
||||||
running bool
|
running bool
|
||||||
stream chan models.Metrics
|
stream chan models.Metrics
|
||||||
done chan bool
|
done chan bool
|
||||||
@@ -21,28 +26,33 @@ type Kubernetes struct {
|
|||||||
|
|
||||||
func NewKubernetes(client *kubernetes.Clientset, name string) *Kubernetes {
|
func NewKubernetes(client *kubernetes.Clientset, name string) *Kubernetes {
|
||||||
return &Kubernetes{
|
return &Kubernetes{
|
||||||
Metrics: models.Metrics{},
|
Metrics: models.Metrics{},
|
||||||
name: name,
|
name: name,
|
||||||
client: client,
|
client: clientset.New(client.RESTClient()),
|
||||||
scaleCpu: config.GetSwitchVal("scaleCpu"),
|
clientset: client,
|
||||||
|
scaleCpu: config.GetSwitchVal("scaleCpu"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Kubernetes) Start() {
|
func (k *Kubernetes) Start() {
|
||||||
//c.done = make(chan bool)
|
k.done = make(chan bool)
|
||||||
//c.stream = make(chan models.Metrics)
|
k.stream = make(chan models.Metrics)
|
||||||
//stats := make(chan *api.Stats)
|
|
||||||
|
|
||||||
//go func() {
|
go func() {
|
||||||
// opts := api.StatsOptions{
|
k.running = false
|
||||||
// ID: c.id,
|
for {
|
||||||
// Stats: stats,
|
|
||||||
// Stream: true,
|
cm, err := k.client.Metrics().PodMetricses("akozlenkov").List(metav1.ListOptions{})
|
||||||
// Done: c.done,
|
if err != nil {
|
||||||
// }
|
log.Errorf(">>>>>> %s here %s", k.name, err.Error())
|
||||||
// c.client.Stats(opts)
|
continue
|
||||||
// c.running = false
|
}
|
||||||
//}()
|
log.Debugf(">>>> %+v", cm)
|
||||||
|
//for _, m := range cm.Containers {
|
||||||
|
// log.Debugf(">>>> %+v", m)
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
//go func() {
|
//go func() {
|
||||||
// defer close(c.stream)
|
// defer close(c.stream)
|
||||||
@@ -56,8 +66,8 @@ func (c *Kubernetes) Start() {
|
|||||||
// log.Infof("collector stopped for container: %s", c.id)
|
// log.Infof("collector stopped for container: %s", c.id)
|
||||||
//}()
|
//}()
|
||||||
|
|
||||||
//c.running = true
|
k.running = true
|
||||||
//log.Infof("collector started for container: %s", c.id)
|
log.Infof("collector started for container: %s", k.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Kubernetes) Running() bool {
|
func (c *Kubernetes) Running() bool {
|
||||||
@@ -69,7 +79,7 @@ func (c *Kubernetes) Stream() chan models.Metrics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Kubernetes) Logs() LogCollector {
|
func (c *Kubernetes) Logs() LogCollector {
|
||||||
return NewKubernetesLogs(c.name, c.client)
|
return NewKubernetesLogs(c.name, c.clientset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop collector
|
// Stop collector
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package connector
|
package connector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/bcicen/ctop/connector/collector"
|
"github.com/bcicen/ctop/connector/collector"
|
||||||
"github.com/bcicen/ctop/connector/manager"
|
"github.com/bcicen/ctop/connector/manager"
|
||||||
@@ -59,42 +62,46 @@ func NewKubernetes() Connector {
|
|||||||
}
|
}
|
||||||
go k.Loop()
|
go k.Loop()
|
||||||
k.refreshAll()
|
k.refreshAll()
|
||||||
|
go k.watchEvents()
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k *Kubernetes) watchEvents() {
|
||||||
|
for {
|
||||||
|
log.Info("kubernetes event listener starting")
|
||||||
|
allEvents, err := k.clientset.CoreV1().Events(namespace).List(metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range allEvents.Items {
|
||||||
|
if e.Kind != "pod" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
actionName := strings.Split(e.Action, ":")[0]
|
||||||
|
|
||||||
|
switch actionName {
|
||||||
|
case "start", "die", "pause", "unpause", "health_status":
|
||||||
|
log.Debugf("handling docker event: action=%s id=%s", e.Action, e.UID)
|
||||||
|
k.needsRefresh <- e.Name
|
||||||
|
case "destroy":
|
||||||
|
log.Debugf("handling docker event: action=%s id=%s", e.Action, e.UID)
|
||||||
|
k.delByID(e.Name)
|
||||||
|
default:
|
||||||
|
log.Debugf("handling docker event: %v", e)
|
||||||
|
k.needsRefresh <- e.Name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
func (k *Kubernetes) Loop() {
|
func (k *Kubernetes) Loop() {
|
||||||
for id := range k.needsRefresh {
|
for id := range k.needsRefresh {
|
||||||
c := k.MustGet(id)
|
c := k.MustGet(id)
|
||||||
k.refresh(c)
|
k.refresh(c)
|
||||||
}
|
}
|
||||||
//log.Debug(">>>>>>1")
|
|
||||||
//for {
|
|
||||||
// log.Debug(">>>>>>2")
|
|
||||||
// pods, err := k.clientset.CoreV1().Pods("").List(metav1.ListOptions{})
|
|
||||||
// if err != nil {
|
|
||||||
// panic(err.Error())
|
|
||||||
// }
|
|
||||||
// log.Debugf("There are %d pods in the cluster\n", len(pods.Items))
|
|
||||||
|
|
||||||
// // Examples for error handling:
|
|
||||||
// // - Use helper functions like e.g. errors.IsNotFound()
|
|
||||||
// // - And/or cast to StatusError and use its properties like e.g. ErrStatus.Message
|
|
||||||
// namespace := "akozlenkov"
|
|
||||||
// pod := "example-xxxxx"
|
|
||||||
// _, err = k.clientset.CoreV1().Pods(namespace).Get(pod, metav1.GetOptions{})
|
|
||||||
// if errors.IsNotFound(err) {
|
|
||||||
// log.Debugf("Pod %s in namespace %s not found\n", pod, namespace)
|
|
||||||
// } else if statusError, isStatus := err.(*errors.StatusError); isStatus {
|
|
||||||
// log.Debugf("Error getting pod %s in namespace %s: %v\n",
|
|
||||||
// pod, namespace, statusError.ErrStatus.Message)
|
|
||||||
// } else if err != nil {
|
|
||||||
// panic(err.Error())
|
|
||||||
// } else {
|
|
||||||
// log.Debugf("Found pod %s in namespace %s\n", pod, namespace)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// time.Sleep(10 * time.Second)
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a single container, creating one anew if not existing
|
// Get a single container, creating one anew if not existing
|
||||||
@@ -123,13 +130,25 @@ func (k *Kubernetes) refresh(c *container.Container) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.SetMeta("name", insp.Name)
|
c.SetMeta("name", insp.Name)
|
||||||
c.SetMeta("image", "stub")
|
if len(insp.Spec.Containers) >= 1 {
|
||||||
c.SetMeta("IPs", "stub")
|
c.SetMeta("image", insp.Spec.Containers[0].Image)
|
||||||
c.SetMeta("ports", "stub")
|
c.SetMeta("ports", k8sPort(insp.Spec.Containers[0].Ports))
|
||||||
c.SetMeta("created", "stub")
|
for _, env := range insp.Spec.Containers[0].Env {
|
||||||
c.SetMeta("health", "stub")
|
c.SetMeta("[ENV-VAR]", env.Name+"="+env.Value)
|
||||||
c.SetMeta("[ENV-VAR]", "stub")
|
}
|
||||||
c.SetState("stub")
|
}
|
||||||
|
c.SetMeta("IPs", insp.Status.PodIP)
|
||||||
|
c.SetMeta("created", insp.CreationTimestamp.Format("Mon Jan 2 15:04:05 2006"))
|
||||||
|
c.SetMeta("health", string(insp.Status.Phase))
|
||||||
|
c.SetState("running")
|
||||||
|
}
|
||||||
|
|
||||||
|
func k8sPort(ports []v1.ContainerPort) string {
|
||||||
|
str := []string{}
|
||||||
|
for _, p := range ports {
|
||||||
|
str = append(str, fmt.Sprintf("%s:%d -> %d", p.HostIP, p.HostPort, p.ContainerPort))
|
||||||
|
}
|
||||||
|
return strings.Join(str, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *Kubernetes) inspect(id string) *v1.Pod {
|
func (k *Kubernetes) inspect(id string) *v1.Pod {
|
||||||
@@ -167,9 +186,12 @@ func (k *Kubernetes) refreshAll() {
|
|||||||
|
|
||||||
for _, pod := range allPods.Items {
|
for _, pod := range allPods.Items {
|
||||||
c := k.MustGet(pod.Name)
|
c := k.MustGet(pod.Name)
|
||||||
|
c.SetMeta("uid", string(pod.UID))
|
||||||
c.SetMeta("name", pod.Name)
|
c.SetMeta("name", pod.Name)
|
||||||
if pod.Initializers != nil && pod.Initializers.Result != nil {
|
if pod.Initializers != nil && pod.Initializers.Result != nil {
|
||||||
c.SetState(pod.Initializers.Result.Status)
|
c.SetState(pod.Initializers.Result.Status)
|
||||||
|
} else {
|
||||||
|
c.SetState(string(pod.Status.Phase))
|
||||||
}
|
}
|
||||||
k.needsRefresh <- c.Id
|
k.needsRefresh <- c.Id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,11 +67,11 @@ func (s *Status) SetHealth(val string) {
|
|||||||
color := ui.ColorDefault
|
color := ui.ColorDefault
|
||||||
|
|
||||||
switch val {
|
switch val {
|
||||||
case "healthy":
|
case "healthy", "Succeeded":
|
||||||
color = ui.ThemeAttr("status.ok")
|
color = ui.ThemeAttr("status.ok")
|
||||||
case "unhealthy":
|
case "unhealthy", "Failed", "Unknown":
|
||||||
color = ui.ThemeAttr("status.danger")
|
color = ui.ThemeAttr("status.danger")
|
||||||
case "starting":
|
case "starting", "Pending", "Running":
|
||||||
color = ui.ThemeAttr("status.warn")
|
color = ui.ThemeAttr("status.warn")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
main.go
2
main.go
@@ -36,7 +36,7 @@ func main() {
|
|||||||
|
|
||||||
// parse command line arguments
|
// parse command line arguments
|
||||||
var (
|
var (
|
||||||
versionFlag = flag.Bool("V", false, "output version information and exit")
|
versionFlag = flag.Bool("version", false, "output version information and exit")
|
||||||
helpFlag = flag.Bool("h", false, "display this help dialog")
|
helpFlag = flag.Bool("h", false, "display this help dialog")
|
||||||
filterFlag = flag.String("f", "", "filter containers")
|
filterFlag = flag.String("f", "", "filter containers")
|
||||||
activeOnlyFlag = flag.Bool("a", false, "show active containers only")
|
activeOnlyFlag = flag.Bool("a", false, "show active containers only")
|
||||||
|
|||||||
Reference in New Issue
Block a user