| ... | ... |
@@ -199,7 +199,7 @@ func ParseRun(args []string, capabilities *Capabilities) (*Config, *HostConfig, |
| 199 | 199 |
cmd.Var(flVolumes, "v", "Bind mount a volume (e.g. from the host: -v /host:/container, from docker: -v /container)") |
| 200 | 200 |
|
| 201 | 201 |
var flVolumesFrom utils.ListOpts |
| 202 |
- cmd.Var(&flVolumesFrom, "volumes-from", "Mount volumes from the specified container") |
|
| 202 |
+ cmd.Var(&flVolumesFrom, "volumes-from", "Mount volumes from the specified container(s)") |
|
| 203 | 203 |
|
| 204 | 204 |
flEntrypoint := cmd.String("entrypoint", "", "Overwrite the default entrypoint of the image")
|
| 205 | 205 |
|
| ... | ... |
@@ -749,9 +749,23 @@ func (container *Container) Start() (err error) {
|
| 749 | 749 |
|
| 750 | 750 |
// Apply volumes from another container if requested |
| 751 | 751 |
if container.Config.VolumesFrom != "" {
|
| 752 |
- volumes := strings.Split(container.Config.VolumesFrom, ",") |
|
| 753 |
- for _, v := range volumes {
|
|
| 754 |
- c := container.runtime.Get(v) |
|
| 752 |
+ containerSpecs := strings.Split(container.Config.VolumesFrom, ",") |
|
| 753 |
+ for _, containerSpec := range containerSpecs {
|
|
| 754 |
+ mountRW := true |
|
| 755 |
+ specParts := strings.SplitN(containerSpec, ":", 2) |
|
| 756 |
+ switch len(specParts) {
|
|
| 757 |
+ case 0: |
|
| 758 |
+ return fmt.Errorf("Malformed volumes-from specification: %s", container.Config.VolumesFrom)
|
|
| 759 |
+ case 2: |
|
| 760 |
+ switch specParts[1] {
|
|
| 761 |
+ case "ro": |
|
| 762 |
+ mountRW = false |
|
| 763 |
+ case "rw": // mountRW is already true |
|
| 764 |
+ default: |
|
| 765 |
+ return fmt.Errorf("Malformed volumes-from speficication: %s", containerSpec)
|
|
| 766 |
+ } |
|
| 767 |
+ } |
|
| 768 |
+ c := container.runtime.Get(specParts[0]) |
|
| 755 | 769 |
if c == nil {
|
| 756 | 770 |
return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
|
| 757 | 771 |
} |
| ... | ... |
@@ -764,7 +778,7 @@ func (container *Container) Start() (err error) {
|
| 764 | 764 |
} |
| 765 | 765 |
container.Volumes[volPath] = id |
| 766 | 766 |
if isRW, exists := c.VolumesRW[volPath]; exists {
|
| 767 |
- container.VolumesRW[volPath] = isRW |
|
| 767 |
+ container.VolumesRW[volPath] = isRW && mountRW |
|
| 768 | 768 |
} |
| 769 | 769 |
} |
| 770 | 770 |
|
| ... | ... |
@@ -1338,6 +1338,68 @@ func TestBindMounts(t *testing.T) {
|
| 1338 | 1338 |
} |
| 1339 | 1339 |
} |
| 1340 | 1340 |
|
| 1341 |
+// Test that -volumes-from supports both read-only mounts |
|
| 1342 |
+func TestFromVolumesInReadonlyMode(t *testing.T) {
|
|
| 1343 |
+ runtime := mkRuntime(t) |
|
| 1344 |
+ defer nuke(runtime) |
|
| 1345 |
+ container, _, err := runtime.Create( |
|
| 1346 |
+ &Config{
|
|
| 1347 |
+ Image: GetTestImage(runtime).ID, |
|
| 1348 |
+ Cmd: []string{"/bin/echo", "-n", "foobar"},
|
|
| 1349 |
+ Volumes: map[string]struct{}{"/test": {}},
|
|
| 1350 |
+ }, |
|
| 1351 |
+ "", |
|
| 1352 |
+ ) |
|
| 1353 |
+ if err != nil {
|
|
| 1354 |
+ t.Fatal(err) |
|
| 1355 |
+ } |
|
| 1356 |
+ defer runtime.Destroy(container) |
|
| 1357 |
+ _, err = container.Output() |
|
| 1358 |
+ if err != nil {
|
|
| 1359 |
+ t.Fatal(err) |
|
| 1360 |
+ } |
|
| 1361 |
+ if !container.VolumesRW["/test"] {
|
|
| 1362 |
+ t.Fail() |
|
| 1363 |
+ } |
|
| 1364 |
+ |
|
| 1365 |
+ container2, _, err := runtime.Create( |
|
| 1366 |
+ &Config{
|
|
| 1367 |
+ Image: GetTestImage(runtime).ID, |
|
| 1368 |
+ Cmd: []string{"/bin/echo", "-n", "foobar"},
|
|
| 1369 |
+ VolumesFrom: container.ID + ":ro", |
|
| 1370 |
+ }, |
|
| 1371 |
+ "", |
|
| 1372 |
+ ) |
|
| 1373 |
+ if err != nil {
|
|
| 1374 |
+ t.Fatal(err) |
|
| 1375 |
+ } |
|
| 1376 |
+ defer runtime.Destroy(container2) |
|
| 1377 |
+ |
|
| 1378 |
+ _, err = container2.Output() |
|
| 1379 |
+ if err != nil {
|
|
| 1380 |
+ t.Fatal(err) |
|
| 1381 |
+ } |
|
| 1382 |
+ |
|
| 1383 |
+ if container.Volumes["/test"] != container2.Volumes["/test"] {
|
|
| 1384 |
+ t.Logf("container volumes do not match: %s | %s ",
|
|
| 1385 |
+ container.Volumes["/test"], |
|
| 1386 |
+ container2.Volumes["/test"]) |
|
| 1387 |
+ t.Fail() |
|
| 1388 |
+ } |
|
| 1389 |
+ |
|
| 1390 |
+ _, exists := container2.VolumesRW["/test"] |
|
| 1391 |
+ if !exists {
|
|
| 1392 |
+ t.Logf("container2 is missing '/test' volume: %s", container2.VolumesRW)
|
|
| 1393 |
+ t.Fail() |
|
| 1394 |
+ } |
|
| 1395 |
+ |
|
| 1396 |
+ if container2.VolumesRW["/test"] != false {
|
|
| 1397 |
+ t.Log("'/test' volume mounted in read-write mode, expected read-only")
|
|
| 1398 |
+ t.Fail() |
|
| 1399 |
+ } |
|
| 1400 |
+} |
|
| 1401 |
+ |
|
| 1402 |
+ |
|
| 1341 | 1403 |
// Test that VolumesRW values are copied to the new container. Regression test for #1201 |
| 1342 | 1404 |
func TestVolumesFromReadonlyMount(t *testing.T) {
|
| 1343 | 1405 |
runtime := mkRuntime(t) |
| ... | ... |
@@ -576,7 +576,7 @@ network communication. |
| 576 | 576 |
-u="": Username or UID |
| 577 | 577 |
-dns=[]: Set custom dns servers for the container |
| 578 | 578 |
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "container-dir" is missing, then docker creates a new volume. |
| 579 |
- -volumes-from="": Mount all volumes from the given container |
|
| 579 |
+ -volumes-from="": Mount all volumes from the given container(s) |
|
| 580 | 580 |
-entrypoint="": Overwrite the default entrypoint set by the image |
| 581 | 581 |
-w="": Working directory inside the container |
| 582 | 582 |
-lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" |
| ... | ... |
@@ -668,6 +668,17 @@ can access the network and environment of the redis container via |
| 668 | 668 |
environment variables. The ``-name`` flag will assign the name ``console`` |
| 669 | 669 |
to the newly created container. |
| 670 | 670 |
|
| 671 |
+.. code-block:: bash |
|
| 672 |
+ |
|
| 673 |
+ docker run -volumes-from 777f7dc92da7,ba8c0c54f0f2:ro -i -t ubuntu pwd |
|
| 674 |
+ |
|
| 675 |
+The ``-volumes-from`` flag mounts all the defined volumes from the |
|
| 676 |
+refrence containers. Containers can be specified by a comma seperated |
|
| 677 |
+list or by repetitions of the ``-volumes-from`` argument. The container |
|
| 678 |
+id may be optionally suffixed with ``:ro`` or ``:rw`` to mount the volumes in |
|
| 679 |
+read-only or read-write mode, respectively. By default, the volumes are mounted |
|
| 680 |
+in the same mode (rw or ro) as the reference container. |
|
| 681 |
+ |
|
| 671 | 682 |
.. _cli_search: |
| 672 | 683 |
|
| 673 | 684 |
``search`` |