Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

"github.com/Sirupsen/logrus"
containertypes "github.com/docker/docker/api/types/container"
mounttypes "github.com/docker/docker/api/types/mount"
networktypes "github.com/docker/docker/api/types/network"
"github.com/docker/docker/daemon/exec"
"github.com/docker/docker/daemon/logger"
Expand Down Expand Up @@ -551,6 +552,7 @@ func (container *Container) ShouldRestart() bool {
// AddMountPointWithVolume adds a new mount point configured with a volume to the container.
func (container *Container) AddMountPointWithVolume(destination string, vol volume.Volume, rw bool) {
container.MountPoints[destination] = &volume.MountPoint{
Type: mounttypes.TypeVolume,
Name: vol.Name(),
Driver: vol.DriverName(),
Destination: destination,
Expand Down
7 changes: 6 additions & 1 deletion daemon/create_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/Sirupsen/logrus"
containertypes "github.com/docker/docker/api/types/container"
mounttypes "github.com/docker/docker/api/types/mount"
"github.com/docker/docker/container"
"github.com/docker/docker/pkg/stringid"
"github.com/opencontainers/runc/libcontainer/label"
Expand Down Expand Up @@ -63,7 +64,11 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
// this is only called when the container is created.
func (daemon *Daemon) populateVolumes(c *container.Container) error {
for _, mnt := range c.MountPoints {
if !mnt.CopyData || mnt.Volume == nil {
if mnt.Volume == nil {
continue
}

if mnt.Type != mounttypes.TypeVolume || !mnt.CopyData {
continue
}

Expand Down
2 changes: 1 addition & 1 deletion daemon/create_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain

for spec := range config.Volumes {

mp, err := volume.ParseMountSpec(spec, hostConfig.VolumeDriver)
mp, err := volume.ParseMountRaw(spec, hostConfig.VolumeDriver)
if err != nil {
return fmt.Errorf("Unrecognised volume spec: %v", err)
}
Expand Down
4 changes: 4 additions & 0 deletions daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ func (daemon *Daemon) restore() error {
wg.Add(1)
go func(c *container.Container) {
defer wg.Done()
if err := backportMountSpec(c); err != nil {
logrus.Errorf("Failed to migrate old mounts to use new spec format")
}

rm := c.RestartManager(false)
if c.IsRunning() || c.IsPaused() {
if err := daemon.containerd.Restore(c.ID, libcontainerd.WithRestartManager(rm)); err != nil {
Expand Down
1 change: 1 addition & 0 deletions daemon/inspect_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func addMountPoints(container *container.Container) []types.MountPoint {
mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
for _, m := range container.MountPoints {
mountPoints = append(mountPoints, types.MountPoint{
Type: m.Type,
Name: m.Name,
Source: m.Path(),
Destination: m.Destination,
Expand Down
1 change: 1 addition & 0 deletions daemon/inspect_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ func addMountPoints(container *container.Container) []types.MountPoint {
mountPoints := make([]types.MountPoint, 0, len(container.MountPoints))
for _, m := range container.MountPoints {
mountPoints = append(mountPoints, types.MountPoint{
Type: m.Type,
Name: m.Name,
Source: m.Path(),
Destination: m.Destination,
Expand Down
2 changes: 1 addition & 1 deletion daemon/mounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (daemon *Daemon) removeMountPoints(container *container.Container, rm bool)
if rm {
// Do not remove named mountpoints
// these are mountpoints specified like `docker run -v <name>:/foo`
if m.Named {
if m.Spec.Source != "" {
continue
}
err := daemon.volumes.Remove(m.Volume)
Expand Down
105 changes: 98 additions & 7 deletions daemon/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import (

"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
mounttypes "github.com/docker/docker/api/types/mount"
"github.com/docker/docker/container"
dockererrors "github.com/docker/docker/errors"
"github.com/docker/docker/volume"
"github.com/opencontainers/runc/libcontainer/label"
)

var (
Expand Down Expand Up @@ -106,7 +109,8 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
Driver: m.Driver,
Destination: m.Destination,
Propagation: m.Propagation,
Named: m.Named,
Spec: m.Spec,
CopyData: false,
}

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

// 3. Read bind mounts
for _, b := range hostConfig.Binds {
// #10618
bind, err := volume.ParseMountSpec(b, hostConfig.VolumeDriver)
bind, err := volume.ParseMountRaw(b, hostConfig.VolumeDriver)
if err != nil {
return err
}

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

if len(bind.Name) > 0 {
if bind.Type == mounttypes.TypeVolume {
// create the volume
v, err := daemon.volumes.CreateWithRef(bind.Name, bind.Driver, container.ID, nil, nil)
if err != nil {
Expand All @@ -144,16 +148,59 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
bind.Source = v.Path()
// bind.Name is an already existing volume, we need to use that here
bind.Driver = v.DriverName()
bind.Named = true
if bind.Driver == "local" {
bind = setBindModeIfNull(bind)
if bind.Driver == volume.DefaultDriverName {
setBindModeIfNull(bind)
}
}

binds[bind.Destination] = true
mountPoints[bind.Destination] = bind
}

for _, cfg := range hostConfig.Mounts {
mp, err := volume.ParseMountSpec(cfg)
if err != nil {
return dockererrors.NewBadRequestError(err)
}

if binds[mp.Destination] {
return fmt.Errorf("Duplicate mount point '%s'", cfg.Target)
}

if mp.Type == mounttypes.TypeVolume {
var v volume.Volume
if cfg.VolumeOptions != nil {
var driverOpts map[string]string
if cfg.VolumeOptions.DriverConfig != nil {
driverOpts = cfg.VolumeOptions.DriverConfig.Options
}
v, err = daemon.volumes.CreateWithRef(mp.Name, mp.Driver, container.ID, driverOpts, cfg.VolumeOptions.Labels)
} else {
v, err = daemon.volumes.CreateWithRef(mp.Name, mp.Driver, container.ID, nil, nil)
}
if err != nil {
return err
}

if err := label.Relabel(mp.Source, container.MountLabel, false); err != nil {
return err
}
mp.Volume = v
mp.Name = v.Name()
mp.Driver = v.DriverName()

// only use the cached path here since getting the path is not neccessary right now and calling `Path()` may be slow
if cv, ok := v.(interface {
CachedPath() string
}); ok {
mp.Source = cv.CachedPath()
}
}

binds[mp.Destination] = true
mountPoints[mp.Destination] = mp
}

container.Lock()

// 4. Cleanup old volumes that are about to be reassigned.
Expand Down Expand Up @@ -183,3 +230,47 @@ func (daemon *Daemon) lazyInitializeVolume(containerID string, m *volume.MountPo
}
return nil
}

func backportMountSpec(container *container.Container) error {
for target, m := range container.MountPoints {
if m.Spec.Type != "" {
// if type is set on even one mount, no need to migrate
return nil
}
if m.Name != "" {
m.Type = mounttypes.TypeVolume
m.Spec.Type = mounttypes.TypeVolume

// make sure this is not an anyonmous volume before setting the spec source
if _, exists := container.Config.Volumes[target]; !exists {
m.Spec.Source = m.Name
}
if container.HostConfig.VolumeDriver != "" {
m.Spec.VolumeOptions = &mounttypes.VolumeOptions{
DriverConfig: &mounttypes.Driver{Name: container.HostConfig.VolumeDriver},
}
}
if strings.Contains(m.Mode, "nocopy") {
if m.Spec.VolumeOptions == nil {
m.Spec.VolumeOptions = &mounttypes.VolumeOptions{}
}
m.Spec.VolumeOptions.NoCopy = true
}
} else {
m.Type = mounttypes.TypeBind
m.Spec.Type = mounttypes.TypeBind
m.Spec.Source = m.Source
if m.Propagation != "" {
m.Spec.BindOptions = &mounttypes.BindOptions{
Propagation: m.Propagation,
}
}
}

m.Spec.Target = m.Destination
if !m.RW {
m.Spec.ReadOnly = true
}
}
return container.ToDiskLocking()
}
3 changes: 1 addition & 2 deletions daemon/volumes_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,10 @@ func sortMounts(m []container.Mount) []container.Mount {
// setBindModeIfNull is platform specific processing to ensure the
// shared mode is set to 'z' if it is null. This is called in the case
// of processing a named volume and not a typical bind.
func setBindModeIfNull(bind *volume.MountPoint) *volume.MountPoint {
func setBindModeIfNull(bind *volume.MountPoint) {
if bind.Mode == "" {
bind.Mode = "z"
}
return bind
}

// migrateVolume links the contents of a volume created pre Docker 1.7
Expand Down
4 changes: 2 additions & 2 deletions daemon/volumes_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er

// setBindModeIfNull is platform specific processing which is a no-op on
// Windows.
func setBindModeIfNull(bind *volume.MountPoint) *volume.MountPoint {
return bind
func setBindModeIfNull(bind *volume.MountPoint) {
return
}
1 change: 1 addition & 0 deletions docs/reference/api/docker_remote_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ This section lists each version from latest to oldest. Each listing includes a
* `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.
* `POST /containers/create/` and `POST /containers/(name)/update` now validates restart policies.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah oups… I did add a trailing slash there 😓

* `POST /containers/create` now validates IPAMConfig in NetworkingConfig, and returns error for invalid IPv4 and IPv6 addresses (`--ip` and `--ip6` in `docker create/run`).
* `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`

### v1.24 API changes

Expand Down
6 changes: 4 additions & 2 deletions docs/reference/api/docker_remote_api_v1.24.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@ Create a container
"StorageOpt": {},
"CgroupParent": "",
"VolumeDriver": "",
"ShmSize": 67108864
"ShmSize": 67108864,
"Mounts": []
},
"NetworkingConfig": {
"EndpointsConfig": {
Expand Down Expand Up @@ -610,7 +611,8 @@ Return low-level information on the container `id`
"VolumesFrom": null,
"Ulimits": [{}],
"VolumeDriver": "",
"ShmSize": 67108864
"ShmSize": 67108864,
"Mounts": []
},
"HostnamePath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hostname",
"HostsPath": "/var/lib/docker/containers/ba033ac4401106a3b513bc9d639eee123ad78ca3616b921167cd74b20e25ed39/hosts",
Expand Down
18 changes: 18 additions & 0 deletions docs/reference/api/docker_remote_api_v1.25.md
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,24 @@ Create a container
- **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.
- **VolumeDriver** - Driver that this container users to mount volumes.
- **ShmSize** - Size of `/dev/shm` in bytes. The size must be greater than 0. If omitted the system uses 64MB.
- **Mounts** – Specification for mounts to be added to the container.
- **Target** – Container path.
- **Source** – Mount source (e.g. a volume name, a host path).
- **Type** – The mount type (`bind`, or `volume`).
Available types (for the `Type` field):
- **bind** - Mounts a file or directory from the host into the container. Must exist prior to creating the container.
- **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.
- **ReadOnly** – A boolean indicating whether the mount should be read-only.
- **BindOptions** - Optional configuration for the `bind` type.
- **Propagation** – A propagation mode with the value `[r]private`, `[r]shared`, or `[r]slave`.
- **VolumeOptions** – Optional configuration for the `volume` type.
- **NoCopy** – A boolean indicating if volume should be
populated with the data from the target. (Default false)
- **Labels** – User-defined name and labels for the volume as key/value pairs: `{"name": "value"}`
- **DriverConfig** – Map of driver-specific options.
- **Name** - Name of the driver to use to create the volume.
- **Options** - key/value map of driver specific options.


**Query parameters**:

Expand Down
Loading