mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #32251 from AkihiroSuda/run-mount
cli: add `--mount` to `docker run`
This commit is contained in:
commit
945a119c8a
8 changed files with 258 additions and 0 deletions
|
@ -11,6 +11,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
|
@ -31,6 +32,7 @@ type containerOptions struct {
|
|||
attach opts.ListOpts
|
||||
volumes opts.ListOpts
|
||||
tmpfs opts.ListOpts
|
||||
mounts opts.MountOpt
|
||||
blkioWeightDevice opts.WeightdeviceOpt
|
||||
deviceReadBps 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.volumesFrom, "volumes-from", "Mount volumes from the specified container(s)")
|
||||
flags.VarP(&copts.volumes, "volume", "v", "Bind mount a volume")
|
||||
flags.Var(&copts.mounts, "mount", "Attach a filesystem mount to the container")
|
||||
|
||||
// Health-checking
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
volumes := copts.volumes.GetMap()
|
||||
// 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,
|
||||
Sysctls: copts.sysctls.GetAll(),
|
||||
Runtime: copts.runtime,
|
||||
Mounts: mounts,
|
||||
}
|
||||
|
||||
if copts.autoRemove && !hostConfig.RestartPolicy.IsNone() {
|
||||
|
|
|
@ -1518,6 +1518,7 @@ _docker_container_run_and_create() {
|
|||
--memory-swap
|
||||
--memory-swappiness
|
||||
--memory-reservation
|
||||
--mount
|
||||
--name
|
||||
--network
|
||||
--network-alias
|
||||
|
|
|
@ -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' -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 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 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'
|
||||
|
@ -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' -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 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 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'
|
||||
|
|
|
@ -629,6 +629,7 @@ __docker_container_subcommand() {
|
|||
"($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)--mac-address=[Container MAC address]:MAC address: "
|
||||
"($help)*--mount=[Attach a filesystem mount to the container]:mount: "
|
||||
"($help)--name=[Container name]:name: "
|
||||
"($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: "
|
||||
|
|
|
@ -85,6 +85,7 @@ Options:
|
|||
--memory-reservation string Memory soft limit
|
||||
--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)
|
||||
--mount value Attach a filesytem mount to the container (default [])
|
||||
--name string Assign a name to the container
|
||||
--network-alias value Add network-scoped alias for the container (default [])
|
||||
--network string Connect a container to a network (default "default")
|
||||
|
|
|
@ -95,6 +95,7 @@ Options:
|
|||
--memory-reservation string Memory soft limit
|
||||
--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)
|
||||
--mount value Attach a filesystem mount to the container (default [])
|
||||
--name string Assign a name to the container
|
||||
--network-alias value Add network-scoped alias for the container (default [])
|
||||
--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/)
|
||||
|
||||
|
||||
### 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)
|
||||
|
||||
```bash
|
||||
|
|
|
@ -4422,6 +4422,184 @@ func (s *DockerSuite) TestRunMountReadOnlyDevShm(c *check.C) {
|
|||
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
|
||||
// /etc/hostname. Test case for 29100
|
||||
func (s *DockerSuite) TestRunHostnameFQDN(c *check.C) {
|
||||
|
|
|
@ -61,6 +61,7 @@ docker-run - Run a command in a new container
|
|||
[**--memory-reservation**[=*MEMORY-RESERVATION*]]
|
||||
[**--memory-swap**[=*LIMIT*]]
|
||||
[**--memory-swappiness**[=*MEMORY-SWAPPINESS*]]
|
||||
[**--mount**[=*[MOUNT]*]]
|
||||
[**--name**[=*NAME*]]
|
||||
[**--network-alias**[=*[]*]]
|
||||
[**--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
|
||||
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**=""
|
||||
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:
|
||||
`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**=""
|
||||
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
|
||||
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**=""
|
||||
Container's volume driver. This driver creates volumes specified either from
|
||||
a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag.
|
||||
|
|
Loading…
Reference in a new issue