Skip to content

Commit

Permalink
prometheus metrics: add option to specify listen address
Browse files Browse the repository at this point in the history
In the situation that you have multiple interfaces/IP addresses,
we want to be able to specify which one we want to expose the
prometheus metrics on.
  • Loading branch information
jpiper authored and aauren committed Nov 6, 2023
1 parent 961c63b commit fcf0ad9
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ Usage of kube-router:
--loadbalancer-sync-period duration The delay between checking for missed services (e.g. '5s', '1m'). Must be greater than 0. (default 1m0s)
--masquerade-all SNAT all traffic to cluster IP/node port.
--master string The address of the Kubernetes API server (overrides any value in kubeconfig).
--metrics-addr string Prometheus metrics address to listen on, (Default: all interfaces)
--metrics-path string Prometheus metrics path (default "/metrics")
--metrics-port uint16 Prometheus metrics port, (Default 0, Disabled)
--nodeport-bindon-all-ip For service of NodePort type create IPVS service that listens on all IP's of the node.
Expand Down
10 changes: 10 additions & 0 deletions pkg/cmd/kube-router.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cloudnativelabs/kube-router/v2/pkg/healthcheck"
"github.com/cloudnativelabs/kube-router/v2/pkg/metrics"
"github.com/cloudnativelabs/kube-router/v2/pkg/options"
"github.com/cloudnativelabs/kube-router/v2/pkg/utils"
"github.com/cloudnativelabs/kube-router/v2/pkg/version"
"k8s.io/klog/v2"

Expand Down Expand Up @@ -115,6 +116,15 @@ func (kr *KubeRouter) Run() error {
go hc.RunCheck(healthChan, stopCh, &wg)

if kr.Config.MetricsPort > 0 && kr.Config.MetricsPort < 65535 {

// Verify the metrics address/port combo provided is listenable
if err := utils.TCPAddressBindable(kr.Config.MetricsAddr, kr.Config.MetricsPort); err != nil {
return fmt.Errorf("failed to listen on %s:%d for metrics: %w",
kr.Config.MetricsAddr,
int(kr.Config.MetricsPort),
err)
}

kr.Config.MetricsEnabled = true
mc, err := metrics.NewMetricsController(kr.Config)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion pkg/metrics/metrics_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ var (
// Controller Holds settings for the metrics controller
type Controller struct {
MetricsPath string
MetricsAddr string
MetricsPort uint16
}

Expand All @@ -236,7 +237,7 @@ func (mc *Controller) Run(healthChan chan<- *healthcheck.ControllerHeartbeat, st
DefaultRegisterer.MustRegister(ControllerIpvsMetricsExportTime)

srv := &http.Server{
Addr: ":" + strconv.Itoa(int(mc.MetricsPort)),
Addr: mc.MetricsAddr + ":" + strconv.Itoa(int(mc.MetricsPort)),
Handler: http.DefaultServeMux,
ReadHeaderTimeout: 5 * time.Second}

Expand Down Expand Up @@ -267,6 +268,7 @@ func (mc *Controller) Run(healthChan chan<- *healthcheck.ControllerHeartbeat, st
// NewMetricsController returns new MetricController object
func NewMetricsController(config *options.KubeRouterConfig) (*Controller, error) {
mc := Controller{}
mc.MetricsAddr = config.MetricsAddr
mc.MetricsPath = config.MetricsPath
mc.MetricsPort = config.MetricsPort
return &mc, nil
Expand Down
2 changes: 2 additions & 0 deletions pkg/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type KubeRouterConfig struct {
MetricsEnabled bool
MetricsPath string
MetricsPort uint16
MetricsAddr string
NodePortBindOnAllIP bool
NodePortRange string
OverlayType string
Expand Down Expand Up @@ -190,6 +191,7 @@ func (s *KubeRouterConfig) AddFlags(fs *pflag.FlagSet) {
"The address of the Kubernetes API server (overrides any value in kubeconfig).")
fs.StringVar(&s.MetricsPath, "metrics-path", "/metrics", "Prometheus metrics path")
fs.Uint16Var(&s.MetricsPort, "metrics-port", 0, "Prometheus metrics port, (Default 0, Disabled)")
fs.StringVar(&s.MetricsAddr, "metrics-addr", "", "Prometheus metrics address to listen on, (Default: all interfaces)")
fs.BoolVar(&s.NodePortBindOnAllIP, "nodeport-bindon-all-ip", false,
"For service of NodePort type create IPVS service that listens on all IP's of the node.")
fs.BoolVar(&s.FullMeshMode, "nodes-full-mesh", true,
Expand Down
13 changes: 13 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package utils

import (
"fmt"
"io"
"net"
"strconv"
"sync"
)

Expand Down Expand Up @@ -86,3 +88,14 @@ func SliceContainsString(needle string, haystack []string) bool {
}
return false
}

// TCPAddressBindable checks to see if an IP/port is bindable by attempting to open a listener then closing it
// returns nil if successful
func TCPAddressBindable(addr string, port uint16) error {
endpoint := addr + ":" + strconv.Itoa(int(port))
ln, err := net.Listen("tcp", endpoint)
if err != nil {
return fmt.Errorf("unable to open %s: %w", endpoint, err)
}
return ln.Close()
}

0 comments on commit fcf0ad9

Please sign in to comment.