Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
Akihiro Suda authored on 2017/03/31 15:41:45... | ... |
@@ -11,6 +11,7 @@ import ( |
11 | 11 |
"strings" |
12 | 12 |
"time" |
13 | 13 |
|
14 |
+ "github.com/Sirupsen/logrus" |
|
14 | 15 |
"github.com/docker/docker/api/types/container" |
15 | 16 |
networktypes "github.com/docker/docker/api/types/network" |
16 | 17 |
"github.com/docker/docker/api/types/strslice" |
... | ... |
@@ -31,6 +32,7 @@ type containerOptions struct { |
31 | 31 |
attach opts.ListOpts |
32 | 32 |
volumes opts.ListOpts |
33 | 33 |
tmpfs opts.ListOpts |
34 |
+ mounts opts.MountOpt |
|
34 | 35 |
blkioWeightDevice opts.WeightdeviceOpt |
35 | 36 |
deviceReadBps opts.ThrottledeviceOpt |
36 | 37 |
deviceWriteBps opts.ThrottledeviceOpt |
... | ... |
@@ -223,6 +225,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions { |
223 | 223 |
flags.Var(&copts.tmpfs, "tmpfs", "Mount a tmpfs directory") |
224 | 224 |
flags.Var(&copts.volumesFrom, "volumes-from", "Mount volumes from the specified container(s)") |
225 | 225 |
flags.VarP(&copts.volumes, "volume", "v", "Bind mount a volume") |
226 |
+ flags.Var(&copts.mounts, "mount", "Attach a filesystem mount to the container") |
|
226 | 227 |
|
227 | 228 |
// Health-checking |
228 | 229 |
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 |
321 | 321 |
return nil, errors.Errorf("invalid value: %d. Valid memory swappiness range is 0-100", swappiness) |
322 | 322 |
} |
323 | 323 |
|
324 |
+ mounts := copts.mounts.Value() |
|
325 |
+ if len(mounts) > 0 && copts.volumeDriver != "" { |
|
326 |
+ logrus.Warn("`--volume-driver` is ignored for volumes specified via `--mount`. Use `--mount type=volume,volume-driver=...` instead.") |
|
327 |
+ } |
|
324 | 328 |
var binds []string |
325 | 329 |
volumes := copts.volumes.GetMap() |
326 | 330 |
// add any bind targets to the list of container volumes |
... | ... |
@@ -589,6 +596,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err |
589 | 589 |
Tmpfs: tmpfs, |
590 | 590 |
Sysctls: copts.sysctls.GetAll(), |
591 | 591 |
Runtime: copts.runtime, |
592 |
+ Mounts: mounts, |
|
592 | 593 |
} |
593 | 594 |
|
594 | 595 |
if copts.autoRemove && !hostConfig.RestartPolicy.IsNone() { |
... | ... |
@@ -138,6 +138,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l link -d 'Add |
138 | 138 |
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)' |
139 | 139 |
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)' |
140 | 140 |
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)" |
141 |
+complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l mount -d 'Attach a filesystem mount to the container' |
|
141 | 142 |
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l name -d 'Assign a name to the container' |
142 | 143 |
complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l net -d 'Set the Network mode for the container' |
143 | 144 |
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 |
330 | 330 |
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)' |
331 | 331 |
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)' |
332 | 332 |
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)" |
333 |
+complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l mount -d 'Attach a filesystem mount to the container' |
|
333 | 334 |
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l name -d 'Assign a name to the container' |
334 | 335 |
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l net -d 'Set the Network mode for the container' |
335 | 336 |
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() { |
629 | 629 |
"($help)--log-driver=[Default driver for container logs]:logging driver:__docker_complete_log_drivers" |
630 | 630 |
"($help)*--log-opt=[Log driver specific options]:log driver options:__docker_complete_log_options" |
631 | 631 |
"($help)--mac-address=[Container MAC address]:MAC address: " |
632 |
+ "($help)*--mount=[Attach a filesystem mount to the container]:mount: " |
|
632 | 633 |
"($help)--name=[Container name]:name: " |
633 | 634 |
"($help)--network=[Connect a container to a network]:network mode:(bridge none container host)" |
634 | 635 |
"($help)*--network-alias=[Add network-scoped alias for the container]:alias: " |
... | ... |
@@ -85,6 +85,7 @@ Options: |
85 | 85 |
--memory-reservation string Memory soft limit |
86 | 86 |
--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap |
87 | 87 |
--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1) |
88 |
+ --mount value Attach a filesytem mount to the container (default []) |
|
88 | 89 |
--name string Assign a name to the container |
89 | 90 |
--network-alias value Add network-scoped alias for the container (default []) |
90 | 91 |
--network string Connect a container to a network (default "default") |
... | ... |
@@ -95,6 +95,7 @@ Options: |
95 | 95 |
--memory-reservation string Memory soft limit |
96 | 96 |
--memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap |
97 | 97 |
--memory-swappiness int Tune container memory swappiness (0 to 100) (default -1) |
98 |
+ --mount value Attach a filesystem mount to the container (default []) |
|
98 | 99 |
--name string Assign a name to the container |
99 | 100 |
--network-alias value Add network-scoped alias for the container (default []) |
100 | 101 |
--network string Connect a container to a network |
... | ... |
@@ -316,6 +317,29 @@ docker run -v c:\foo:c:\existing-directory-with-contents ... |
316 | 316 |
|
317 | 317 |
For in-depth information about volumes, refer to [manage data in containers](https://docs.docker.com/engine/tutorials/dockervolumes/) |
318 | 318 |
|
319 |
+ |
|
320 |
+### Add bind-mounts or volumes using the --mount flag |
|
321 |
+ |
|
322 |
+The `--mount` flag allows you to mount volumes, host-directories and `tmpfs` |
|
323 |
+mounts in a container. |
|
324 |
+ |
|
325 |
+The `--mount` flag supports most options that are supported by the `-v` or the |
|
326 |
+`--volume` flag, but uses a different syntax. For in-depth information on the |
|
327 |
+`--mount` flag, and a comparison between `--volume` and `--mount`, refer to |
|
328 |
+the [service create command reference](service_create.md#add-bind-mounts-or-volumes). |
|
329 |
+ |
|
330 |
+Even though there is no plan to deprecate `--volume`, usage of `--mount` is recommended. |
|
331 |
+ |
|
332 |
+Examples: |
|
333 |
+ |
|
334 |
+```bash |
|
335 |
+$ docker run --read-only --mount type=volume,target=/icanwrite busybox touch /icanwrite/here |
|
336 |
+``` |
|
337 |
+ |
|
338 |
+```bash |
|
339 |
+$ docker run -t -i --mount type=bind,src=/data,dst=/data busybox sh |
|
340 |
+``` |
|
341 |
+ |
|
319 | 342 |
### Publish or expose port (-p, --expose) |
320 | 343 |
|
321 | 344 |
```bash |
... | ... |
@@ -4422,6 +4422,184 @@ func (s *DockerSuite) TestRunMountReadOnlyDevShm(c *check.C) { |
4422 | 4422 |
c.Assert(out, checker.Contains, "Read-only file system") |
4423 | 4423 |
} |
4424 | 4424 |
|
4425 |
+func (s *DockerSuite) TestRunMount(c *check.C) { |
|
4426 |
+ testRequires(c, DaemonIsLinux, SameHostDaemon, NotUserNamespace) |
|
4427 |
+ |
|
4428 |
+ // mnt1, mnt2, and testCatFooBar are commonly used in multiple test cases |
|
4429 |
+ tmpDir, err := ioutil.TempDir("", "mount") |
|
4430 |
+ if err != nil { |
|
4431 |
+ c.Fatal(err) |
|
4432 |
+ } |
|
4433 |
+ defer os.RemoveAll(tmpDir) |
|
4434 |
+ mnt1, mnt2 := path.Join(tmpDir, "mnt1"), path.Join(tmpDir, "mnt2") |
|
4435 |
+ if err := os.Mkdir(mnt1, 0755); err != nil { |
|
4436 |
+ c.Fatal(err) |
|
4437 |
+ } |
|
4438 |
+ if err := os.Mkdir(mnt2, 0755); err != nil { |
|
4439 |
+ c.Fatal(err) |
|
4440 |
+ } |
|
4441 |
+ if err := ioutil.WriteFile(path.Join(mnt1, "test1"), []byte("test1"), 0644); err != nil { |
|
4442 |
+ c.Fatal(err) |
|
4443 |
+ } |
|
4444 |
+ if err := ioutil.WriteFile(path.Join(mnt2, "test2"), []byte("test2"), 0644); err != nil { |
|
4445 |
+ c.Fatal(err) |
|
4446 |
+ } |
|
4447 |
+ testCatFooBar := func(cName string) error { |
|
4448 |
+ out, _ := dockerCmd(c, "exec", cName, "cat", "/foo/test1") |
|
4449 |
+ if out != "test1" { |
|
4450 |
+ return fmt.Errorf("%s not mounted on /foo", mnt1) |
|
4451 |
+ } |
|
4452 |
+ out, _ = dockerCmd(c, "exec", cName, "cat", "/bar/test2") |
|
4453 |
+ if out != "test2" { |
|
4454 |
+ return fmt.Errorf("%s not mounted on /bar", mnt2) |
|
4455 |
+ } |
|
4456 |
+ return nil |
|
4457 |
+ } |
|
4458 |
+ |
|
4459 |
+ type testCase struct { |
|
4460 |
+ equivalents [][]string |
|
4461 |
+ valid bool |
|
4462 |
+ // fn should be nil if valid==false |
|
4463 |
+ fn func(cName string) error |
|
4464 |
+ } |
|
4465 |
+ cases := []testCase{ |
|
4466 |
+ { |
|
4467 |
+ equivalents: [][]string{ |
|
4468 |
+ { |
|
4469 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1), |
|
4470 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,dst=/bar", mnt2), |
|
4471 |
+ }, |
|
4472 |
+ { |
|
4473 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1), |
|
4474 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,target=/bar", mnt2), |
|
4475 |
+ }, |
|
4476 |
+ { |
|
4477 |
+ "--volume", mnt1 + ":/foo", |
|
4478 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,target=/bar", mnt2), |
|
4479 |
+ }, |
|
4480 |
+ }, |
|
4481 |
+ valid: true, |
|
4482 |
+ fn: testCatFooBar, |
|
4483 |
+ }, |
|
4484 |
+ { |
|
4485 |
+ equivalents: [][]string{ |
|
4486 |
+ { |
|
4487 |
+ "--mount", fmt.Sprintf("type=volume,src=%s,dst=/foo", mnt1), |
|
4488 |
+ "--mount", fmt.Sprintf("type=volume,src=%s,dst=/bar", mnt2), |
|
4489 |
+ }, |
|
4490 |
+ { |
|
4491 |
+ "--mount", fmt.Sprintf("type=volume,src=%s,dst=/foo", mnt1), |
|
4492 |
+ "--mount", fmt.Sprintf("type=volume,src=%s,target=/bar", mnt2), |
|
4493 |
+ }, |
|
4494 |
+ }, |
|
4495 |
+ valid: false, |
|
4496 |
+ }, |
|
4497 |
+ { |
|
4498 |
+ equivalents: [][]string{ |
|
4499 |
+ { |
|
4500 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1), |
|
4501 |
+ "--mount", fmt.Sprintf("type=volume,src=%s,dst=/bar", mnt2), |
|
4502 |
+ }, |
|
4503 |
+ { |
|
4504 |
+ "--volume", mnt1 + ":/foo", |
|
4505 |
+ "--mount", fmt.Sprintf("type=volume,src=%s,target=/bar", mnt2), |
|
4506 |
+ }, |
|
4507 |
+ }, |
|
4508 |
+ valid: false, |
|
4509 |
+ fn: testCatFooBar, |
|
4510 |
+ }, |
|
4511 |
+ { |
|
4512 |
+ equivalents: [][]string{ |
|
4513 |
+ { |
|
4514 |
+ "--read-only", |
|
4515 |
+ "--mount", "type=volume,dst=/bar", |
|
4516 |
+ }, |
|
4517 |
+ }, |
|
4518 |
+ valid: true, |
|
4519 |
+ fn: func(cName string) error { |
|
4520 |
+ _, _, err := dockerCmdWithError("exec", cName, "touch", "/bar/icanwritehere") |
|
4521 |
+ return err |
|
4522 |
+ }, |
|
4523 |
+ }, |
|
4524 |
+ { |
|
4525 |
+ equivalents: [][]string{ |
|
4526 |
+ { |
|
4527 |
+ "--read-only", |
|
4528 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1), |
|
4529 |
+ "--mount", "type=volume,dst=/bar", |
|
4530 |
+ }, |
|
4531 |
+ { |
|
4532 |
+ "--read-only", |
|
4533 |
+ "--volume", fmt.Sprintf("%s:/foo", mnt1), |
|
4534 |
+ "--mount", "type=volume,dst=/bar", |
|
4535 |
+ }, |
|
4536 |
+ }, |
|
4537 |
+ valid: true, |
|
4538 |
+ fn: func(cName string) error { |
|
4539 |
+ out, _ := dockerCmd(c, "exec", cName, "cat", "/foo/test1") |
|
4540 |
+ if out != "test1" { |
|
4541 |
+ return fmt.Errorf("%s not mounted on /foo", mnt1) |
|
4542 |
+ } |
|
4543 |
+ _, _, err := dockerCmdWithError("exec", cName, "touch", "/bar/icanwritehere") |
|
4544 |
+ return err |
|
4545 |
+ }, |
|
4546 |
+ }, |
|
4547 |
+ { |
|
4548 |
+ equivalents: [][]string{ |
|
4549 |
+ { |
|
4550 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1), |
|
4551 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt2), |
|
4552 |
+ }, |
|
4553 |
+ { |
|
4554 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,dst=/foo", mnt1), |
|
4555 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,target=/foo", mnt2), |
|
4556 |
+ }, |
|
4557 |
+ { |
|
4558 |
+ "--volume", fmt.Sprintf("%s:/foo", mnt1), |
|
4559 |
+ "--mount", fmt.Sprintf("type=bind,src=%s,target=/foo", mnt2), |
|
4560 |
+ }, |
|
4561 |
+ }, |
|
4562 |
+ valid: false, |
|
4563 |
+ }, |
|
4564 |
+ { |
|
4565 |
+ equivalents: [][]string{ |
|
4566 |
+ { |
|
4567 |
+ "--volume", fmt.Sprintf("%s:/foo", mnt1), |
|
4568 |
+ "--mount", fmt.Sprintf("type=volume,src=%s,target=/foo", mnt2), |
|
4569 |
+ }, |
|
4570 |
+ }, |
|
4571 |
+ valid: false, |
|
4572 |
+ }, |
|
4573 |
+ { |
|
4574 |
+ equivalents: [][]string{ |
|
4575 |
+ { |
|
4576 |
+ "--mount", "type=volume,target=/foo", |
|
4577 |
+ "--mount", "type=volume,target=/foo", |
|
4578 |
+ }, |
|
4579 |
+ }, |
|
4580 |
+ valid: false, |
|
4581 |
+ }, |
|
4582 |
+ } |
|
4583 |
+ |
|
4584 |
+ for i, testCase := range cases { |
|
4585 |
+ for j, opts := range testCase.equivalents { |
|
4586 |
+ cName := fmt.Sprintf("mount-%d-%d", i, j) |
|
4587 |
+ _, _, err := dockerCmdWithError(append([]string{"run", "-i", "-d", "--name", cName}, |
|
4588 |
+ append(opts, []string{"busybox", "top"}...)...)...) |
|
4589 |
+ if testCase.valid { |
|
4590 |
+ c.Assert(err, check.IsNil, |
|
4591 |
+ check.Commentf("got error while creating a container with %v (%s)", opts, cName)) |
|
4592 |
+ c.Assert(testCase.fn(cName), check.IsNil, |
|
4593 |
+ check.Commentf("got error while executing test for %v (%s)", opts, cName)) |
|
4594 |
+ dockerCmd(c, "rm", "-f", cName) |
|
4595 |
+ } else { |
|
4596 |
+ c.Assert(err, checker.NotNil, |
|
4597 |
+ check.Commentf("got nil while creating a container with %v (%s)", opts, cName)) |
|
4598 |
+ } |
|
4599 |
+ } |
|
4600 |
+ } |
|
4601 |
+} |
|
4602 |
+ |
|
4425 | 4603 |
// Test that passing a FQDN as hostname properly sets hostname, and |
4426 | 4604 |
// /etc/hostname. Test case for 29100 |
4427 | 4605 |
func (s *DockerSuite) TestRunHostnameFQDN(c *check.C) { |
... | ... |
@@ -61,6 +61,7 @@ docker-run - Run a command in a new container |
61 | 61 |
[**--memory-reservation**[=*MEMORY-RESERVATION*]] |
62 | 62 |
[**--memory-swap**[=*LIMIT*]] |
63 | 63 |
[**--memory-swappiness**[=*MEMORY-SWAPPINESS*]] |
64 |
+[**--mount**[=*[MOUNT]*]] |
|
64 | 65 |
[**--name**[=*NAME*]] |
65 | 66 |
[**--network-alias**[=*[]*]] |
66 | 67 |
[**--network**[=*"bridge"*]] |
... | ... |
@@ -425,6 +426,42 @@ unit, `b` is used. Set LIMIT to `-1` to enable unlimited swap. |
425 | 425 |
The IPv6 link-local address will be based on the device's MAC address |
426 | 426 |
according to RFC4862. |
427 | 427 |
|
428 |
+**--mount**=[*[type=TYPE[,TYPE-SPECIFIC-OPTIONS]]*] |
|
429 |
+ Attach a filesystem mount to the container |
|
430 |
+ |
|
431 |
+ Current supported mount `TYPES` are `bind`, `volume`, and `tmpfs`. |
|
432 |
+ |
|
433 |
+ e.g. |
|
434 |
+ |
|
435 |
+ `type=bind,source=/path/on/host,destination=/path/in/container` |
|
436 |
+ |
|
437 |
+ `type=volume,source=my-volume,destination=/path/in/container,volume-label="color=red",volume-label="shape=round"` |
|
438 |
+ |
|
439 |
+ `type=tmpfs,tmpfs-size=512M,destination=/path/in/container` |
|
440 |
+ |
|
441 |
+ Common Options: |
|
442 |
+ |
|
443 |
+ * `src`, `source`: mount source spec for `bind` and `volume`. Mandatory for `bind`. |
|
444 |
+ * `dst`, `destination`, `target`: mount destination spec. |
|
445 |
+ * `ro`, `read-only`: `true` or `false` (default). |
|
446 |
+ |
|
447 |
+ Options specific to `bind`: |
|
448 |
+ |
|
449 |
+ * `bind-propagation`: `shared`, `slave`, `private`, `rshared`, `rslave`, or `rprivate`(default). See also `mount(2)`. |
|
450 |
+ * `consistency`: `consistent`(default), `cached`, or `delegated`. Currently, only effective for Docker for Mac. |
|
451 |
+ |
|
452 |
+ Options specific to `volume`: |
|
453 |
+ |
|
454 |
+ * `volume-driver`: Name of the volume-driver plugin. |
|
455 |
+ * `volume-label`: Custom metadata. |
|
456 |
+ * `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. |
|
457 |
+ * `volume-opt`: specific to a given volume driver. |
|
458 |
+ |
|
459 |
+ Options specific to `tmpfs`: |
|
460 |
+ |
|
461 |
+ * `tmpfs-size`: Size of the tmpfs mount in bytes. Unlimited by default in Linux. |
|
462 |
+ * `tmpfs-mode`: File mode of the tmpfs in octal. (e.g. `700` or `0700`.) Defaults to `1777` in Linux. |
|
463 |
+ |
|
428 | 464 |
**--name**="" |
429 | 465 |
Assign a name to the container |
430 | 466 |
|
... | ... |
@@ -604,6 +641,9 @@ options are the same as the Linux default `mount` flags. If you do not specify |
604 | 604 |
any options, the systems uses the following options: |
605 | 605 |
`rw,noexec,nosuid,nodev,size=65536k`. |
606 | 606 |
|
607 |
+ See also `--mount`, which is the successor of `--tmpfs` and `--volume`. |
|
608 |
+ Even though there is no plan to deprecate `--tmpfs`, usage of `--mount` is recommended. |
|
609 |
+ |
|
607 | 610 |
**-u**, **--user**="" |
608 | 611 |
Sets the username or UID used and optionally the groupname or GID for the specified command. |
609 | 612 |
|
... | ... |
@@ -704,6 +744,9 @@ change propagation properties of source mount. Say `/` is source mount for |
704 | 704 |
To disable automatic copying of data from the container path to the volume, use |
705 | 705 |
the `nocopy` flag. The `nocopy` flag can be set on bind mounts and named volumes. |
706 | 706 |
|
707 |
+See also `--mount`, which is the successor of `--tmpfs` and `--volume`. |
|
708 |
+Even though there is no plan to deprecate `--volume`, usage of `--mount` is recommended. |
|
709 |
+ |
|
707 | 710 |
**--volume-driver**="" |
708 | 711 |
Container's volume driver. This driver creates volumes specified either from |
709 | 712 |
a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag. |