Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP : Expose active/inactive connection to service backend as prometheus metrics #65

Merged
merged 1 commit into from
Jul 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions app/controllers/network_services_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"net"
"net/http"
"reflect"
"strconv"
"strings"
Expand All @@ -18,6 +19,8 @@ import (
"github.com/coreos/go-iptables/iptables"
"github.com/golang/glog"
"github.com/mqliang/libipvs"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/vishvananda/netlink"
"k8s.io/client-go/kubernetes"
)
Expand All @@ -27,10 +30,21 @@ const (
IFACE_NOT_FOUND = "Link not found"
IFACE_HAS_ADDR = "file exists"
IPVS_SERVER_EXISTS = "file exists"
namespace = "kube_router"
)

var (
h libipvs.IPVSHandle
serviceBackendActiveConn = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: namespace,
Name: "service_backend_active_connections",
Help: "Active conntection to backend of service",
}, []string{"namespace", "service_name", "backend"})
serviceBackendInactiveConn = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Namespace: namespace,
Name: "service_backend_inactive_connections",
Help: "Active conntection to backend of service",
}, []string{"namespace", "service_name", "backend"})
)

// Network services controller enables local node as network service proxy through IPVS/LVS.
Expand All @@ -55,6 +69,8 @@ type NetworkServicesController struct {

// internal representation of kubernetes service
type serviceInfo struct {
name string
namespace string
clusterIP net.IP
port int
protocol string
Expand Down Expand Up @@ -90,6 +106,12 @@ func (nsc *NetworkServicesController) Run(stopCh <-chan struct{}, wg *sync.WaitG
return errors.New("Failed to do add masqurade rule in POSTROUTING chain of nat table due to: %s" + err.Error())
}

// register metrics
prometheus.MustRegister(serviceBackendActiveConn)
prometheus.MustRegister(serviceBackendInactiveConn)
http.Handle("/metrics", promhttp.Handler())
go http.ListenAndServe(":8080", nil)

// enable ipvs connection tracking
err = ensureIpvsConntrack()
if err != nil {
Expand Down Expand Up @@ -132,6 +154,7 @@ func (nsc *NetworkServicesController) sync() {
glog.Errorf("Error syncing hairpin iptable rules: %s", err.Error())
}
nsc.syncIpvsServices(nsc.serviceMap, nsc.endpointsMap)
nsc.publishMetrics(nsc.serviceMap)
}

// handle change in endpoints update from the API server
Expand Down Expand Up @@ -308,6 +331,41 @@ func (nsc *NetworkServicesController) syncIpvsServices(serviceInfoMap serviceInf
return nil
}

func (nsc *NetworkServicesController) publishMetrics(serviceInfoMap serviceInfoMap) error {
ipvsSvcs, err := h.ListServices()
if err != nil {
return errors.New("Failed to list IPVS services: " + err.Error())
}

for _, svc := range serviceInfoMap {
for _, ipvsSvc := range ipvsSvcs {
if strings.Compare(svc.clusterIP.String(), ipvsSvc.Address.String()) == 0 &&
svc.protocol == ipvsSvc.Protocol.String() && uint16(svc.port) == ipvsSvc.Port {
dsts, err := h.ListDestinations(ipvsSvc)
if err != nil {
glog.Errorf("Failed to get list of servers from ipvs service")
}
for _, dst := range dsts {
serviceBackendActiveConn.WithLabelValues(svc.namespace, svc.name, dst.Address.String()).Set(float64(dst.ActiveConns))
serviceBackendInactiveConn.WithLabelValues(svc.namespace, svc.name, dst.Address.String()).Set(float64(dst.InactConns))
}
}
if strings.Compare(nsc.nodeIP.String(), ipvsSvc.Address.String()) == 0 &&
svc.protocol == ipvsSvc.Protocol.String() && uint16(svc.port) == ipvsSvc.Port {
dsts, err := h.ListDestinations(ipvsSvc)
if err != nil {
glog.Errorf("Failed to get list of servers from ipvs service")
}
for _, dst := range dsts {
serviceBackendActiveConn.WithLabelValues(svc.namespace, svc.name, dst.Address.String()).Set(float64(dst.ActiveConns))
serviceBackendInactiveConn.WithLabelValues(svc.namespace, svc.name, dst.Address.String()).Set(float64(dst.InactConns))
}
}
}
}
return nil
}

func buildServicesInfo() serviceInfoMap {
serviceMap := make(serviceInfoMap)
for _, svc := range watchers.ServiceWatcher.List() {
Expand All @@ -328,6 +386,8 @@ func buildServicesInfo() serviceInfoMap {
port: int(port.Port),
protocol: strings.ToLower(string(port.Protocol)),
nodePort: int(port.NodePort),
name: svc.ObjectMeta.Name,
namespace: svc.ObjectMeta.Namespace,
}

svcInfo.sessionAffinity = (svc.Spec.SessionAffinity == "ClientIP")
Expand Down
33 changes: 30 additions & 3 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ import:
version: master
- package: github.com/aws/aws-sdk-go/
version: ^v1.8.36
- package: github.com/prometheus/client_golang
version: ~0.8.0
11 changes: 11 additions & 0 deletions vendor/github.com/aws/aws-sdk-go/CHANGELOG.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vendor/github.com/aws/aws-sdk-go/aws/version.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading