diff --git a/docs/Extensions.md b/docs/Extensions.md index 70ba6c58..fc35f6af 100644 --- a/docs/Extensions.md +++ b/docs/Extensions.md @@ -25,6 +25,19 @@ services: x-podman.rootfs: "/path/to/rootfs" ``` +* `x-podman.cgroup_conf` - Run the container with list of cgroup v2 configuration entries passed to Podman via `--cgroup-conf`. + +Example: +```yaml +version: "3" +services: + my_service: + command: ["/bin/busybox"] + x-podman.cgroup_conf: + - memory.high=1000M + - memory.min=200M +``` + For explanations of these extensions, please refer to the [Podman Documentation](https://docs.podman.io/). ## Secrets diff --git a/newsfragments/cgroup-conf-configuration.feature b/newsfragments/cgroup-conf-configuration.feature new file mode 100644 index 00000000..67bffaca --- /dev/null +++ b/newsfragments/cgroup-conf-configuration.feature @@ -0,0 +1 @@ +Support extension `x-podman.cgroup_conf` in services, for configuring cgroup v2 parameters of container. diff --git a/podman_compose.py b/podman_compose.py index 3bc24826..a70b7bc5 100755 --- a/podman_compose.py +++ b/podman_compose.py @@ -1557,6 +1557,8 @@ async def container_to_args( podman_args.extend(["--uidmap", uidmap]) for gidmap in cnt.get('x-podman.gidmaps', []): podman_args.extend(["--gidmap", gidmap]) + for conf in cnt.get('x-podman.cgroup_conf', []): + podman_args.extend(["--cgroup-conf", conf]) if cnt.get("x-podman.no_hosts", False): podman_args.extend(["--no-hosts"]) rootfs = cnt.get('x-podman.rootfs') diff --git a/tests/integration/cgroup_conf/__init__.py b/tests/integration/cgroup_conf/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration/cgroup_conf/docker-compose.yml b/tests/integration/cgroup_conf/docker-compose.yml new file mode 100644 index 00000000..3eda0cff --- /dev/null +++ b/tests/integration/cgroup_conf/docker-compose.yml @@ -0,0 +1,8 @@ +version: "3.7" +services: + cgroupconf: + image: busybox + command: httpd -f -p 8123 -h /tmp/ + x-podman.cgroup_conf: + - memory.high=712M + - memory.max=800M diff --git a/tests/integration/cgroup_conf/test_podman_compose_cgroup_conf.py b/tests/integration/cgroup_conf/test_podman_compose_cgroup_conf.py new file mode 100644 index 00000000..8250ef77 --- /dev/null +++ b/tests/integration/cgroup_conf/test_podman_compose_cgroup_conf.py @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0 + +import json +import os +import unittest + +from tests.integration.test_utils import RunSubprocessMixin +from tests.integration.test_utils import podman_compose_path +from tests.integration.test_utils import test_path + + +class TestPodmanCompose(unittest.TestCase, RunSubprocessMixin): + def test_cgroup_conf(self) -> None: + compose_path = os.path.join(test_path(), "cgroup_conf", "docker-compose.yml") + try: + self.run_subprocess_assert_returncode([ + podman_compose_path(), + "-f", + compose_path, + "up", + "-d", + ]) + + out, _ = self.run_subprocess_assert_returncode([ + "podman", + "inspect", + "cgroup_conf_cgroupconf_1", + ]) + + inspect_out = json.loads(out) + host_config_map = inspect_out[0].get("HostConfig", {}).get("CgroupConf", {}) + self.assertEqual('712M', host_config_map['memory.high']) + self.assertEqual('800M', host_config_map['memory.max']) + + # check memory.high in container + out, _ = self.run_subprocess_assert_returncode([ + "podman", + "exec", + "-ti", + "cgroup_conf_cgroupconf_1", + "sh", + "-c", + "cat /sys/fs/cgroup/memory.high", + ]) + self.assertEqual(out, b"746586112\r\n") + + # check memory.max in container + out, _ = self.run_subprocess_assert_returncode([ + "podman", + "exec", + "-ti", + "cgroup_conf_cgroupconf_1", + "sh", + "-c", + "cat /sys/fs/cgroup/memory.max", + ]) + self.assertEqual(out, b"838860800\r\n") + finally: + out, _ = self.run_subprocess_assert_returncode([ + podman_compose_path(), + "-f", + compose_path, + "down", + ]) diff --git a/tests/unit/test_container_to_args.py b/tests/unit/test_container_to_args.py index 028f8dad..f5429220 100644 --- a/tests/unit/test_container_to_args.py +++ b/tests/unit/test_container_to_args.py @@ -251,6 +251,27 @@ async def test_gidmaps_extension(self) -> None: ], ) + async def test_cgroup_conf_extension(self) -> None: + c = create_compose_mock() + + cnt = get_minimal_container() + cnt['x-podman.cgroup_conf'] = ['memory.high=1000M', 'memory.min=200M'] + + args = await container_to_args(c, cnt) + self.assertEqual( + args, + [ + "--name=project_name_service_name1", + "-d", + "--network=bridge:alias=service_name", + '--cgroup-conf', + 'memory.high=1000M', + '--cgroup-conf', + 'memory.min=200M', + "busybox", + ], + ) + async def test_rootfs_extension(self) -> None: c = create_compose_mock()