From 605ea383ddcf3f3417caafb92ba99a4889f65f2d Mon Sep 17 00:00:00 2001 From: Jordan May Date: Wed, 18 Sep 2024 10:30:52 -0400 Subject: [PATCH] Add support for Spot VMs --- api/v1beta1/gcpmachine_types.go | 13 +++++++++++ api/v1beta1/zz_generated.deepcopy.go | 5 +++++ cloud/scope/machine.go | 10 +++++++++ ...tructure.cluster.x-k8s.io_gcpmachines.yaml | 9 ++++++++ ....cluster.x-k8s.io_gcpmachinetemplates.yaml | 9 ++++++++ docs/book/src/topics/preemptible-vms.md | 22 +++++++++++++++++++ 6 files changed, 68 insertions(+) diff --git a/api/v1beta1/gcpmachine_types.go b/api/v1beta1/gcpmachine_types.go index 7e27e7845..849754b35 100644 --- a/api/v1beta1/gcpmachine_types.go +++ b/api/v1beta1/gcpmachine_types.go @@ -216,6 +216,12 @@ type CustomerEncryptionKey struct { // +optional SuppliedKey *SuppliedKey `json:"suppliedKey,omitempty"` } +type ProvisioningModel string + +const ( + ProvisioningModelStandard ProvisioningModel = "Standard" + ProvisioningModelSpot ProvisioningModel = "Spot" +) // GCPMachineSpec defines the desired state of GCPMachine. type GCPMachineSpec struct { @@ -302,6 +308,13 @@ type GCPMachineSpec struct { // +optional Preemptible bool `json:"preemptible,omitempty"` + // ProvisioningModel defines if instance is spot. + // If set to "Standard" while preemptible is true, then the VM will be of type "Preemptible". + // If "Spot", VM type is "Spot". When unspecified, defaults to "Standard". + // +kubebuilder:validation:Enum=Standard;Spot + // +optional + ProvisioningModel *ProvisioningModel `json:"provisioningModel,omitempty"` + // IPForwarding Allows this instance to send and receive packets with non-matching destination or source IPs. // This is required if you plan to use this instance to forward routes. Defaults to enabled. // +kubebuilder:validation:Enum=Enabled;Disabled diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 78c0f8571..3c8560ad9 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -475,6 +475,11 @@ func (in *GCPMachineSpec) DeepCopyInto(out *GCPMachineSpec) { *out = new(ServiceAccount) (*in).DeepCopyInto(*out) } + if in.ProvisioningModel != nil { + in, out := &in.ProvisioningModel, &out.ProvisioningModel + *out = new(ProvisioningModel) + **out = **in + } if in.IPForwarding != nil { in, out := &in.IPForwarding, &out.IPForwarding *out = new(IPForwarding) diff --git a/cloud/scope/machine.go b/cloud/scope/machine.go index 96f745822..ce5d02d55 100644 --- a/cloud/scope/machine.go +++ b/cloud/scope/machine.go @@ -402,6 +402,16 @@ func (m *MachineScope) InstanceSpec(log logr.Logger) *compute.Instance { Preemptible: m.GCPMachine.Spec.Preemptible, }, } + if m.GCPMachine.Spec.ProvisioningModel != nil { + switch *m.GCPMachine.Spec.ProvisioningModel { + case infrav1.ProvisioningModelSpot: + instance.Scheduling.ProvisioningModel = "SPOT" + case infrav1.ProvisioningModelStandard: + instance.Scheduling.ProvisioningModel = "STANDARD" + default: + log.Error(errors.New("Invalid value"), "Unknown ProvisioningModel value", "Spec.ProvisioningModel", *m.GCPMachine.Spec.ProvisioningModel) + } + } instance.CanIpForward = true if m.GCPMachine.Spec.IPForwarding != nil && *m.GCPMachine.Spec.IPForwarding == infrav1.IPForwardingDisabled { diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmachines.yaml index 24955802d..8badc01a9 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmachines.yaml @@ -235,6 +235,15 @@ spec: description: ProviderID is the unique identifier as specified by the cloud provider. type: string + provisioningModel: + description: |- + ProvisioningModel defines if instance is spot. + If set to "Standard" while preemptible is true, then the VM will be of type "Preemptible". + If "Spot", VM type is "Spot". When unspecified, defaults to "Standard". + enum: + - Standard + - Spot + type: string publicIP: description: |- PublicIP specifies whether the instance should get a public IP. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmachinetemplates.yaml index 5cc470597..68203f92a 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_gcpmachinetemplates.yaml @@ -250,6 +250,15 @@ spec: description: ProviderID is the unique identifier as specified by the cloud provider. type: string + provisioningModel: + description: |- + ProvisioningModel defines if instance is spot. + If set to "Standard" while preemptible is true, then the VM will be of type "Preemptible". + If "Spot", VM type is "Spot". When unspecified, defaults to "Standard". + enum: + - Standard + - Spot + type: string publicIP: description: |- PublicIP specifies whether the instance should get a public IP. diff --git a/docs/book/src/topics/preemptible-vms.md b/docs/book/src/topics/preemptible-vms.md index b0e9636d9..ade417896 100644 --- a/docs/book/src/topics/preemptible-vms.md +++ b/docs/book/src/topics/preemptible-vms.md @@ -28,3 +28,25 @@ spec: vmSize: E2 preemptible: true ``` + +## Spot VMs +[Spot VMs are the latest version of preemptible VMs.](https://cloud.google.com/compute/docs/instances/spot) + +To use a Spot VM instead of a Preemptible VM, add `provisioningModel` to `GCPMachineTemplate` and set it to `Spot`. + +```yaml +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: GCPMachineTemplate +metadata: + name: capg-md-0 +spec: + region: us-west-1 + template: + osDisk: + diskSizeGB: 30 + managedDisk: + storageAccountType: STANDARD + osType: Linux + vmSize: E2 + provisioningModel: Spot +```