Move merging of kubelet configs to populate instance groups so we have only one place to fetch them

The kubelet config can be configured in a number of places. Merge them earlier so we only need to check the config in the IG kubeletConfig
This commit is contained in:
Ole Markus With 2022-08-11 11:06:05 +02:00
parent 86be353777
commit d471845dce
2 changed files with 150 additions and 37 deletions

View File

@ -20,10 +20,8 @@ import (
"strings"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/nodelabels"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/util/pkg/architectures"
"k8s.io/kops/util/pkg/reflectutils"
)
// Config is the configuration for the nodeup binary
@ -139,7 +137,6 @@ type APIServerConfig struct {
func NewConfig(cluster *kops.Cluster, instanceGroup *kops.InstanceGroup) (*Config, *BootConfig) {
role := instanceGroup.Spec.Role
isMaster := role == kops.InstanceGroupRoleMaster
clusterHooks := filterHooks(cluster.Spec.Hooks, instanceGroup.Spec.Role)
igHooks := filterHooks(instanceGroup.Spec.Hooks, instanceGroup.Spec.Role)
@ -165,39 +162,6 @@ func NewConfig(cluster *kops.Cluster, instanceGroup *kops.InstanceGroup) (*Confi
config.EnableLifecycleHook = true
}
if isMaster {
reflectutils.JSONMergeStruct(&config.KubeletConfig, cluster.Spec.MasterKubelet)
// A few settings in Kubelet override those in MasterKubelet. I'm not sure why.
if cluster.Spec.Kubelet != nil && cluster.Spec.Kubelet.AnonymousAuth != nil && !*cluster.Spec.Kubelet.AnonymousAuth {
config.KubeletConfig.AnonymousAuth = fi.Bool(false)
}
} else {
reflectutils.JSONMergeStruct(&config.KubeletConfig, cluster.Spec.Kubelet)
}
if isMaster || role == kops.InstanceGroupRoleAPIServer {
config.APIServerConfig = &APIServerConfig{
KubeAPIServer: cluster.Spec.KubeAPIServer,
}
}
if instanceGroup.Spec.Kubelet != nil {
useSecureKubelet := config.KubeletConfig.AnonymousAuth != nil && !*config.KubeletConfig.AnonymousAuth
reflectutils.JSONMergeStruct(&config.KubeletConfig, instanceGroup.Spec.Kubelet)
if useSecureKubelet {
config.KubeletConfig.AnonymousAuth = fi.Bool(false)
}
}
// We include the NodeLabels in the userdata even for Kubernetes 1.16 and later so that
// rolling update will still replace nodes when they change.
config.KubeletConfig.NodeLabels = nodelabels.BuildNodeLabels(cluster, instanceGroup)
config.KubeletConfig.Taints = append(config.KubeletConfig.Taints, instanceGroup.Spec.Taints...)
if instanceGroup.Spec.UpdatePolicy != nil {
config.UpdatePolicy = *instanceGroup.Spec.UpdatePolicy
} else if cluster.Spec.UpdatePolicy != nil {
@ -214,6 +178,16 @@ func NewConfig(cluster *kops.Cluster, instanceGroup *kops.InstanceGroup) (*Confi
config.UseInstanceIDForNodeName = true
}
if instanceGroup.Spec.Kubelet != nil {
config.KubeletConfig = *instanceGroup.Spec.Kubelet
}
if instanceGroup.HasAPIServer() {
config.APIServerConfig = &APIServerConfig{
KubeAPIServer: cluster.Spec.KubeAPIServer,
}
}
return &config, &bootConfig
}

View File

@ -24,6 +24,8 @@ import (
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/validation"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/pkg/nodelabels"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
"k8s.io/kops/upup/pkg/fi/cloudup/openstack"
@ -60,7 +62,6 @@ var awsDedicatedInstanceExceptions = map[string]bool{
}
// PopulateInstanceGroupSpec sets default values in the InstanceGroup
// The InstanceGroup is simpler than the cluster spec, so we just populate in place (like the rest of k8s)
func PopulateInstanceGroupSpec(cluster *kops.Cluster, input *kops.InstanceGroup, cloud fi.Cloud, channel *kops.Channel) (*kops.InstanceGroup, error) {
klog.Infof("Populating instance group spec for %q", input.GetName())
@ -73,6 +74,110 @@ func PopulateInstanceGroupSpec(cluster *kops.Cluster, input *kops.InstanceGroup,
ig := &kops.InstanceGroup{}
reflectutils.JSONMergeStruct(ig, input)
spec := &ig.Spec
// TODO: Clean up
if ig.IsMaster() {
if ig.Spec.MachineType == "" {
ig.Spec.MachineType, err = defaultMachineType(cloud, cluster, ig)
if err != nil {
return nil, fmt.Errorf("error assigning default machine type for masters: %v", err)
}
}
if ig.Spec.MinSize == nil {
ig.Spec.MinSize = fi.Int32(1)
}
if ig.Spec.MaxSize == nil {
ig.Spec.MaxSize = fi.Int32(1)
}
} else if ig.Spec.Role == kops.InstanceGroupRoleBastion {
if ig.Spec.MachineType == "" {
ig.Spec.MachineType, err = defaultMachineType(cloud, cluster, ig)
if err != nil {
return nil, fmt.Errorf("error assigning default machine type for bastions: %v", err)
}
}
if ig.Spec.MinSize == nil {
ig.Spec.MinSize = fi.Int32(1)
}
if ig.Spec.MaxSize == nil {
ig.Spec.MaxSize = fi.Int32(1)
}
} else {
if ig.IsAPIServerOnly() && !featureflag.APIServerNodes.Enabled() {
return nil, fmt.Errorf("apiserver nodes requires the APIServerNodes feature flag to be enabled")
}
if ig.Spec.MachineType == "" {
ig.Spec.MachineType, err = defaultMachineType(cloud, cluster, ig)
if err != nil {
return nil, fmt.Errorf("error assigning default machine type for nodes: %v", err)
}
}
if ig.Spec.MinSize == nil {
ig.Spec.MinSize = fi.Int32(2)
}
if ig.Spec.MaxSize == nil {
ig.Spec.MaxSize = fi.Int32(2)
}
}
if ig.Spec.Image == "" {
architecture, err := MachineArchitecture(cloud, ig.Spec.MachineType)
if err != nil {
return nil, fmt.Errorf("unable to determine machine architecture for InstanceGroup %q: %v", ig.ObjectMeta.Name, err)
}
ig.Spec.Image = defaultImage(cluster, channel, architecture)
if ig.Spec.Image == "" {
return nil, fmt.Errorf("unable to determine default image for InstanceGroup %s", ig.ObjectMeta.Name)
}
}
if ig.Spec.Tenancy != "" && ig.Spec.Tenancy != "default" {
switch cluster.Spec.GetCloudProvider() {
case kops.CloudProviderAWS:
if _, ok := awsDedicatedInstanceExceptions[ig.Spec.MachineType]; ok {
return nil, fmt.Errorf("invalid dedicated instance type: %s", ig.Spec.MachineType)
}
default:
klog.Warning("Trying to set tenancy on non-AWS environment")
}
}
if ig.IsMaster() {
if len(ig.Spec.Subnets) == 0 {
return nil, fmt.Errorf("master InstanceGroup %s did not specify any Subnets", ig.ObjectMeta.Name)
}
} else if ig.IsAPIServerOnly() && cluster.Spec.IsIPv6Only() {
if len(ig.Spec.Subnets) == 0 {
for _, subnet := range cluster.Spec.Subnets {
if subnet.Type != kops.SubnetTypePrivate && subnet.Type != kops.SubnetTypeUtility {
ig.Spec.Subnets = append(ig.Spec.Subnets, subnet.Name)
}
}
}
} else {
if len(ig.Spec.Subnets) == 0 {
for _, subnet := range cluster.Spec.Subnets {
if subnet.Type != kops.SubnetTypeDualStack && subnet.Type != kops.SubnetTypeUtility {
ig.Spec.Subnets = append(ig.Spec.Subnets, subnet.Name)
}
}
}
if len(ig.Spec.Subnets) == 0 {
for _, subnet := range cluster.Spec.Subnets {
if subnet.Type != kops.SubnetTypeUtility {
ig.Spec.Subnets = append(ig.Spec.Subnets, subnet.Name)
}
}
}
}
if len(ig.Spec.Subnets) == 0 {
return nil, fmt.Errorf("unable to infer any Subnets for InstanceGroup %s ", ig.ObjectMeta.Name)
}
hasGPU := false
clusterNvidia := false
if cluster.Spec.Containerd != nil && cluster.Spec.Containerd.NvidiaGPU != nil && fi.BoolValue(cluster.Spec.Containerd.NvidiaGPU.Enabled) {
@ -117,6 +222,40 @@ func PopulateInstanceGroupSpec(cluster *kops.Cluster, input *kops.InstanceGroup,
if ig.Spec.Manager == "" {
ig.Spec.Manager = kops.InstanceManagerCloudGroup
}
if spec.Kubelet == nil {
spec.Kubelet = &kops.KubeletConfigSpec{}
}
kubeletConfig := spec.Kubelet
// We include the NodeLabels in the userdata even for Kubernetes 1.16 and later so that
// rolling update will still replace nodes when they change.
kubeletConfig.NodeLabels = nodelabels.BuildNodeLabels(cluster, ig)
kubeletConfig.Taints = append(kubeletConfig.Taints, spec.Taints...)
if ig.IsMaster() {
reflectutils.JSONMergeStruct(kubeletConfig, cluster.Spec.MasterKubelet)
// A few settings in Kubelet override those in MasterKubelet. I'm not sure why.
if cluster.Spec.Kubelet != nil && cluster.Spec.Kubelet.AnonymousAuth != nil && !*cluster.Spec.Kubelet.AnonymousAuth {
kubeletConfig.AnonymousAuth = fi.Bool(false)
}
} else {
reflectutils.JSONMergeStruct(kubeletConfig, cluster.Spec.Kubelet)
}
if ig.Spec.Kubelet != nil {
useSecureKubelet := fi.BoolValue(kubeletConfig.AnonymousAuth)
reflectutils.JSONMergeStruct(kubeletConfig, spec.Kubelet)
if useSecureKubelet {
kubeletConfig.AnonymousAuth = fi.Bool(false)
}
}
return ig, nil
}