opts/mount: add tmpfs-specific options

added following options:

 * tmpfs-size
 * tmpfs-mode

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
This commit is contained in:
Akihiro Suda 2016-11-08 05:32:21 +00:00
parent 383a2f046b
commit 45ed6a7579
4 changed files with 75 additions and 8 deletions

View File

@ -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

View File

@ -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> | **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></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`

View File

@ -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 { if mount.VolumeOptions != nil && mount.Type != mounttypes.TypeVolume {
return fmt.Errorf("cannot mix 'volume-*' options with mount type '%s'", mounttypes.TypeBind) return fmt.Errorf("cannot mix 'volume-*' options with mount type '%s'", mount.Type)
} }
if mount.Type == mounttypes.TypeVolume && mount.BindOptions != nil { if mount.BindOptions != nil && mount.Type != mounttypes.TypeBind {
return fmt.Errorf("cannot mix 'bind-*' options with mount type '%s'", mounttypes.TypeVolume) 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) m.values = append(m.values, mount)

View File

@ -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")
}