[lxc-devel] [lxd/master] containers: add limits.kernel.[limit name] support

brauner on Github lxc-bot at linuxcontainers.org
Mon Oct 9 10:39:11 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 449 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20171009/04a33839/attachment.bin>
-------------- next part --------------
From 551e0f6e8af088da5393dc3285a6dec780eacf4a Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 9 Oct 2017 12:16:35 +0200
Subject: [PATCH 1/2] containers: add limits.kernel.[limit name] support

This adds support for liblxc's lxc.prlimit.[limit name] feature.

Closes #3272.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 doc/api-extensions.md |  4 ++++
 doc/containers.md     |  1 +
 lxd/api_1.0.go        |  1 +
 lxd/container_lxc.go  | 24 ++++++++++++++++++++++++
 shared/container.go   |  5 +++++
 5 files changed, 35 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 92cc342cc..c9b4ec0c0 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -339,3 +339,7 @@ use by another LXD instance.
 ## storage\_block\_filesystem\_btrfs
 This adds support for btrfs as a storage volume filesystem, in addition to ext4
 and xfs.
+
+## kernel\_limits
+This adds support for setting process limits such as maximum number of open
+files for the container via `nofile`. The format is `limits.kernel.[limit name]`.
diff --git a/doc/containers.md b/doc/containers.md
index 591868919..2d3404b86 100644
--- a/doc/containers.md
+++ b/doc/containers.md
@@ -33,6 +33,7 @@ limits.cpu                           | string    | - (all)       | yes
 limits.cpu.allowance                 | string    | 100%          | yes           | -                                    | How much of the CPU can be used. Can be a percentage (e.g. 50%) for a soft limit or hard a chunk of time (25ms/100ms)
 limits.cpu.priority                  | integer   | 10 (maximum)  | yes           | -                                    | CPU scheduling priority compared to other containers sharing the same CPUs (overcommit) (integer between 0 and 10)
 limits.disk.priority                 | integer   | 5 (medium)    | yes           | -                                    | When under load, how much priority to give to the container's I/O requests (integer between 0 and 10)
+limits.kernel.\*                     | string    | -             | no            | kernel\_limits                       | This limits kernel resources per container (e.g. number of open files)
 limits.memory                        | string    | - (all)       | yes           | -                                    | Percentage of the host's memory or fixed value in bytes (supports kB, MB, GB, TB, PB and EB suffixes)
 limits.memory.enforce                | string    | hard          | yes           | -                                    | If hard, container can't exceed its memory limit. If soft, the container can exceed its memory limit when extra host memory is available.
 limits.memory.swap                   | boolean   | true          | yes           | -                                    | Whether to allow some of the container's memory to be swapped out to disk
diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go
index 0dd41bfaa..a17d1a111 100644
--- a/lxd/api_1.0.go
+++ b/lxd/api_1.0.go
@@ -125,6 +125,7 @@ func api10Get(d *Daemon, r *http.Request) Response {
 			"storage_volatile_initial_source",
 			"storage_ceph_force_osd_reuse",
 			"storage_block_filesystem_btrfs",
+			"kernel_limits",
 		},
 		APIStatus:  "stable",
 		APIVersion: version.APIVersion,
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index c4f7d761c..ce8918179 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -154,6 +154,12 @@ func lxcSetConfigItem(c *lxc.Container, key string, value string) error {
 		}
 	}
 
+	if strings.HasPrefix(key, "lxc.prlimit.") {
+		if !lxc.VersionAtLeast(2, 1, 0) {
+			return fmt.Errorf(`Process limits require libxc >= 2.1`)
+		}
+	}
+
 	err := c.SetConfigItem(key, value)
 	if err != nil {
 		return fmt.Errorf("Failed to set LXC config: %s=%s", key, value)
@@ -198,6 +204,12 @@ func lxcValidConfig(rawLxc string) error {
 			return fmt.Errorf("Setting lxc.ephemeral is not allowed")
 		}
 
+		if strings.HasPrefix(key, "lxc.prlimit.") {
+			return fmt.Errorf(`Process limits should be set via ` +
+				`"limits.kernel.[limit name]" and not ` +
+				`directly via "lxc.prlimit.[limit name]"`)
+		}
+
 		networkKeyPrefix := "lxc.net."
 		if !lxc.VersionAtLeast(2, 1, 0) {
 			networkKeyPrefix = "lxc.network."
@@ -1284,6 +1296,18 @@ func (c *containerLXC) initLXC() error {
 		}
 	}
 
+	// Setup process limits
+	for k, v := range c.expandedConfig {
+		if strings.HasPrefix(k, "limits.kernel.") {
+			prlimitSuffix := strings.TrimPrefix(k, "limits.kernel.")
+			prlimitKey := fmt.Sprintf("lxc.prlimit.%s", prlimitSuffix)
+			err = lxcSetConfigItem(cc, prlimitKey, v)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
 	// Setup devices
 	networkidx := 0
 	for _, k := range c.expandedDevices.DeviceNames() {
diff --git a/shared/container.go b/shared/container.go
index 96a348b17..94835dcc5 100644
--- a/shared/container.go
+++ b/shared/container.go
@@ -231,5 +231,10 @@ func ConfigKeyChecker(key string) (func(value string) error, error) {
 		return IsAny, nil
 	}
 
+	if strings.HasPrefix(key, "limits.kernel.") &&
+		(len(key) > len("limits.kernel.")) {
+		return IsAny, nil
+	}
+
 	return nil, fmt.Errorf("Bad key: %s", key)
 }

From ad268b9444c6322e875d146049870d5fede0d250 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 9 Oct 2017 12:37:14 +0200
Subject: [PATCH 2/2] tests: api extension kernel_limits

Closes #3272.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 test/main.sh                 |  1 +
 test/suites/kernel_limits.sh | 17 +++++++++++++++++
 2 files changed, 18 insertions(+)
 create mode 100644 test/suites/kernel_limits.sh

diff --git a/test/main.sh b/test/main.sh
index c49b481ec..9b76f3faa 100755
--- a/test/main.sh
+++ b/test/main.sh
@@ -184,6 +184,7 @@ run_test test_storage_profiles "storage profiles"
 run_test test_container_import "container import"
 run_test test_storage_volume_attach "attaching storage volumes"
 run_test test_storage_driver_ceph "ceph storage driver"
+run_test test_kernel_limits "kernel limits"
 
 # shellcheck disable=SC2034
 TEST_RESULT=success
diff --git a/test/suites/kernel_limits.sh b/test/suites/kernel_limits.sh
new file mode 100644
index 000000000..8873c5ea5
--- /dev/null
+++ b/test/suites/kernel_limits.sh
@@ -0,0 +1,17 @@
+test_kernel_limits() {
+  echo "==> API extension kernel_limits"
+
+  ensure_import_testimage
+  lxc init testimage limits
+  # Set it to a limit < 65536 because older systemd's do not have my nofile
+  # limit patch.
+  lxc config set limits limits.kernel.nofile 3000
+  lxc start limits
+  pid=$(lxc info limits | grep ^Pid | awk '{print $2}')
+  soft=$(cat /proc/"${pid}"/limits | grep ^"Max open files" | awk '{print $4}')
+  hard=$(cat /proc/"${pid}"/limits | grep ^"Max open files" | awk '{print $5}')
+
+  lxc delete --force limits 
+
+  [ "${soft}" = "3000" ] && [ "${hard}" = "3000" ]
+}


More information about the lxc-devel mailing list