feat(spotinst): new hybrid mode

This commit is contained in:
liranp 2019-07-15 11:54:43 +03:00
parent a31abc8873
commit 23c0cdab36
No known key found for this signature in database
GPG Key ID: D5F03857002C1A93
8 changed files with 87 additions and 23 deletions

View File

@ -76,6 +76,8 @@ var (
Spotinst = New("Spotinst", Bool(false))
// SpotinstOcean toggles the use of Spotinst Ocean instance group implementation.
SpotinstOcean = New("SpotinstOcean", Bool(false))
// SpotinstHybrid toggles between hybrid and full instance group implementations.
SpotinstHybrid = New("SpotinstHybrid", Bool(false))
// SpotinstController toggles the installation of the Spotinst controller addon.
SpotinstController = New("SpotinstController", Bool(true))
// VPCSkipEnableDNSSupport if set will make that a VPC does not need DNSSupport enabled.

View File

@ -15,6 +15,7 @@ go_library(
"//pkg/featureflag:go_default_library",
"//pkg/model:go_default_library",
"//pkg/model/defaults:go_default_library",
"//pkg/model/spotinstmodel:go_default_library",
"//upup/pkg/fi:go_default_library",
"//upup/pkg/fi/cloudup/awstasks:go_default_library",
"//upup/pkg/fi/fitasks:go_default_library",

View File

@ -20,9 +20,12 @@ import (
"fmt"
"strings"
"k8s.io/klog"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/pkg/model"
"k8s.io/kops/pkg/model/defaults"
"k8s.io/kops/pkg/model/spotinstmodel"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
@ -54,6 +57,13 @@ func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
for _, ig := range b.InstanceGroups {
name := b.AutoscalingGroupName(ig)
if featureflag.SpotinstHybrid.Enabled() {
if spotinstmodel.ManageInstanceGroup(ig) {
klog.V(2).Infof("Skipping instance group: %q", name)
continue
}
}
// @check if his instancegroup is backed by a fleet and override with a launch template
task, err := func() (fi.Task, error) {
switch UseLaunchTemplate(ig) {

View File

@ -9,7 +9,6 @@ go_library(
"//pkg/apis/kops:go_default_library",
"//pkg/featureflag:go_default_library",
"//pkg/model:go_default_library",
"//pkg/model/awsmodel:go_default_library",
"//pkg/model/defaults:go_default_library",
"//upup/pkg/fi:go_default_library",
"//upup/pkg/fi/cloudup/awstasks:go_default_library",

View File

@ -26,7 +26,6 @@ import (
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/pkg/model"
"k8s.io/kops/pkg/model/awsmodel"
"k8s.io/kops/pkg/model/defaults"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
@ -34,6 +33,10 @@ import (
)
const (
// InstanceGroupLabelManaged is the metadata label used on the instance
// group to specify that the Spotinst provider should be used to upon creation.
InstanceGroupLabelManaged = "spotinst.io/managed"
// InstanceGroupLabelSpotPercentage is the metadata label used on the
// instance group to specify the percentage of Spot instances that
// should spin up from the target capacity.
@ -101,7 +104,7 @@ const (
// InstanceGroupModelBuilder configures InstanceGroup objects
type InstanceGroupModelBuilder struct {
*awsmodel.AWSModelContext
*model.KopsModelContext
BootstrapScript *model.BootstrapScript
Lifecycle *fi.Lifecycle
@ -115,8 +118,16 @@ func (b *InstanceGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
var err error
for _, ig := range b.InstanceGroups {
klog.V(2).Infof("Building instance group: %q", b.AutoscalingGroupName(ig))
name := b.AutoscalingGroupName(ig)
if featureflag.SpotinstHybrid.Enabled() {
if !ManageInstanceGroup(ig) {
klog.V(2).Infof("Skipping instance group: %q", name)
continue
}
}
klog.V(2).Infof("Building instance group: %q", name)
switch ig.Spec.Role {
// Create both Master and Bastion instance groups as Elastigroups.
@ -642,7 +653,7 @@ func (b *InstanceGroupModelBuilder) buildRootVolumeOpts(ig *kops.InstanceGroup)
{
typ := fi.StringValue(ig.Spec.RootVolumeType)
if typ == "" {
typ = awsmodel.DefaultVolumeType
typ = "gp2"
}
opts.Type = fi.String(typ)
}
@ -913,3 +924,11 @@ func defaultSpotPercentage(ig *kops.InstanceGroup) *float64 {
return &percentage
}
// ManageInstanceGroup indicates whether the instance group labeled with
// a metadata label `spotinst.io/managed` which means the Spotinst provider
// should be used to upon creation if the `SpotinstHybrid` feature flag is on.
func ManageInstanceGroup(ig *kops.InstanceGroup) bool {
managed, _ := strconv.ParseBool(ig.ObjectMeta.Labels[InstanceGroupLabelManaged])
return managed
}

View File

@ -61,6 +61,7 @@ func ListResourcesAWS(cloud awsup.AWSCloud, clusterName string) (map[string]*res
//ListCloudFormationStacks,
// EC2
ListAutoScalingGroups,
ListInstances,
ListKeypairs,
ListSecurityGroups,
@ -86,9 +87,6 @@ func ListResourcesAWS(cloud awsup.AWSCloud, clusterName string) (map[string]*res
if featureflag.Spotinst.Enabled() {
// Spotinst resources
listFunctions = append(listFunctions, ListSpotinstResources)
} else {
// AutoScaling Groups
listFunctions = append(listFunctions, ListAutoScalingGroups)
}
for _, fn := range listFunctions {

View File

@ -741,24 +741,32 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
}
switch kops.CloudProviderID(cluster.Spec.CloudProvider) {
case kops.CloudProviderAWS:
awsModelContext := &awsmodel.AWSModelContext{
KopsModelContext: modelContext,
}
{
awsModelContext := &awsmodel.AWSModelContext{
KopsModelContext: modelContext,
}
if featureflag.Spotinst.Enabled() {
l.Builders = append(l.Builders, &spotinstmodel.InstanceGroupModelBuilder{
awsModelBuilder := &awsmodel.AutoscalingGroupModelBuilder{
AWSModelContext: awsModelContext,
BootstrapScript: bootstrapScriptBuilder,
Lifecycle: &clusterLifecycle,
SecurityLifecycle: &securityLifecycle,
})
} else {
l.Builders = append(l.Builders, &awsmodel.AutoscalingGroupModelBuilder{
AWSModelContext: awsModelContext,
BootstrapScript: bootstrapScriptBuilder,
Lifecycle: &clusterLifecycle,
SecurityLifecycle: &securityLifecycle,
})
}
if featureflag.Spotinst.Enabled() {
l.Builders = append(l.Builders, &spotinstmodel.InstanceGroupModelBuilder{
KopsModelContext: modelContext,
BootstrapScript: bootstrapScriptBuilder,
Lifecycle: &clusterLifecycle,
SecurityLifecycle: &securityLifecycle,
})
if featureflag.SpotinstHybrid.Enabled() {
l.Builders = append(l.Builders, awsModelBuilder)
}
} else {
l.Builders = append(l.Builders, awsModelBuilder)
}
}
case kops.CloudProviderDO:
doModelContext := &domodel.DOModelContext{

View File

@ -344,6 +344,12 @@ func NewEC2Filter(name string, values ...string) *ec2.Filter {
// DeleteGroup deletes an aws autoscaling group
func (c *awsCloudImplementation) DeleteGroup(g *cloudinstances.CloudInstanceGroup) error {
if c.spotinst != nil {
if featureflag.SpotinstHybrid.Enabled() {
if _, ok := g.Raw.(*autoscaling.Group); ok {
return deleteGroup(c, g)
}
}
return spotinst.DeleteInstanceGroup(c.spotinst, g)
}
@ -425,6 +431,12 @@ func deleteGroup(c AWSCloud, g *cloudinstances.CloudInstanceGroup) error {
// DeleteInstance deletes an aws instance
func (c *awsCloudImplementation) DeleteInstance(i *cloudinstances.CloudInstanceGroupMember) error {
if c.spotinst != nil {
if featureflag.SpotinstHybrid.Enabled() {
if _, ok := i.CloudInstanceGroup.Raw.(*autoscaling.Group); ok {
return deleteInstance(c, i)
}
}
return spotinst.DeleteInstance(c.spotinst, i)
}
@ -490,8 +502,23 @@ func detachInstance(c AWSCloud, i *cloudinstances.CloudInstanceGroupMember) erro
// GetCloudGroups returns a groups of instances that back a kops instance groups
func (c *awsCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
if c.spotinst != nil {
return spotinst.GetCloudGroups(c.spotinst, cluster,
instancegroups, warnUnmatched, nodes)
sgroups, err := spotinst.GetCloudGroups(c.spotinst, cluster, instancegroups, warnUnmatched, nodes)
if err != nil {
return nil, err
}
if featureflag.SpotinstHybrid.Enabled() {
agroups, err := getCloudGroups(c, cluster, instancegroups, warnUnmatched, nodes)
if err != nil {
return nil, err
}
for name, group := range agroups {
sgroups[name] = group
}
}
return sgroups, nil
}
return getCloudGroups(c, cluster, instancegroups, warnUnmatched, nodes)