| ... | ... |
@@ -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 |
|
| ... | ... |
@@ -763,9 +763,23 @@ func (container *Container) Start() (err error) {
|
| 763 | 763 |
|
| 764 | 764 |
// Apply volumes from another container if requested |
| 765 | 765 |
if container.Config.VolumesFrom != "" {
|
| 766 |
- volumes := strings.Split(container.Config.VolumesFrom, ",") |
|
| 767 |
- for _, v := range volumes {
|
|
| 768 |
- c := container.runtime.Get(v) |
|
| 766 |
+ containerSpecs := strings.Split(container.Config.VolumesFrom, ",") |
|
| 767 |
+ for _, containerSpec := range containerSpecs {
|
|
| 768 |
+ mountRW := true |
|
| 769 |
+ specParts := strings.SplitN(containerSpec, ":", 2) |
|
| 770 |
+ switch len(specParts) {
|
|
| 771 |
+ case 0: |
|
| 772 |
+ return fmt.Errorf("Malformed volumes-from specification: %s", container.Config.VolumesFrom)
|
|
| 773 |
+ case 2: |
|
| 774 |
+ switch specParts[1] {
|
|
| 775 |
+ case "ro": |
|
| 776 |
+ mountRW = false |
|
| 777 |
+ case "rw": // mountRW is already true |
|
| 778 |
+ default: |
|
| 779 |
+ return fmt.Errorf("Malformed volumes-from speficication: %s", containerSpec)
|
|
| 780 |
+ } |
|
| 781 |
+ } |
|
| 782 |
+ c := container.runtime.Get(specParts[0]) |
|
| 769 | 783 |
if c == nil {
|
| 770 | 784 |
return fmt.Errorf("Container %s not found. Impossible to mount its volumes", container.ID)
|
| 771 | 785 |
} |
| ... | ... |
@@ -778,7 +792,7 @@ func (container *Container) Start() (err error) {
|
| 778 | 778 |
} |
| 779 | 779 |
container.Volumes[volPath] = id |
| 780 | 780 |
if isRW, exists := c.VolumesRW[volPath]; exists {
|
| 781 |
- container.VolumesRW[volPath] = isRW |
|
| 781 |
+ container.VolumesRW[volPath] = isRW && mountRW |
|
| 782 | 782 |
} |
| 783 | 783 |
} |
| 784 | 784 |
|
| ... | ... |
@@ -1338,6 +1338,67 @@ 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 |
+ |
|
| 1341 | 1402 |
// Test that VolumesRW values are copied to the new container. Regression test for #1201 |
| 1342 | 1403 |
func TestVolumesFromReadonlyMount(t *testing.T) {
|
| 1343 | 1404 |
runtime := mkRuntime(t) |
| ... | ... |
@@ -648,7 +648,7 @@ network communication. |
| 648 | 648 |
-u="": Username or UID |
| 649 | 649 |
-dns=[]: Set custom dns servers for the container |
| 650 | 650 |
-v=[]: Create a bind mount with: [host-dir]:[container-dir]:[rw|ro]. If "container-dir" is missing, then docker creates a new volume. |
| 651 |
- -volumes-from="": Mount all volumes from the given container |
|
| 651 |
+ -volumes-from="": Mount all volumes from the given container(s) |
|
| 652 | 652 |
-entrypoint="": Overwrite the default entrypoint set by the image |
| 653 | 653 |
-w="": Working directory inside the container |
| 654 | 654 |
-lxc-conf=[]: Add custom lxc options -lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" |
| ... | ... |
@@ -740,6 +740,17 @@ can access the network and environment of the redis container via |
| 740 | 740 |
environment variables. The ``-name`` flag will assign the name ``console`` |
| 741 | 741 |
to the newly created container. |
| 742 | 742 |
|
| 743 |
+.. code-block:: bash |
|
| 744 |
+ |
|
| 745 |
+ docker run -volumes-from 777f7dc92da7,ba8c0c54f0f2:ro -i -t ubuntu pwd |
|
| 746 |
+ |
|
| 747 |
+The ``-volumes-from`` flag mounts all the defined volumes from the |
|
| 748 |
+refrence containers. Containers can be specified by a comma seperated |
|
| 749 |
+list or by repetitions of the ``-volumes-from`` argument. The container |
|
| 750 |
+id may be optionally suffixed with ``:ro`` or ``:rw`` to mount the volumes in |
|
| 751 |
+read-only or read-write mode, respectively. By default, the volumes are mounted |
|
| 752 |
+in the same mode (rw or ro) as the reference container. |
|
| 753 |
+ |
|
| 743 | 754 |
.. _cli_search: |
| 744 | 755 |
|
| 745 | 756 |
``search`` |