Merge pull request #1639 from gabrielstedman/feat/allow-iface-not-up

Add an opt-in flag/env var to allow kube-vip to start when interface exists but is not up
This commit is contained in:
Daniel Finneran
2026-07-25 11:49:39 +03:00
committed by GitHub
6 changed files with 42 additions and 3 deletions

View File

@@ -60,6 +60,7 @@ func init() {
// Basic flags
kubeVipCmd.PersistentFlags().StringVar(&initConfig.Interface, "interface", "", "Name of the interface to bind to")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.ServicesInterface, "serviceInterface", "", "Name of the interface to bind to (for services)")
kubeVipCmd.PersistentFlags().BoolVar(&initConfig.AllowInterfaceNotUp, "allowInterfaceNotUp", false, "Allow kube-vip to start even if the interface is not up")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIP, "vip", "", "The Virtual IP address")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.VIPSubnet, "vipSubnet", "", "The Virtual IP address subnet e.g. /32 /24 /8 etc.. (Default to 32 for IPv4 and 128 for IPv6)")
kubeVipCmd.PersistentFlags().StringVar(&initConfig.NodeName, "nodeName", "", "Name to be used for lease holder. Must be unique for each node/instance")

View File

@@ -77,6 +77,16 @@ func ParseEnvironment(c *Config) error {
c.ServicesInterface = env
}
// Tolerate a down interface
env = os.Getenv(vipAllowInterfaceNotUp)
if env != "" {
b, err := strconv.ParseBool(env)
if err != nil {
return err
}
c.AllowInterfaceNotUp = b
}
// Find Kubernetes Leader Election configuration
env = os.Getenv(vipLeaderElection)
if env != "" {

View File

@@ -51,6 +51,9 @@ const (
// vipServicesInterface - defines the interface that the service vips should bind too
vipServicesInterface = "vip_servicesinterface"
// vipAllowInterfaceNotUp - defines if kube-vip should tolerate a down interface
vipAllowInterfaceNotUp = "vip_allow_interface_not_up"
// vipSubnet - defines the subnet that the vip will use
vipSubnet = "vip_subnet"

View File

@@ -239,6 +239,17 @@ func generatePodSpec(c *Config, image, imageVersion string, inCluster bool) (*co
newEnvironment = append(newEnvironment, svcInterface...)
}
// Tolerate a down interface
if c.AllowInterfaceNotUp {
allowIface := []corev1.EnvVar{
{
Name: vipAllowInterfaceNotUp,
Value: strconv.FormatBool(c.AllowInterfaceNotUp),
},
}
newEnvironment = append(newEnvironment, allowIface...)
}
// If a subnet is required for the VIP
if c.VIPSubnet != "" {
// build environment variables

View File

@@ -1,6 +1,7 @@
package kubevip
import (
"errors"
"fmt"
log "log/slog"
@@ -12,6 +13,8 @@ const (
Auto = "auto"
)
var ErrInterfaceNotUp = errors.New("interface is not up")
func (c *Config) CheckSubnetExists() error {
if c.VIPSubnet == "" && c.VIP != "" && c.Address == "" {
return fmt.Errorf("vip_subnet must be set if using vip_address instead of address environment variable")
@@ -23,15 +26,23 @@ func (c *Config) CheckSubnetExists() error {
func (c *Config) CheckInterface() error {
if c.Interface != "" {
if err := isValidInterface(c.Interface); err != nil {
if errors.Is(err, ErrInterfaceNotUp) && c.AllowInterfaceNotUp {
log.Warn("interface is not up, continuing as allowInterfaceNotUp is set", "interface", c.Interface)
} else {
return fmt.Errorf("%s is not valid interface, reason: %w", c.Interface, err)
}
}
}
if c.ServicesInterface != "" {
if err := isValidInterface(c.ServicesInterface); err != nil {
if errors.Is(err, ErrInterfaceNotUp) && c.AllowInterfaceNotUp {
log.Warn("interface is not up, continuing as allowInterfaceNotUp is set", "interface", c.ServicesInterface)
} else {
return fmt.Errorf("%s is not valid interface, reason: %w", c.ServicesInterface, err)
}
}
}
return nil
}
@@ -58,7 +69,7 @@ func isValidInterface(iface string) error {
iface,
)
} else if attrs.OperState != netlink.OperUp {
return fmt.Errorf("%s is not up", iface)
return fmt.Errorf("%s %w", iface, ErrInterfaceNotUp)
}
return nil

View File

@@ -115,6 +115,9 @@ type Config struct {
// ServicesInterface is the network interface to bind to for services (optional)
ServicesInterface string `yaml:"servicesInterface,omitempty"`
// AllowInterfaceNotUp allows kube-vip to start even when the interface is not up
AllowInterfaceNotUp bool `yaml:"allowInterfaceNotUp,omitempty"`
// EnableLoadBalancer, provides the flexibility to make the load-balancer optional
EnableLoadBalancer bool `yaml:"enableLoadBalancer"`