Skip to content

Commit fc7b904

Browse files
committed
Add new HostConfig field, Mounts.
`Mounts` allows users to specify in a much safer way the volumes they want to use in the container. This replaces `Binds` and `Volumes`, which both still exist, but `Mounts` and `Binds`/`Volumes` are exclussive. The CLI will continue to use `Binds` and `Volumes` due to concerns with parsing the volume specs on the client side and cross-platform support (for now). The new API follows exactly the services mount API. Example usage of `Mounts`: ``` $ curl -XPOST localhost:2375/containers/create -d '{ "Image": "alpine:latest", "HostConfig": { "Mounts": [{ "Type": "Volume", "Target": "/foo" },{ "Type": "bind", "Source": "/var/run/docker.sock", "Target": "/var/run/docker.sock", },{ "Type": "volume", "Name": "important_data", "Target": "/var/data", "ReadOnly": true, "VolumeOptions": { "DriverConfig": { Name: "awesomeStorage", Options: {"size": "10m"}, Labels: {"some":"label"} } }] } }' ``` There are currently 2 types of mounts: - **bind**: Paths on the host that get mounted into the container. Paths must exist prior to creating the container. - **volume**: Volumes that persist after the container is removed. Not all fields are available in each type, and validation is done to ensure these fields aren't mixed up between types. Signed-off-by: Brian Goff <[email protected]>
1 parent 675144f commit fc7b904

30 files changed

+922
-330
lines changed

container/container.go

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/Sirupsen/logrus"
1919
containertypes "github.com/docker/docker/api/types/container"
20+
mounttypes "github.com/docker/docker/api/types/mount"
2021
networktypes "github.com/docker/docker/api/types/network"
2122
"github.com/docker/docker/daemon/exec"
2223
"github.com/docker/docker/daemon/logger"
@@ -551,6 +552,7 @@ func (container *Container) ShouldRestart() bool {
551552
// AddMountPointWithVolume adds a new mount point configured with a volume to the container.
552553
func (container *Container) AddMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
553554
container.MountPoints[destination] = &volume.MountPoint{
555+
Type: mounttypes.TypeVolume,
554556
Name: vol.Name(),
555557
Driver: vol.DriverName(),
556558
Destination: destination,

daemon/create_unix.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/Sirupsen/logrus"
1111
containertypes "github.com/docker/docker/api/types/container"
12+
mounttypes "github.com/docker/docker/api/types/mount"
1213
"github.com/docker/docker/container"
1314
"github.com/docker/docker/pkg/stringid"
1415
"github.com/opencontainers/runc/libcontainer/label"
@@ -63,7 +64,11 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
6364
// this is only called when the container is created.
6465
func (daemon *Daemon) populateVolumes(c *container.Container) error {
6566
for _, mnt := range c.MountPoints {
66-
if !mnt.CopyData || mnt.Volume == nil {
67+
if mnt.Volume == nil {
68+
continue
69+
}
70+
71+
if mnt.Type != mounttypes.TypeVolume || !mnt.CopyData {
6772
continue
6873
}
6974

daemon/create_windows.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
1818

1919
for spec := range config.Volumes {
2020

21-
mp, err := volume.ParseMountSpec(spec, hostConfig.VolumeDriver)
21+
mp, err := volume.ParseMountRaw(spec, hostConfig.VolumeDriver)
2222
if err != nil {
2323
return fmt.Errorf("Unrecognised volume spec: %v", err)
2424
}

daemon/inspect_unix.go

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func addMountPoints(container *container.Container) []types.MountPoint {
6868
mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
6969
for _, m := range container.MountPoints {
7070
mountPoints = append(mountPoints, types.MountPoint{
71+
Type: m.Type,
7172
Name: m.Name,
7273
Source: m.Path(),
7374
Destination: m.Destination,

daemon/inspect_windows.go

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ func addMountPoints(container *container.Container) []types.MountPoint {
1616
mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
1717
for _, m := range container.MountPoints {
1818
mountPoints = append(mountPoints, types.MountPoint{
19+
Type: m.Type,
1920
Name: m.Name,
2021
Source: m.Path(),
2122
Destination: m.Destination,

daemon/mounts.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func (daemon *Daemon) removeMountPoints(container *container.Container, rm bool)
2727
if rm {
2828
// Do not remove named mountpoints
2929
// these are mountpoints specified like `docker run -v <name>:/foo`
30-
if m.Named {
30+
if m.Spec.Source != "" {
3131
continue
3232
}
3333
err := daemon.volumes.Remove(m.Volume)

daemon/volumes.go

+54-7
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ import (
99

1010
"github.com/docker/docker/api/types"
1111
containertypes "github.com/docker/docker/api/types/container"
12+
mounttypes "github.com/docker/docker/api/types/mount"
1213
"github.com/docker/docker/container"
14+
dockererrors "github.com/docker/docker/errors"
1315
"github.com/docker/docker/volume"
16+
"github.com/opencontainers/runc/libcontainer/label"
1417
)
1518

1619
var (
@@ -106,7 +109,8 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
106109
Driver: m.Driver,
107110
Destination: m.Destination,
108111
Propagation: m.Propagation,
109-
Named: m.Named,
112+
Spec: m.Spec,
113+
CopyData: false,
110114
}
111115

112116
if len(cp.Source) == 0 {
@@ -123,18 +127,18 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
123127

124128
// 3. Read bind mounts
125129
for _, b := range hostConfig.Binds {
126-
// #10618
127-
bind, err := volume.ParseMountSpec(b, hostConfig.VolumeDriver)
130+
bind, err := volume.ParseMountRaw(b, hostConfig.VolumeDriver)
128131
if err != nil {
129132
return err
130133
}
131134

135+
// #10618
132136
_, tmpfsExists := hostConfig.Tmpfs[bind.Destination]
133137
if binds[bind.Destination] || tmpfsExists {
134138
return fmt.Errorf("Duplicate mount point '%s'", bind.Destination)
135139
}
136140

137-
if len(bind.Name) > 0 {
141+
if bind.Type == mounttypes.TypeVolume {
138142
// create the volume
139143
v, err := daemon.volumes.CreateWithRef(bind.Name, bind.Driver, container.ID, nil, nil)
140144
if err != nil {
@@ -144,16 +148,59 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
144148
bind.Source = v.Path()
145149
// bind.Name is an already existing volume, we need to use that here
146150
bind.Driver = v.DriverName()
147-
bind.Named = true
148-
if bind.Driver == "local" {
149-
bind = setBindModeIfNull(bind)
151+
if bind.Driver == volume.DefaultDriverName {
152+
setBindModeIfNull(bind)
150153
}
151154
}
152155

153156
binds[bind.Destination] = true
154157
mountPoints[bind.Destination] = bind
155158
}
156159

160+
for _, cfg := range hostConfig.Mounts {
161+
mp, err := volume.ParseMountSpec(cfg)
162+
if err != nil {
163+
return dockererrors.NewBadRequestError(err)
164+
}
165+
166+
if binds[mp.Destination] {
167+
return fmt.Errorf("Duplicate mount point '%s'", cfg.Target)
168+
}
169+
170+
if mp.Type == mounttypes.TypeVolume {
171+
var v volume.Volume
172+
if cfg.VolumeOptions != nil {
173+
var driverOpts map[string]string
174+
if cfg.VolumeOptions.DriverConfig != nil {
175+
driverOpts = cfg.VolumeOptions.DriverConfig.Options
176+
}
177+
v, err = daemon.volumes.CreateWithRef(mp.Name, mp.Driver, container.ID, driverOpts, cfg.VolumeOptions.Labels)
178+
} else {
179+
v, err = daemon.volumes.CreateWithRef(mp.Name, mp.Driver, container.ID, nil, nil)
180+
}
181+
if err != nil {
182+
return err
183+
}
184+
185+
if err := label.Relabel(mp.Source, container.MountLabel, false); err != nil {
186+
return err
187+
}
188+
mp.Volume = v
189+
mp.Name = v.Name()
190+
mp.Driver = v.DriverName()
191+
192+
// only use the cached path here since getting the path is not neccessary right now and calling `Path()` may be slow
193+
if cv, ok := v.(interface {
194+
CachedPath() string
195+
}); ok {
196+
mp.Source = cv.CachedPath()
197+
}
198+
}
199+
200+
binds[mp.Destination] = true
201+
mountPoints[mp.Destination] = mp
202+
}
203+
157204
container.Lock()
158205

159206
// 4. Cleanup old volumes that are about to be reassigned.

daemon/volumes_unix.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,10 @@ func sortMounts(m []container.Mount) []container.Mount {
8585
// setBindModeIfNull is platform specific processing to ensure the
8686
// shared mode is set to 'z' if it is null. This is called in the case
8787
// of processing a named volume and not a typical bind.
88-
func setBindModeIfNull(bind *volume.MountPoint) *volume.MountPoint {
88+
func setBindModeIfNull(bind *volume.MountPoint) {
8989
if bind.Mode == "" {
9090
bind.Mode = "z"
9191
}
92-
return bind
9392
}
9493

9594
// migrateVolume links the contents of a volume created pre Docker 1.7

daemon/volumes_windows.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,6 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
4646

4747
// setBindModeIfNull is platform specific processing which is a no-op on
4848
// Windows.
49-
func setBindModeIfNull(bind *volume.MountPoint) *volume.MountPoint {
50-
return bind
49+
func setBindModeIfNull(bind *volume.MountPoint) {
50+
return
5151
}

docs/reference/api/docker_remote_api.md

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ This section lists each version from latest to oldest. Each listing includes a
122122
* `DELETE /volumes/(name)` now accepts a `force` query parameter to force removal of volumes that were already removed out of band by the volume driver plugin.
123123
* `POST /containers/create/` and `POST /containers/(name)/update` now validates restart policies.
124124
* `POST /containers/create` now validates IPAMConfig in NetworkingConfig, and returns error for invalid IPv4 and IPv6 addresses (`--ip` and `--ip6` in `docker create/run`).
125+
* `POST /containers/create` now takes a `Mounts` field in `HostConfig` which replaces `Binds` and `Volumes`. *note*: `Binds` and `Volumes` are still available but are exclusive with `Mounts`
125126

126127
### v1.24 API changes
127128

docs/reference/api/docker_remote_api_v1.24.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ Create a container
334334
"StorageOpt": {},
335335
"CgroupParent": "",
336336
"VolumeDriver": "",
337-
"ShmSize": 67108864
337+
"ShmSize": 67108864,
338+
"Mounts": []
338339
},
339340
"NetworkingConfig": {
340341
"EndpointsConfig": {
@@ -610,7 +611,8 @@ Return low-level information on the container `id`
610611
"VolumesFrom": null,
611612
"Ulimits": [{}],
612613
"VolumeDriver": "",
613-
"ShmSize": 67108864
614+
"ShmSize": 67108864,
615+
"Mounts": []
614616
},
615617
"HostnamePath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hostname",
616618
"HostsPath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hosts",

docs/reference/api/docker_remote_api_v1.25.md

+18
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,24 @@ Create a container
486486
- **CgroupParent** - Path to `cgroups` under which the container's `cgroup` is created. If the path is not absolute, the path is considered to be relative to the `cgroups` path of the init process. Cgroups are created if they do not already exist.
487487
- **VolumeDriver** - Driver that this container users to mount volumes.
488488
- **ShmSize** - Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB.
489+
- **Mounts** – Specification for mounts to be added to the container.
490+
- **Target** – Container path.
491+
- **Source** – Mount source (e.g. a volume name, a host path).
492+
- **Type** – The mount type (`bind`, or `volume`).
493+
Available types (for the `Type` field):
494+
- **bind** - Mounts a file or directory from the host into the container. Must exist prior to creating the container.
495+
- **volume** - Creates a volume with the given name and options (or uses a pre-existing volume with the same name and options). These are **not** removed when the container is removed.
496+
- **ReadOnly** – A boolean indicating whether the mount should be read-only.
497+
- **BindOptions** - Optional configuration for the `bind` type.
498+
- **Propagation** – A propagation mode with the value `[r]private`, `[r]shared`, or `[r]slave`.
499+
- **VolumeOptions** – Optional configuration for the `volume` type.
500+
- **NoCopy** – A boolean indicating if volume should be
501+
populated with the data from the target. (Default false)
502+
- **Labels** – User-defined name and labels for the volume as key/value pairs: `{"name": "value"}`
503+
- **DriverConfig** – Map of driver-specific options.
504+
- **Name** - Name of the driver to use to create the volume.
505+
- **Options** - key/value map of driver specific options.
506+
489507

490508
**Query parameters**:
491509

0 commit comments

Comments
 (0)