Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sidecar containers to resource requests computation #2099

Merged
merged 9 commits into from
May 7, 2024
34 changes: 22 additions & 12 deletions pkg/util/limitrange/limitrange.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,18 +88,8 @@ func TotalRequests(ps *corev1.PodSpec) corev1.ResourceList {
for i := range ps.Containers {
sumContainers = resource.MergeResourceListKeepSum(sumContainers, ps.Containers[i].Resources.Requests)
}

// take into account the maximum of any non sidecar init containers and add the sidecar containers
maxNonSidecarInitContainers := corev1.ResourceList{}
sumSidecarContainers := corev1.ResourceList{}
for i := range ps.InitContainers {
// Is the init container a sidecar container?
if ps.InitContainers[i].RestartPolicy != nil && *ps.InitContainers[i].RestartPolicy == corev1.ContainerRestartPolicyAlways {
sumSidecarContainers = resource.MergeResourceListKeepSum(sumSidecarContainers, ps.InitContainers[i].Resources.Requests)
} else {
maxNonSidecarInitContainers = resource.MergeResourceListKeepMax(maxNonSidecarInitContainers, ps.InitContainers[i].Resources.Requests)
}
}
maxNonSidecarInitContainers := calculateRegularInitContainersResources(ps.InitContainers)
sumSidecarContainers := calculateSidecarContainersResources(ps.InitContainers)

total := resource.MergeResourceListKeepMax(
resource.MergeResourceListKeepSum(maxNonSidecarInitContainers, sumSidecarContainers),
Expand All @@ -110,6 +100,26 @@ func TotalRequests(ps *corev1.PodSpec) corev1.ResourceList {
return total
}

func calculateRegularInitContainersResources(initContainers []corev1.Container) corev1.ResourceList {
total := corev1.ResourceList{}
for i := range initContainers {
if initContainers[i].RestartPolicy == nil || *initContainers[i].RestartPolicy != corev1.ContainerRestartPolicyAlways {
total = resource.MergeResourceListKeepMax(total, initContainers[i].Resources.Requests)
}
}
return total
}

func calculateSidecarContainersResources(initContainers []corev1.Container) corev1.ResourceList {
total := corev1.ResourceList{}
for i := range initContainers {
if initContainers[i].RestartPolicy != nil && *initContainers[i].RestartPolicy == corev1.ContainerRestartPolicyAlways {
total = resource.MergeResourceListKeepSum(total, initContainers[i].Resources.Requests)
}
}
return total
}

// ValidatePodSpec verifies if the provided podSpec (ps) first into the boundaries of the summary (s).
func (s Summary) ValidatePodSpec(ps *corev1.PodSpec, path *field.Path) []string {
reasons := []string{}
Expand Down
257 changes: 167 additions & 90 deletions pkg/util/limitrange/limitrange_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/utils/field"
"k8s.io/utils/ptr"

testingutil "sigs.k8s.io/kueue/pkg/util/testing"
)
Expand Down Expand Up @@ -161,90 +160,184 @@ func TestSummarize(t *testing.T) {
}

func TestTotalRequest(t *testing.T) {
containers := []corev1.Container{
{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1"),
corev1.ResourceMemory: resource.MustParse("2Gi"),
},
},
},
{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1500m"),
"example.com/gpu": resource.MustParse("2"),
},
},
},
{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("4"),
corev1.ResourceMemory: resource.MustParse("2Gi"),
},
},
},
{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1500m"),
"example.com/gpu": resource.MustParse("2"),
},
},
},
{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1"),
corev1.ResourceMemory: resource.MustParse("2Gi"),
"example.com/gpu": resource.MustParse("2"),
},
},
RestartPolicy: ptr.To(corev1.ContainerRestartPolicyAlways),
},
}
cases := map[string]struct {
podSpec *corev1.PodSpec
want corev1.ResourceList
}{
"sum up main containers": {
"pod without init containers": {
podSpec: &corev1.PodSpec{
Containers: containers[:2],
Containers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1500m").
WithResourceReq("example.com/gpu", "2").
Obj(),
},
},
want: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("2500m"),
corev1.ResourceMemory: resource.MustParse("2Gi"),
"example.com/gpu": resource.MustParse("2"),
},
},
"one init wants more": {
"pod only with regular init containers": {
podSpec: &corev1.PodSpec{
InitContainers: containers[2:4],
Containers: containers[:2],
InitContainers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "4").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1500m").
WithResourceReq("example.com/gpu", "2").
Obj(),
},
Containers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1500m").
WithResourceReq("example.com/gpu", "2").
Obj(),
},
},
want: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("4000m"),
corev1.ResourceMemory: resource.MustParse("2Gi"),
"example.com/gpu": resource.MustParse("2"),
},
},
"include sidecar container": {
"pod only with sidecar containers": {
podSpec: &corev1.PodSpec{
InitContainers: containers[2:],
Containers: containers[:2],
InitContainers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "4").
WithResourceReq(corev1.ResourceMemory, "2Gi").
AsSidecar().
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1500m").
WithResourceReq("example.com/gpu", "2").
AsSidecar().
Obj(),
},
Containers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1500m").
WithResourceReq("example.com/gpu", "2").
Obj(),
},
},
want: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("5000m"),
corev1.ResourceCPU: resource.MustParse("8000m"),
corev1.ResourceMemory: resource.MustParse("4Gi"),
"example.com/gpu": resource.MustParse("4"),
},
},
"pod only with init containers": {
podSpec: &corev1.PodSpec{
InitContainers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1").
WithResourceReq(corev1.ResourceMemory, "1Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "2").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "3").
WithResourceReq(corev1.ResourceMemory, "3Gi").
AsSidecar().
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "4").
WithResourceReq(corev1.ResourceMemory, "4Gi").
AsSidecar().
Obj(),
},
},
want: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("9"),
corev1.ResourceMemory: resource.MustParse("9Gi"),
},
},
"pod with regular init and sidecar containers": {
podSpec: &corev1.PodSpec{
InitContainers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1").
WithResourceReq(corev1.ResourceMemory, "1Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "2").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "3").
WithResourceReq(corev1.ResourceMemory, "3Gi").
AsSidecar().
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "4").
WithResourceReq(corev1.ResourceMemory, "4Gi").
AsSidecar().
Obj(),
},
Containers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "2").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "4").
WithResourceReq("example.com/gpu", "4").
Obj(),
},
},
want: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("13"),
corev1.ResourceMemory: resource.MustParse("9Gi"),
"example.com/gpu": resource.MustParse("4"),
},
},
"adds overhead": {
podSpec: &corev1.PodSpec{
InitContainers: containers[2:],
Containers: containers[:2],
InitContainers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "4").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1500m").
WithResourceReq("example.com/gpu", "2").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1").
WithResourceReq(corev1.ResourceMemory, "2Gi").
WithResourceReq("example.com/gpu", "2").
AsSidecar().
Obj(),
},
Containers: []corev1.Container{
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1500m").
WithResourceReq("example.com/gpu", "2").
Obj(),
},
Overhead: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1"),
corev1.ResourceMemory: resource.MustParse("1Gi"),
Expand All @@ -271,42 +364,26 @@ func TestTotalRequest(t *testing.T) {
func TestValidatePodSpec(t *testing.T) {
podSpec := &corev1.PodSpec{
Containers: []corev1.Container{
{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1"),
corev1.ResourceMemory: resource.MustParse("2Gi"),
"example.com/mainContainerGpu": resource.MustParse("2"),
},
},
},
{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1500m"),
"example.com/gpu": resource.MustParse("2"),
},
},
},
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1").
WithResourceReq(corev1.ResourceMemory, "2Gi").
WithResourceReq("example.com/mainContainerGpu", "2").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1500m").
WithResourceReq("example.com/gpu", "2").
Obj(),
},
InitContainers: []corev1.Container{
{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("4"),
corev1.ResourceMemory: resource.MustParse("2Gi"),
},
},
},
{
Resources: corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1500m"),
"example.com/gpu": resource.MustParse("2"),
"example.com/initContainerGpu": resource.MustParse("2"),
},
},
},
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "4").
WithResourceReq(corev1.ResourceMemory, "2Gi").
Obj(),
*testingutil.MakeContainer().
WithResourceReq(corev1.ResourceCPU, "1500m").
WithResourceReq("example.com/gpu", "2").
WithResourceReq("example.com/initContainerGpu", "2").
Obj(),
},
Overhead: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1"),
Expand Down
Loading