Skip to content

Commit

Permalink
feat: Implemented NodeOverlay with support for custom pricing
Browse files Browse the repository at this point in the history
  • Loading branch information
ellistarn committed Jun 6, 2024
1 parent f2de2b4 commit af92b99
Show file tree
Hide file tree
Showing 21 changed files with 542 additions and 103 deletions.
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module sigs.k8s.io/karpenter

go 1.22.3
go 1.22.4

require (
github.com/Pallinder/go-randomdata v1.2.0
github.com/avast/retry-go v3.0.0+incompatible
github.com/awslabs/operatorpkg v0.0.0-20240514175841-edb8fe5824b4
github.com/awslabs/operatorpkg v0.0.0-20240605172541-88cf99023fa4
github.com/docker/docker v26.1.3+incompatible
github.com/go-logr/logr v1.4.2
github.com/imdario/mergo v0.3.16
Expand All @@ -29,6 +29,7 @@ require (
k8s.io/component-base v0.30.1
k8s.io/csi-translation-lib v0.30.1
k8s.io/klog/v2 v2.120.1
k8s.io/kubernetes v1.30.1
k8s.io/utils v0.0.0-20240102154912-e7106e64919e
knative.dev/pkg v0.0.0-20230712131115-7051d301e7f4
sigs.k8s.io/controller-runtime v0.18.3
Expand Down Expand Up @@ -90,7 +91,7 @@ require (
golang.org/x/term v0.20.0 // indirect
golang.org/x/tools v0.21.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/api v0.124.0 // indirect
google.golang.org/api v0.126.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
Expand Down
10 changes: 6 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/awslabs/operatorpkg v0.0.0-20240514175841-edb8fe5824b4 h1:Du6S9Xa+/VuCpoSwOW7QpPM30IEIvB91WJEIltWQwRk=
github.com/awslabs/operatorpkg v0.0.0-20240514175841-edb8fe5824b4/go.mod h1:YcidmUg8Pjk349+jd+sRCdo6h3jzxqAY1VDNgVJKbSA=
github.com/awslabs/operatorpkg v0.0.0-20240605172541-88cf99023fa4 h1:EVFVrteX0PQuofO9Ah4rf4aGyUkBM3lLuKgzwilAEAg=
github.com/awslabs/operatorpkg v0.0.0-20240605172541-88cf99023fa4/go.mod h1:OR0NDOTl6XUXKgcksUab5d7mCnpaZf7Ko4eWEbheJTY=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Expand Down Expand Up @@ -550,8 +550,8 @@ google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.124.0 h1:dP6Ef1VgOGqQ8eiv4GiY8RhmeyqzovcXBYPDUYG8Syo=
google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4=
google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o=
google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
Expand Down Expand Up @@ -671,6 +671,8 @@ k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
k8s.io/kubernetes v1.30.1 h1:XlqS6KslLEA5mQzLK2AJrhr4Z1m8oJfkhHiWJ5lue+I=
k8s.io/kubernetes v1.30.1/go.mod h1:yPbIk3MhmhGigX62FLJm+CphNtjxqCvAIFQXup6RKS0=
k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ=
k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
knative.dev/pkg v0.0.0-20230712131115-7051d301e7f4 h1:oO/BQJpVCFTSTMHF/S6u+nPtIvbHDTsvbPZvdCZAFjs=
Expand Down
83 changes: 83 additions & 0 deletions pkg/apis/crds/karpenter.sh_nodeoverlays.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.15.0
name: nodeoverlays.karpenter.sh
spec:
group: karpenter.sh
names:
categories:
- karpenter
kind: NodeOverlay
listKind: NodeOverlayList
plural: nodeoverlays
singular: nodeoverlay
scope: Cluster
versions:
- name: v1beta1
schema:
openAPIV3Schema:
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
properties:
pricePercent:
description: PricePercent modifies the price of the simulated node
(PriceAdjustment + (Price * PricePercent / 100)).
type: integer
selector:
description: Selector matches against simulated nodes and modifies
their scheduling properties. Matches all if empty.
items:
description: |-
A node selector requirement is a selector that contains values, a key, and an operator
that relates the key and values.
properties:
key:
description: The label key that the selector applies to.
type: string
operator:
description: |-
Represents a key's relationship to a set of values.
Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt.
type: string
values:
description: |-
An array of string values. If the operator is In or NotIn,
the values array must be non-empty. If the operator is Exists or DoesNotExist,
the values array must be empty. If the operator is Gt or Lt, the values
array must have a single element, which will be interpreted as an integer.
This array is replaced during a strategic merge patch.
items:
type: string
type: array
x-kubernetes-list-type: atomic
required:
- key
- operator
type: object
type: array
type: object
required:
- spec
type: object
served: true
storage: true
71 changes: 71 additions & 0 deletions pkg/apis/v1beta1/nodeoverlay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
Copyright The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1beta1

import (
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +kubebuilder:object:root=true
type NodeOverlayList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []NodeOverlay `json:"items"`
}

// +kubebuilder:object:root=true
// +kubebuilder:resource:path=nodeoverlays,scope=Cluster,categories=karpenter
type NodeOverlay struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

// +required
Spec NodeOverlaySpec `json:"spec"`
}

type NodeOverlaySpec struct {
// Selector matches against simulated nodes and modifies their scheduling properties. Matches all if empty.
// +optional
Selector []v1.NodeSelectorRequirement `json:"selector,omitempty"`
// PricePercent modifies the price of the simulated node (PriceAdjustment + (Price * PricePercent / 100)).
// +optional
PricePercent *int `json:"pricePercent,omitempty"`

//
// The following fields are not yet implemented
//

// PriceAdjustment modifies the price of the simulated node (PriceAdjustment + (Price * PricePercent / 100)).
// +optional
// PriceAdjustment *int `json:"priceAdjustment,omitempty"`

// Requirements add additional scheduling requirements to the Node, which may be targeted by pod scheduling constraints
// This feature is not currently implemented
// +optional
// Requirements []v1.NodeSelectorRequirement `json:"requirements,omitempty"`

// Capacity adds resource capacities to the simulated Node, but will not replace existing values.
// This feature is not currently implemented
// +optional
// Capacity v1.ResourceList

// Overhead subtracts resources from the simulated Node
// This feature is not currently implemented
// +optional
// Overhead v1.ResourceList `json:"overhead,omitempty"`
}
47 changes: 47 additions & 0 deletions pkg/apis/v1beta1/nodeoverlay.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
# Reduce on-demand prices to 90%
# https://github.com/aws/karpenter-provider-aws/issues/3860
# https://github.com/aws/karpenter-provider-aws/pull/4697
kind: NodeOverlay
metadata:
name: discount
spec:
selector:
matchLabels:
karpenter.sh/capacity-type: on-demand
pricePercent: 90
---
# Support for extended resource types (e.g. smarter-devices/fuse)
# https://github.com/kubernetes-sigs/karpenter/issues/751
https://github.com/kubernetes-sigs/karpenter/issues/729
kind: NodeOverlay
metadata:
name: discount
spec:
selector:
matchLabels:
karpenter.sh/capacity-type: on-demand
matchExpressions:
- key: node.kubernetes.io/instance-type
operator: In
values:
- m5.large
- m5.2xlarge
- m5.4xlarge
- m5.8xlarge
- m5.12xlarge
capacity:
smarter-devices/fuse: 1
---
# Add memory overhead of 10Mi to all instances with 2Gi memory
# https://github.com/aws/karpenter-provider-aws/issues/5161
kind: NodeOverlay
metadata:
name: discount
spec:
selector:
matchLabels:
karpenter.k8s.aws/instance-memory: 2048
overhead:
memory: 10Mi
---
85 changes: 85 additions & 0 deletions pkg/apis/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 11 additions & 7 deletions pkg/controllers/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"sigs.k8s.io/karpenter/pkg/cloudprovider"
"sigs.k8s.io/karpenter/pkg/controllers/disruption"
"sigs.k8s.io/karpenter/pkg/controllers/disruption/orchestration"
"sigs.k8s.io/karpenter/pkg/controllers/instancetypes"
"sigs.k8s.io/karpenter/pkg/controllers/leasegarbagecollection"
metricsnode "sigs.k8s.io/karpenter/pkg/controllers/metrics/node"
metricsnodepool "sigs.k8s.io/karpenter/pkg/controllers/metrics/nodepool"
Expand Down Expand Up @@ -52,15 +53,18 @@ func NewControllers(
cloudProvider cloudprovider.CloudProvider,
) []controller.Controller {

p := provisioning.NewProvisioner(kubeClient, recorder, cloudProvider, cluster)
provisioner := provisioning.NewProvisioner(kubeClient, recorder, cloudProvider, cluster)
evictionQueue := terminator.NewQueue(kubeClient, recorder)
disruptionQueue := orchestration.NewQueue(kubeClient, recorder, cluster, clock, p)

disruptionQueue := orchestration.NewQueue(kubeClient, recorder, cluster, clock, provisioner)
instanceTypesProvider := instancetypes.NewController(kubeClient, cloudProvider)
return []controller.Controller{
p, evictionQueue, disruptionQueue,
disruption.NewController(clock, kubeClient, p, cloudProvider, recorder, cluster, disruptionQueue),
provisioning.NewPodController(kubeClient, p, recorder),
provisioning.NewNodeController(kubeClient, p, recorder),
provisioner,
evictionQueue,
disruptionQueue,
instanceTypesProvider,
disruption.NewController(clock, kubeClient, provisioner, instanceTypesProvider, recorder, cluster, disruptionQueue),
provisioning.NewPodController(kubeClient, provisioner, recorder),
provisioning.NewNodeController(kubeClient, provisioner, recorder),
nodepoolhash.NewController(kubeClient),
informer.NewDaemonSetController(kubeClient, cluster),
informer.NewNodeController(kubeClient, cluster),
Expand Down
Loading

0 comments on commit af92b99

Please sign in to comment.