Skip to content

Commit

Permalink
Add inode metrics (#136)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattcontinisio authored Dec 16, 2024
1 parent 489a070 commit bbd4e1c
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 9 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ helm upgrade --install my-deployment k8s-ephemeral-storage-metrics/k8s-ephemeral
| metrics.ephemeral_storage_node_capacity | bool | `true` | Capacity of ephemeral storage for a node |
| metrics.ephemeral_storage_node_percentage | bool | `true` | Percentage of ephemeral storage used on a node |
| metrics.ephemeral_storage_pod_usage | bool | `true` | Current ephemeral byte usage of pod |
| metrics.ephemeral_storage_inodes | bool | `true` | Current ephemeral inode usage of pod |
| metrics.port | int | `9100` | Adjust the metric port as needed (default 9100) |
| nodeSelector | object | `{}` | |
| podAnnotations | object | `{}` | |
Expand Down
1 change: 1 addition & 0 deletions chart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ helm upgrade --install my-deployment k8s-ephemeral-storage-metrics/k8s-ephemeral
| metrics.ephemeral_storage_node_capacity | bool | `true` | Capacity of ephemeral storage for a node |
| metrics.ephemeral_storage_node_percentage | bool | `true` | Percentage of ephemeral storage used on a node |
| metrics.ephemeral_storage_pod_usage | bool | `true` | Current ephemeral byte usage of pod |
| metrics.ephemeral_storage_inodes | bool | `true` | Current ephemeral inode usage of pod |
| metrics.port | int | `9100` | Adjust the metric port as needed (default 9100) |
| nodeSelector | object | `{}` | |
| podAnnotations | object | `{}` | |
Expand Down
4 changes: 4 additions & 0 deletions chart/templates/DeployType.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ spec:
- name: EPHEMERAL_STORAGE_CONTAINER_VOLUME_LIMITS_PERCENTAGE
value: "{{ .Values.metrics.ephemeral_storage_container_volume_limit_percentage }}"
{{- end }}
{{- if .Values.metrics.ephemeral_storage_inodes }}
- name: EPHEMERAL_STORAGE_INODES
value: "{{ .Values.metrics.ephemeral_storage_inodes }}"
{{- end }}
{{- if .Values.kubelet.scrape }}
- name: SCRAPE_FROM_KUBELET
value: "{{ .Values.kubelet.scrape }}"
Expand Down
2 changes: 2 additions & 0 deletions chart/test-values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ metrics:
ephemeral_storage_container_volume_limit_percentage: true
# -- Current ephemeral byte usage of pod
ephemeral_storage_pod_usage: true
# -- Current ephemeral inode usage of pod
ephemeral_storage_inodes: true
# -- Available ephemeral storage for a node
ephemeral_storage_node_available: true
# -- Capacity of ephemeral storage for a node
Expand Down
2 changes: 2 additions & 0 deletions chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ metrics:
ephemeral_storage_container_volume_limit_percentage: true
# -- Current ephemeral byte usage of pod
ephemeral_storage_pod_usage: true
# -- Current ephemeral inode usage of pod
ephemeral_storage_inodes: true
# -- Available ephemeral storage for a node
ephemeral_storage_node_available: true
# -- Capacity of ephemeral storage for a node
Expand Down
17 changes: 12 additions & 5 deletions cmd/app/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ import (
"encoding/json"
"flag"
"fmt"
"net/http"
"strconv"
"time"

"github.com/jmcgrath207/k8s-ephemeral-storage-metrics/pkg/dev"
"github.com/jmcgrath207/k8s-ephemeral-storage-metrics/pkg/node"
"github.com/jmcgrath207/k8s-ephemeral-storage-metrics/pkg/pod"
"github.com/panjf2000/ants/v2"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/rs/zerolog/log"
"net/http"
"strconv"
"time"
)

var (
Expand All @@ -36,6 +37,9 @@ type ephemeralStorageMetrics struct {
AvailableBytes float64 `json:"availableBytes"`
CapacityBytes float64 `json:"capacityBytes"`
UsedBytes float64 `json:"usedBytes"`
Inodes float64 `json:"inodes"`
InodesFree float64 `json:"inodesFree"`
InodesUsed float64 `json:"inodesUsed"`
} `json:"ephemeral-storage"`

Volumes []pod.Volume `json:"volume,omitempty"`
Expand Down Expand Up @@ -63,12 +67,15 @@ func setMetrics(nodeName string) {
usedBytes := p.EphemeralStorage.UsedBytes
availableBytes := p.EphemeralStorage.AvailableBytes
capacityBytes := p.EphemeralStorage.CapacityBytes
if podNamespace == "" || (usedBytes == 0 && availableBytes == 0 && capacityBytes == 0) {
inodes := p.EphemeralStorage.Inodes
inodesFree := p.EphemeralStorage.InodesFree
inodesUsed := p.EphemeralStorage.InodesUsed
if podNamespace == "" || (usedBytes == 0 && availableBytes == 0 && capacityBytes == 0 && inodes == 0 && inodesFree == 0 && inodesUsed == 0) {
log.Warn().Msg(fmt.Sprintf("pod %s/%s on %s has no metrics on its ephemeral storage usage", podName, podNamespace, nodeName))
continue
}
Node.SetMetrics(nodeName, availableBytes, capacityBytes)
Pod.SetMetrics(podName, podNamespace, nodeName, usedBytes, availableBytes, capacityBytes, p.Volumes)
Pod.SetMetrics(podName, podNamespace, nodeName, usedBytes, availableBytes, capacityBytes, inodes, inodesFree, inodesUsed, p.Volumes)
}

adjustTime := sampleIntervalMill - time.Now().Sub(start).Milliseconds()
Expand Down
5 changes: 3 additions & 2 deletions pkg/node/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package node

import (
"fmt"
"math"

"github.com/jmcgrath207/k8s-ephemeral-storage-metrics/pkg/pod"
"github.com/prometheus/client_golang/prometheus"
"github.com/rs/zerolog/log"
"math"
)

var (
Expand Down Expand Up @@ -72,7 +73,7 @@ func (n *Node) SetMetrics(nodeName string, availableBytes float64, capacityBytes

if n.nodeAvailable {
nodeAvailableGaugeVec.With(prometheus.Labels{"node_name": nodeName}).Set(availableBytes)
log.Debug().Msg(fmt.Sprintf("Node: %s availble bytes: %f", nodeName, availableBytes))
log.Debug().Msg(fmt.Sprintf("Node: %s available bytes: %f", nodeName, availableBytes))
}

if n.nodeCapacity {
Expand Down
6 changes: 5 additions & 1 deletion pkg/pod/factory.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package pod

import (
"github.com/jmcgrath207/k8s-ephemeral-storage-metrics/pkg/dev"
"strconv"
"sync"

"github.com/jmcgrath207/k8s-ephemeral-storage-metrics/pkg/dev"
)

var (
Expand All @@ -15,6 +16,7 @@ type Collector struct {
containerVolumeUsage bool
containerLimitsPercentage bool
containerVolumeLimitsPercentage bool
inodes bool
lookup *map[string]pod
lookupMutex *sync.RWMutex
podUsage bool
Expand All @@ -27,12 +29,14 @@ func NewCollector(sampleInterval int64) Collector {
containerVolumeUsage, _ := strconv.ParseBool(dev.GetEnv("EPHEMERAL_STORAGE_CONTAINER_VOLUME_USAGE", "false"))
containerLimitsPercentage, _ := strconv.ParseBool(dev.GetEnv("EPHEMERAL_STORAGE_CONTAINER_LIMIT_PERCENTAGE", "false"))
containerVolumeLimitsPercentage, _ := strconv.ParseBool(dev.GetEnv("EPHEMERAL_STORAGE_CONTAINER_VOLUME_LIMITS_PERCENTAGE", "false"))
inodes, _ := strconv.ParseBool(dev.GetEnv("EPHEMERAL_STORAGE_INODES", "false"))
lookup := make(map[string]pod)

var c = Collector{
containerVolumeUsage: containerVolumeUsage,
containerLimitsPercentage: containerLimitsPercentage,
containerVolumeLimitsPercentage: containerVolumeLimitsPercentage,
inodes: inodes,
lookup: &lookup,
lookupMutex: &lookupMutex,
podUsage: podUsage,
Expand Down
66 changes: 65 additions & 1 deletion pkg/pod/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ var (
containerVolumeUsageVec *prometheus.GaugeVec
containerPercentageLimitsVec *prometheus.GaugeVec
containerPercentageVolumeLimitsVec *prometheus.GaugeVec
inodesGaugeVec *prometheus.GaugeVec
inodesFreeGaugeVec *prometheus.GaugeVec
inodesUsedGaugeVec *prometheus.GaugeVec
)

type Volume struct {
Expand Down Expand Up @@ -104,9 +107,57 @@ func (cr Collector) createMetrics() {
)

prometheus.MustRegister(containerPercentageVolumeLimitsVec)

inodesGaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "ephemeral_storage_inodes",
Help: "Maximum number of inodes in the pod",
},
[]string{
// name of pod for Ephemeral Storage
"pod_name",
// namespace of pod for Ephemeral Storage
"pod_namespace",
// Name of Node where pod is placed.
"node_name",
},
)

prometheus.MustRegister(inodesGaugeVec)

inodesFreeGaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "ephemeral_storage_inodes_free",
Help: "Number of free inodes in the pod",
},
[]string{
// name of pod for Ephemeral Storage
"pod_name",
// namespace of pod for Ephemeral Storage
"pod_namespace",
// Name of Node where pod is placed.
"node_name",
},
)

prometheus.MustRegister(inodesFreeGaugeVec)

inodesUsedGaugeVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "ephemeral_storage_inodes_used",
Help: "Number of used inodes in the pod",
},
[]string{
// name of pod for Ephemeral Storage
"pod_name",
// namespace of pod for Ephemeral Storage
"pod_namespace",
// Name of Node where pod is placed.
"node_name",
},
)

prometheus.MustRegister(inodesUsedGaugeVec)
}

func (cr Collector) SetMetrics(podName string, podNamespace string, nodeName string, usedBytes float64, availableBytes float64, capacityBytes float64, volumes []Volume) {
func (cr Collector) SetMetrics(podName string, podNamespace string, nodeName string, usedBytes float64, availableBytes float64, capacityBytes float64, inodes float64, inodesFree float64, inodesUsed float64, volumes []Volume) {

var setValue float64
cr.lookupMutex.RLock()
Expand Down Expand Up @@ -198,11 +249,24 @@ func (cr Collector) SetMetrics(podName string, podNamespace string, nodeName str
podGaugeVec.With(labels).Set(usedBytes)
log.Debug().Msg(fmt.Sprintf("pod %s/%s on %s with usedBytes: %f", podNamespace, podName, nodeName, usedBytes))
}

if cr.inodes {
labels := prometheus.Labels{"pod_namespace": podNamespace,
"pod_name": podName, "node_name": nodeName}
inodesGaugeVec.With(labels).Set(inodes)
inodesFreeGaugeVec.With(labels).Set(inodesFree)
inodesUsedGaugeVec.With(labels).Set(inodesUsed)
log.Debug().Msg(fmt.Sprintf("pod %s/%s on %s with inodes: %f, inodesFree: %f, inodesUsed: %f", podNamespace, podName, nodeName, inodes, inodesFree, inodesUsed))
}
}

// Evicts exporter metrics by pod and container name
func evictPodByName(p v1.Pod) {
podGaugeVec.DeletePartialMatch(prometheus.Labels{"pod_name": p.Name})
inodesGaugeVec.DeletePartialMatch(prometheus.Labels{"pod_name": p.Name})
inodesFreeGaugeVec.DeletePartialMatch(prometheus.Labels{"pod_name": p.Name})
inodesUsedGaugeVec.DeletePartialMatch(prometheus.Labels{"pod_name": p.Name})

// TODO: Look into removing this for loop and delete by pod_name
// e.g. containerVolumeUsageVec.DeletePartialMatch(prometheus.Labels{"pod_name": p.Name})
for _, c := range p.Spec.Containers {
Expand Down
24 changes: 24 additions & 0 deletions tests/e2e/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,30 @@ func getContainerVolumeUsage(podName string) float64 {
return currentPodSize
}

func getInodes(podName string) float64 {
output := requestPrometheusString()
re := regexp.MustCompile(fmt.Sprintf(`ephemeral_storage_inodes.+pod_name="%s.+\}\s(.+)`, podName))
match := re.FindAllStringSubmatch(output, 2)
inodes, _ := strconv.ParseFloat(match[0][1], 64)
return inodes
}

func getInodesFree(podName string) float64 {
output := requestPrometheusString()
re := regexp.MustCompile(fmt.Sprintf(`ephemeral_storage_inodes_free.+pod_name="%s.+\}\s(.+)`, podName))
match := re.FindAllStringSubmatch(output, 2)
inodesFree, _ := strconv.ParseFloat(match[0][1], 64)
return inodesFree
}

func getInodesUsed(podName string) float64 {
output := requestPrometheusString()
re := regexp.MustCompile(fmt.Sprintf(`ephemeral_storage_inodes_used.+pod_name="%s.+\}\s(.+)`, podName))
match := re.FindAllStringSubmatch(output, 2)
inodesUsed, _ := strconv.ParseFloat(match[0][1], 64)
return inodesUsed
}

func WatchEphemeralSize(podName string, desiredSizeChange float64, timeout time.Duration, getPodSize getPodSize) {
// Watch Prometheus Metrics until the ephemeral storage shrinks or grows to a certain desiredSizeChange.
var currentPodSize float64
Expand Down

0 comments on commit bbd4e1c

Please sign in to comment.