Selaa lähdekoodia

opts/mount: add tmpfs-specific options

added following options:

 * tmpfs-size
 * tmpfs-mode

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
Akihiro Suda 8 vuotta sitten
vanhempi
commit
45ed6a7579

+ 2 - 2
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/)
 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.
 mounts in a container.
 
 
 The `--mount` flag supports most options that are supported by the `-v` or the
 The `--mount` flag supports most options that are supported by the `-v` or the

+ 14 - 2
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
 system. These types are _data volumes_ (often referred to simply as volumes) and
 _bind-mounts_.
 _bind-mounts_.
 
 
+Additionally, Docker also supports tmpfs mounts.
+
 A **bind-mount** makes a file or directory on the host available to the
 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
 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
 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.
 containers. Docker uses a _volume driver_ to create, manage, and mount volumes.
 You can back up or restore volumes using Docker commands.
 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
 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
 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
 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
 | Option                                   | Required                  | Description
 |:-----------------------------------------|:--------------------------|:-----------------------------------------------------------------------------------------
 |:-----------------------------------------|:--------------------------|:-----------------------------------------------------------------------------------------
-| **type**                                 |                           | The type of mount, can be either `volume`, or `bind`. Defaults to `volume` if no type is specified.<ul><li>`volume`: mounts a [managed volume](volume_create.md) into the container.</li><li>`bind`: bind-mounts a directory or file from the host into the container.</li></ul>
-| **src** or **source**                    | for `type=bind`&nbsp;only | <ul><li>`type=volume`: `src` is an optional way to specify the name of the volume (for example, `src=my-volume`). If the named volume does not exist, it is automatically created. If no `src` is specified, the volume is assigned a random name which is guaranteed to be unique on the host, but may not be unique cluster-wide. A randomly-named volume has the same lifecycle as its container and is destroyed when the *container* is destroyed (which is upon `service update`, or when scaling or re-balancing the service).</li><li>`type=bind`: `src` is required, and specifies an absolute path to the file or directory to bind-mount (for example, `src=/path/on/host/`).  An error is produced if the file or directory does not exist.</li></ul>
+| **type**                                 |                           | The type of mount, can be either `volume`, `bind`, or `tmpfs`. Defaults to `volume` if no type is specified.<ul><li>`volume`: mounts a [managed volume](volume_create.md) into the container.</li><li>`bind`: bind-mounts a directory or file from the host into the container.</li><li>`tmpfs`: mount a tmpfs in the container</li></ul>
+| **src** or **source**                    | for `type=bind`&nbsp;only | <ul><li>`type=volume`: `src` is an optional way to specify the name of the volume (for example, `src=my-volume`). If the named volume does not exist, it is automatically created. If no `src` is specified, the volume is assigned a random name which is guaranteed to be unique on the host, but may not be unique cluster-wide. A randomly-named volume has the same lifecycle as its container and is destroyed when the *container* is destroyed (which is upon `service update`, or when scaling or re-balancing the service).</li><li>`type=bind`: `src` is required, and specifies an absolute path to the file or directory to bind-mount (for example, `src=/path/on/host/`).  An error is produced if the file or directory does not exist.</li><li>`type=tmpfs`: `src` is not supported.</li></ul>
 | **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.
 | **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.<br /><br /><ul><li>`true` or `1` or no value: Mounts the bind or volume read-only.</li><li>`false` or `0`: Mounts the bind or volume read-write.</li></ul>
 | **readonly** or **ro**                   |                           | The Engine mounts binds and volumes `read-write` unless `readonly` option is given when mounting the bind or volume.<br /><br /><ul><li>`true` or `1` or no value: Mounts the bind or volume read-only.</li><li>`false` or `0`: Mounts the bind or volume read-write.</li></ul>
 
 
@@ -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.<br /><br />A value is optional:<ul><li>`true` or `1`: Default if you do not provide a value. Disables copying.</li><li>`false` or `0`: Enables copying.</li></ul>
 | **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.<br /><br />A value is optional:<ul><li>`true` or `1`: Default if you do not provide a value. Disables copying.</li><li>`false` or `0`: Enables copying.</li></ul>
 | **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.
 | **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"
 #### Differences between "--mount" and "--volume"
 
 
 The `--mount` flag supports most options that are supported by the `-v`
 The `--mount` flag supports most options that are supported by the `-v`

+ 28 - 4
opts/mount.go

@@ -3,10 +3,12 @@ package opts
 import (
 import (
 	"encoding/csv"
 	"encoding/csv"
 	"fmt"
 	"fmt"
+	"os"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 
 
 	mounttypes "github.com/docker/docker/api/types/mount"
 	mounttypes "github.com/docker/docker/api/types/mount"
+	"github.com/docker/go-units"
 )
 )
 
 
 // MountOpt is a Value type for parsing mounts
 // MountOpt is a Value type for parsing mounts
@@ -43,6 +45,13 @@ func (m *MountOpt) Set(value string) error {
 		return mount.BindOptions
 		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) {
 	setValueOnMap := func(target map[string]string, value string) {
 		parts := strings.SplitN(value, "=", 2)
 		parts := strings.SplitN(value, "=", 2)
 		if len(parts) == 1 {
 		if len(parts) == 1 {
@@ -102,6 +111,18 @@ func (m *MountOpt) Set(value string) error {
 				volumeOptions().DriverConfig.Options = make(map[string]string)
 				volumeOptions().DriverConfig.Options = make(map[string]string)
 			}
 			}
 			setValueOnMap(volumeOptions().DriverConfig.Options, value)
 			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:
 		default:
 			return fmt.Errorf("unexpected key '%s' in '%s'", key, field)
 			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")
 		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.BindOptions != nil && mount.Type != mounttypes.TypeBind {
+		return fmt.Errorf("cannot mix 'bind-*' 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.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)
 	m.values = append(m.values, mount)

+ 31 - 0
opts/mount_test.go

@@ -1,6 +1,7 @@
 package opts
 package opts
 
 
 import (
 import (
+	"os"
 	"testing"
 	"testing"
 
 
 	mounttypes "github.com/docker/docker/api/types/mount"
 	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=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")
 	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")
+}