Skip to content

Commit

Permalink
feat: adding multiple namespace watch
Browse files Browse the repository at this point in the history
Signed-off-by: gkarthiks <github.gkarthiks@gmail.com>
  • Loading branch information
gkarthiks committed Aug 9, 2020
1 parent d0ccc58 commit 4cf0b0f
Show file tree
Hide file tree
Showing 19 changed files with 370 additions and 435 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## Changelog

## 0.2.0
- Migrated from client-go to discovery-k8s
- Added multiple selective namespace watch capabilities

## 0.1.1
- Added additional documentation.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,20 @@ To run the *CRE* in a contained namespace, i.e., watch only particular namespace
```yaml
- env:
- name: WATCH_NAMESPACE
valueFrom:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
fieldPath: metadata.namespace
```
The CRE can also take multiple namespace in a comma separated list. Like the below. Note that the namespaces should be added as the comma spearated string and not individual strings by themselves.
```yaml
- env:
- name: WATCH_NAMESPACE
value: "default, kube-system, reporting"
```
Still, *CRE* will require a *service account* which has access to `list` all the `pods` under `core v1` apiGroup and `metrics` apiGroup.

### Sample CRE metrics exported:
Expand Down Expand Up @@ -83,4 +92,4 @@ The below sample [Grafana](https://grafana.com/) dashboard will show the sample
The docker image can be found [here <img src="./docker-logo.png" width="40" height="40" align="center"/> .](https://cloud.docker.com/repository/docker/gkarthics/container-resource-exporter)

## Helm Chart:
The helm chart is available [here](./helm-chart) for easy installation.
The helm chart is available [here](https://hub.helm.sh/charts/gkarthiks/prometheus-container-resource-exporter) for easy installation.
79 changes: 32 additions & 47 deletions container_resource_exporter.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
package main

import (
"context"
_ "expvar"
"fmt"
discovery "github.com/gkarthiks/k8s-discovery"
"io"
"net/http"
"os"
"strconv"
"strings"
"sync"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
v1 "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
metricsTypes "k8s.io/metrics/pkg/apis/metrics/v1beta1"
metrics "k8s.io/metrics/pkg/client/clientset/versioned"
)

var (
kubeconfig *string
k8s *discovery.K8s
pods *corev1.PodList
clientset *v1.Clientset
metricClientSet *metrics.Clientset
watchNamespace string
nsSlice []string
err error
avail bool
podCounts = make(map[string]int)
Expand All @@ -47,43 +45,20 @@ type Exporter struct {

func init() {
logrus.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
k8s, _ = discovery.NewK8s()
watchNamespace, avail = os.LookupEnv("WATCH_NAMESPACE")
if avail {
logrus.Infof("Chosen namespace to scrape: %s", watchNamespace)
if strings.Contains(watchNamespace, ",") {
splitNamespace := strings.Split(watchNamespace, ",")
for _, indNs := range splitNamespace {
nsSlice = append(nsSlice, strings.TrimSpace(indNs))
}
}
} else {
logrus.Info("No watch namespace provided, defaulting to cluster level")
watchNamespace = ""
}

// uncomment below, if running outside cluster
// if home := 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")
// }

// config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
// if err != nil {
// panic(err.Error())
// }

// if running inside cluster
config, err := rest.InClusterConfig()
if err != nil {
panic(err.Error())
}

// k8s core api client
clientset, err = kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
// k8s metrics api client
metricClientSet, err = metrics.NewForConfig(config)
if err != nil {
panic(err)
}

}

func main() {
Expand All @@ -102,7 +77,7 @@ func main() {
})
http.HandleFunc("/healthz", func(rw http.ResponseWriter, r *http.Request) {
logrus.Info("Running healthz check")
io.WriteString(rw, "Running good")
_, _ = io.WriteString(rw, "Running good")
})
logrus.Info("Serving on port :9000")
logrus.Fatal(http.ListenAndServe(":9000", nil))
Expand Down Expand Up @@ -164,7 +139,17 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
var wg = sync.WaitGroup{}

// Polling core API
pods, err = clientset.CoreV1().Pods(watchNamespace).List(metav1.ListOptions{})
if len(nsSlice) > 0 {
var podSlices = &corev1.PodList{}
for _, namespace := range nsSlice {
logrus.Infof("Currently scrapping the %s namespace", namespace)
pods, err = k8s.Clientset.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{})
podSlices.Items = append(podSlices.Items, pods.Items...)
}
pods = podSlices
} else {
pods, err = k8s.Clientset.CoreV1().Pods(watchNamespace).List(context.Background(), metav1.ListOptions{})
}
if err != nil {
logrus.Error(err.Error())
}
Expand Down Expand Up @@ -196,7 +181,7 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {

go setPodCount(podCountNamespace)

podMetrics, err := metricClientSet.MetricsV1beta1().PodMetricses(watchNamespace).List(metav1.ListOptions{})
podMetrics, err := k8s.MetricsClientSet.MetricsV1beta1().PodMetricses(watchNamespace).List(context.Background(), metav1.ListOptions{})
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -247,10 +232,10 @@ func setPodCount(podCountsNamespace chan string) {

}

// Uncomment if running outside the cluster {fetches the local kubeconfig}
// func homeDir() string {
// if h := os.Getenv("HOME"); h != "" {
// return h
// }
// return os.Getenv("USERPROFILE") // windows
// }
//Uncomment if running outside the cluster {fetches the local kubeconfig}
func homeDir() string {
if h := os.Getenv("HOME"); h != "" {
return h
}
return os.Getenv("USERPROFILE") // windows
}
12 changes: 12 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module container-resource-exporter

go 1.14

require (
github.com/gkarthiks/k8s-discovery v0.18.3
github.com/prometheus/client_golang v1.7.1
github.com/sirupsen/logrus v1.6.0
k8s.io/api v0.18.2
k8s.io/apimachinery v0.18.2
k8s.io/metrics v0.18.2
)
Loading

0 comments on commit 4cf0b0f

Please # to comment.