зеркало из https://github.com/Azure/kube-advisor.git
list by pod, add nodemetrics
This commit is contained in:
Родитель
652ebc6296
Коммит
e2dade3777
|
@ -1,12 +1,6 @@
|
||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/fatih/color"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
|
|
||||||
version = "v1.7.0"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/ghodss/yaml"
|
name = "github.com/ghodss/yaml"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
@ -67,18 +61,6 @@
|
||||||
revision = "1624edc4454b8682399def8740d46db5e4362ba4"
|
revision = "1624edc4454b8682399def8740d46db5e4362ba4"
|
||||||
version = "1.1.5"
|
version = "1.1.5"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/mattn/go-colorable"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
|
||||||
version = "v0.0.9"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/mattn/go-isatty"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
|
||||||
version = "v0.0.3"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/mattn/go-runewidth"
|
name = "github.com/mattn/go-runewidth"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
@ -172,8 +154,8 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "k8s.io/apimachinery"
|
name = "k8s.io/apimachinery"
|
||||||
packages = ["pkg/api/errors","pkg/api/meta","pkg/api/resource","pkg/apis/meta/v1","pkg/apis/meta/v1/unstructured","pkg/apis/meta/v1beta1","pkg/conversion","pkg/conversion/queryparams","pkg/fields","pkg/labels","pkg/runtime","pkg/runtime/schema","pkg/runtime/serializer","pkg/runtime/serializer/json","pkg/runtime/serializer/protobuf","pkg/runtime/serializer/recognizer","pkg/runtime/serializer/streaming","pkg/runtime/serializer/versioning","pkg/selection","pkg/types","pkg/util/clock","pkg/util/errors","pkg/util/framer","pkg/util/intstr","pkg/util/json","pkg/util/net","pkg/util/runtime","pkg/util/sets","pkg/util/validation","pkg/util/validation/field","pkg/util/wait","pkg/util/yaml","pkg/version","pkg/watch","third_party/forked/golang/reflect"]
|
packages = ["pkg/api/errors","pkg/api/meta","pkg/api/resource","pkg/apis/meta/v1","pkg/apis/meta/v1/unstructured","pkg/apis/meta/v1beta1","pkg/conversion","pkg/conversion/queryparams","pkg/fields","pkg/labels","pkg/runtime","pkg/runtime/schema","pkg/runtime/serializer","pkg/runtime/serializer/json","pkg/runtime/serializer/protobuf","pkg/runtime/serializer/recognizer","pkg/runtime/serializer/streaming","pkg/runtime/serializer/versioning","pkg/selection","pkg/types","pkg/util/clock","pkg/util/errors","pkg/util/framer","pkg/util/intstr","pkg/util/json","pkg/util/net","pkg/util/runtime","pkg/util/sets","pkg/util/validation","pkg/util/validation/field","pkg/util/wait","pkg/util/yaml","pkg/version","pkg/watch","third_party/forked/golang/reflect"]
|
||||||
revision = "302974c03f7e50f16561ba237db776ab93594ef6"
|
revision = "103fd098999dc9c0c88536f5c9ad2e5da39373ae"
|
||||||
version = "kubernetes-1.10.0"
|
version = "kubernetes-1.11.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "k8s.io/client-go"
|
name = "k8s.io/client-go"
|
||||||
|
@ -181,9 +163,15 @@
|
||||||
revision = "7d04d0e2a0a1a4d4a1cd6baa432a2301492e4e65"
|
revision = "7d04d0e2a0a1a4d4a1cd6baa432a2301492e4e65"
|
||||||
version = "v8.0.0"
|
version = "v8.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "k8s.io/metrics"
|
||||||
|
packages = ["pkg/apis/metrics","pkg/apis/metrics/v1alpha1","pkg/apis/metrics/v1beta1","pkg/client/clientset_generated/clientset","pkg/client/clientset_generated/clientset/scheme","pkg/client/clientset_generated/clientset/typed/metrics/v1alpha1","pkg/client/clientset_generated/clientset/typed/metrics/v1beta1"]
|
||||||
|
revision = "7afb501849915187f5b29c9727e106cbc6299d1c"
|
||||||
|
version = "kubernetes-1.11.2"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "a4691b4b3e97cf7c975063b053695a5902a76cbfe4d04afebb83861063f1d8ae"
|
inputs-digest = "313e4a4d7b8f98ab52b376065f0e361e700e044fcc5a05739b0b09d61d511227"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "k8s.io/apimachinery"
|
name = "k8s.io/apimachinery"
|
||||||
version = "kubernetes-1.10.0"
|
version = "kubernetes-1.11.2"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "k8s.io/metrics"
|
||||||
|
version = "kubernetes-1.11.2"
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "k8s.io/client-go"
|
name = "k8s.io/client-go"
|
||||||
|
|
110
kube_advisor.go
110
kube_advisor.go
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -11,10 +12,22 @@ import (
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
|
||||||
|
"k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||||
|
metrics "k8s.io/metrics/pkg/client/clientset_generated/clientset"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkContainer(c v1.Container, ns string) (StatusCheck, bool) {
|
func checkContainer(c v1.Container, p v1.Pod, pm v1beta1.PodMetrics) (PodStatusCheck, bool) {
|
||||||
sc := StatusCheck{ContainerName: c.Name, Namespace: ns, Missing: make(map[string]bool)}
|
sc := PodStatusCheck{
|
||||||
|
ContainerName: c.Name,
|
||||||
|
PodName: p.Name,
|
||||||
|
Missing: make(map[string]bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range pm.Containers {
|
||||||
|
sc.PodCPU = c.Usage.Cpu().String()
|
||||||
|
sc.PodMemory = c.Usage.Memory().String()
|
||||||
|
}
|
||||||
|
|
||||||
if c.Resources.Limits.Cpu().IsZero() {
|
if c.Resources.Limits.Cpu().IsZero() {
|
||||||
sc.Missing["CPU Resource Limits Missing"] = true
|
sc.Missing["CPU Resource Limits Missing"] = true
|
||||||
|
@ -29,18 +42,26 @@ func checkContainer(c v1.Container, ns string) (StatusCheck, bool) {
|
||||||
sc.Missing["Memory Request Limits Missing"] = true
|
sc.Missing["Memory Request Limits Missing"] = true
|
||||||
}
|
}
|
||||||
if len(sc.Missing) == 0 {
|
if len(sc.Missing) == 0 {
|
||||||
return StatusCheck{}, false
|
return PodStatusCheck{}, false
|
||||||
}
|
}
|
||||||
return sc, true
|
return sc, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatusCheck represents a container and its resource and request limit status
|
// PodStatusCheck represents a container and its resource and request limit status
|
||||||
type StatusCheck struct {
|
type PodStatusCheck struct {
|
||||||
|
PodName string
|
||||||
ContainerName string
|
ContainerName string
|
||||||
Namespace string
|
PodCPU string
|
||||||
|
PodMemory string
|
||||||
Missing map[string]bool
|
Missing map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NodeStatusCheck struct {
|
||||||
|
NodeName string
|
||||||
|
NodeCPU string
|
||||||
|
NodeMemory string
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
kubePtr := flag.Bool("use-kubeconfig", false, "use kubeconfig on local system")
|
kubePtr := flag.Bool("use-kubeconfig", false, "use kubeconfig on local system")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
@ -64,59 +85,55 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
metricClient, err := metrics.NewForConfig(config)
|
||||||
deploymentsAppsV1, err := clientset.AppsV1().Deployments("").List(metav1.ListOptions{})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("failed to get deployments:", err)
|
log.Fatal(err)
|
||||||
}
|
|
||||||
daemonsetsAppsV1, err := clientset.AppsV1().DaemonSets("").List(metav1.ListOptions{})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("failed to get daemon sets:", err)
|
|
||||||
}
|
|
||||||
statefulsetsAppsV1, err := clientset.AppsV1().StatefulSets("").List(metav1.ListOptions{})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("failed to get stateful sets:", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
statusChecksWrapper := make(map[string][]*StatusCheck)
|
statusChecksWrapper := make(map[string][]*PodStatusCheck)
|
||||||
|
|
||||||
// Gather container statusChecksWrapper from Deployments
|
pods, _ := clientset.CoreV1().Pods("").List(metav1.ListOptions{})
|
||||||
for _, d := range deploymentsAppsV1.Items {
|
if err != nil {
|
||||||
containers := d.Spec.Template.Spec.Containers
|
log.Fatalln("failed to get pods:", err)
|
||||||
|
}
|
||||||
|
for _, p := range pods.Items {
|
||||||
|
containers := p.Spec.Containers
|
||||||
for _, c := range containers {
|
for _, c := range containers {
|
||||||
status, ok := checkContainer(c, d.Namespace)
|
podMetricsList, _ := metricClient.MetricsV1beta1().PodMetricses("").List(metav1.ListOptions{})
|
||||||
if ok {
|
for _, pm := range podMetricsList.Items {
|
||||||
statusChecksWrapper[d.GetName()] = append(statusChecksWrapper[d.GetName()], &status)
|
if p.Name == pm.Name {
|
||||||
|
status, ok := checkContainer(c, p, pm)
|
||||||
|
if ok {
|
||||||
|
statusChecksWrapper[p.Namespace] = append(statusChecksWrapper[p.Namespace], &status)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gather container statusChecksWrapper from StatefulSets
|
var nodeStatuses []*NodeStatusCheck
|
||||||
for _, ss := range statefulsetsAppsV1.Items {
|
nodeMetricsList, _ := metricClient.MetricsV1beta1().NodeMetricses().List(metav1.ListOptions{})
|
||||||
containers := ss.Spec.Template.Spec.Containers
|
for _, nm := range nodeMetricsList.Items {
|
||||||
for _, c := range containers {
|
ns := NodeStatusCheck{NodeName: nm.Name, NodeCPU: nm.Usage.Cpu().String(), NodeMemory: nm.Usage.Memory().String()}
|
||||||
status, ok := checkContainer(c, ss.Namespace)
|
nodeStatuses = append(nodeStatuses, &ns)
|
||||||
if ok {
|
|
||||||
statusChecksWrapper[ss.GetName()] = append(statusChecksWrapper[ss.GetName()], &status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gather container statusChecksWrapper from DaemonSets
|
nodeTable := tablewriter.NewWriter(os.Stdout)
|
||||||
for _, ds := range daemonsetsAppsV1.Items {
|
nodeTable.SetHeader([]string{"Node", "Node CPU Usage", "Node Memory Usage"})
|
||||||
containers := ds.Spec.Template.Spec.Containers
|
nodeTable.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor},
|
||||||
for _, c := range containers {
|
tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor},
|
||||||
status, ok := checkContainer(c, ds.Namespace)
|
tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor})
|
||||||
if ok {
|
nodeTable.SetAutoMergeCells(true)
|
||||||
statusChecksWrapper[ds.GetName()] = append(statusChecksWrapper[ds.GetName()], &status)
|
nodeTable.SetRowLine(true)
|
||||||
}
|
for _, ns := range nodeStatuses {
|
||||||
}
|
nodeTable.Append([]string{ns.NodeName, ns.NodeCPU, ns.NodeMemory})
|
||||||
}
|
}
|
||||||
|
|
||||||
issuesTable := tablewriter.NewWriter(os.Stdout)
|
issuesTable := tablewriter.NewWriter(os.Stdout)
|
||||||
for k, statusChecks := range statusChecksWrapper {
|
for k, statusChecks := range statusChecksWrapper {
|
||||||
issuesTable.SetHeader([]string{"Deployment/StatefulSet/DaemonSet", "Namespace", "Container", "Issue"})
|
issuesTable.SetHeader([]string{"Namespace", "Pod Name", "Pod CPU/Memory", "Container", "Issue"})
|
||||||
issuesTable.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor},
|
issuesTable.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor},
|
||||||
|
tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor},
|
||||||
tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor},
|
tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor},
|
||||||
tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor},
|
tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor},
|
||||||
tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor})
|
tablewriter.Colors{tablewriter.Bold, tablewriter.BgBlackColor})
|
||||||
|
@ -124,11 +141,11 @@ func main() {
|
||||||
issuesTable.SetRowLine(true)
|
issuesTable.SetRowLine(true)
|
||||||
for _, s := range statusChecks {
|
for _, s := range statusChecks {
|
||||||
for key := range s.Missing {
|
for key := range s.Missing {
|
||||||
issuesTable.Append([]string{k, s.Namespace, s.ContainerName, key})
|
resourceString := fmt.Sprintf("%v / %v", s.PodCPU, s.PodMemory)
|
||||||
|
issuesTable.Append([]string{k, s.PodName, resourceString, s.ContainerName, key})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
issuesTable.Render()
|
|
||||||
|
|
||||||
remediationTable := tablewriter.NewWriter(os.Stdout)
|
remediationTable := tablewriter.NewWriter(os.Stdout)
|
||||||
remediationTable.SetHeader([]string{"Issue", "Remediation"})
|
remediationTable.SetHeader([]string{"Issue", "Remediation"})
|
||||||
|
@ -139,5 +156,8 @@ func main() {
|
||||||
remediationTable.Append([]string{"Memory Request Limits Missing", "Consider setting resource and request limits to prevent resource starvation: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/"})
|
remediationTable.Append([]string{"Memory Request Limits Missing", "Consider setting resource and request limits to prevent resource starvation: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/"})
|
||||||
remediationTable.Append([]string{"CPU Resource Limits Missing", "Consider setting resource and request limits to prevent resource starvation: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/"})
|
remediationTable.Append([]string{"CPU Resource Limits Missing", "Consider setting resource and request limits to prevent resource starvation: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/"})
|
||||||
remediationTable.Append([]string{"Memory Resource Limits Missing", "Consider setting resource and request limits to prevent resource starvation: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/"})
|
remediationTable.Append([]string{"Memory Resource Limits Missing", "Consider setting resource and request limits to prevent resource starvation: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/"})
|
||||||
|
|
||||||
|
issuesTable.Render()
|
||||||
|
nodeTable.Render()
|
||||||
remediationTable.Render()
|
remediationTable.Render()
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче