Skip to content

Commit 612a380

Browse files
committed
feat(controller): add ephemeral-storage restriction
1 parent 2be591d commit 612a380

3 files changed

Lines changed: 46 additions & 21 deletions

File tree

rootfs/api/models/app.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,12 @@ def _gather_app_settings(self, release, app_settings, process_type, replicas):
11001100
pod_termination_grace_period_seconds = int(config.values.get(
11011101
'KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDS', settings.KUBERNETES_POD_TERMINATION_GRACE_PERIOD_SECONDS)) # noqa
11021102

1103+
# get limits and requests ephemeral_storage
1104+
ephemeral_storage = "{}/{}".format(
1105+
settings.KUBERNETES_REQUESTS_EPHEMERAL_STORAGE,
1106+
settings.KUBERNETES_LIMITS_EPHEMERAL_STORAGE,
1107+
)
1108+
11031109
# set the image pull policy that is associated with the application container
11041110
image_pull_policy = config.values.get('IMAGE_PULL_POLICY', settings.IMAGE_PULL_POLICY)
11051111

@@ -1117,6 +1123,7 @@ def _gather_app_settings(self, release, app_settings, process_type, replicas):
11171123
return {
11181124
'memory': config.memory,
11191125
'cpu': config.cpu,
1126+
'ephemeral_storage': ephemeral_storage,
11201127
'tags': config.tags,
11211128
'envs': envs,
11221129
'registry': config.registry,

rootfs/api/settings/production.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,12 @@
336336
# Default quota spec for application namespace
337337
KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC = os.environ.get('KUBERNETES_NAMESPACE_DEFAULT_QUOTA_SPEC', '') # noqa
338338

339+
# See spec.containers[].resources.requests.ephemeral-storage
340+
KUBERNETES_REQUESTS_EPHEMERAL_STORAGE = os.environ.get('KUBERNETES_REQUESTS_EPHEMERAL_STORAGE', '1Gi') # noqa
341+
342+
# See spec.containers[].resources.limits.ephemeral-storage
343+
KUBERNETES_LIMITS_EPHEMERAL_STORAGE = os.environ.get('KUBERNETES_LIMITS_EPHEMERAL_STORAGE', '2Gi') # noqa
344+
339345
# registry settings
340346
REGISTRY_HOST = os.environ.get('DRYCC_REGISTRY_PROXY_HOST', '127.0.0.1')
341347
REGISTRY_PORT = os.environ.get('DRYCC_REGISTRY_PROXY_PORT', 5000)

rootfs/scheduler/resources/pod.py

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -231,18 +231,16 @@ def _set_resources(self, container, kwargs):
231231
app_type = kwargs.get("app_type")
232232
mem = kwargs.get("memory", {}).get(app_type)
233233
cpu = kwargs.get("cpu", {}).get(app_type)
234-
234+
ephemeral_storage = kwargs.get("ephemeral_storage")
235+
resources = defaultdict(dict)
235236
if mem or cpu:
236-
resources = defaultdict(dict)
237-
238237
if mem:
239238
if "/" in mem:
240239
parts = mem.split("/")
241-
resources["requests"]["memory"] = self._format_memory(parts[0])
242-
resources["limits"]["memory"] = self._format_memory(parts[1])
240+
resources["requests"]["memory"] = self._format_size(parts[0])
241+
resources["limits"]["memory"] = self._format_size(parts[1])
243242
else:
244-
resources["limits"]["memory"] = self._format_memory(mem)
245-
243+
resources["limits"]["memory"] = self._format_size(mem)
246244
if cpu:
247245
# CPU needs to be defined as lower case
248246
if "/" in cpu:
@@ -251,27 +249,37 @@ def _set_resources(self, container, kwargs):
251249
resources["limits"]["cpu"] = parts[1].lower()
252250
else:
253251
resources["limits"]["cpu"] = cpu.lower()
254-
252+
if ephemeral_storage:
253+
# ephemeral_storage needs to be defined as lower case
254+
if "/" in ephemeral_storage:
255+
parts = ephemeral_storage.split("/")
256+
resources["requests"]["ephemeral_storage"] = self._format_size(parts[0])
257+
resources["limits"]["ephemeral_storage"] = self._format_size(parts[1])
258+
else:
259+
resources["limits"]["ephemeral_storage"] = self._format_size(
260+
ephemeral_storage)
255261
if resources:
256262
container["resources"] = dict(resources)
257263

258-
def _get_termination_grace_period(self, kwargs):
264+
@staticmethod
265+
def _get_termination_grace_period(kwargs):
259266
""" return termination grace period """
260267
app_type = kwargs.get("app_type")
261268
timeout_global = kwargs.get('pod_termination_grace_period_seconds', 30)
262269
timeout_local = kwargs.get("pod_termination_grace_period_each", {}).get(app_type)
263270

264271
return timeout_global if timeout_local is None else int(timeout_local)
265272

266-
def _format_memory(self, mem):
273+
@staticmethod
274+
def _format_size(size):
267275
""" Format memory limit value """
268-
if mem[-2:-1].isalpha() and mem[-1].isalpha():
269-
mem = mem[:-1]
276+
if size[-2:-1].isalpha() and size[-1].isalpha():
277+
size = size[:-1]
270278

271-
if mem[-1].isalpha():
279+
if size[-1].isalpha():
272280
# memory needs to be upper cased (only first char)
273-
mem = mem.upper() + "i"
274-
return mem
281+
size = size.upper() + "i"
282+
return size
275283

276284
def _set_health_checks(self, container, env, **kwargs):
277285
healthchecks = kwargs.get('healthcheck', None)
@@ -288,13 +296,13 @@ def _set_health_checks(self, container, env, **kwargs):
288296
elif kwargs.get('routable', False):
289297
self._default_readiness_probe(container, kwargs.get('build_type'), env.get('PORT', None)) # noqa
290298

291-
def _set_lifecycle_hooks(self, container, env, **kwargs):
299+
@staticmethod
300+
def _set_lifecycle_hooks(container, env, **kwargs):
292301
app_type = kwargs.get("app_type")
293302
lifecycle_post_start = kwargs.get('lifecycle_post_start', {})
294303
lifecycle_post_start = lifecycle_post_start.get(app_type)
295304
lifecycle_pre_stop = kwargs.get('lifecycle_pre_stop', {})
296305
lifecycle_pre_stop = lifecycle_pre_stop.get(app_type)
297-
lifecycle = defaultdict(dict)
298306
if lifecycle_post_start or lifecycle_pre_stop:
299307
lifecycle = defaultdict(dict)
300308

@@ -341,7 +349,8 @@ def _default_readiness_probe(self, container, build_type, port=None):
341349
This should be added only for the build pack apps when a custom liveness probe is not set to
342350
make sure that the pod is ready only when the slug is downloaded and started running.
343351
"""
344-
def _default_buildpack_readiness_probe(self, delay=30, timeout=5, period_seconds=5,
352+
@staticmethod
353+
def _default_buildpack_readiness_probe(delay=30, timeout=5, period_seconds=5,
345354
success_threshold=1, failure_threshold=1):
346355
readinessprobe = {
347356
'readinessProbe': {
@@ -364,7 +373,8 @@ def _default_buildpack_readiness_probe(self, delay=30, timeout=5, period_seconds
364373
}
365374
return readinessprobe
366375

367-
def _default_dockerapp_readiness_probe(self, port, delay=5, timeout=5, period_seconds=5,
376+
@staticmethod
377+
def _default_dockerapp_readiness_probe(port, delay=5, timeout=5, period_seconds=5,
368378
success_threshold=1, failure_threshold=1):
369379
"""
370380
Applies tcp socket readiness probe to the docker app container only if some port is exposed
@@ -387,7 +397,8 @@ def _default_dockerapp_readiness_probe(self, port, delay=5, timeout=5, period_se
387397
}
388398
return readinessprobe
389399

390-
def _set_custom_termination_period(self, container, period_seconds=900):
400+
@staticmethod
401+
def _set_custom_termination_period(container, period_seconds=900):
391402
"""
392403
Applies a custom terminationGracePeriod only if provided as env variable.
393404
"""
@@ -473,7 +484,8 @@ def readiness_status(self, pod):
473484
# Seems like the most sensible default
474485
return 'Unknown'
475486

476-
def liveness_status(self, pod):
487+
@staticmethod
488+
def liveness_status(pod):
477489
"""Check if the pods liveness probe status has passed all checks"""
478490
for condition in pod['status']['conditions']:
479491
# type = Ready is the only binary type right now

0 commit comments

Comments
 (0)