mirror of https://github.com/kubernetes/kops.git
feat(spotinst): new hybrid mode
This commit is contained in:
parent
a31abc8873
commit
23c0cdab36
|
|
@ -76,6 +76,8 @@ var (
|
||||||
Spotinst = New("Spotinst", Bool(false))
|
Spotinst = New("Spotinst", Bool(false))
|
||||||
// SpotinstOcean toggles the use of Spotinst Ocean instance group implementation.
|
// SpotinstOcean toggles the use of Spotinst Ocean instance group implementation.
|
||||||
SpotinstOcean = New("SpotinstOcean", Bool(false))
|
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 toggles the installation of the Spotinst controller addon.
|
||||||
SpotinstController = New("SpotinstController", Bool(true))
|
SpotinstController = New("SpotinstController", Bool(true))
|
||||||
// VPCSkipEnableDNSSupport if set will make that a VPC does not need DNSSupport enabled.
|
// VPCSkipEnableDNSSupport if set will make that a VPC does not need DNSSupport enabled.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ go_library(
|
||||||
"//pkg/featureflag:go_default_library",
|
"//pkg/featureflag:go_default_library",
|
||||||
"//pkg/model:go_default_library",
|
"//pkg/model:go_default_library",
|
||||||
"//pkg/model/defaults:go_default_library",
|
"//pkg/model/defaults:go_default_library",
|
||||||
|
"//pkg/model/spotinstmodel:go_default_library",
|
||||||
"//upup/pkg/fi:go_default_library",
|
"//upup/pkg/fi:go_default_library",
|
||||||
"//upup/pkg/fi/cloudup/awstasks:go_default_library",
|
"//upup/pkg/fi/cloudup/awstasks:go_default_library",
|
||||||
"//upup/pkg/fi/fitasks:go_default_library",
|
"//upup/pkg/fi/fitasks:go_default_library",
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"k8s.io/klog"
|
||||||
"k8s.io/kops/pkg/apis/kops"
|
"k8s.io/kops/pkg/apis/kops"
|
||||||
|
"k8s.io/kops/pkg/featureflag"
|
||||||
"k8s.io/kops/pkg/model"
|
"k8s.io/kops/pkg/model"
|
||||||
"k8s.io/kops/pkg/model/defaults"
|
"k8s.io/kops/pkg/model/defaults"
|
||||||
|
"k8s.io/kops/pkg/model/spotinstmodel"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
|
"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 {
|
for _, ig := range b.InstanceGroups {
|
||||||
name := b.AutoscalingGroupName(ig)
|
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
|
// @check if his instancegroup is backed by a fleet and override with a launch template
|
||||||
task, err := func() (fi.Task, error) {
|
task, err := func() (fi.Task, error) {
|
||||||
switch UseLaunchTemplate(ig) {
|
switch UseLaunchTemplate(ig) {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ go_library(
|
||||||
"//pkg/apis/kops:go_default_library",
|
"//pkg/apis/kops:go_default_library",
|
||||||
"//pkg/featureflag:go_default_library",
|
"//pkg/featureflag:go_default_library",
|
||||||
"//pkg/model:go_default_library",
|
"//pkg/model:go_default_library",
|
||||||
"//pkg/model/awsmodel:go_default_library",
|
|
||||||
"//pkg/model/defaults:go_default_library",
|
"//pkg/model/defaults:go_default_library",
|
||||||
"//upup/pkg/fi:go_default_library",
|
"//upup/pkg/fi:go_default_library",
|
||||||
"//upup/pkg/fi/cloudup/awstasks:go_default_library",
|
"//upup/pkg/fi/cloudup/awstasks:go_default_library",
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"k8s.io/kops/pkg/apis/kops"
|
"k8s.io/kops/pkg/apis/kops"
|
||||||
"k8s.io/kops/pkg/featureflag"
|
"k8s.io/kops/pkg/featureflag"
|
||||||
"k8s.io/kops/pkg/model"
|
"k8s.io/kops/pkg/model"
|
||||||
"k8s.io/kops/pkg/model/awsmodel"
|
|
||||||
"k8s.io/kops/pkg/model/defaults"
|
"k8s.io/kops/pkg/model/defaults"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
|
"k8s.io/kops/upup/pkg/fi/cloudup/awstasks"
|
||||||
|
|
@ -34,6 +33,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
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
|
// InstanceGroupLabelSpotPercentage is the metadata label used on the
|
||||||
// instance group to specify the percentage of Spot instances that
|
// instance group to specify the percentage of Spot instances that
|
||||||
// should spin up from the target capacity.
|
// should spin up from the target capacity.
|
||||||
|
|
@ -101,7 +104,7 @@ const (
|
||||||
|
|
||||||
// InstanceGroupModelBuilder configures InstanceGroup objects
|
// InstanceGroupModelBuilder configures InstanceGroup objects
|
||||||
type InstanceGroupModelBuilder struct {
|
type InstanceGroupModelBuilder struct {
|
||||||
*awsmodel.AWSModelContext
|
*model.KopsModelContext
|
||||||
|
|
||||||
BootstrapScript *model.BootstrapScript
|
BootstrapScript *model.BootstrapScript
|
||||||
Lifecycle *fi.Lifecycle
|
Lifecycle *fi.Lifecycle
|
||||||
|
|
@ -115,8 +118,16 @@ func (b *InstanceGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
for _, ig := range b.InstanceGroups {
|
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 {
|
switch ig.Spec.Role {
|
||||||
|
|
||||||
// Create both Master and Bastion instance groups as Elastigroups.
|
// 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)
|
typ := fi.StringValue(ig.Spec.RootVolumeType)
|
||||||
if typ == "" {
|
if typ == "" {
|
||||||
typ = awsmodel.DefaultVolumeType
|
typ = "gp2"
|
||||||
}
|
}
|
||||||
opts.Type = fi.String(typ)
|
opts.Type = fi.String(typ)
|
||||||
}
|
}
|
||||||
|
|
@ -913,3 +924,11 @@ func defaultSpotPercentage(ig *kops.InstanceGroup) *float64 {
|
||||||
|
|
||||||
return &percentage
|
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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ func ListResourcesAWS(cloud awsup.AWSCloud, clusterName string) (map[string]*res
|
||||||
//ListCloudFormationStacks,
|
//ListCloudFormationStacks,
|
||||||
|
|
||||||
// EC2
|
// EC2
|
||||||
|
ListAutoScalingGroups,
|
||||||
ListInstances,
|
ListInstances,
|
||||||
ListKeypairs,
|
ListKeypairs,
|
||||||
ListSecurityGroups,
|
ListSecurityGroups,
|
||||||
|
|
@ -86,9 +87,6 @@ func ListResourcesAWS(cloud awsup.AWSCloud, clusterName string) (map[string]*res
|
||||||
if featureflag.Spotinst.Enabled() {
|
if featureflag.Spotinst.Enabled() {
|
||||||
// Spotinst resources
|
// Spotinst resources
|
||||||
listFunctions = append(listFunctions, ListSpotinstResources)
|
listFunctions = append(listFunctions, ListSpotinstResources)
|
||||||
} else {
|
|
||||||
// AutoScaling Groups
|
|
||||||
listFunctions = append(listFunctions, ListAutoScalingGroups)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fn := range listFunctions {
|
for _, fn := range listFunctions {
|
||||||
|
|
|
||||||
|
|
@ -741,24 +741,32 @@ func (c *ApplyClusterCmd) Run(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
switch kops.CloudProviderID(cluster.Spec.CloudProvider) {
|
switch kops.CloudProviderID(cluster.Spec.CloudProvider) {
|
||||||
case kops.CloudProviderAWS:
|
case kops.CloudProviderAWS:
|
||||||
awsModelContext := &awsmodel.AWSModelContext{
|
{
|
||||||
KopsModelContext: modelContext,
|
awsModelContext := &awsmodel.AWSModelContext{
|
||||||
}
|
KopsModelContext: modelContext,
|
||||||
|
}
|
||||||
|
|
||||||
if featureflag.Spotinst.Enabled() {
|
awsModelBuilder := &awsmodel.AutoscalingGroupModelBuilder{
|
||||||
l.Builders = append(l.Builders, &spotinstmodel.InstanceGroupModelBuilder{
|
|
||||||
AWSModelContext: awsModelContext,
|
AWSModelContext: awsModelContext,
|
||||||
BootstrapScript: bootstrapScriptBuilder,
|
BootstrapScript: bootstrapScriptBuilder,
|
||||||
Lifecycle: &clusterLifecycle,
|
Lifecycle: &clusterLifecycle,
|
||||||
SecurityLifecycle: &securityLifecycle,
|
SecurityLifecycle: &securityLifecycle,
|
||||||
})
|
}
|
||||||
} else {
|
|
||||||
l.Builders = append(l.Builders, &awsmodel.AutoscalingGroupModelBuilder{
|
if featureflag.Spotinst.Enabled() {
|
||||||
AWSModelContext: awsModelContext,
|
l.Builders = append(l.Builders, &spotinstmodel.InstanceGroupModelBuilder{
|
||||||
BootstrapScript: bootstrapScriptBuilder,
|
KopsModelContext: modelContext,
|
||||||
Lifecycle: &clusterLifecycle,
|
BootstrapScript: bootstrapScriptBuilder,
|
||||||
SecurityLifecycle: &securityLifecycle,
|
Lifecycle: &clusterLifecycle,
|
||||||
})
|
SecurityLifecycle: &securityLifecycle,
|
||||||
|
})
|
||||||
|
|
||||||
|
if featureflag.SpotinstHybrid.Enabled() {
|
||||||
|
l.Builders = append(l.Builders, awsModelBuilder)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
l.Builders = append(l.Builders, awsModelBuilder)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case kops.CloudProviderDO:
|
case kops.CloudProviderDO:
|
||||||
doModelContext := &domodel.DOModelContext{
|
doModelContext := &domodel.DOModelContext{
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,12 @@ func NewEC2Filter(name string, values ...string) *ec2.Filter {
|
||||||
// DeleteGroup deletes an aws autoscaling group
|
// DeleteGroup deletes an aws autoscaling group
|
||||||
func (c *awsCloudImplementation) DeleteGroup(g *cloudinstances.CloudInstanceGroup) error {
|
func (c *awsCloudImplementation) DeleteGroup(g *cloudinstances.CloudInstanceGroup) error {
|
||||||
if c.spotinst != nil {
|
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)
|
return spotinst.DeleteInstanceGroup(c.spotinst, g)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -425,6 +431,12 @@ func deleteGroup(c AWSCloud, g *cloudinstances.CloudInstanceGroup) error {
|
||||||
// DeleteInstance deletes an aws instance
|
// DeleteInstance deletes an aws instance
|
||||||
func (c *awsCloudImplementation) DeleteInstance(i *cloudinstances.CloudInstanceGroupMember) error {
|
func (c *awsCloudImplementation) DeleteInstance(i *cloudinstances.CloudInstanceGroupMember) error {
|
||||||
if c.spotinst != nil {
|
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)
|
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
|
// 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) {
|
func (c *awsCloudImplementation) GetCloudGroups(cluster *kops.Cluster, instancegroups []*kops.InstanceGroup, warnUnmatched bool, nodes []v1.Node) (map[string]*cloudinstances.CloudInstanceGroup, error) {
|
||||||
if c.spotinst != nil {
|
if c.spotinst != nil {
|
||||||
return spotinst.GetCloudGroups(c.spotinst, cluster,
|
sgroups, err := spotinst.GetCloudGroups(c.spotinst, cluster, instancegroups, warnUnmatched, nodes)
|
||||||
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)
|
return getCloudGroups(c, cluster, instancegroups, warnUnmatched, nodes)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue