Skip to content

Commit

Permalink
Implement resource constraints on nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
aojea committed Feb 11, 2020
1 parent a1faf46 commit 8790b26
Show file tree
Hide file tree
Showing 9 changed files with 159 additions and 1 deletion.
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
Expand Down Expand Up @@ -112,6 +114,7 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtD
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand All @@ -120,6 +123,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Expand Down
15 changes: 15 additions & 0 deletions pkg/apis/config/v1alpha4/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ limitations under the License.

package v1alpha4

import (
"k8s.io/apimachinery/pkg/api/resource"
)

// Cluster contains kind cluster configuration
type Cluster struct {
TypeMeta `yaml:",inline"`
Expand Down Expand Up @@ -106,6 +110,9 @@ type Node struct {
// binded to a host Port
ExtraPortMappings []PortMapping `yaml:"extraPortMappings,omitempty"`

// Constraints describes the node resources constraints
Constraints NodeResources `json:"constraints,omitempty"`

// KubeadmConfigPatches are applied to the generated kubeadm config as
// merge patches. The `kind` field must match the target object, and
// if `apiVersion` is specified it will only be applied to matching objects.
Expand Down Expand Up @@ -271,3 +278,11 @@ const (
// PortMappingProtocolSCTP specifies SCTP protocol
PortMappingProtocolSCTP PortMappingProtocol = "SCTP"
)

// NodeResources represents the node resources (CPU/Memory)
type NodeResources struct {
// The maximum amount of memory the node can use.
Memory resource.Quantity `json:"memory,omitempty"`
// Specify how much of the available CPU resources a node can use
Cpus resource.Quantity `json:"cpus,omitempty"`
}
19 changes: 19 additions & 0 deletions pkg/apis/config/v1alpha4/zz_generated.deepcopy.go

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

21 changes: 20 additions & 1 deletion pkg/cluster/internal/providers/docker/provision.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,10 @@ func runArgsForNode(node *config.Node, clusterIPFamily config.ClusterIPFamily, n
args...,
)

// convert mounts and port mappings to container run args
// convert mounts, port mappings and resource constraints to container run args
args = append(args, generateMountBindings(node.ExtraMounts...)...)
args = append(args, generatePortMappings(clusterIPFamily, node.ExtraPortMappings...)...)
args = append(args, generateNodeConstraints(node.Constraints)...)

// finally, specify the image to run
return append(args, node.Image)
Expand Down Expand Up @@ -311,3 +312,21 @@ func generatePortMappings(clusterIPFamily config.ClusterIPFamily, portMappings .
}
return args
}

// generateNodeConstraints converts the nodesConstraints to a list of args for docker
// https://docs.docker.com/config/containers/resource_constraints/
func generateNodeConstraints(resources config.NodeResources) []string {
var args []string
if resources.Cpus.Sign() > 0 {
args = append(args, fmt.Sprintf("--cpus=%s", resources.Cpus.String()))
}

if resources.Memory.Sign() > 0 {
args = append(args, fmt.Sprintf("--memory=%s", resources.Memory.String()))
// prevent a container from using swap because we want to emulate a real node
// https://docs.docker.com/config/containers/resource_constraints/#prevent-a-container-from-using-swap
args = append(args, fmt.Sprintf("--memory-swap=%s", resources.Memory.String()))
}

return args
}
15 changes: 15 additions & 0 deletions pkg/internal/apis/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ limitations under the License.

package config

import (
"k8s.io/apimachinery/pkg/api/resource"
)

// Cluster contains kind cluster configuration
type Cluster struct {
// Nodes contains the list of nodes defined in the `kind` Cluster
Expand Down Expand Up @@ -89,6 +93,9 @@ type Node struct {
// KubeadmConfigPatchesJSON6902 are applied to the generated kubeadm config
// as patchesJson6902 to `kustomize build`
KubeadmConfigPatchesJSON6902 []PatchJSON6902

// Constraints describes the node resources constraints
Constraints NodeResources
}

// NodeRole defines possible role for nodes in a Kubernetes cluster managed by `kind`
Expand Down Expand Up @@ -222,3 +229,11 @@ const (
// PortMappingProtocolSCTP specifies SCTP protocol
PortMappingProtocolSCTP PortMappingProtocol = "SCTP"
)

// NodeResources represents the node resources (CPU/Memory)
type NodeResources struct {
// The maximum amount of memory the node can use.
Memory resource.Quantity
// Specify how much of the available CPU resources a node can use.
Cpus resource.Quantity
}
13 changes: 13 additions & 0 deletions pkg/internal/apis/config/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package config
import (
"net"

"k8s.io/apimachinery/pkg/api/resource"

"sigs.k8s.io/kind/pkg/errors"
)

Expand Down Expand Up @@ -101,6 +103,17 @@ func (n *Node) Validate() error {
}
}

// validate node resource constraints
if n.Constraints.Cpus.Sign() < 0 {
errs = append(errs, errors.New("invalid number of Cpus"))
}

// minimum memory size is 4m
minMemory := resource.MustParse("4m")
if n.Constraints.Memory.Sign() != 0 && n.Constraints.Memory.Cmp(minMemory) < 0 {
errs = append(errs, errors.New("invalid Memory Size (minimum 4m)"))
}

if len(errs) > 0 {
return errors.NewAggregate(errs)
}
Expand Down
35 changes: 35 additions & 0 deletions pkg/internal/apis/config/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package config
import (
"testing"

"k8s.io/apimachinery/pkg/api/resource"

"sigs.k8s.io/kind/pkg/errors"
)

Expand Down Expand Up @@ -107,6 +109,21 @@ func TestClusterValidate(t *testing.T) {
}(),
ExpectErrors: 1,
},
{
Name: "wrong resources constraints node",
Cluster: func() Cluster {
c := Cluster{}
SetDefaultsCluster(&c)
n, n2 := Node{}, Node{}
SetDefaultsNode(&n)
SetDefaultsNode(&n2)
n.Constraints.Cpus = resource.MustParse("-12")
n.Constraints.Memory = resource.MustParse("1m")
c.Nodes = []Node{n, n2}
return c
}(),
ExpectErrors: 1,
},
}

for _, tc := range cases {
Expand Down Expand Up @@ -202,6 +219,24 @@ func TestNodeValidate(t *testing.T) {
}(),
ExpectErrors: 1,
},
{
TestName: "Negative CPU constraint",
Node: func() Node {
cfg := newDefaultedNode(ControlPlaneRole)
cfg.Constraints.Cpus = resource.MustParse("-12")
return cfg
}(),
ExpectErrors: 1,
},
{
TestName: "Minimum value for memory constraint",
Node: func() Node {
cfg := newDefaultedNode(ControlPlaneRole)
cfg.Constraints.Memory = resource.MustParse("2m")
return cfg
}(),
ExpectErrors: 1,
},
{
TestName: "Invalid HostPort",
Node: func() Node {
Expand Down
19 changes: 19 additions & 0 deletions pkg/internal/apis/config/zz_generated.deepcopy.go

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

19 changes: 19 additions & 0 deletions site/content/docs/user/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,25 @@ networking:
ipFamily: ipv6
```

#### Limit node resources
You can set CPU and memory limits for your cluster nodes in the configuration file.

```yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
# the control plane node
- role: control-plane
constraints:
memory: "200m"
cpus: "2"
- role: worker
constraints:
memory: "100m"
cpus: "1"
```


### Configure kind to use a proxy
If you are running kind in an environment that requires a proxy, you may need to configure kind to use it.

Expand Down

0 comments on commit 8790b26

Please sign in to comment.