diff --git a/api/client/build.go b/api/client/build.go index 55efc1ba35..d4e2d514e4 100644 --- a/api/client/build.go +++ b/api/client/build.go @@ -59,6 +59,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { dockerfileName := cmd.String([]string{"f", "-file"}, "", "Name of the Dockerfile (Default is 'PATH/Dockerfile')") flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit") flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap") + flShmSize := cmd.String([]string{"-shm-size"}, "", "Size of /dev/shm, default value is 64MB") flCPUShares := cmd.Int64([]string{"#c", "-cpu-shares"}, 0, "CPU shares (relative weight)") flCPUPeriod := cmd.Int64([]string{"-cpu-period"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) period") flCPUQuota := cmd.Int64([]string{"-cpu-quota"}, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota") @@ -210,6 +211,18 @@ func (cli *DockerCli) CmdBuild(args ...string) error { } } + var shmSize int64 = 67108864 // initial SHM size is 64MB + if *flShmSize != "" { + parsedShmSize, err := units.RAMInBytes(*flShmSize) + if err != nil { + return err + } + if parsedShmSize <= 0 { + return fmt.Errorf("--shm-size: SHM size must be greater than 0 . You specified: %v ", parsedShmSize) + } + shmSize = parsedShmSize + } + // Send the build context v := url.Values{ "t": flTags.GetAll(), @@ -248,6 +261,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error { v.Set("cpuperiod", strconv.FormatInt(*flCPUPeriod, 10)) v.Set("memory", strconv.FormatInt(memory, 10)) v.Set("memswap", strconv.FormatInt(memorySwap, 10)) + v.Set("shmsize", strconv.FormatInt(shmSize, 10)) v.Set("cgroupparent", *flCgroupParent) v.Set("dockerfile", relDockerfile) diff --git a/api/server/router/local/image.go b/api/server/router/local/image.go index fd78ee2cda..7e41eac894 100644 --- a/api/server/router/local/image.go +++ b/api/server/router/local/image.go @@ -323,6 +323,7 @@ func (s *router) postBuild(ctx context.Context, w http.ResponseWriter, r *http.R buildConfig.ForceRemove = httputils.BoolValue(r, "forcerm") buildConfig.MemorySwap = httputils.Int64ValueOrZero(r, "memswap") buildConfig.Memory = httputils.Int64ValueOrZero(r, "memory") + buildConfig.ShmSize = httputils.Int64ValueOrZero(r, "shmsize") buildConfig.CPUShares = httputils.Int64ValueOrZero(r, "cpushares") buildConfig.CPUPeriod = httputils.Int64ValueOrZero(r, "cpuperiod") buildConfig.CPUQuota = httputils.Int64ValueOrZero(r, "cpuquota") diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go index a75f768e82..bd4283daf9 100644 --- a/builder/dockerfile/builder.go +++ b/builder/dockerfile/builder.go @@ -60,6 +60,7 @@ type Config struct { Memory int64 MemorySwap int64 + ShmSize int64 CPUShares int64 CPUPeriod int64 CPUQuota int64 diff --git a/builder/dockerfile/internals.go b/builder/dockerfile/internals.go index 2af67e7507..a023d8c99c 100644 --- a/builder/dockerfile/internals.go +++ b/builder/dockerfile/internals.go @@ -508,6 +508,7 @@ func (b *Builder) create() (*daemon.Container, error) { CgroupParent: b.CgroupParent, Memory: b.Memory, MemorySwap: b.MemorySwap, + ShmSize: b.ShmSize, Ulimits: b.Ulimits, Isolation: b.Isolation, } diff --git a/daemon/container_unix.go b/daemon/container_unix.go index 53c337549b..a925717fe6 100644 --- a/daemon/container_unix.go +++ b/daemon/container_unix.go @@ -1357,7 +1357,12 @@ func (daemon *Daemon) setupIpcDirs(container *Container) error { return err } - if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel("mode=1777,size=65536k", container.getMountLabel())); err != nil { + // When ShmSize is 0 or less, the SHM size is set to 64MB. + if container.hostConfig.ShmSize <= 0 { + container.hostConfig.ShmSize = 67108864 + } + shmproperty := "mode=1777,size=" + strconv.FormatInt(container.hostConfig.ShmSize, 10) + if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel(shmproperty, container.getMountLabel())); err != nil { return fmt.Errorf("mounting shm tmpfs: %s", err) } if err := os.Chown(shmPath, rootUID, rootGID); err != nil { diff --git a/docs/reference/api/docker_remote_api_v1.22.md b/docs/reference/api/docker_remote_api_v1.22.md index 01f67f3568..d84a4b9c48 100644 --- a/docs/reference/api/docker_remote_api_v1.22.md +++ b/docs/reference/api/docker_remote_api_v1.22.md @@ -208,7 +208,8 @@ Create a container "LogConfig": { "Type": "json-file", "Config": {} }, "SecurityOpt": [""], "CgroupParent": "", - "VolumeDriver": "" + "VolumeDriver": "", + "ShmSize": 67108864 } } @@ -318,6 +319,7 @@ Json Parameters: `json-file` logging driver. - **CgroupParent** - Path to `cgroups` under which the container's `cgroup` is created. If the path is not absolute, the path is considered to be relative to the `cgroups` path of the init process. Cgroups are created if they do not already exist. - **VolumeDriver** - Driver that this container users to mount volumes. + - **ShmSize** - Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB. Query Parameters: @@ -430,7 +432,8 @@ Return low-level information on the container `id` "SecurityOpt": null, "VolumesFrom": null, "Ulimits": [{}], - "VolumeDriver": "" + "VolumeDriver": "", + "ShmSize": 67108864 }, "HostnamePath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hostname", "HostsPath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hosts", @@ -1435,6 +1438,7 @@ Query Parameters: context for command(s) run via the Dockerfile's `RUN` instruction or for variable expansion in other Dockerfile instructions. This is not meant for passing secret values. [Read more about the buildargs instruction](../../reference/builder.md#arg) +- **shmsize** - Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB. Request Headers: diff --git a/docs/reference/commandline/build.md b/docs/reference/commandline/build.md index 32a51ceb8b..72da56d80e 100644 --- a/docs/reference/commandline/build.md +++ b/docs/reference/commandline/build.md @@ -31,6 +31,7 @@ parent = "smn_cli" --pull=false Always attempt to pull a newer version of the image -q, --quiet=false Suppress the verbose output generated by the containers --rm=true Remove intermediate containers after a successful build + --shm-size=[] Size of `/dev/shm`. The format is ``. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. -t, --tag=[] Name and optionally a tag in the 'name:tag' format --ulimit=[] Ulimit options diff --git a/docs/reference/commandline/create.md b/docs/reference/commandline/create.md index 9c4b19bd8c..a7ed5dda17 100644 --- a/docs/reference/commandline/create.md +++ b/docs/reference/commandline/create.md @@ -65,6 +65,7 @@ Creates a new container. --restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped) --security-opt=[] Security options --stop-signal="SIGTERM" Signal to stop a container + --shm-size=[] Size of `/dev/shm`. The format is ``. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. -t, --tty=false Allocate a pseudo-TTY -u, --user="" Username or UID --ulimit=[] Ulimit options diff --git a/docs/reference/commandline/run.md b/docs/reference/commandline/run.md index 3ad93f2fa3..5d6ad1877f 100644 --- a/docs/reference/commandline/run.md +++ b/docs/reference/commandline/run.md @@ -68,6 +68,7 @@ parent = "smn_cli" --read-only=false Mount the container's root filesystem as read only --restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped) --rm=false Automatically remove the container when it exits + --shm-size=[] Size of `/dev/shm`. The format is ``. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. --security-opt=[] Security Options --sig-proxy=true Proxy received signals to the process --stop-signal="SIGTERM" Signal to stop a container diff --git a/docs/reference/run.md b/docs/reference/run.md index 5ea79d4b28..a14429651e 100644 --- a/docs/reference/run.md +++ b/docs/reference/run.md @@ -626,6 +626,10 @@ container: | `--blkio-weight-device=""` | Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`) | | `--oom-kill-disable=false` | Whether to disable OOM Killer for the container or not. | | `--memory-swappiness="" ` | Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100. | +| `--shm-size="" ` | Size of `/dev/shm`. The format is ``. `number` must be greater than `0`. | +| | Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or | +| | `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size | +| | entirely, the system uses `64m`. | ### User memory constraints diff --git a/man/docker-build.1.md b/man/docker-build.1.md index 4bf4deea59..01889f76d2 100644 --- a/man/docker-build.1.md +++ b/man/docker-build.1.md @@ -19,6 +19,7 @@ docker-build - Build a new image from the source code at PATH [**-t**|**--tag**[=*[]*]] [**-m**|**--memory**[=*MEMORY*]] [**--memory-swap**[=*MEMORY-SWAP*]] +[**--shm-size**[=*SHM-SIZE*]] [**--cpu-period**[=*0*]] [**--cpu-quota**[=*0*]] [**--cpuset-cpus**[=*CPUSET-CPUS*]] @@ -90,6 +91,11 @@ set as the **URL**, the repository is cloned locally and then sent as the contex **--memory-swap**=*MEMORY-SWAP* Total memory (memory + swap), '-1' to disable swap. +**--shm-size**=*SHM-SIZE* + Size of `/dev/shm`. The format is ``. `number` must be greater than `0`. + Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. + If you omit the size entirely, the system uses `64m`. + **--cpu-shares**=*0* CPU shares (relative weight). diff --git a/man/docker-create.1.md b/man/docker-create.1.md index b919234073..fed6278afe 100644 --- a/man/docker-create.1.md +++ b/man/docker-create.1.md @@ -54,6 +54,7 @@ docker-create - Create a new container [**--restart**[=*RESTART*]] [**--security-opt**[=*[]*]] [**--stop-signal**[=*SIGNAL*]] +[**--shm-size**[=*[]*]] [**-t**|**--tty**[=*false*]] [**-u**|**--user**[=*USER*]] [**--ulimit**[=*[]*]] @@ -252,6 +253,11 @@ This value should always larger than **-m**, so you should always use this with **--restart**="*no*" Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped). +**--shm-size**="" + Size of `/dev/shm`. The format is ``. `number` must be greater than `0`. + Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. + If you omit the size entirely, the system uses `64m`. + **--security-opt**=[] Security Options diff --git a/man/docker-run.1.md b/man/docker-run.1.md index 72475b098a..2be6b1b5c0 100644 --- a/man/docker-run.1.md +++ b/man/docker-run.1.md @@ -56,6 +56,7 @@ docker-run - Run a command in a new container [**--rm**[=*false*]] [**--security-opt**[=*[]*]] [**--stop-signal**[=*SIGNAL*]] +[**--shm-size**[=*[]*]] [**--sig-proxy**[=*true*]] [**-t**|**--tty**[=*false*]] [**-u**|**--user**[=*USER*]] @@ -410,6 +411,11 @@ its root filesystem mounted as read only prohibiting any writes. **--stop-signal**=*SIGTERM* Signal to stop a container. Default is SIGTERM. +**--shm-size**="" + Size of `/dev/shm`. The format is ``. + `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m`(megabytes), or `g` (gigabytes). + If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. + **--sig-proxy**=*true*|*false* Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is *true*. diff --git a/runconfig/hostconfig.go b/runconfig/hostconfig.go index 5552ab6062..f1bd7c7af2 100644 --- a/runconfig/hostconfig.go +++ b/runconfig/hostconfig.go @@ -211,6 +211,7 @@ type HostConfig struct { SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux. Ulimits []*ulimit.Ulimit // List of ulimits to be set in the container UTSMode UTSMode // UTS namespace to use for the container + ShmSize int64 // Total shm memory usage // Applicable to Windows ConsoleSize [2]int // Initial console size diff --git a/runconfig/parse.go b/runconfig/parse.go index 4647916bcb..244df6c8f1 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -105,6 +105,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe flVolumeDriver = cmd.String([]string{"-volume-driver"}, "", "Optional volume driver for the container") flStopSignal = cmd.String([]string{"-stop-signal"}, signal.DefaultStopSignal, fmt.Sprintf("Signal to stop a container, %v by default", signal.DefaultStopSignal)) flIsolation = cmd.String([]string{"-isolation"}, "", "Container isolation level") + flShmSize = cmd.String([]string{"-shm-size"}, "", "Size of /dev/shm, default value is 64MB") ) cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR") @@ -200,6 +201,18 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe return nil, nil, cmd, fmt.Errorf("Invalid value: %d. Valid memory swappiness range is 0-100", swappiness) } + var parsedShm int64 = 67108864 // initial SHM size is 64MB + if *flShmSize != "" { + var err error + parsedShm, err = units.RAMInBytes(*flShmSize) + if err != nil { + return nil, nil, cmd, fmt.Errorf("--shm-size: invalid SHM size") + } + if parsedShm <= 0 { + return nil, nil, cmd, fmt.Errorf("--shm-size: SHM size must be greater than 0 . You specified: %v ", parsedShm) + } + } + var binds []string // add any bind targets to the list of container volumes for bind := range flVolumes.GetMap() { @@ -381,6 +394,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe CgroupParent: *flCgroupParent, VolumeDriver: *flVolumeDriver, Isolation: IsolationLevel(*flIsolation), + ShmSize: parsedShm, } // When allocating stdin in attached mode, close stdin at client disconnect diff --git a/runconfig/parse_test.go b/runconfig/parse_test.go index d2406b094d..7f2a87ae8a 100644 --- a/runconfig/parse_test.go +++ b/runconfig/parse_test.go @@ -524,6 +524,18 @@ func TestParseModes(t *testing.T) { if !hostconfig.UTSMode.Valid() { t.Fatalf("Expected a valid UTSMode, got %v", hostconfig.UTSMode) } + // shm-size ko + if _, _, _, err = parseRun([]string{"--shm-size=a128m", "img", "cmd"}); err == nil || err.Error() != "--shm-size: invalid SHM size" { + t.Fatalf("Expected an error with message '--shm-size: invalid SHM size', got %v", err) + } + // shm-size ok + _, hostconfig, _, err = parseRun([]string{"--shm-size=128m", "img", "cmd"}) + if err != nil { + t.Fatal(err) + } + if hostconfig.ShmSize != 134217728 { + t.Fatalf("Expected a valid ShmSize, got %v", hostconfig.ShmSize) + } } func TestParseRestartPolicy(t *testing.T) {