move IPv6DualStack feature to stable. (#104691)
* kube-proxy * endpoints controller * app: kube-controller-manager * app: cloud-controller-manager * kubelet * app: api-server * node utils + registry/strategy * api: validation (comment removal) * api:pod strategy (util pkg) * api: docs * core: integration testing * kubeadm: change feature gate to GA * service registry and rest stack * move feature to GA * generated
This commit is contained in:

committed by
GitHub

parent
c74d799677
commit
a53e2eaeab
@@ -25,13 +25,11 @@ import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
cloudprovider "k8s.io/cloud-provider"
|
||||
"k8s.io/cloud-provider/app"
|
||||
cloudcontrollerconfig "k8s.io/cloud-provider/app/config"
|
||||
genericcontrollermanager "k8s.io/controller-manager/app"
|
||||
"k8s.io/controller-manager/controller"
|
||||
"k8s.io/controller-manager/pkg/features"
|
||||
"k8s.io/klog/v2"
|
||||
nodeipamcontrolleroptions "k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
|
||||
nodeipamcontroller "k8s.io/kubernetes/pkg/controller/nodeipam"
|
||||
@@ -79,11 +77,6 @@ func startNodeIpamController(initContext app.ControllerInitContext, ccmConfig *c
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// failure: more than one cidr and dual stack is not enabled
|
||||
if len(clusterCIDRs) > 1 && !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
|
||||
return nil, false, fmt.Errorf("len of ClusterCIDRs==%v and dualstack feature is not enabled", len(clusterCIDRs))
|
||||
}
|
||||
|
||||
// failure: more than one cidr but they are not configured as dual stack
|
||||
if len(clusterCIDRs) > 1 && !dualStack {
|
||||
return nil, false, fmt.Errorf("len of ClusterCIDRs==%v and they are not configured as dual stack (at least one from each IPFamily", len(clusterCIDRs))
|
||||
@@ -111,11 +104,6 @@ func startNodeIpamController(initContext app.ControllerInitContext, ccmConfig *c
|
||||
|
||||
// the following checks are triggered if both serviceCIDR and secondaryServiceCIDR are provided
|
||||
if serviceCIDR != nil && secondaryServiceCIDR != nil {
|
||||
// should have dual stack flag enabled
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
|
||||
return nil, false, fmt.Errorf("secondary service cidr is provided and IPv6DualStack feature is not enabled")
|
||||
}
|
||||
|
||||
// should be dual stack (from different IPFamilies)
|
||||
dualstackServiceCIDR, err := netutils.IsDualStackCIDRs([]*net.IPNet{serviceCIDR, secondaryServiceCIDR})
|
||||
if err != nil {
|
||||
@@ -126,24 +114,11 @@ func startNodeIpamController(initContext app.ControllerInitContext, ccmConfig *c
|
||||
}
|
||||
}
|
||||
|
||||
var nodeCIDRMaskSizeIPv4, nodeCIDRMaskSizeIPv6 int
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
|
||||
// only --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 supported with dual stack clusters.
|
||||
// --node-cidr-mask-size flag is incompatible with dual stack clusters.
|
||||
nodeCIDRMaskSizeIPv4, nodeCIDRMaskSizeIPv6, err = setNodeCIDRMaskSizesDualStack(nodeIPAMConfig)
|
||||
} else {
|
||||
// only --node-cidr-mask-size supported with single stack clusters.
|
||||
// --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 flags are incompatible with dual stack clusters.
|
||||
nodeCIDRMaskSizeIPv4, nodeCIDRMaskSizeIPv6, err = setNodeCIDRMaskSizes(nodeIPAMConfig)
|
||||
}
|
||||
|
||||
nodeCIDRMaskSizes, err := setNodeCIDRMaskSizes(nodeIPAMConfig, clusterCIDRs)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// get list of node cidr mask sizes
|
||||
nodeCIDRMaskSizes := getNodeCIDRMaskSizes(clusterCIDRs, nodeCIDRMaskSizeIPv4, nodeCIDRMaskSizeIPv6)
|
||||
|
||||
nodeIpamController, err := nodeipamcontroller.NewNodeIpamController(
|
||||
ctx.InformerFactory.Core().V1().Nodes(),
|
||||
cloud,
|
||||
@@ -180,50 +155,75 @@ func processCIDRs(cidrsList string) ([]*net.IPNet, bool, error) {
|
||||
return cidrs, dualstack, nil
|
||||
}
|
||||
|
||||
// setNodeCIDRMaskSizes returns the IPv4 and IPv6 node cidr mask sizes.
|
||||
// If --node-cidr-mask-size not set, then it will return default IPv4 and IPv6 cidr mask sizes.
|
||||
func setNodeCIDRMaskSizes(cfg nodeipamconfig.NodeIPAMControllerConfiguration) (int, int, error) {
|
||||
ipv4Mask, ipv6Mask := defaultNodeMaskCIDRIPv4, defaultNodeMaskCIDRIPv6
|
||||
// NodeCIDRMaskSizeIPv4 and NodeCIDRMaskSizeIPv6 can be used only for dual-stack clusters
|
||||
if cfg.NodeCIDRMaskSizeIPv4 != 0 || cfg.NodeCIDRMaskSizeIPv6 != 0 {
|
||||
return ipv4Mask, ipv6Mask, errors.New("usage of --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 are not allowed with non dual-stack clusters")
|
||||
}
|
||||
if cfg.NodeCIDRMaskSize != 0 {
|
||||
ipv4Mask = int(cfg.NodeCIDRMaskSize)
|
||||
ipv6Mask = int(cfg.NodeCIDRMaskSize)
|
||||
}
|
||||
return ipv4Mask, ipv6Mask, nil
|
||||
}
|
||||
|
||||
// setNodeCIDRMaskSizesDualStack returns the IPv4 and IPv6 node cidr mask sizes to the value provided
|
||||
// setNodeCIDRMaskSizes returns the IPv4 and IPv6 node cidr mask sizes to the value provided
|
||||
// for --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 respectively. If value not provided,
|
||||
// then it will return default IPv4 and IPv6 cidr mask sizes.
|
||||
func setNodeCIDRMaskSizesDualStack(cfg nodeipamconfig.NodeIPAMControllerConfiguration) (int, int, error) {
|
||||
ipv4Mask, ipv6Mask := defaultNodeMaskCIDRIPv4, defaultNodeMaskCIDRIPv6
|
||||
// NodeCIDRMaskSize can be used only for single stack clusters
|
||||
if cfg.NodeCIDRMaskSize != 0 {
|
||||
return ipv4Mask, ipv6Mask, errors.New("usage of --node-cidr-mask-size is not allowed with dual-stack clusters")
|
||||
func setNodeCIDRMaskSizes(cfg nodeipamconfig.NodeIPAMControllerConfiguration, clusterCIDRs []*net.IPNet) ([]int, error) {
|
||||
|
||||
sortedSizes := func(maskSizeIPv4, maskSizeIPv6 int) []int {
|
||||
nodeMaskCIDRs := make([]int, len(clusterCIDRs))
|
||||
|
||||
for idx, clusterCIDR := range clusterCIDRs {
|
||||
if netutils.IsIPv6CIDR(clusterCIDR) {
|
||||
nodeMaskCIDRs[idx] = maskSizeIPv6
|
||||
} else {
|
||||
nodeMaskCIDRs[idx] = maskSizeIPv4
|
||||
}
|
||||
}
|
||||
return nodeMaskCIDRs
|
||||
}
|
||||
if cfg.NodeCIDRMaskSizeIPv4 != 0 {
|
||||
|
||||
// --node-cidr-mask-size flag is incompatible with dual stack clusters.
|
||||
ipv4Mask, ipv6Mask := defaultNodeMaskCIDRIPv4, defaultNodeMaskCIDRIPv6
|
||||
isDualstack := len(clusterCIDRs) > 1
|
||||
|
||||
// case one: cluster is dualstack (i.e, more than one cidr)
|
||||
if isDualstack {
|
||||
// if --node-cidr-mask-size then fail, user must configure the correct dual-stack mask sizes (or use default)
|
||||
if cfg.NodeCIDRMaskSize != 0 {
|
||||
return nil, errors.New("usage of --node-cidr-mask-size is not allowed with dual-stack clusters")
|
||||
}
|
||||
|
||||
if cfg.NodeCIDRMaskSizeIPv4 != 0 {
|
||||
ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4)
|
||||
}
|
||||
if cfg.NodeCIDRMaskSizeIPv6 != 0 {
|
||||
ipv6Mask = int(cfg.NodeCIDRMaskSizeIPv6)
|
||||
}
|
||||
return sortedSizes(ipv4Mask, ipv6Mask), nil
|
||||
}
|
||||
|
||||
maskConfigured := cfg.NodeCIDRMaskSize != 0
|
||||
maskV4Configured := cfg.NodeCIDRMaskSizeIPv4 != 0
|
||||
maskV6Configured := cfg.NodeCIDRMaskSizeIPv6 != 0
|
||||
isSingleStackIPv6 := netutils.IsIPv6CIDR(clusterCIDRs[0])
|
||||
|
||||
// original flag is set
|
||||
if maskConfigured {
|
||||
// original mask flag is still the main reference.
|
||||
if maskV4Configured || maskV6Configured {
|
||||
return nil, errors.New("usage of --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 is not allowed if --node-cidr-mask-size is set. For dual-stack clusters please unset it and use IPFamily specific flags")
|
||||
}
|
||||
|
||||
mask := int(cfg.NodeCIDRMaskSize)
|
||||
return sortedSizes(mask, mask), nil
|
||||
}
|
||||
|
||||
if maskV4Configured {
|
||||
if isSingleStackIPv6 {
|
||||
return nil, errors.New("usage of --node-cidr-mask-size-ipv4 is not allowed for a single-stack IPv6 cluster")
|
||||
}
|
||||
|
||||
ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4)
|
||||
}
|
||||
if cfg.NodeCIDRMaskSizeIPv6 != 0 {
|
||||
|
||||
// !maskV4Configured && !maskConfigured && maskV6Configured
|
||||
if maskV6Configured {
|
||||
if !isSingleStackIPv6 {
|
||||
return nil, errors.New("usage of --node-cidr-mask-size-ipv6 is not allowed for a single-stack IPv4 cluster")
|
||||
}
|
||||
|
||||
ipv6Mask = int(cfg.NodeCIDRMaskSizeIPv6)
|
||||
}
|
||||
return ipv4Mask, ipv6Mask, nil
|
||||
}
|
||||
|
||||
// getNodeCIDRMaskSizes is a helper function that helps the generate the node cidr mask
|
||||
// sizes slice based on the cluster cidr slice
|
||||
func getNodeCIDRMaskSizes(clusterCIDRs []*net.IPNet, maskSizeIPv4, maskSizeIPv6 int) []int {
|
||||
nodeMaskCIDRs := make([]int, len(clusterCIDRs))
|
||||
|
||||
for idx, clusterCIDR := range clusterCIDRs {
|
||||
if netutils.IsIPv6CIDR(clusterCIDR) {
|
||||
nodeMaskCIDRs[idx] = maskSizeIPv6
|
||||
} else {
|
||||
nodeMaskCIDRs[idx] = maskSizeIPv4
|
||||
}
|
||||
}
|
||||
return nodeMaskCIDRs
|
||||
return sortedSizes(ipv4Mask, ipv6Mask), nil
|
||||
}
|
||||
|
@@ -27,7 +27,6 @@ import (
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
aggregatorscheme "k8s.io/kube-aggregator/pkg/apiserver/scheme"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
@@ -54,13 +53,7 @@ func validateClusterIPFlags(options *ServerRunOptions) []error {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
// Secondary IP validation
|
||||
// ControllerManager needs DualStack feature flags
|
||||
secondaryServiceClusterIPRangeUsed := (options.SecondaryServiceClusterIPRange.IP != nil)
|
||||
if secondaryServiceClusterIPRangeUsed && !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
|
||||
errs = append(errs, fmt.Errorf("secondary service cluster-ip range(--service-cluster-ip-range[1]) can only be used if %v feature is enabled", string(features.IPv6DualStack)))
|
||||
}
|
||||
|
||||
// note: While the cluster might be dualstack (i.e. pods with multiple IPs), the user may choose
|
||||
// to only ingress traffic within and into the cluster on one IP family only. this family is decided
|
||||
// by the range set on --service-cluster-ip-range. If/when the user decides to use dual stack services
|
||||
|
@@ -20,9 +20,6 @@ import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
netutils "k8s.io/utils/net"
|
||||
)
|
||||
|
||||
@@ -55,90 +52,61 @@ func makeOptionsWithCIDRs(serviceCIDR string, secondaryServiceCIDR string) *Serv
|
||||
|
||||
func TestClusterServiceIPRange(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
options *ServerRunOptions
|
||||
enableDualStack bool
|
||||
expectErrors bool
|
||||
name string
|
||||
options *ServerRunOptions
|
||||
expectErrors bool
|
||||
}{
|
||||
{
|
||||
name: "no service cidr",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("", ""),
|
||||
enableDualStack: false,
|
||||
name: "no service cidr",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("", ""),
|
||||
},
|
||||
{
|
||||
name: "only secondary service cidr, dual stack gate on",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("", "10.0.0.0/16"),
|
||||
enableDualStack: true,
|
||||
name: "only secondary service cidr",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("", "10.0.0.0/16"),
|
||||
},
|
||||
{
|
||||
name: "only secondary service cidr, dual stack gate off",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("", "10.0.0.0/16"),
|
||||
enableDualStack: false,
|
||||
name: "primary and secondary are provided but not dual stack v4-v4",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/16", "11.0.0.0/16"),
|
||||
},
|
||||
{
|
||||
name: "primary and secondary are provided but not dual stack v4-v4",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/16", "11.0.0.0/16"),
|
||||
enableDualStack: true,
|
||||
name: "primary and secondary are provided but not dual stack v6-v6",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("2000::/108", "3000::/108"),
|
||||
},
|
||||
{
|
||||
name: "primary and secondary are provided but not dual stack v6-v6",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("2000::/108", "3000::/108"),
|
||||
enableDualStack: true,
|
||||
name: "service cidr is too big",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/8", ""),
|
||||
},
|
||||
{
|
||||
name: "valid dual stack with gate disabled",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/16", "3000::/108"),
|
||||
enableDualStack: false,
|
||||
},
|
||||
{
|
||||
name: "service cidr is too big",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/8", ""),
|
||||
enableDualStack: true,
|
||||
},
|
||||
{
|
||||
name: "dual-stack secondary cidr too big",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/16", "3000::/64"),
|
||||
enableDualStack: true,
|
||||
},
|
||||
{
|
||||
name: "valid v6-v4 dual stack + gate on + endpointSlice gate is on",
|
||||
expectErrors: false,
|
||||
options: makeOptionsWithCIDRs("3000::/108", "10.0.0.0/16"),
|
||||
enableDualStack: true,
|
||||
name: "dual-stack secondary cidr too big",
|
||||
expectErrors: true,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/16", "3000::/64"),
|
||||
},
|
||||
|
||||
/* success cases */
|
||||
{
|
||||
name: "valid primary",
|
||||
expectErrors: false,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/16", ""),
|
||||
enableDualStack: false,
|
||||
name: "valid primary",
|
||||
expectErrors: false,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/16", ""),
|
||||
},
|
||||
{
|
||||
name: "valid v4-v6 dual stack + gate on",
|
||||
expectErrors: false,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/16", "3000::/108"),
|
||||
enableDualStack: true,
|
||||
name: "valid v4-v6 dual stack",
|
||||
expectErrors: false,
|
||||
options: makeOptionsWithCIDRs("10.0.0.0/16", "3000::/108"),
|
||||
},
|
||||
{
|
||||
name: "valid v6-v4 dual stack + gate on",
|
||||
expectErrors: false,
|
||||
options: makeOptionsWithCIDRs("3000::/108", "10.0.0.0/16"),
|
||||
enableDualStack: true,
|
||||
name: "valid v6-v4 dual stack",
|
||||
expectErrors: false,
|
||||
options: makeOptionsWithCIDRs("3000::/108", "10.0.0.0/16"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IPv6DualStack, tc.enableDualStack)()
|
||||
errs := validateClusterIPFlags(tc.options)
|
||||
if len(errs) > 0 && !tc.expectErrors {
|
||||
t.Errorf("expected no errors, errors found %+v", errs)
|
||||
|
@@ -110,11 +110,6 @@ func startNodeIpamController(ctx ControllerContext) (controller.Interface, bool,
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// failure: more than one cidr and dual stack is not enabled
|
||||
if len(clusterCIDRs) > 1 && !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
|
||||
return nil, false, fmt.Errorf("len of ClusterCIDRs==%v and dualstack or EndpointSlice feature is not enabled", len(clusterCIDRs))
|
||||
}
|
||||
|
||||
// failure: more than one cidr but they are not configured as dual stack
|
||||
if len(clusterCIDRs) > 1 && !dualStack {
|
||||
return nil, false, fmt.Errorf("len of ClusterCIDRs==%v and they are not configured as dual stack (at least one from each IPFamily)", len(clusterCIDRs))
|
||||
@@ -142,11 +137,6 @@ func startNodeIpamController(ctx ControllerContext) (controller.Interface, bool,
|
||||
|
||||
// the following checks are triggered if both serviceCIDR and secondaryServiceCIDR are provided
|
||||
if serviceCIDR != nil && secondaryServiceCIDR != nil {
|
||||
// should have dual stack flag enabled
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
|
||||
return nil, false, fmt.Errorf("secondary service cidr is provided and IPv6DualStack feature is not enabled")
|
||||
}
|
||||
|
||||
// should be dual stack (from different IPFamilies)
|
||||
dualstackServiceCIDR, err := netutils.IsDualStackCIDRs([]*net.IPNet{serviceCIDR, secondaryServiceCIDR})
|
||||
if err != nil {
|
||||
@@ -157,24 +147,13 @@ func startNodeIpamController(ctx ControllerContext) (controller.Interface, bool,
|
||||
}
|
||||
}
|
||||
|
||||
var nodeCIDRMaskSizeIPv4, nodeCIDRMaskSizeIPv6 int
|
||||
if dualStack {
|
||||
// only --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 supported with dual stack clusters.
|
||||
// --node-cidr-mask-size flag is incompatible with dual stack clusters.
|
||||
nodeCIDRMaskSizeIPv4, nodeCIDRMaskSizeIPv6, err = setNodeCIDRMaskSizesDualStack(ctx.ComponentConfig.NodeIPAMController)
|
||||
} else {
|
||||
// only --node-cidr-mask-size supported with single stack clusters.
|
||||
// --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 flags are incompatible with single stack clusters.
|
||||
nodeCIDRMaskSizeIPv4, nodeCIDRMaskSizeIPv6, err = setNodeCIDRMaskSizes(ctx.ComponentConfig.NodeIPAMController)
|
||||
}
|
||||
|
||||
// only --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 supported with dual stack clusters.
|
||||
// --node-cidr-mask-size flag is incompatible with dual stack clusters.
|
||||
nodeCIDRMaskSizes, err := setNodeCIDRMaskSizes(ctx.ComponentConfig.NodeIPAMController, clusterCIDRs)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// get list of node cidr mask sizes
|
||||
nodeCIDRMaskSizes := getNodeCIDRMaskSizes(clusterCIDRs, nodeCIDRMaskSizeIPv4, nodeCIDRMaskSizeIPv6)
|
||||
|
||||
nodeIpamController, err := nodeipamcontroller.NewNodeIpamController(
|
||||
ctx.InformerFactory.Core().V1().Nodes(),
|
||||
ctx.Cloud,
|
||||
@@ -257,11 +236,6 @@ func startRouteController(ctx ControllerContext) (controller.Interface, bool, er
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
// failure: more than one cidr and dual stack is not enabled
|
||||
if len(clusterCIDRs) > 1 && !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) {
|
||||
return nil, false, fmt.Errorf("len of ClusterCIDRs==%v and dualstack feature is not enabled", len(clusterCIDRs))
|
||||
}
|
||||
|
||||
// failure: more than one cidr but they are not configured as dual stack
|
||||
if len(clusterCIDRs) > 1 && !dualStack {
|
||||
return nil, false, fmt.Errorf("len of ClusterCIDRs==%v and they are not configured as dual stack (at least one from each IPFamily", len(clusterCIDRs))
|
||||
@@ -627,54 +601,79 @@ func processCIDRs(cidrsList string) ([]*net.IPNet, bool, error) {
|
||||
return cidrs, dualstack, nil
|
||||
}
|
||||
|
||||
// setNodeCIDRMaskSizes returns the IPv4 and IPv6 node cidr mask sizes.
|
||||
// If --node-cidr-mask-size not set, then it will return default IPv4 and IPv6 cidr mask sizes.
|
||||
func setNodeCIDRMaskSizes(cfg nodeipamconfig.NodeIPAMControllerConfiguration) (int, int, error) {
|
||||
ipv4Mask, ipv6Mask := defaultNodeMaskCIDRIPv4, defaultNodeMaskCIDRIPv6
|
||||
// NodeCIDRMaskSizeIPv4 and NodeCIDRMaskSizeIPv6 can be used only for dual-stack clusters
|
||||
if cfg.NodeCIDRMaskSizeIPv4 != 0 || cfg.NodeCIDRMaskSizeIPv6 != 0 {
|
||||
return ipv4Mask, ipv6Mask, errors.New("usage of --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 are not allowed with non dual-stack clusters")
|
||||
}
|
||||
if cfg.NodeCIDRMaskSize != 0 {
|
||||
ipv4Mask = int(cfg.NodeCIDRMaskSize)
|
||||
ipv6Mask = int(cfg.NodeCIDRMaskSize)
|
||||
}
|
||||
return ipv4Mask, ipv6Mask, nil
|
||||
}
|
||||
|
||||
// setNodeCIDRMaskSizesDualStack returns the IPv4 and IPv6 node cidr mask sizes to the value provided
|
||||
// setNodeCIDRMaskSizes returns the IPv4 and IPv6 node cidr mask sizes to the value provided
|
||||
// for --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 respectively. If value not provided,
|
||||
// then it will return default IPv4 and IPv6 cidr mask sizes.
|
||||
func setNodeCIDRMaskSizesDualStack(cfg nodeipamconfig.NodeIPAMControllerConfiguration) (int, int, error) {
|
||||
ipv4Mask, ipv6Mask := defaultNodeMaskCIDRIPv4, defaultNodeMaskCIDRIPv6
|
||||
// NodeCIDRMaskSize can be used only for single stack clusters
|
||||
if cfg.NodeCIDRMaskSize != 0 {
|
||||
return ipv4Mask, ipv6Mask, errors.New("usage of --node-cidr-mask-size is not allowed with dual-stack clusters")
|
||||
func setNodeCIDRMaskSizes(cfg nodeipamconfig.NodeIPAMControllerConfiguration, clusterCIDRs []*net.IPNet) ([]int, error) {
|
||||
|
||||
sortedSizes := func(maskSizeIPv4, maskSizeIPv6 int) []int {
|
||||
nodeMaskCIDRs := make([]int, len(clusterCIDRs))
|
||||
|
||||
for idx, clusterCIDR := range clusterCIDRs {
|
||||
if netutils.IsIPv6CIDR(clusterCIDR) {
|
||||
nodeMaskCIDRs[idx] = maskSizeIPv6
|
||||
} else {
|
||||
nodeMaskCIDRs[idx] = maskSizeIPv4
|
||||
}
|
||||
}
|
||||
return nodeMaskCIDRs
|
||||
}
|
||||
if cfg.NodeCIDRMaskSizeIPv4 != 0 {
|
||||
|
||||
// --node-cidr-mask-size flag is incompatible with dual stack clusters.
|
||||
ipv4Mask, ipv6Mask := defaultNodeMaskCIDRIPv4, defaultNodeMaskCIDRIPv6
|
||||
isDualstack := len(clusterCIDRs) > 1
|
||||
|
||||
// case one: cluster is dualstack (i.e, more than one cidr)
|
||||
if isDualstack {
|
||||
// if --node-cidr-mask-size then fail, user must configure the correct dual-stack mask sizes (or use default)
|
||||
if cfg.NodeCIDRMaskSize != 0 {
|
||||
return nil, errors.New("usage of --node-cidr-mask-size is not allowed with dual-stack clusters")
|
||||
|
||||
}
|
||||
|
||||
if cfg.NodeCIDRMaskSizeIPv4 != 0 {
|
||||
ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4)
|
||||
}
|
||||
if cfg.NodeCIDRMaskSizeIPv6 != 0 {
|
||||
ipv6Mask = int(cfg.NodeCIDRMaskSizeIPv6)
|
||||
}
|
||||
return sortedSizes(ipv4Mask, ipv6Mask), nil
|
||||
}
|
||||
|
||||
maskConfigured := cfg.NodeCIDRMaskSize != 0
|
||||
maskV4Configured := cfg.NodeCIDRMaskSizeIPv4 != 0
|
||||
maskV6Configured := cfg.NodeCIDRMaskSizeIPv6 != 0
|
||||
isSingleStackIPv6 := netutils.IsIPv6CIDR(clusterCIDRs[0])
|
||||
|
||||
// original flag is set
|
||||
if maskConfigured {
|
||||
// original mask flag is still the main reference.
|
||||
if maskV4Configured || maskV6Configured {
|
||||
return nil, errors.New("usage of --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 is not allowed if --node-cidr-mask-size is set. For dual-stack clusters please unset it and use IPFamily specific flags")
|
||||
}
|
||||
|
||||
mask := int(cfg.NodeCIDRMaskSize)
|
||||
return sortedSizes(mask, mask), nil
|
||||
}
|
||||
|
||||
if maskV4Configured {
|
||||
if isSingleStackIPv6 {
|
||||
return nil, errors.New("usage of --node-cidr-mask-size-ipv4 is not allowed for a single-stack IPv6 cluster")
|
||||
}
|
||||
|
||||
ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4)
|
||||
}
|
||||
if cfg.NodeCIDRMaskSizeIPv6 != 0 {
|
||||
|
||||
// !maskV4Configured && !maskConfigured && maskV6Configured
|
||||
if maskV6Configured {
|
||||
if !isSingleStackIPv6 {
|
||||
return nil, errors.New("usage of --node-cidr-mask-size-ipv6 is not allowed for a single-stack IPv4 cluster")
|
||||
}
|
||||
|
||||
ipv6Mask = int(cfg.NodeCIDRMaskSizeIPv6)
|
||||
}
|
||||
return ipv4Mask, ipv6Mask, nil
|
||||
return sortedSizes(ipv4Mask, ipv6Mask), nil
|
||||
}
|
||||
|
||||
// getNodeCIDRMaskSizes is a helper function that helps the generate the node cidr mask
|
||||
// sizes slice based on the cluster cidr slice
|
||||
func getNodeCIDRMaskSizes(clusterCIDRs []*net.IPNet, maskSizeIPv4, maskSizeIPv6 int) []int {
|
||||
nodeMaskCIDRs := make([]int, len(clusterCIDRs))
|
||||
|
||||
for idx, clusterCIDR := range clusterCIDRs {
|
||||
if netutils.IsIPv6CIDR(clusterCIDR) {
|
||||
nodeMaskCIDRs[idx] = maskSizeIPv6
|
||||
} else {
|
||||
nodeMaskCIDRs[idx] = maskSizeIPv4
|
||||
}
|
||||
}
|
||||
return nodeMaskCIDRs
|
||||
}
|
||||
|
||||
func startStorageVersionGCController(ctx ControllerContext) (controller.Interface, bool, error) {
|
||||
go storageversiongc.NewStorageVersionGC(
|
||||
ctx.ClientBuilder.ClientOrDie("storage-version-garbage-collector"),
|
||||
|
@@ -44,13 +44,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
toolswatch "k8s.io/client-go/tools/watch"
|
||||
"k8s.io/component-base/configz"
|
||||
"k8s.io/component-base/metrics"
|
||||
utilsysctl "k8s.io/component-helpers/node/utils/sysctl"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/proxy"
|
||||
proxyconfigapi "k8s.io/kubernetes/pkg/proxy/apis/config"
|
||||
"k8s.io/kubernetes/pkg/proxy/apis/config/scheme"
|
||||
@@ -183,29 +181,25 @@ func newProxyServer(
|
||||
iptInterface = utiliptables.New(execer, primaryProtocol)
|
||||
|
||||
var ipt [2]utiliptables.Interface
|
||||
dualStack := utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) && proxyMode != proxyModeUserspace
|
||||
if dualStack {
|
||||
dualStack := true // While we assume that node supports, we do further checks below
|
||||
|
||||
if proxyMode != proxyModeUserspace {
|
||||
// Create iptables handlers for both families, one is already created
|
||||
// Always ordered as IPv4, IPv6
|
||||
if primaryProtocol == utiliptables.ProtocolIPv4 {
|
||||
ipt[0] = iptInterface
|
||||
ipt[1] = utiliptables.New(execer, utiliptables.ProtocolIPv6)
|
||||
|
||||
// Just because the feature gate is enabled doesn't mean the node
|
||||
// actually supports dual-stack
|
||||
if _, err := ipt[1].ChainExists(utiliptables.TableNAT, utiliptables.ChainPostrouting); err != nil {
|
||||
klog.Warningf("No iptables support for IPv6: %v", err)
|
||||
dualStack = false
|
||||
}
|
||||
} else {
|
||||
ipt[0] = utiliptables.New(execer, utiliptables.ProtocolIPv4)
|
||||
ipt[1] = iptInterface
|
||||
}
|
||||
}
|
||||
if dualStack {
|
||||
klog.V(0).InfoS("kube-proxy running in dual-stack mode", "ipFamily", iptInterface.Protocol())
|
||||
} else {
|
||||
klog.V(0).InfoS("kube-proxy running in single-stack mode", "ipFamily", iptInterface.Protocol())
|
||||
|
||||
for _, perFamilyIpt := range ipt {
|
||||
if !perFamilyIpt.Present() {
|
||||
klog.V(0).InfoS("kube-proxy running in single-stack mode, this ipFamily is not supported", "ipFamily", perFamilyIpt.Protocol())
|
||||
dualStack = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if proxyMode == proxyModeIPTables {
|
||||
@@ -216,8 +210,8 @@ func newProxyServer(
|
||||
}
|
||||
|
||||
if dualStack {
|
||||
klog.V(0).InfoS("kube-proxy running in dual-stack mode", "ipFamily", iptInterface.Protocol())
|
||||
klog.V(0).InfoS("Creating dualStackProxier for iptables")
|
||||
|
||||
// Always ordered to match []ipt
|
||||
var localDetectors [2]proxyutiliptables.LocalTrafficDetector
|
||||
localDetectors, err = getDualStackLocalDetectorTuple(detectLocalMode, config, ipt, nodeInfo)
|
||||
@@ -241,7 +235,8 @@ func newProxyServer(
|
||||
healthzServer,
|
||||
config.NodePortAddresses,
|
||||
)
|
||||
} else { // Create a single-stack proxier.
|
||||
} else {
|
||||
// Create a single-stack proxier if and only if the node does not support dual-stack (i.e, no iptables support).
|
||||
var localDetector proxyutiliptables.LocalTrafficDetector
|
||||
localDetector, err = getLocalDetector(detectLocalMode, config, iptInterface, nodeInfo)
|
||||
if err != nil {
|
||||
|
@@ -39,7 +39,7 @@ const (
|
||||
|
||||
// InitFeatureGates are the default feature gates for the init command
|
||||
var InitFeatureGates = FeatureList{
|
||||
IPv6DualStack: {FeatureSpec: featuregate.FeatureSpec{Default: true, PreRelease: featuregate.Beta}},
|
||||
IPv6DualStack: {FeatureSpec: featuregate.FeatureSpec{Default: true, LockToDefault: true, PreRelease: featuregate.GA}, HiddenInHelpText: true},
|
||||
PublicKeysECDSA: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
||||
RootlessControlPlane: {FeatureSpec: featuregate.FeatureSpec{Default: false, PreRelease: featuregate.Alpha}},
|
||||
}
|
||||
|
@@ -1130,9 +1130,8 @@ func RunKubelet(kubeServer *options.KubeletServer, kubeDeps *kubelet.Dependencie
|
||||
}
|
||||
}
|
||||
}
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.IPv6DualStack) && len(nodeIPs) > 1 {
|
||||
return fmt.Errorf("dual-stack --node-ip %q not supported in a single-stack cluster", kubeServer.NodeIP)
|
||||
} else if len(nodeIPs) > 2 || (len(nodeIPs) == 2 && netutils.IsIPv6(nodeIPs[0]) == netutils.IsIPv6(nodeIPs[1])) {
|
||||
|
||||
if len(nodeIPs) > 2 || (len(nodeIPs) == 2 && netutils.IsIPv6(nodeIPs[0]) == netutils.IsIPv6(nodeIPs[1])) {
|
||||
return fmt.Errorf("bad --node-ip %q; must contain either a single IP or a dual-stack pair of IPs", kubeServer.NodeIP)
|
||||
} else if len(nodeIPs) == 2 && kubeServer.CloudProvider != "" {
|
||||
return fmt.Errorf("dual-stack --node-ip %q not supported when using a cloud provider", kubeServer.NodeIP)
|
||||
|
Reference in New Issue
Block a user