Auto detect default interface for VIP

This commit is contained in:
thebsdbox
2021-10-19 11:17:33 +01:00
parent c94c15a6b9
commit 0d492faaf0
7 changed files with 94 additions and 7 deletions

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/vip"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -43,6 +44,15 @@ var kubeManifestPod = &cobra.Command{
// TODO - A load of text detailing what's actually happening
kubevip.ParseEnvironment(&initConfig)
// TODO - check for certain things VIP/interfaces
if initConfig.AutoInterface {
defaultIF, err := vip.GetDefaultGatewayInterface()
if err != nil {
log.Fatalf("unable to set default interface -> [%v]", err)
}
initConfig.Interface = defaultIF.Name
}
if initConfig.Interface == "" {
cmd.Help()
log.Fatalln("No interface is specified for kube-vip to bind to")
@@ -69,6 +79,15 @@ var kubeManifestDaemon = &cobra.Command{
// TODO - A load of text detailing what's actually happening
kubevip.ParseEnvironment(&initConfig)
// TODO - check for certain things VIP/interfaces
if initConfig.AutoInterface {
defaultIF, err := vip.GetDefaultGatewayInterface()
if err != nil {
log.Fatalf("unable to set default interface -> [%v]", err)
}
initConfig.Interface = defaultIF.Name
}
if initConfig.Interface == "" {
cmd.Help()
log.Fatalln("No interface is specified for kube-vip to bind to")

View File

@@ -10,6 +10,7 @@ import (
"github.com/kube-vip/kube-vip/pkg/kubevip"
"github.com/kube-vip/kube-vip/pkg/manager"
"github.com/kube-vip/kube-vip/pkg/packet"
"github.com/kube-vip/kube-vip/pkg/vip"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
log "github.com/sirupsen/logrus"
@@ -67,6 +68,8 @@ func init() {
initConfig.LocalPeer = *localpeer
//initConfig.Peers = append(initConfig.Peers, *localpeer)
kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.AutoInterface, "autoInterface", false, "Name of the interface to bind to")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesInterface, "serviceInterface", "", "Name of the interface to bind to (for services)")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address")
@@ -209,6 +212,19 @@ var kubeVipManager = &cobra.Command{
// Set the logging level for all subsequent functions
log.SetLevel(log.Level(logLevel))
if initConfig.AutoInterface {
defaultIF, err := vip.GetDefaultGatewayInterface()
if err != nil {
log.Fatalf("unable to set default interface -> [%v]", err)
}
initConfig.Interface = defaultIF.Name
}
if initConfig.Interface == "" {
cmd.Help()
log.Fatalln("No interface is specified for kube-vip to bind to")
}
go servePrometheusHTTPServer(cmd.Context(), PrometheusHTTPServerConfig{
Addr: initConfig.PrometheusHTTPServer,
})
@@ -240,7 +256,7 @@ var kubeVipManager = &cobra.Command{
// Define the new service manager
mgr, err := manager.New(configMap, &initConfig)
if err != nil {
log.Fatalf("%v", err)
log.Fatalf("configuring new Manager error -> %v", err)
}
prometheus.MustRegister(mgr.PrometheusCollector()...)
@@ -248,7 +264,7 @@ var kubeVipManager = &cobra.Command{
// Start the service manager, this will watch the config Map and construct kube-vip services for it
err = mgr.Start()
if err != nil {
log.Fatalf("%v", err)
log.Fatalf("starting new Manager error -> %v", err)
}
},
}

View File

@@ -24,6 +24,9 @@ const (
//vipInterface - defines the interface that the vip should bind too
vipInterface = "vip_interface"
//vipAutoInterface - defines the interface that the vip should bind too
vipAutoInterface = "vip_autointerface"
//vipServicesInterface - defines the interface that the service vips should bind too
vipServicesInterface = "vip_servicesinterface"

View File

@@ -34,6 +34,16 @@ func ParseEnvironment(c *Config) error {
c.Interface = env
}
// Find interface
env = os.Getenv(vipAutoInterface)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.AutoInterface = b
}
// Find (services) interface
env = os.Getenv(vipServicesInterface)
if env != "" {
@@ -449,22 +459,37 @@ func parseEnvironmentLoadBalancer(c *Config) error {
// generatePodSpec will take a kube-vip config and generate a Pod spec
func generatePodSpec(c *Config, imageVersion string, inCluster bool) *corev1.Pod {
command := "manager"
// build environment variables
newEnvironment := []corev1.EnvVar{
{
Name: vipArp,
Value: strconv.FormatBool(c.EnableARP),
},
{
Name: vipInterface,
Value: c.Interface,
},
{
Name: port,
Value: fmt.Sprintf("%d", c.Port),
},
}
if c.AutoInterface {
// build environment variables
autoInterface := []corev1.EnvVar{
{
Name: vipAutoInterface,
Value: strconv.FormatBool(c.AutoInterface),
},
}
newEnvironment = append(newEnvironment, autoInterface...)
} else {
iface := []corev1.EnvVar{
{
Name: vipInterface,
Value: c.Interface,
},
}
newEnvironment = append(newEnvironment, iface...)
}
// Detect if we should be using a seperate interface for sercices
if c.ServicesInterface != "" {
// build environment variables

View File

@@ -63,6 +63,9 @@ type Config struct {
// Interface is the network interface to bind to (default: First Adapter)
Interface string `yaml:"interface,omitempty"`
// AutoInterface is the network interface to bind to (Adapter is determined from Default Gateway)
AutoInterface bool `yaml:"interface,omitempty"`
// ServicesInterface is the network interface to bind to for services (optional)
ServicesInterface string `yaml:"servicesInterface,omitempty"`

View File

@@ -93,7 +93,7 @@ func New(configMap string, config *kubevip.Config) (*Manager, error) {
// Second check in home directory for kube config
configPath = filepath.Join(os.Getenv("HOME"), ".kube", "config")
if fileExists(configPath) {
log.Debugf("Using external Kubernetes configuration from file [%s]", configPath)
log.Debugf("Using external Kubernetes configuration from home file [%s]", configPath)
cfg, err = clientcmd.BuildConfigFromFlags("", configPath)
if err != nil {
return nil, err

View File

@@ -4,8 +4,10 @@ import (
"fmt"
"net"
"strings"
"syscall"
"github.com/pkg/errors"
"github.com/vishvananda/netlink"
)
// LookupHost resolves dnsName and return an IP or an error
@@ -64,3 +66,22 @@ func GetFullMask(address string) (string, error) {
}
return "", fmt.Errorf("failed to parse %s as either IPv4 or IPv6", address)
}
// GetDefaultGatewayInterface return default gateway interface link
func GetDefaultGatewayInterface() (*net.Interface, error) {
routes, err := netlink.RouteList(nil, syscall.AF_INET)
if err != nil {
return nil, err
}
for _, route := range routes {
if route.Dst == nil || route.Dst.String() == "0.0.0.0/0" {
if route.LinkIndex <= 0 {
return nil, errors.New("Found default route but could not determine interface")
}
return net.InterfaceByIndex(route.LinkIndex)
}
}
return nil, errors.New("Unable to find default route")
}