Skip to content

Commit

Permalink
Merge pull request #235 from FNNDSC/shm-size
Browse files Browse the repository at this point in the history
Implement support for changing SHM_SIZE
  • Loading branch information
jennydaman committed May 7, 2024
2 parents 11cf327 + 1510670 commit 1e7eff1
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ https://github.com/containers/podman/blob/main/troubleshooting.md#symptom-23
| `PFCON_SELECTOR` | label on the pfcon container, may be specified for pman to self-discover `VOLUME_NAME` (default: `org.chrisproject.role=pfcon`) |
| `CONTAINER_USER` | Set job container user in the form `UID:GID`, may be a range for random values |
| `ENABLE_HOME_WORKAROUND` | If set to "yes" then set job environment variable `HOME=/tmp` |
| `SHM_SIZE` | Size of `/dev/shm` in mebibytes. (Supported only in Docker, Podman, and Kubernetes.) |
| `JOB_LABELS` | CSV list of key=value pairs, labels to apply to container jobs |
| `JOB_LOGS_TAIL` | (int) maximum size of job logs |
| `IGNORE_LIMITS` | If set to "yes" then do not set resource limits on container jobs (for making things work without effort) |
Expand Down
3 changes: 3 additions & 0 deletions pman/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from importlib.metadata import Distribution

from pman.memsize import Memsize
from pman._helpers import get_storebase_from_docker

pkg = Distribution.from_name(__package__)
Expand All @@ -28,6 +29,8 @@ def __init__(self):
self.IGNORE_LIMITS = env.bool('IGNORE_LIMITS', False)
self.CONTAINER_USER = env('CONTAINER_USER', None)
self.ENABLE_HOME_WORKAROUND = env.bool('ENABLE_HOME_WORKAROUND', False)
shm_size = env.int('SHM_SIZE', None)
self.SHM_SIZE = None if shm_size is None else Memsize(shm_size)

self.CONTAINER_ENV = env('CONTAINER_ENV', 'docker')
if self.CONTAINER_ENV == 'podman': # podman is just an alias for docker
Expand Down
5 changes: 5 additions & 0 deletions pman/dockermgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ def schedule_job(self, image: Image, command: List[str], name: JobName,
if gid is not None:
user_spec['group_add'] = [gid]

shm_size = {}
if (s := self.config.get('SHM_SIZE')) is not None:
shm_size['shm_size'] = s.as_mb()

return self.__docker.containers.run(
image=image,
command=command,
Expand All @@ -69,6 +73,7 @@ def schedule_job(self, image: Image, command: List[str], name: JobName,
labels=self.job_labels,
**limits,
**user_spec,
**shm_size,
**volumes
)

Expand Down
19 changes: 17 additions & 2 deletions pman/kubernetesmgr.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,29 @@ def create_job(self, image, command, name, resources_dict, env_l, uid, gid,
read_only=False
)

dshm_volume = []
dshm_mount = []
if (s := self.config.get('SHM_SIZE')) is not None:
dshm_volume.append(k_client.V1Volume(
name='dshm',
empty_dir=k_client.V1EmptyDirVolumeSource(
medium='Memory',
size_limit=s.as_mib()
)
))
dshm_mount.append(k_client.V1VolumeMount(
mount_path='/dev/shm',
name='dshm',
))

container = k_client.V1Container(
name=name,
image=image,
env=env,
command=command,
security_context=k_client.V1SecurityContext(**security_context),
resources=k_client.V1ResourceRequirements(limits=limits),
volume_mounts=[volume_mount_inputdir, volume_mount_outputdir]
volume_mounts=[volume_mount_inputdir, volume_mount_outputdir, *dshm_mount]
)

pod_template_metadata = None
Expand All @@ -213,7 +228,7 @@ def create_job(self, image, command, name, resources_dict, env_l, uid, gid,
metadata=pod_template_metadata,
spec=k_client.V1PodSpec(restart_policy='Never',
containers=[container],
volumes=[volume],
volumes=[volume, *dshm_volume],
node_selector=node_selector),

)
Expand Down
19 changes: 19 additions & 0 deletions pman/memsize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from dataclasses import dataclass


@dataclass
class Memsize:
"""
A quantity of bytes.
"""

mebibytes: int

def as_mb(self) -> str:
"""Value as megabyte string, ending in 'm'"""
mb = int(1.048576 * self.mebibytes)
return f'{mb}m'

def as_mib(self) -> str:
"""Value as mebibyte string, ending in 'Mi'"""
return f'{self.mebibytes}Mi'

0 comments on commit 1e7eff1

Please sign in to comment.