Implemet docker update command

It's used for updating properties of one or more containers, we only
support resource configs for now. It can be extended in the future.

Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
This commit is contained in:
Qiang Huang 2015-12-28 19:19:26 +08:00
parent b0be88c111
commit 8799c4fc0f
22 changed files with 728 additions and 2 deletions

View file

@ -43,6 +43,7 @@ type apiClient interface {
ContainerStop(containerID string, timeout int) error
ContainerTop(containerID string, arguments []string) (types.ContainerProcessList, error)
ContainerUnpause(containerID string) error
ContainerUpdate(containerID string, hostConfig container.HostConfig) error
ContainerWait(containerID string) (int, error)
CopyFromContainer(containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error)
CopyToContainer(options types.CopyToContainerOptions) error

View file

@ -0,0 +1,12 @@
package lib
import (
"github.com/docker/docker/api/types/container"
)
// ContainerUpdate updates resources of a container
func (cli *Client) ContainerUpdate(containerID string, hostConfig container.HostConfig) error {
resp, err := cli.post("/containers/"+containerID+"/update", nil, hostConfig, nil)
ensureReaderClosed(resp)
return err
}

104
api/client/update.go Normal file
View file

@ -0,0 +1,104 @@
package client
import (
"fmt"
"github.com/docker/docker/api/types/container"
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/go-units"
)
// CmdUpdate updates resources of one or more containers.
//
// Usage: docker update [OPTIONS] CONTAINER [CONTAINER...]
func (cli *DockerCli) CmdUpdate(args ...string) error {
cmd := Cli.Subcmd("update", []string{"CONTAINER [CONTAINER...]"}, Cli.DockerCommands["update"].Description, true)
flBlkioWeight := cmd.Uint16([]string{"-blkio-weight"}, 0, "Block IO (relative weight), between 10 and 1000")
flCPUPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit CPU CFS (Completely Fair Scheduler) period")
flCPUQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit CPU CFS (Completely Fair Scheduler) quota")
flCpusetCpus := cmd.String([]string{"-cpuset-cpus"}, "", "CPUs in which to allow execution (0-3, 0,1)")
flCpusetMems := cmd.String([]string{"-cpuset-mems"}, "", "MEMs in which to allow execution (0-3, 0,1)")
flCPUShares := cmd.Int64([]string{"#c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit")
flMemoryReservation := cmd.String([]string{"-memory-reservation"}, "", "Memory soft limit")
flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap")
flKernelMemory := cmd.String([]string{"-kernel-memory"}, "", "Kernel memory limit")
cmd.Require(flag.Min, 1)
cmd.ParseFlags(args, true)
if cmd.NFlag() == 0 {
return fmt.Errorf("You must provide one or more flags when using this command.")
}
var err error
var flMemory int64
if *flMemoryString != "" {
flMemory, err = units.RAMInBytes(*flMemoryString)
if err != nil {
return err
}
}
var memoryReservation int64
if *flMemoryReservation != "" {
memoryReservation, err = units.RAMInBytes(*flMemoryReservation)
if err != nil {
return err
}
}
var memorySwap int64
if *flMemorySwap != "" {
if *flMemorySwap == "-1" {
memorySwap = -1
} else {
memorySwap, err = units.RAMInBytes(*flMemorySwap)
if err != nil {
return err
}
}
}
var kernelMemory int64
if *flKernelMemory != "" {
kernelMemory, err = units.RAMInBytes(*flKernelMemory)
if err != nil {
return err
}
}
resources := container.Resources{
BlkioWeight: *flBlkioWeight,
CpusetCpus: *flCpusetCpus,
CpusetMems: *flCpusetMems,
CPUShares: *flCPUShares,
Memory: flMemory,
MemoryReservation: memoryReservation,
MemorySwap: memorySwap,
KernelMemory: kernelMemory,
CPUPeriod: *flCPUPeriod,
CPUQuota: *flCPUQuota,
}
hostConfig := container.HostConfig{
Resources: resources,
}
names := cmd.Args()
var errNames []string
for _, name := range names {
if err := cli.client.ContainerUpdate(name, hostConfig); err != nil {
fmt.Fprintf(cli.err, "%s\n", err)
errNames = append(errNames, name)
} else {
fmt.Fprintf(cli.out, "%s\n", name)
}
}
if len(errNames) > 0 {
return fmt.Errorf("Error: failed to update resources of containers: %v", errNames)
}
return nil
}

View file

@ -42,6 +42,7 @@ type stateBackend interface {
ContainerStart(name string, hostConfig *container.HostConfig) error
ContainerStop(name string, seconds int) error
ContainerUnpause(name string) error
ContainerUpdate(name string, hostConfig *container.HostConfig) ([]string, error)
ContainerWait(name string, timeout time.Duration) (int, error)
Exists(id string) bool
IsPaused(id string) bool

View file

@ -57,6 +57,7 @@ func (r *containerRouter) initRoutes() {
local.NewPostRoute("/exec/{name:.*}/start", r.postContainerExecStart),
local.NewPostRoute("/exec/{name:.*}/resize", r.postContainerExecResize),
local.NewPostRoute("/containers/{name:.*}/rename", r.postContainerRename),
local.NewPostRoute("/containers/{name:.*}/update", r.postContainerUpdate),
// PUT
local.NewPutRoute("/containers/{name:.*}/archive", r.putContainersArchive),
// DELETE

View file

@ -323,6 +323,30 @@ func (s *containerRouter) postContainerRename(ctx context.Context, w http.Respon
return nil
}
func (s *containerRouter) postContainerUpdate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
}
if err := httputils.CheckForJSON(r); err != nil {
return err
}
_, hostConfig, err := runconfig.DecodeContainerConfig(r.Body)
if err != nil {
return err
}
name := vars["name"]
warnings, err := s.backend.ContainerUpdate(name, hostConfig)
if err != nil {
return err
}
return httputils.WriteJSON(w, http.StatusOK, &types.ContainerUpdateResponse{
Warnings: warnings,
})
}
func (s *containerRouter) postContainersCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err

View file

@ -28,6 +28,13 @@ type ContainerExecCreateResponse struct {
ID string `json:"Id"`
}
// ContainerUpdateResponse contains response of Remote API:
// POST /containers/{name:.*}/update
type ContainerUpdateResponse struct {
// Warnings are any warnings encountered during the updating of the container.
Warnings []string `json:"Warnings"`
}
// AuthResponse contains response of Remote API:
// POST "/auth"
type AuthResponse struct {

View file

@ -64,6 +64,7 @@ var dockerCommands = []Command{
{"tag", "Tag an image into a repository"},
{"top", "Display the running processes of a container"},
{"unpause", "Unpause all processes within a container"},
{"update", "Update resources of one or more containers"},
{"version", "Show the Docker version information"},
{"volume", "Manage Docker volumes"},
{"wait", "Block until a container stops, then print its exit code"},

View file

@ -13,6 +13,7 @@ import (
"syscall"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
@ -543,6 +544,75 @@ func (container *Container) IpcMounts() []execdriver.Mount {
return mounts
}
func updateCommand(c *execdriver.Command, resources container.Resources) {
c.Resources.BlkioWeight = resources.BlkioWeight
c.Resources.CPUShares = resources.CPUShares
c.Resources.CPUPeriod = resources.CPUPeriod
c.Resources.CPUQuota = resources.CPUQuota
c.Resources.CpusetCpus = resources.CpusetCpus
c.Resources.CpusetMems = resources.CpusetMems
c.Resources.Memory = resources.Memory
c.Resources.MemorySwap = resources.MemorySwap
c.Resources.MemoryReservation = resources.MemoryReservation
c.Resources.KernelMemory = resources.KernelMemory
}
// UpdateContainer updates resources of a container.
func (container *Container) UpdateContainer(hostConfig *container.HostConfig) error {
container.Lock()
resources := hostConfig.Resources
cResources := &container.HostConfig.Resources
if resources.BlkioWeight != 0 {
cResources.BlkioWeight = resources.BlkioWeight
}
if resources.CPUShares != 0 {
cResources.CPUShares = resources.CPUShares
}
if resources.CPUPeriod != 0 {
cResources.CPUPeriod = resources.CPUPeriod
}
if resources.CPUQuota != 0 {
cResources.CPUQuota = resources.CPUQuota
}
if resources.CpusetCpus != "" {
cResources.CpusetCpus = resources.CpusetCpus
}
if resources.CpusetMems != "" {
cResources.CpusetMems = resources.CpusetMems
}
if resources.Memory != 0 {
cResources.Memory = resources.Memory
}
if resources.MemorySwap != 0 {
cResources.MemorySwap = resources.MemorySwap
}
if resources.MemoryReservation != 0 {
cResources.MemoryReservation = resources.MemoryReservation
}
if resources.KernelMemory != 0 {
cResources.KernelMemory = resources.KernelMemory
}
container.Unlock()
// If container is not running, update hostConfig struct is enough,
// resources will be updated when the container is started again.
// If container is running (including paused), we need to update
// the command so we can update configs to the real world.
if container.IsRunning() {
container.Lock()
updateCommand(container.Command, resources)
container.Unlock()
}
if err := container.ToDiskLocking(); err != nil {
logrus.Errorf("Error saving updated container: %v", err)
return err
}
return nil
}
func detachMounted(path string) error {
return syscall.Unmount(path, syscall.MNT_DETACH)
}

View file

@ -3,6 +3,7 @@
package container
import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/volume"
)
@ -47,6 +48,11 @@ func (container *Container) TmpfsMounts() []execdriver.Mount {
return nil
}
// UpdateContainer updates resources of a container
func (container *Container) UpdateContainer(hostConfig *container.HostConfig) error {
return nil
}
// appendNetworkMounts appends any network mounts to the array of mount points passed in.
// Windows does not support network mounts (not to be confused with SMB network mounts), so
// this is a no-op.

View file

@ -91,6 +91,9 @@ type Driver interface {
// Stats returns resource stats for a running container
Stats(id string) (*ResourceStats, error)
// Update updates resource configs for a container
Update(c *Command) error
// SupportsHooks refers to the driver capability to exploit pre/post hook functionality
SupportsHooks() bool
}

View file

@ -398,6 +398,26 @@ func (d *Driver) Stats(id string) (*execdriver.ResourceStats, error) {
}, nil
}
// Update updates configs for a container
func (d *Driver) Update(c *execdriver.Command) error {
d.Lock()
cont := d.activeContainers[c.ID]
d.Unlock()
if cont == nil {
return execdriver.ErrNotRunning
}
config := cont.Config()
if err := execdriver.SetupCgroups(&config, c); err != nil {
return err
}
if err := cont.Set(config); err != nil {
return err
}
return nil
}
// TtyConsole implements the exec driver Terminal interface.
type TtyConsole struct {
console libcontainer.Console

View file

@ -0,0 +1,14 @@
// +build windows
package windows
import (
"fmt"
"github.com/docker/docker/daemon/execdriver"
)
// Update updates resource configs for a container.
func (d *Driver) Update(c *execdriver.Command) error {
return fmt.Errorf("Windows: Update not implemented")
}

58
daemon/update.go Normal file
View file

@ -0,0 +1,58 @@
package daemon
import (
"fmt"
"github.com/docker/docker/api/types/container"
)
// ContainerUpdate updates resources of the container
func (daemon *Daemon) ContainerUpdate(name string, hostConfig *container.HostConfig) ([]string, error) {
var warnings []string
warnings, err := daemon.verifyContainerSettings(hostConfig, nil)
if err != nil {
return warnings, err
}
if err := daemon.update(name, hostConfig); err != nil {
return warnings, err
}
return warnings, nil
}
func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) error {
if hostConfig == nil {
return nil
}
container, err := daemon.GetContainer(name)
if err != nil {
return err
}
if container.RemovalInProgress || container.Dead {
return fmt.Errorf("Container is marked for removal and cannot be \"update\".")
}
if container.IsRunning() && hostConfig.KernelMemory != 0 {
return fmt.Errorf("Can not update kernel memory to a running container, please stop it first.")
}
if err := container.UpdateContainer(hostConfig); err != nil {
return err
}
// If container is not running, update hostConfig struct is enough,
// resources will be updated when the container is started again.
// If container is running (including paused), we need to update configs
// to the real world.
if container.IsRunning() {
if err := daemon.execDriver.Update(container.Command); err != nil {
return err
}
}
return nil
}

View file

@ -1003,6 +1003,50 @@ Status Codes:
- **404** no such container
- **500** server error
### Update a container
`POST /containers/(id)/update`
Update resource configs of one or more containers.
**Example request**:
POST /containers/(id)/update HTTP/1.1
Content-Type: application/json
{
"HostConfig": {
"Resources": {
"BlkioWeight": 300,
"CpuShares": 512,
"CpuPeriod": 100000,
"CpuQuota": 50000,
"CpusetCpus": "0,1",
"CpusetMems": "0",
"Memory": 314572800,
"MemorySwap": 514288000,
"MemoryReservation": 209715200,
"KernelMemory": 52428800,
}
}
}
**Example response**:
HTTP/1.1 200 OK
Content-Type: application/json
{
"Warnings": []
}
Status Codes:
- **200** no error
- **400** bad parameter
- **404** no such container
- **500** server error
### Rename a container
`POST /containers/(id)/rename`

File diff suppressed because one or more lines are too long

View file

@ -59,6 +59,7 @@ You start the Docker daemon with the command line. How you start the daemon affe
* [stop](stop.md)
* [top](top.md)
* [unpause](unpause.md)
* [update](update.md)
* [wait](wait.md)
### Hub and registry commands

View file

@ -0,0 +1,61 @@
<!--[metadata]>
+++
title = "update"
description = "The update command description and usage"
keywords = ["resources, update, dynamically"]
[menu.main]
parent = "smn_cli"
+++
<![end-metadata]-->
## update
Usage: docker update [OPTIONS] CONTAINER [CONTAINER...]
Updates container resource limits
--help=false Print usage
--blkio-weight=0 Block IO (relative weight), between 10 and 1000
--cpu-shares=0 CPU shares (relative weight)
--cpu-period=0 Limit the CPU CFS (Completely Fair Scheduler) period
--cpu-quota=0 Limit the CPU CFS (Completely Fair Scheduler) quota
--cpuset-cpus="" CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems="" Memory nodes (MEMs) in which to allow execution (0-3, 0,1)
-m, --memory="" Memory limit
--memory-reservation="" Memory soft limit
--memory-swap="" Total memory (memory + swap), '-1' to disable swap
--kernel-memory="" Kernel memory limit: container must be stopped
The `docker update` command dynamically updates container resources. Use this
command to prevent containers from consuming too many resources from their
Docker host. With a single command, you can place limits on a single
container or on many. To specify more than one container, 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.
## EXAMPLES
The following sections illustrate ways to use this command.
### Update a container with cpu-shares=512
To limit a container's cpu-shares to 512, first identify the container
name or ID. You can use **docker ps** to find these values. You can also
use the ID returned from the **docker run** command. Then, do the following:
```bash
$ docker update --cpu-shares 512 abebf7571666
```
### Update a container with cpu-shares and memory
To update multiple resource configurations for multiple containers:
```bash
$ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse
```

View file

@ -0,0 +1,43 @@
// +build !windows
package main
import (
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
func (s *DockerSuite) TestApiUpdateContainer(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, memoryLimitSupport)
testRequires(c, swapMemorySupport)
name := "apiUpdateContainer"
hostConfig := map[string]interface{}{
"Memory": 314572800,
"MemorySwap": 524288000,
}
dockerCmd(c, "run", "-d", "--name", name, "-m", "200M", "busybox", "top")
_, _, err := sockRequest("POST", "/containers/"+name+"/update", hostConfig)
c.Assert(err, check.IsNil)
memory, err := inspectField(name, "HostConfig.Memory")
c.Assert(err, check.IsNil)
if memory != "314572800" {
c.Fatalf("Got the wrong memory value, we got %d, expected 314572800(300M).", memory)
}
file := "/sys/fs/cgroup/memory/memory.limit_in_bytes"
out, _ := dockerCmd(c, "exec", name, "cat", file)
c.Assert(strings.TrimSpace(out), checker.Equals, "314572800")
memorySwap, err := inspectField(name, "HostConfig.MemorySwap")
c.Assert(err, check.IsNil)
if memorySwap != "524288000" {
c.Fatalf("Got the wrong memorySwap value, we got %d, expected 524288000(500M).", memorySwap)
}
file = "/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"
out, _ = dockerCmd(c, "exec", name, "cat", file)
c.Assert(strings.TrimSpace(out), checker.Equals, "524288000")
}

View file

@ -226,7 +226,7 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
}
// Number of commands for standard release and experimental release
standard := 40
standard := 41
experimental := 1
expected := standard + experimental
if isLocalDaemon {

View file

@ -0,0 +1,162 @@
// +build !windows
package main
import (
"strings"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
)
func (s *DockerSuite) TestUpdateRunningContainer(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, memoryLimitSupport)
name := "test-update-container"
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "top")
dockerCmd(c, "update", "-m", "500M", name)
memory, err := inspectField(name, "HostConfig.Memory")
c.Assert(err, check.IsNil)
if memory != "524288000" {
c.Fatalf("Got the wrong memory value, we got %d, expected 524288000(500M).", memory)
}
file := "/sys/fs/cgroup/memory/memory.limit_in_bytes"
out, _ := dockerCmd(c, "exec", name, "cat", file)
c.Assert(strings.TrimSpace(out), checker.Equals, "524288000")
}
func (s *DockerSuite) TestUpdateRunningContainerWithRestart(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, memoryLimitSupport)
name := "test-update-container"
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "top")
dockerCmd(c, "update", "-m", "500M", name)
dockerCmd(c, "restart", name)
memory, err := inspectField(name, "HostConfig.Memory")
c.Assert(err, check.IsNil)
if memory != "524288000" {
c.Fatalf("Got the wrong memory value, we got %d, expected 524288000(500M).", memory)
}
file := "/sys/fs/cgroup/memory/memory.limit_in_bytes"
out, _ := dockerCmd(c, "exec", name, "cat", file)
c.Assert(strings.TrimSpace(out), checker.Equals, "524288000")
}
func (s *DockerSuite) TestUpdateStoppedContainer(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, memoryLimitSupport)
name := "test-update-container"
file := "/sys/fs/cgroup/memory/memory.limit_in_bytes"
dockerCmd(c, "run", "--name", name, "-m", "300M", "busybox", "cat", file)
dockerCmd(c, "update", "-m", "500M", name)
memory, err := inspectField(name, "HostConfig.Memory")
c.Assert(err, check.IsNil)
if memory != "524288000" {
c.Fatalf("Got the wrong memory value, we got %d, expected 524288000(500M).", memory)
}
out, _ := dockerCmd(c, "start", "-a", name)
c.Assert(strings.TrimSpace(out), checker.Equals, "524288000")
}
func (s *DockerSuite) TestUpdatePausedContainer(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, cpuShare)
name := "test-update-container"
dockerCmd(c, "run", "-d", "--name", name, "--cpu-shares", "1000", "busybox", "top")
dockerCmd(c, "pause", name)
dockerCmd(c, "update", "--cpu-shares", "500", name)
out, err := inspectField(name, "HostConfig.CPUShares")
c.Assert(err, check.IsNil)
if out != "500" {
c.Fatalf("Got the wrong cpu shares value, we got %d, expected 500.", out)
}
dockerCmd(c, "unpause", name)
file := "/sys/fs/cgroup/cpu/cpu.shares"
out, _ = dockerCmd(c, "exec", name, "cat", file)
c.Assert(strings.TrimSpace(out), checker.Equals, "500")
}
func (s *DockerSuite) TestUpdateWithUntouchedFields(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, memoryLimitSupport)
testRequires(c, cpuShare)
name := "test-update-container"
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "--cpu-shares", "800", "busybox", "top")
dockerCmd(c, "update", "-m", "500M", name)
// Update memory and not touch cpus, `cpuset.cpus` should still have the old value
out, err := inspectField(name, "HostConfig.CPUShares")
c.Assert(err, check.IsNil)
c.Assert(out, check.Equals, "800")
file := "/sys/fs/cgroup/cpu/cpu.shares"
out, _ = dockerCmd(c, "exec", name, "cat", file)
c.Assert(strings.TrimSpace(out), checker.Equals, "800")
}
func (s *DockerSuite) TestUpdateContainerInvalidValue(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, memoryLimitSupport)
name := "test-update-container"
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "true")
out, _, err := dockerCmdWithError("update", "-m", "2M", name)
c.Assert(err, check.NotNil)
expected := "Minimum memory limit allowed is 4MB"
c.Assert(out, checker.Contains, expected)
}
func (s *DockerSuite) TestUpdateContainerWithoutFlags(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, memoryLimitSupport)
name := "test-update-container"
dockerCmd(c, "run", "-d", "--name", name, "-m", "300M", "busybox", "true")
_, _, err := dockerCmdWithError("update", name)
c.Assert(err, check.NotNil)
}
func (s *DockerSuite) TestUpdateKernelMemory(c *check.C) {
testRequires(c, DaemonIsLinux)
testRequires(c, kernelMemorySupport)
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)
out, err := inspectField(name, "HostConfig.KernelMemory")
c.Assert(err, check.IsNil)
// Update kernel memory to a running container with failure should not change HostConfig
if out != "52428800" {
c.Fatalf("Got the wrong memory value, we got %d, expected 52428800(50M).", out)
}
dockerCmd(c, "stop", name)
dockerCmd(c, "update", "--kernel-memory", "100M", name)
dockerCmd(c, "start", name)
out, err = inspectField(name, "HostConfig.KernelMemory")
c.Assert(err, check.IsNil)
if out != "104857600" {
c.Fatalf("Got the wrong memory value, we got %d, expected 104857600(100M).", out)
}
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")
}

93
man/docker-update.1.md Normal file
View file

@ -0,0 +1,93 @@
% DOCKER(1) Docker User Manuals
% Docker Community
% JUNE 2014
# NAME
docker-update - Update resource configs of one or more containers
# SYNOPSIS
**docker update**
[**--blkio-weight**[=*[BLKIO-WEIGHT]*]]
[**--cpu-shares**[=*0*]]
[**--cpu-period**[=*0*]]
[**--cpu-quota**[=*0*]]
[**--cpuset-cpus**[=*CPUSET-CPUS*]]
[**--cpuset-mems**[=*CPUSET-MEMS*]]
[**--help**]
[**--kernel-memory**[=*KERNEL-MEMORY*]]
[**-m**|**--memory**[=*MEMORY*]]
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
[**--memory-swap**[=*MEMORY-SWAP*]]
CONTAINER [CONTAINER...]
# DESCRIPTION
The `docker update` command dynamically updates container resources. Use this
command to prevent containers from consuming too many resources from their
Docker host. With a single command, you can place limits on a single
container or on many. To specify more than one container, 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.
# OPTIONS
**--blkio-weight**=0
Block IO weight (relative weight) accepts a weight value between 10 and 1000.
**--cpu-shares**=0
CPU shares (relative weight)
**--cpu-period**=0
Limit the CPU CFS (Completely Fair Scheduler) period
**--cpu-quota**=0
Limit the CPU CFS (Completely Fair Scheduler) quota
**--cpuset-cpus**=""
CPUs in which to allow execution (0-3, 0,1)
**--cpuset-mems**=""
Memory nodes(MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
**--help**
Print usage statement
**--kernel-memory**=""
Kernel memory limit (format: `<number>[<unit>]`, 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.
**-m**, **--memory**=""
Memory limit (format: <number><optional unit>, where unit = b, k, m or g)
**--memory-reservation**=""
Memory soft limit (format: <number>[<unit>], where unit = b, k, m or g)
**--memory-swap**=""
Total memory limit (memory + swap)
# EXAMPLES
The following sections illustrate ways to use this command.
### Update a container with cpu-shares=512
To limit a container's cpu-shares to 512, first identify the container
name or ID. You can use **docker ps** to find these values. You can also
use the ID returned from the **docker run** command. Then, do the following:
```bash
$ docker update --cpu-shares 512 abebf7571666
```
### Update a container with cpu-shares and memory
To update multiple resource configurations for multiple containers:
```bash
$ docker update --cpu-shares 512 -m 300M abebf7571666 hopeful_morse
```