Skip to content

Commit fcf0ad9

Browse files
jpiperaauren
authored andcommitted
prometheus metrics: add option to specify listen address
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.
1 parent 961c63b commit fcf0ad9

File tree

5 files changed

+29
-1
lines changed

5 files changed

+29
-1
lines changed

docs/user-guide.md

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ Usage of kube-router:
102102
--loadbalancer-sync-period duration The delay between checking for missed services (e.g. '5s', '1m'). Must be greater than 0. (default 1m0s)
103103
--masquerade-all SNAT all traffic to cluster IP/node port.
104104
--master string The address of the Kubernetes API server (overrides any value in kubeconfig).
105+
--metrics-addr string Prometheus metrics address to listen on, (Default: all interfaces)
105106
--metrics-path string Prometheus metrics path (default "/metrics")
106107
--metrics-port uint16 Prometheus metrics port, (Default 0, Disabled)
107108
--nodeport-bindon-all-ip For service of NodePort type create IPVS service that listens on all IP's of the node.

pkg/cmd/kube-router.go

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/cloudnativelabs/kube-router/v2/pkg/healthcheck"
1717
"github.com/cloudnativelabs/kube-router/v2/pkg/metrics"
1818
"github.com/cloudnativelabs/kube-router/v2/pkg/options"
19+
"github.com/cloudnativelabs/kube-router/v2/pkg/utils"
1920
"github.com/cloudnativelabs/kube-router/v2/pkg/version"
2021
"k8s.io/klog/v2"
2122

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

117118
if kr.Config.MetricsPort > 0 && kr.Config.MetricsPort < 65535 {
119+
120+
// Verify the metrics address/port combo provided is listenable
121+
if err := utils.TCPAddressBindable(kr.Config.MetricsAddr, kr.Config.MetricsPort); err != nil {
122+
return fmt.Errorf("failed to listen on %s:%d for metrics: %w",
123+
kr.Config.MetricsAddr,
124+
int(kr.Config.MetricsPort),
125+
err)
126+
}
127+
118128
kr.Config.MetricsEnabled = true
119129
mc, err := metrics.NewMetricsController(kr.Config)
120130
if err != nil {

pkg/metrics/metrics_controller.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ var (
214214
// Controller Holds settings for the metrics controller
215215
type Controller struct {
216216
MetricsPath string
217+
MetricsAddr string
217218
MetricsPort uint16
218219
}
219220

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

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

@@ -267,6 +268,7 @@ func (mc *Controller) Run(healthChan chan<- *healthcheck.ControllerHeartbeat, st
267268
// NewMetricsController returns new MetricController object
268269
func NewMetricsController(config *options.KubeRouterConfig) (*Controller, error) {
269270
mc := Controller{}
271+
mc.MetricsAddr = config.MetricsAddr
270272
mc.MetricsPath = config.MetricsPath
271273
mc.MetricsPort = config.MetricsPort
272274
return &mc, nil

pkg/options/options.go

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ type KubeRouterConfig struct {
6060
MetricsEnabled bool
6161
MetricsPath string
6262
MetricsPort uint16
63+
MetricsAddr string
6364
NodePortBindOnAllIP bool
6465
NodePortRange string
6566
OverlayType string
@@ -190,6 +191,7 @@ func (s *KubeRouterConfig) AddFlags(fs *pflag.FlagSet) {
190191
"The address of the Kubernetes API server (overrides any value in kubeconfig).")
191192
fs.StringVar(&s.MetricsPath, "metrics-path", "/metrics", "Prometheus metrics path")
192193
fs.Uint16Var(&s.MetricsPort, "metrics-port", 0, "Prometheus metrics port, (Default 0, Disabled)")
194+
fs.StringVar(&s.MetricsAddr, "metrics-addr", "", "Prometheus metrics address to listen on, (Default: all interfaces)")
193195
fs.BoolVar(&s.NodePortBindOnAllIP, "nodeport-bindon-all-ip", false,
194196
"For service of NodePort type create IPVS service that listens on all IP's of the node.")
195197
fs.BoolVar(&s.FullMeshMode, "nodes-full-mesh", true,

pkg/utils/utils.go

+13
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package utils
22

33
import (
4+
"fmt"
45
"io"
56
"net"
7+
"strconv"
68
"sync"
79
)
810

@@ -86,3 +88,14 @@ func SliceContainsString(needle string, haystack []string) bool {
8688
}
8789
return false
8890
}
91+
92+
// TCPAddressBindable checks to see if an IP/port is bindable by attempting to open a listener then closing it
93+
// returns nil if successful
94+
func TCPAddressBindable(addr string, port uint16) error {
95+
endpoint := addr + ":" + strconv.Itoa(int(port))
96+
ln, err := net.Listen("tcp", endpoint)
97+
if err != nil {
98+
return fmt.Errorf("unable to open %s: %w", endpoint, err)
99+
}
100+
return ln.Close()
101+
}

0 commit comments

Comments
 (0)