Merge pull request #32251 from AkihiroSuda/run-mount

cli: add `--mount` to `docker run`
This commit is contained in:
Vincent Demeester 2017-04-05 22:34:47 +02:00 committed by GitHub
commit 945a119c8a
8 changed files with 258 additions and 0 deletions

View File

@ -11,6 +11,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
networktypes "github.com/docker/docker/api/types/network" networktypes "github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/strslice" "github.com/docker/docker/api/types/strslice"
@ -31,6 +32,7 @@ type containerOptions struct {
attach opts.ListOpts attach opts.ListOpts
volumes opts.ListOpts volumes opts.ListOpts
tmpfs opts.ListOpts tmpfs opts.ListOpts
mounts opts.MountOpt
blkioWeightDevice opts.WeightdeviceOpt blkioWeightDevice opts.WeightdeviceOpt
deviceReadBps opts.ThrottledeviceOpt deviceReadBps opts.ThrottledeviceOpt
deviceWriteBps opts.ThrottledeviceOpt deviceWriteBps opts.ThrottledeviceOpt
@ -223,6 +225,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
flags.Var(&copts.tmpfs, "tmpfs", "Mount a tmpfs directory") flags.Var(&copts.tmpfs, "tmpfs", "Mount a tmpfs directory")
flags.Var(&copts.volumesFrom, "volumes-from", "Mount volumes from the specified container(s)") flags.Var(&copts.volumesFrom, "volumes-from", "Mount volumes from the specified container(s)")
flags.VarP(&copts.volumes, "volume", "v", "Bind mount a volume") flags.VarP(&copts.volumes, "volume", "v", "Bind mount a volume")
flags.Var(&copts.mounts, "mount", "Attach a filesystem mount to the container")
// Health-checking // Health-checking
flags.StringVar(&copts.healthCmd, "health-cmd", "", "Command to run to check health") flags.StringVar(&copts.healthCmd, "health-cmd", "", "Command to run to check health")
@ -321,6 +324,10 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
return nil, errors.Errorf("invalid value: %d. Valid memory swappiness range is 0-100", swappiness) return nil, errors.Errorf("invalid value: %d. Valid memory swappiness range is 0-100", swappiness)
} }
mounts := copts.mounts.Value()
if len(mounts) > 0 && copts.volumeDriver != "" {
logrus.Warn("`--volume-driver` is ignored for volumes specified via `--mount`. Use `--mount type=volume,volume-driver=...` instead.")
}
var binds []string var binds []string
volumes := copts.volumes.GetMap() volumes := copts.volumes.GetMap()
// add any bind targets to the list of container volumes // add any bind targets to the list of container volumes
@ -589,6 +596,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
Tmpfs: tmpfs, Tmpfs: tmpfs,
Sysctls: copts.sysctls.GetAll(), Sysctls: copts.sysctls.GetAll(),
Runtime: copts.runtime, Runtime: copts.runtime,
Mounts: mounts,
} }
if copts.autoRemove && !hostConfig.RestartPolicy.IsNone() { if copts.autoRemove && !hostConfig.RestartPolicy.IsNone() {

View File

@ -1518,6 +1518,7 @@ _docker_container_run_and_create() {
--memory-swap --memory-swap
--memory-swappiness --memory-swappiness
--memory-reservation --memory-reservation
--mount
--name --name
--network --network
--network-alias --network-alias

View File

@ -138,6 +138,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)' complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mac-address -d 'Container MAC address (e.g., 92:d0:c6:0a:29:33)' complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mac-address -d 'Container MAC address (e.g., 92:d0:c6:0a:29:33)'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)" complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mount -d 'Attach a filesystem mount to the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l name -d 'Assign a name to the container' complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l name -d 'Assign a name to the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l net -d 'Set the Network mode for the container' complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l net -d 'Set the Network mode for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces' complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces'
@ -330,6 +331,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l link -d 'Add li
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s m -l memory -d 'Memory limit (format: <number>[<unit>], where unit = b, k, m or g)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mac-address -d 'Container MAC address (e.g., 92:d0:c6:0a:29:33)' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mac-address -d 'Container MAC address (e.g., 92:d0:c6:0a:29:33)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)" complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l memory-swap -d "Total memory usage (memory + swap), set '-1' to disable swap (format: <number>[<unit>], where unit = b, k, m or g)"
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mount -d 'Attach a filesystem mount to the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l name -d 'Assign a name to the container' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l name -d 'Assign a name to the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l net -d 'Set the Network mode for the container' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l net -d 'Set the Network mode for the container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s P -l publish-all -d 'Publish all exposed ports to random ports on the host interfaces'

View File

@ -629,6 +629,7 @@ __docker_container_subcommand() {
"($help)--log-driver=[Default driver for container logs]:logging driver:__docker_complete_log_drivers" "($help)--log-driver=[Default driver for container logs]:logging driver:__docker_complete_log_drivers"
"($help)*--log-opt=[Log driver specific options]:log driver options:__docker_complete_log_options" "($help)*--log-opt=[Log driver specific options]:log driver options:__docker_complete_log_options"
"($help)--mac-address=[Container MAC address]:MAC address: " "($help)--mac-address=[Container MAC address]:MAC address: "
"($help)*--mount=[Attach a filesystem mount to the container]:mount: "
"($help)--name=[Container name]:name: " "($help)--name=[Container name]:name: "
"($help)--network=[Connect a container to a network]:network mode:(bridge none container host)" "($help)--network=[Connect a container to a network]:network mode:(bridge none container host)"
"($help)*--network-alias=[Add network-scoped alias for the container]:alias: " "($help)*--network-alias=[Add network-scoped alias for the container]:alias: "

View File

@ -85,6 +85,7 @@ Options:
--memory-reservation string Memory soft limit --memory-reservation string Memory soft limit
--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap --memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap
--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1) --memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)
--mount value Attach a filesytem mount to the container (default [])
--name string Assign a name to the container --name string Assign a name to the container
--network-alias value Add network-scoped alias for the container (default []) --network-alias value Add network-scoped alias for the container (default [])
--network string Connect a container to a network (default "default") --network string Connect a container to a network (default "default")

View File

@ -95,6 +95,7 @@ Options:
--memory-reservation string Memory soft limit --memory-reservation string Memory soft limit
--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap --memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap
--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1) --memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)
--mount value Attach a filesystem mount to the container (default [])
--name string Assign a name to the container --name string Assign a name to the container
--network-alias value Add network-scoped alias for the container (default []) --network-alias value Add network-scoped alias for the container (default [])
--network string Connect a container to a network --network string Connect a container to a network
@ -316,6 +317,29 @@ docker run -v c:\foo:c:\existing-directory-with-contents ...
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 bind-mounts or volumes using the --mount flag
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
`--volume` flag, but uses a different syntax. For in-depth information on the
`--mount` flag, and a comparison between `--volume` and `--mount`, refer to
the [service create command reference](service_create.md#add-bind-mounts-or-volumes).
Even though there is no plan to deprecate `--volume`, usage of `--mount` is recommended.
Examples:
```bash
$ docker run --read-only --mount type=volume,target=/icanwrite busybox touch /icanwrite/here
```
```bash
$ docker run -t -i --mount type=bind,src=/data,dst=/data busybox sh
```
### Publish or expose port (-p, --expose) ### Publish or expose port (-p, --expose)
```bash ```bash

View File

@ -4422,6 +4422,184 @@ func (s *DockerSuite) TestRunMountReadOnlyDevShm(c *check.C) {
c.Assert(out, checker.Contains, "Read-only file system") c.Assert(out, checker.Contains, "Read-only file system")
} }
func (s *DockerSuite) TestRunMount(c *check.C) {
testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace)
// mnt1, mnt2, and testCatFooBar are commonly used in multiple test cases
tmpDir, err := ioutil.TempDir("", "mount")
if err != nil {
c.Fatal(err)
}
defer os.RemoveAll(tmpDir)
mnt1, mnt2 := path.Join(tmpDir, "mnt1"), path.Join(tmpDir, "mnt2")
if err := os.Mkdir(mnt1, 0755); err != nil {
c.Fatal(err)
}
if err := os.Mkdir(mnt2, 0755); err != nil {
c.Fatal(err)
}
if err := ioutil.WriteFile(path.Join(mnt1, "test1"), []byte("test1"), 0644); err != nil {
c.Fatal(err)
}
if err := ioutil.WriteFile(path.Join(mnt2, "test2"), []byte("test2"), 0644); err != nil {
c.Fatal(err)
}
testCatFooBar := func(cName string) error {
out, _ := dockerCmd(c, "exec", cName, "cat", "/foo/test1")
if out != "test1" {
return fmt.Errorf("%s not mounted on /foo", mnt1)
}
out, _ = dockerCmd(c, "exec", cName, "cat", "/bar/test2")
if out != "test2" {
return fmt.Errorf("%s not mounted on /bar", mnt2)
}
return nil
}
type testCase struct {
equivalents [][]string
valid bool
// fn should be nil if valid==false
fn func(cName string) error
}
cases := []testCase{
{
equivalents: [][]string{
{
"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
"--mount", fmt.Sprintf("type=bind,src=%s,dst=/bar", mnt2),
},
{
"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
"--mount", fmt.Sprintf("type=bind,src=%s,target=/bar", mnt2),
},
{
"--volume", mnt1 + ":/foo",
"--mount", fmt.Sprintf("type=bind,src=%s,target=/bar", mnt2),
},
},
valid: true,
fn: testCatFooBar,
},
{
equivalents: [][]string{
{
"--mount", fmt.Sprintf("type=volume,src=%s,dst=/foo", mnt1),
"--mount", fmt.Sprintf("type=volume,src=%s,dst=/bar", mnt2),
},
{
"--mount", fmt.Sprintf("type=volume,src=%s,dst=/foo", mnt1),
"--mount", fmt.Sprintf("type=volume,src=%s,target=/bar", mnt2),
},
},
valid: false,
},
{
equivalents: [][]string{
{
"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
"--mount", fmt.Sprintf("type=volume,src=%s,dst=/bar", mnt2),
},
{
"--volume", mnt1 + ":/foo",
"--mount", fmt.Sprintf("type=volume,src=%s,target=/bar", mnt2),
},
},
valid: false,
fn: testCatFooBar,
},
{
equivalents: [][]string{
{
"--read-only",
"--mount", "type=volume,dst=/bar",
},
},
valid: true,
fn: func(cName string) error {
_, _, err := dockerCmdWithError("exec", cName, "touch", "/bar/icanwritehere")
return err
},
},
{
equivalents: [][]string{
{
"--read-only",
"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
"--mount", "type=volume,dst=/bar",
},
{
"--read-only",
"--volume", fmt.Sprintf("%s:/foo", mnt1),
"--mount", "type=volume,dst=/bar",
},
},
valid: true,
fn: func(cName string) error {
out, _ := dockerCmd(c, "exec", cName, "cat", "/foo/test1")
if out != "test1" {
return fmt.Errorf("%s not mounted on /foo", mnt1)
}
_, _, err := dockerCmdWithError("exec", cName, "touch", "/bar/icanwritehere")
return err
},
},
{
equivalents: [][]string{
{
"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt2),
},
{
"--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1),
"--mount", fmt.Sprintf("type=bind,src=%s,target=/foo", mnt2),
},
{
"--volume", fmt.Sprintf("%s:/foo", mnt1),
"--mount", fmt.Sprintf("type=bind,src=%s,target=/foo", mnt2),
},
},
valid: false,
},
{
equivalents: [][]string{
{
"--volume", fmt.Sprintf("%s:/foo", mnt1),
"--mount", fmt.Sprintf("type=volume,src=%s,target=/foo", mnt2),
},
},
valid: false,
},
{
equivalents: [][]string{
{
"--mount", "type=volume,target=/foo",
"--mount", "type=volume,target=/foo",
},
},
valid: false,
},
}
for i, testCase := range cases {
for j, opts := range testCase.equivalents {
cName := fmt.Sprintf("mount-%d-%d", i, j)
_, _, err := dockerCmdWithError(append([]string{"run", "-i", "-d", "--name", cName},
append(opts, []string{"busybox", "top"}...)...)...)
if testCase.valid {
c.Assert(err, check.IsNil,
check.Commentf("got error while creating a container with %v (%s)", opts, cName))
c.Assert(testCase.fn(cName), check.IsNil,
check.Commentf("got error while executing test for %v (%s)", opts, cName))
dockerCmd(c, "rm", "-f", cName)
} else {
c.Assert(err, checker.NotNil,
check.Commentf("got nil while creating a container with %v (%s)", opts, cName))
}
}
}
}
// Test that passing a FQDN as hostname properly sets hostname, and // Test that passing a FQDN as hostname properly sets hostname, and
// /etc/hostname. Test case for 29100 // /etc/hostname. Test case for 29100
func (s *DockerSuite) TestRunHostnameFQDN(c *check.C) { func (s *DockerSuite) TestRunHostnameFQDN(c *check.C) {

View File

@ -61,6 +61,7 @@ docker-run - Run a command in a new container
[**--memory-reservation**[=*MEMORY-RESERVATION*]] [**--memory-reservation**[=*MEMORY-RESERVATION*]]
[**--memory-swap**[=*LIMIT*]] [**--memory-swap**[=*LIMIT*]]
[**--memory-swappiness**[=*MEMORY-SWAPPINESS*]] [**--memory-swappiness**[=*MEMORY-SWAPPINESS*]]
[**--mount**[=*[MOUNT]*]]
[**--name**[=*NAME*]] [**--name**[=*NAME*]]
[**--network-alias**[=*[]*]] [**--network-alias**[=*[]*]]
[**--network**[=*"bridge"*]] [**--network**[=*"bridge"*]]
@ -425,6 +426,42 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap.
The IPv6 link-local address will be based on the device's MAC address The IPv6 link-local address will be based on the device's MAC address
according to RFC4862. according to RFC4862.
**--mount**=[*[type=TYPE[,TYPE-SPECIFIC-OPTIONS]]*]
Attach a filesystem mount to the container
Current supported mount `TYPES` are `bind`, `volume`, and `tmpfs`.
e.g.
`type=bind,source=/path/on/host,destination=/path/in/container`
`type=volume,source=my-volume,destination=/path/in/container,volume-label="color=red",volume-label="shape=round"`
`type=tmpfs,tmpfs-size=512M,destination=/path/in/container`
Common Options:
* `src`, `source`: mount source spec for `bind` and `volume`. Mandatory for `bind`.
* `dst`, `destination`, `target`: mount destination spec.
* `ro`, `read-only`: `true` or `false` (default).
Options specific to `bind`:
* `bind-propagation`: `shared`, `slave`, `private`, `rshared`, `rslave`, or `rprivate`(default). See also `mount(2)`.
* `consistency`: `consistent`(default), `cached`, or `delegated`. Currently, only effective for Docker for Mac.
Options specific to `volume`:
* `volume-driver`: Name of the volume-driver plugin.
* `volume-label`: Custom metadata.
* `volume-nocopy`: `true`(default) or `false`. If set to `false`, the Engine copies existing files and directories under the mount-path into the volume, allowing the host to access them.
* `volume-opt`: specific to a given volume driver.
Options specific to `tmpfs`:
* `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.
**--name**="" **--name**=""
Assign a name to the container Assign a name to the container
@ -604,6 +641,9 @@ options are the same as the Linux default `mount` flags. If you do not specify
any options, the systems uses the following options: any options, the systems uses the following options:
`rw,noexec,nosuid,nodev,size=65536k`. `rw,noexec,nosuid,nodev,size=65536k`.
See also `--mount`, which is the successor of `--tmpfs` and `--volume`.
Even though there is no plan to deprecate `--tmpfs`, usage of `--mount` is recommended.
**-u**, **--user**="" **-u**, **--user**=""
Sets the username or UID used and optionally the groupname or GID for the specified command. Sets the username or UID used and optionally the groupname or GID for the specified command.
@ -704,6 +744,9 @@ change propagation properties of source mount. Say `/` is source mount for
To disable automatic copying of data from the container path to the volume, use To disable automatic copying of data from the container path to the volume, use
the `nocopy` flag. The `nocopy` flag can be set on bind mounts and named volumes. the `nocopy` flag. The `nocopy` flag can be set on bind mounts and named volumes.
See also `--mount`, which is the successor of `--tmpfs` and `--volume`.
Even though there is no plan to deprecate `--volume`, usage of `--mount` is recommended.
**--volume-driver**="" **--volume-driver**=""
Container's volume driver. This driver creates volumes specified either from Container's volume driver. This driver creates volumes specified either from
a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag. a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag.