Skip to content

Commit 838f3c0

Browse files
authored
Merge pull request kubernetes#130577 from KevinTMtz/pod-level-hugepages
[PodLevelResources] Pod Level Hugepage Resources
2 parents 6f13ba0 + 7b38bff commit 838f3c0

File tree

9 files changed

+1372
-171
lines changed

9 files changed

+1372
-171
lines changed

pkg/apis/core/v1/defaults.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
utilfeature "k8s.io/apiserver/pkg/util/feature"
2828
resourcehelper "k8s.io/component-helpers/resource"
2929
"k8s.io/kubernetes/pkg/api/v1/service"
30+
corev1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
3031
"k8s.io/kubernetes/pkg/features"
3132
"k8s.io/kubernetes/pkg/util/parsers"
3233
)
@@ -196,6 +197,7 @@ func SetDefaults_Pod(obj *v1.Pod) {
196197
// Pod Requests default values must be applied after container-level default values
197198
// have been populated.
198199
if utilfeature.DefaultFeatureGate.Enabled(features.PodLevelResources) {
200+
defaultHugePagePodLimits(obj)
199201
defaultPodRequests(obj)
200202
}
201203

@@ -453,14 +455,18 @@ func defaultPodRequests(obj *v1.Pod) {
453455
// PodLevelResources feature) and pod-level requests are not set, the pod-level requests
454456
// default to the effective requests of all the containers for that resource.
455457
for key, aggrCtrLim := range aggrCtrReqs {
456-
if _, exists := podReqs[key]; !exists && resourcehelper.IsSupportedPodLevelResource(key) {
458+
// Defaulting for pod level hugepages requests takes them directly from the pod limit,
459+
// hugepages cannot be overcommited and must have the limit, so we skip them here.
460+
if _, exists := podReqs[key]; !exists && resourcehelper.IsSupportedPodLevelResource(key) && !corev1helper.IsHugePageResourceName(key) {
457461
podReqs[key] = aggrCtrLim.DeepCopy()
458462
}
459463
}
460464

461465
// When no containers specify requests for a resource, the pod-level requests
462466
// will default to match the pod-level limits, if pod-level
463467
// limits exist for that resource.
468+
// Defaulting for pod level hugepages requests is dependent on defaultHugePagePodLimits,
469+
// if defaultHugePagePodLimits defined the limit, the request will be set here.
464470
for key, podLim := range obj.Spec.Resources.Limits {
465471
if _, exists := podReqs[key]; !exists && resourcehelper.IsSupportedPodLevelResource(key) {
466472
podReqs[key] = podLim.DeepCopy()
@@ -473,3 +479,44 @@ func defaultPodRequests(obj *v1.Pod) {
473479
obj.Spec.Resources.Requests = podReqs
474480
}
475481
}
482+
483+
// defaultHugePagePodLimits applies default values for pod-level limits, only when
484+
// container hugepage limits are set, but not at pod level, in following
485+
// scenario:
486+
// 1. When at least one container (regular, init or sidecar) has hugepage
487+
// limits set:
488+
// The pod-level limit becomes equal to the aggregated hugepages limit of all
489+
// the containers in the pod.
490+
func defaultHugePagePodLimits(obj *v1.Pod) {
491+
// We only populate defaults when the pod-level resources are partly specified already.
492+
if obj.Spec.Resources == nil {
493+
return
494+
}
495+
496+
if len(obj.Spec.Resources.Limits) == 0 && len(obj.Spec.Resources.Requests) == 0 {
497+
return
498+
}
499+
500+
var podLims v1.ResourceList
501+
podLims = obj.Spec.Resources.Limits
502+
if podLims == nil {
503+
podLims = make(v1.ResourceList)
504+
}
505+
506+
aggrCtrLims := resourcehelper.AggregateContainerLimits(obj, resourcehelper.PodResourcesOptions{})
507+
508+
// When containers specify limits for hugepages and pod-level limits are not
509+
// set for that resource, the pod-level limit will default to the aggregated
510+
// hugepages limit of all the containers.
511+
for key, aggrCtrLim := range aggrCtrLims {
512+
if _, exists := podLims[key]; !exists && resourcehelper.IsSupportedPodLevelResource(key) && corev1helper.IsHugePageResourceName(key) {
513+
podLims[key] = aggrCtrLim.DeepCopy()
514+
}
515+
}
516+
517+
// Only set pod-level resource limits in the PodSpec if the requirements map
518+
// contains entries after collecting container-level limits and pod-level limits for hugepages.
519+
if len(podLims) > 0 {
520+
obj.Spec.Resources.Limits = podLims
521+
}
522+
}

pkg/apis/core/v1/defaults_test.go

Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,298 @@ func TestPodResourcesDefaults(t *testing.T) {
12221222
},
12231223
},
12241224
},
1225+
}, {
1226+
name: "pod hugepages requests=unset limits=unset, container hugepages requests=unset limits=set",
1227+
podLevelResourcesEnabled: true,
1228+
podResources: &v1.ResourceRequirements{
1229+
Limits: v1.ResourceList{
1230+
"cpu": resource.MustParse("5m"),
1231+
},
1232+
},
1233+
containers: []v1.Container{
1234+
{
1235+
Resources: v1.ResourceRequirements{
1236+
Limits: v1.ResourceList{
1237+
"cpu": resource.MustParse("2m"),
1238+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("4Mi"),
1239+
},
1240+
},
1241+
}, {
1242+
Resources: v1.ResourceRequirements{
1243+
Limits: v1.ResourceList{
1244+
"cpu": resource.MustParse("1m"),
1245+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1246+
},
1247+
},
1248+
},
1249+
},
1250+
expectedPodSpec: v1.PodSpec{
1251+
Resources: &v1.ResourceRequirements{
1252+
Requests: v1.ResourceList{
1253+
"cpu": resource.MustParse("3m"),
1254+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("6Mi"),
1255+
},
1256+
Limits: v1.ResourceList{
1257+
"cpu": resource.MustParse("5m"),
1258+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("6Mi"),
1259+
},
1260+
},
1261+
Containers: []v1.Container{
1262+
{
1263+
Resources: v1.ResourceRequirements{
1264+
Requests: v1.ResourceList{
1265+
"cpu": resource.MustParse("2m"),
1266+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("4Mi"),
1267+
},
1268+
Limits: v1.ResourceList{
1269+
"cpu": resource.MustParse("2m"),
1270+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("4Mi"),
1271+
},
1272+
},
1273+
}, {
1274+
Resources: v1.ResourceRequirements{
1275+
Requests: v1.ResourceList{
1276+
"cpu": resource.MustParse("1m"),
1277+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1278+
},
1279+
Limits: v1.ResourceList{
1280+
"cpu": resource.MustParse("1m"),
1281+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1282+
},
1283+
},
1284+
},
1285+
},
1286+
},
1287+
}, {
1288+
name: "pod hugepages requests=unset limits=set, container hugepages requests=unset limits=set",
1289+
podLevelResourcesEnabled: true,
1290+
podResources: &v1.ResourceRequirements{
1291+
Limits: v1.ResourceList{
1292+
"cpu": resource.MustParse("5m"),
1293+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1294+
},
1295+
},
1296+
containers: []v1.Container{
1297+
{
1298+
Resources: v1.ResourceRequirements{
1299+
Limits: v1.ResourceList{
1300+
"cpu": resource.MustParse("2m"),
1301+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("4Mi"),
1302+
},
1303+
},
1304+
}, {
1305+
Resources: v1.ResourceRequirements{
1306+
Limits: v1.ResourceList{
1307+
"cpu": resource.MustParse("1m"),
1308+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1309+
},
1310+
},
1311+
},
1312+
},
1313+
expectedPodSpec: v1.PodSpec{
1314+
Resources: &v1.ResourceRequirements{
1315+
Requests: v1.ResourceList{
1316+
"cpu": resource.MustParse("3m"),
1317+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1318+
},
1319+
Limits: v1.ResourceList{
1320+
"cpu": resource.MustParse("5m"),
1321+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1322+
},
1323+
},
1324+
Containers: []v1.Container{
1325+
{
1326+
Resources: v1.ResourceRequirements{
1327+
Requests: v1.ResourceList{
1328+
"cpu": resource.MustParse("2m"),
1329+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("4Mi"),
1330+
},
1331+
Limits: v1.ResourceList{
1332+
"cpu": resource.MustParse("2m"),
1333+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("4Mi"),
1334+
},
1335+
},
1336+
}, {
1337+
Resources: v1.ResourceRequirements{
1338+
Requests: v1.ResourceList{
1339+
"cpu": resource.MustParse("1m"),
1340+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1341+
},
1342+
Limits: v1.ResourceList{
1343+
"cpu": resource.MustParse("1m"),
1344+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1345+
},
1346+
},
1347+
},
1348+
},
1349+
},
1350+
}, {
1351+
name: "pod hugepages requests=set limits=set, container hugepages requests=unset limits=set",
1352+
podLevelResourcesEnabled: true,
1353+
podResources: &v1.ResourceRequirements{
1354+
Limits: v1.ResourceList{
1355+
"cpu": resource.MustParse("5m"),
1356+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1357+
},
1358+
Requests: v1.ResourceList{
1359+
"cpu": resource.MustParse("5m"),
1360+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1361+
},
1362+
},
1363+
containers: []v1.Container{
1364+
{
1365+
Resources: v1.ResourceRequirements{
1366+
Limits: v1.ResourceList{
1367+
"cpu": resource.MustParse("2m"),
1368+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("4Mi"),
1369+
},
1370+
},
1371+
}, {
1372+
Resources: v1.ResourceRequirements{
1373+
Limits: v1.ResourceList{
1374+
"cpu": resource.MustParse("1m"),
1375+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1376+
},
1377+
},
1378+
},
1379+
},
1380+
expectedPodSpec: v1.PodSpec{
1381+
Resources: &v1.ResourceRequirements{
1382+
Requests: v1.ResourceList{
1383+
"cpu": resource.MustParse("5m"),
1384+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1385+
},
1386+
Limits: v1.ResourceList{
1387+
"cpu": resource.MustParse("5m"),
1388+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1389+
},
1390+
},
1391+
Containers: []v1.Container{
1392+
{
1393+
Resources: v1.ResourceRequirements{
1394+
Requests: v1.ResourceList{
1395+
"cpu": resource.MustParse("2m"),
1396+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("4Mi"),
1397+
},
1398+
Limits: v1.ResourceList{
1399+
"cpu": resource.MustParse("2m"),
1400+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("4Mi"),
1401+
},
1402+
},
1403+
}, {
1404+
Resources: v1.ResourceRequirements{
1405+
Requests: v1.ResourceList{
1406+
"cpu": resource.MustParse("1m"),
1407+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1408+
},
1409+
Limits: v1.ResourceList{
1410+
"cpu": resource.MustParse("1m"),
1411+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1412+
},
1413+
},
1414+
},
1415+
},
1416+
},
1417+
}, {
1418+
name: "pod hugepages requests=set limits=set, container hugepages requests=unset limits=unset",
1419+
podLevelResourcesEnabled: true,
1420+
podResources: &v1.ResourceRequirements{
1421+
Limits: v1.ResourceList{
1422+
"cpu": resource.MustParse("5m"),
1423+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1424+
},
1425+
Requests: v1.ResourceList{
1426+
"cpu": resource.MustParse("5m"),
1427+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1428+
},
1429+
},
1430+
containers: []v1.Container{
1431+
{
1432+
Resources: v1.ResourceRequirements{},
1433+
},
1434+
},
1435+
expectedPodSpec: v1.PodSpec{
1436+
Resources: &v1.ResourceRequirements{
1437+
Requests: v1.ResourceList{
1438+
"cpu": resource.MustParse("5m"),
1439+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1440+
},
1441+
Limits: v1.ResourceList{
1442+
"cpu": resource.MustParse("5m"),
1443+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1444+
},
1445+
},
1446+
Containers: []v1.Container{
1447+
{
1448+
Resources: v1.ResourceRequirements{},
1449+
},
1450+
},
1451+
},
1452+
}, {
1453+
name: "pod hugepages requests=unset limits=set, container hugepages requests=unset limits=set different hugepagesizes between pod and container level",
1454+
podLevelResourcesEnabled: true,
1455+
podResources: &v1.ResourceRequirements{
1456+
Limits: v1.ResourceList{
1457+
"cpu": resource.MustParse("5m"),
1458+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1459+
},
1460+
},
1461+
containers: []v1.Container{
1462+
{
1463+
Resources: v1.ResourceRequirements{
1464+
Limits: v1.ResourceList{
1465+
"cpu": resource.MustParse("2m"),
1466+
v1.ResourceHugePagesPrefix + "1Gi": resource.MustParse("1Gi"),
1467+
},
1468+
},
1469+
}, {
1470+
Resources: v1.ResourceRequirements{
1471+
Limits: v1.ResourceList{
1472+
"cpu": resource.MustParse("1m"),
1473+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1474+
},
1475+
},
1476+
},
1477+
},
1478+
expectedPodSpec: v1.PodSpec{
1479+
Resources: &v1.ResourceRequirements{
1480+
Requests: v1.ResourceList{
1481+
"cpu": resource.MustParse("3m"),
1482+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1483+
v1.ResourceHugePagesPrefix + "1Gi": resource.MustParse("1Gi"),
1484+
},
1485+
Limits: v1.ResourceList{
1486+
"cpu": resource.MustParse("5m"),
1487+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("10Mi"),
1488+
v1.ResourceHugePagesPrefix + "1Gi": resource.MustParse("1Gi"),
1489+
},
1490+
},
1491+
Containers: []v1.Container{
1492+
{
1493+
Resources: v1.ResourceRequirements{
1494+
Requests: v1.ResourceList{
1495+
"cpu": resource.MustParse("2m"),
1496+
v1.ResourceHugePagesPrefix + "1Gi": resource.MustParse("1Gi"),
1497+
},
1498+
Limits: v1.ResourceList{
1499+
"cpu": resource.MustParse("2m"),
1500+
v1.ResourceHugePagesPrefix + "1Gi": resource.MustParse("1Gi"),
1501+
},
1502+
},
1503+
}, {
1504+
Resources: v1.ResourceRequirements{
1505+
Requests: v1.ResourceList{
1506+
"cpu": resource.MustParse("1m"),
1507+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1508+
},
1509+
Limits: v1.ResourceList{
1510+
"cpu": resource.MustParse("1m"),
1511+
v1.ResourceHugePagesPrefix + "2Mi": resource.MustParse("2Mi"),
1512+
},
1513+
},
1514+
},
1515+
},
1516+
},
12251517
}}
12261518

12271519
for _, tc := range cases {

0 commit comments

Comments
 (0)