From 08c7075c403b86111b2c393b49075a81a1d2263f Mon Sep 17 00:00:00 2001 From: Qiang Huang Date: Tue, 12 Jul 2016 08:07:24 +0800 Subject: [PATCH] Soften limitation of update kernel memory Kernel memory is not allowed to be updated if container is running, it's not actually a precise kernel limitation. Before kernel version 4.6, kernel memory will not be accounted until kernel memory limit is set, if a container created with kernel memory initialized, kernel memory is accounted as soon as process created in container, so kernel memory limit update is allowed afterward. If kernel memory is not initialized, kernel memory consumed by processes in container will not be accounted, so we can't update the limit because the account will be wrong. So update kernel memory of a running container with kernel memory initialized is allowed, we should soften the limitation by docker. Signed-off-by: Qiang Huang --- daemon/update.go | 4 --- docs/reference/commandline/update.md | 20 ++++++++++++--- .../docker_cli_update_unix_test.go | 22 +++++++++++----- man/docker-update.1.md | 25 +++++++++++++++---- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/daemon/update.go b/daemon/update.go index 0a5e76d1cd..73ae16a0c3 100644 --- a/daemon/update.go +++ b/daemon/update.go @@ -61,10 +61,6 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro return errCannotUpdate(container.ID, fmt.Errorf("Container is marked for removal and cannot be \"update\".")) } - if container.IsRunning() && hostConfig.KernelMemory != 0 { - return errCannotUpdate(container.ID, fmt.Errorf("Can not update kernel memory to a running container, please stop it first.")) - } - if err := container.UpdateContainer(hostConfig); err != nil { restoreConfig = true return errCannotUpdate(container.ID, err) diff --git a/docs/reference/commandline/update.md b/docs/reference/commandline/update.md index 4ad4dc9e62..7cd624c9d5 100644 --- a/docs/reference/commandline/update.md +++ b/docs/reference/commandline/update.md @@ -38,9 +38,23 @@ space-separated list of container names or IDs. With the exception of the `--kernel-memory` value, you can specify these options on a running or a stopped container. You can only update -`--kernel-memory` on a stopped container. When you run `docker update` on -stopped container, the next time you restart it, the container uses those -values. +`--kernel-memory` on a stopped container or on a running container with +kernel memory initialized. For example, if you started a container with +command: + + # docker run -ti --name test --kernel-memory 50M ubuntu bash + +You can update kernel memory of this running container: + + # docker update --kernel-memory 80M test + +If you started a container without kernel memory initialized: + + # docker run -ti --name test2 --memory 300M ubuntu bash + +Update kernel memory of running container `test2` will fail, you can only +stop the container and update kernel memory then. The next time you +restart it, the container uses the new value. Another configuration you can change with this command is restart policy, new restart policy will take effect instantly after you run `docker update` diff --git a/integration-cli/docker_cli_update_unix_test.go b/integration-cli/docker_cli_update_unix_test.go index 186c6fe845..0c8bc1e6ca 100644 --- a/integration-cli/docker_cli_update_unix_test.go +++ b/integration-cli/docker_cli_update_unix_test.go @@ -120,17 +120,27 @@ func (s *DockerSuite) TestUpdateKernelMemory(c *check.C) { name := "test-update-container" dockerCmd(c, "run", "-d", "--name", name, "--kernel-memory", "50M", "busybox", "top") - _, _, err := dockerCmdWithError("update", "--kernel-memory", "100M", name) - // Update kernel memory to a running container is not allowed. - c.Assert(err, check.NotNil) + dockerCmd(c, "update", "--kernel-memory", "100M", name) - // Update kernel memory to a running container with failure should not change HostConfig - c.Assert(inspectField(c, name, "HostConfig.KernelMemory"), checker.Equals, "52428800") + c.Assert(inspectField(c, name, "HostConfig.KernelMemory"), checker.Equals, "104857600") + + file := "/sys/fs/cgroup/memory/memory.kmem.limit_in_bytes" + out, _ := dockerCmd(c, "exec", name, "cat", file) + c.Assert(strings.TrimSpace(out), checker.Equals, "104857600") +} + +func (s *DockerSuite) TestUpdateKernelMemoryUninitialized(c *check.C) { + testRequires(c, DaemonIsLinux, kernelMemorySupport) + + name := "test-update-container" + dockerCmd(c, "run", "-d", "--name", name, "busybox", "top") + _, _, err := dockerCmdWithError("update", "--kernel-memory", "100M", name) + // Update kernel memory to a running container without kernel memory initialized is not allowed. + c.Assert(err, check.NotNil) dockerCmd(c, "pause", name) _, _, err = dockerCmdWithError("update", "--kernel-memory", "100M", name) c.Assert(err, check.NotNil) - c.Assert(inspectField(c, name, "HostConfig.KernelMemory"), checker.Equals, "52428800") dockerCmd(c, "unpause", name) dockerCmd(c, "stop", name) diff --git a/man/docker-update.1.md b/man/docker-update.1.md index 87849ef8d5..9d39d78b13 100644 --- a/man/docker-update.1.md +++ b/man/docker-update.1.md @@ -30,9 +30,23 @@ provide space-separated list of container names or IDs. With the exception of the `--kernel-memory` value, you can specify these options on a running or a stopped container. You can only update -`--kernel-memory` on a stopped container. When you run `docker update` on -stopped container, the next time you restart it, the container uses those -values. +`--kernel-memory` on a stopped container or on a running container with +kernel memory initialized. For example, if you started a container with +command: + + # docker run -ti --name test --kernel-memory 50M ubuntu bash + +You can update kernel memory of this running container: + + # docker update --kernel-memory 80M test + +If you started a container without kernel memory initialized: + + # docker run -ti --name test2 --memory 300M ubuntu bash + +Update kernel memory of running container `test2` will fail, you can only +stop the container and update kernel memory then. The next time you +restart it, the container uses the new value. Another configuration you can change with this command is restart policy, new restart policy will take effect instantly after you run `docker update` @@ -63,8 +77,9 @@ on a container. **--kernel-memory**="" Kernel memory limit (format: `[]`, where unit = b, k, m or g) - Note that you can not update kernel memory to a running container, it can only -be updated to a stopped container, and affect after it's started. + Note that you can not update kernel memory to a running container if the container +is started without kernel memory initialized, in this case, it can only be updated +after it's stopped, and affect after it's started. **-m**, **--memory**="" Memory limit (format: , where unit = b, k, m or g)