From 45ed6a75795918d466054e63c462a1a8b553c8c0 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 8 Nov 2016 05:32:21 +0000 Subject: [PATCH] opts/mount: add tmpfs-specific options added following options: * tmpfs-size * tmpfs-mode Signed-off-by: Akihiro Suda --- docs/reference/commandline/run.md | 4 +-- docs/reference/commandline/service_create.md | 16 ++++++++-- opts/mount.go | 32 +++++++++++++++++--- opts/mount_test.go | 31 +++++++++++++++++++ 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/docs/reference/commandline/run.md b/docs/reference/commandline/run.md index fc4a9e5a3a..eb0eba9fa6 100644 --- a/docs/reference/commandline/run.md +++ b/docs/reference/commandline/run.md @@ -264,9 +264,9 @@ Docker daemon. For in-depth information about volumes, refer to [manage data in containers](https://docs.docker.com/engine/tutorials/dockervolumes/) -### Add bin-mounts or volumes using the --mounts flag +### Add bin-mounts or volumes using the --mount flag -The `--mounts` flag allows you to mount volumes, host-directories and `tmpfs` +The `--mount` flag allows you to mount volumes, host-directories and `tmpfs` mounts in a container. The `--mount` flag supports most options that are supported by the `-v` or the diff --git a/docs/reference/commandline/service_create.md b/docs/reference/commandline/service_create.md index 4d95ce96a2..3c16c20209 100644 --- a/docs/reference/commandline/service_create.md +++ b/docs/reference/commandline/service_create.md @@ -172,6 +172,8 @@ or write from files or directories on other containers or the host operating system. These types are _data volumes_ (often referred to simply as volumes) and _bind-mounts_. +Additionally, Docker also supports tmpfs mounts. + A **bind-mount** makes a file or directory on the host available to the container it is mounted within. A bind-mount may be either read-only or read-write. For example, a container might share its host's DNS information by @@ -188,6 +190,8 @@ shared between a container and the host machine, as well as between multiple containers. Docker uses a _volume driver_ to create, manage, and mount volumes. You can back up or restore volumes using Docker commands. +A **tmpfs** mounts a tmpfs inside a container for volatile data. + Consider a situation where your image starts a lightweight web server. You could use that image as a base image, copy in your website's HTML files, and package that into another image. Each time your website changed, you'd need to update @@ -204,8 +208,8 @@ volumes in a service: | Option | Required | Description |:-----------------------------------------|:--------------------------|:----------------------------------------------------------------------------------------- -| **type** | | The type of mount, can be either `volume`, or `bind`. Defaults to `volume` if no type is specified. -| **src** or **source** | for `type=bind` only | +| **type** | | The type of mount, can be either `volume`, `bind`, or `tmpfs`. Defaults to `volume` if no type is specified. +| **src** or **source** | for `type=bind` only | | **dst** or **destination** or **target** | yes | Mount path inside the container, for example `/some/path/in/container/`. If the path does not exist in the container's filesystem, the Engine creates a directory at the specified location before mounting the volume or bind-mount. | **readonly** or **ro** | | The Engine mounts binds and volumes `read-write` unless `readonly` option is given when mounting the bind or volume.

@@ -256,6 +260,14 @@ The following options can only be used for named volumes (`type=volume`); | **volume-nocopy** | By default, if you attach an empty volume to a container, and files or directories already existed at the mount-path in the container (`dst`), the Engine copies those files and directories into the volume, allowing the host to access them. Set `volume-nocopy` to disables copying files from the container's filesystem to the volume and mount the empty volume.

A value is optional: | **volume-opt** | Options specific to a given volume driver, which will be passed to the driver when creating the volume. Options are provided as a comma-separated list of key/value pairs, for example, `volume-opt=some-option=some-value,some-other-option=some-other-value`. For available options for a given driver, refer to that driver's documentation. +#### Options for tmpfs +The following options can only be used for tmpfs mounts (`type=tmpfs`); + +| Option | Description +|:----------------------|:-------------------------------------------------------------------------------------------------------------------- +| **tmpfs-size** | Size of the tmpfs mount in bytes. Unlimited by default in Linux. +| **tmpfs-mode** | File mode of the tmpfs in octal. (e.g. `"700"` or `"0700"`.) Defaults to ``"1777"`` in Linux. + #### Differences between "--mount" and "--volume" The `--mount` flag supports most options that are supported by the `-v` diff --git a/opts/mount.go b/opts/mount.go index b6fccade18..ce6383ddca 100644 --- a/opts/mount.go +++ b/opts/mount.go @@ -3,10 +3,12 @@ package opts import ( "encoding/csv" "fmt" + "os" "strconv" "strings" mounttypes "github.com/docker/docker/api/types/mount" + "github.com/docker/go-units" ) // MountOpt is a Value type for parsing mounts @@ -43,6 +45,13 @@ func (m *MountOpt) Set(value string) error { return mount.BindOptions } + tmpfsOptions := func() *mounttypes.TmpfsOptions { + if mount.TmpfsOptions == nil { + mount.TmpfsOptions = new(mounttypes.TmpfsOptions) + } + return mount.TmpfsOptions + } + setValueOnMap := func(target map[string]string, value string) { parts := strings.SplitN(value, "=", 2) if len(parts) == 1 { @@ -102,6 +111,18 @@ func (m *MountOpt) Set(value string) error { volumeOptions().DriverConfig.Options = make(map[string]string) } setValueOnMap(volumeOptions().DriverConfig.Options, value) + case "tmpfs-size": + sizeBytes, err := units.RAMInBytes(value) + if err != nil { + return fmt.Errorf("invalid value for %s: %s", key, value) + } + tmpfsOptions().SizeBytes = sizeBytes + case "tmpfs-mode": + ui64, err := strconv.ParseUint(value, 8, 32) + if err != nil { + return fmt.Errorf("invalid value for %s: %s", key, value) + } + tmpfsOptions().Mode = os.FileMode(ui64) default: return fmt.Errorf("unexpected key '%s' in '%s'", key, field) } @@ -115,11 +136,14 @@ func (m *MountOpt) Set(value string) error { return fmt.Errorf("target is required") } - if mount.Type == mounttypes.TypeBind && mount.VolumeOptions != nil { - return fmt.Errorf("cannot mix 'volume-*' options with mount type '%s'", mounttypes.TypeBind) + if mount.VolumeOptions != nil && mount.Type != mounttypes.TypeVolume { + return fmt.Errorf("cannot mix 'volume-*' options with mount type '%s'", mount.Type) } - if mount.Type == mounttypes.TypeVolume && mount.BindOptions != nil { - return fmt.Errorf("cannot mix 'bind-*' options with mount type '%s'", mounttypes.TypeVolume) + if mount.BindOptions != nil && mount.Type != mounttypes.TypeBind { + return fmt.Errorf("cannot mix 'bind-*' options with mount type '%s'", mount.Type) + } + if mount.TmpfsOptions != nil && mount.Type != mounttypes.TypeTmpfs { + return fmt.Errorf("cannot mix 'tmpfs-*' options with mount type '%s'", mount.Type) } m.values = append(m.values, mount) diff --git a/opts/mount_test.go b/opts/mount_test.go index 28c551bcc6..59606c38e2 100644 --- a/opts/mount_test.go +++ b/opts/mount_test.go @@ -1,6 +1,7 @@ package opts import ( + "os" "testing" mounttypes "github.com/docker/docker/api/types/mount" @@ -151,3 +152,33 @@ func TestMountOptTypeConflict(t *testing.T) { assert.Error(t, m.Set("type=bind,target=/foo,source=/foo,volume-nocopy=true"), "cannot mix") assert.Error(t, m.Set("type=volume,target=/foo,source=/foo,bind-propagation=rprivate"), "cannot mix") } + +func TestMountOptSetTmpfsNoError(t *testing.T) { + for _, testcase := range []string{ + // tests several aliases that should have same result. + "type=tmpfs,target=/target,tmpfs-size=1m,tmpfs-mode=0700", + "type=tmpfs,target=/target,tmpfs-size=1MB,tmpfs-mode=700", + } { + var mount MountOpt + + assert.NilError(t, mount.Set(testcase)) + + mounts := mount.Value() + assert.Equal(t, len(mounts), 1) + assert.DeepEqual(t, mounts[0], mounttypes.Mount{ + Type: mounttypes.TypeTmpfs, + Target: "/target", + TmpfsOptions: &mounttypes.TmpfsOptions{ + SizeBytes: 1024 * 1024, // not 1000 * 1000 + Mode: os.FileMode(0700), + }, + }) + } +} + +func TestMountOptSetTmpfsError(t *testing.T) { + var m MountOpt + assert.Error(t, m.Set("type=tmpfs,target=/foo,tmpfs-size=foo"), "invalid value for tmpfs-size") + assert.Error(t, m.Set("type=tmpfs,target=/foo,tmpfs-mode=foo"), "invalid value for tmpfs-mode") + assert.Error(t, m.Set("type=tmpfs"), "target is required") +}