зеркало из https://github.com/microsoft/docker.git
Add explicit flags for volume cp/no-cp
This allows a user to specify explicitly to enable automatic copying of data from the container path to the volume path. This does not change the default behavior of automatically copying, but does allow a user to disable it at runtime. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Родитель
c22d09f563
Коммит
b0ac69b67e
|
@ -552,6 +552,7 @@ func (container *Container) AddMountPointWithVolume(destination string, vol volu
|
|||
Destination: destination,
|
||||
RW: rw,
|
||||
Volume: vol,
|
||||
CopyData: volume.DefaultCopyMode,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -185,12 +185,8 @@ func (container *Container) CopyImagePathContent(v volume.Volume, destination st
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := copyExistingContents(rootfs, path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return v.Unmount()
|
||||
defer v.Unmount()
|
||||
return copyExistingContents(rootfs, path)
|
||||
}
|
||||
|
||||
// ShmResourcePath returns path to shm
|
||||
|
|
|
@ -63,8 +63,7 @@ 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 {
|
||||
// skip binds and volumes referenced by other containers (ie, volumes-from)
|
||||
if mnt.Driver == "" || mnt.Volume == nil || len(daemon.volumes.Refs(mnt.Volume)) > 1 {
|
||||
if !mnt.CopyData || mnt.Volume == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
|||
bind = setBindModeIfNull(bind)
|
||||
}
|
||||
}
|
||||
|
||||
if label.RelabelNeeded(bind.Mode) {
|
||||
if err := label.Relabel(bind.Source, container.MountLabel, label.IsShared(bind.Mode)); err != nil {
|
||||
return err
|
||||
|
|
|
@ -126,6 +126,7 @@ This section lists each version from latest to oldest. Each listing includes a
|
|||
* `POST /containers/create` now takes `PidsLimit` field, if the kernel is >= 4.3 and the pids cgroup is supported.
|
||||
* `GET /containers/(id or name)/stats` now returns `pids_stats`, if the kernel is >= 4.3 and the pids cgroup is supported.
|
||||
* `POST /containers/create` now allows you to override usernamespaces remapping and use privileged options for the container.
|
||||
* `POST /containers/create` now allows specifying `nocopy` for named volumes, which disables automatic copying from the container path to the volume.
|
||||
* `POST /auth` now returns an `IdentityToken` when supported by a registry.
|
||||
* `POST /containers/create` with both `Hostname` and `Domainname` fields specified will result in the container's hostname being set to `Hostname`, rather than `Hostname.Domainname`.
|
||||
|
||||
|
|
|
@ -90,10 +90,10 @@ Creates a new container.
|
|||
--uts="" UTS namespace to use
|
||||
-v, --volume=[host-src:]container-dest[:<options>]
|
||||
Bind mount a volume. The comma-delimited
|
||||
`options` are [rw|ro], [z|Z], or
|
||||
[[r]shared|[r]slave|[r]private]. The
|
||||
'host-src' is an absolute path or a name
|
||||
value.
|
||||
`options` are [rw|ro], [z|Z],
|
||||
[[r]shared|[r]slave|[r]private], and
|
||||
[nocopy]. The 'host-src' is an absolute path
|
||||
or a name value.
|
||||
--volume-driver="" Container's volume driver
|
||||
--volumes-from=[] Mount volumes from the specified container(s)
|
||||
-w, --workdir="" Working directory inside the container
|
||||
|
|
|
@ -92,10 +92,10 @@ parent = "smn_cli"
|
|||
--uts="" UTS namespace to use
|
||||
-v, --volume=[host-src:]container-dest[:<options>]
|
||||
Bind mount a volume. The comma-delimited
|
||||
`options` are [rw|ro], [z|Z], or
|
||||
[[r]shared|[r]slave|[r]private]. The
|
||||
'host-src' is an absolute path or a name
|
||||
value.
|
||||
`options` are [rw|ro], [z|Z],
|
||||
[[r]shared|[r]slave|[r]private], and
|
||||
[nocopy]. The 'host-src' is an absolute path
|
||||
or a name value.
|
||||
--volume-driver="" Container's volume driver
|
||||
--volumes-from=[] Mount volumes from the specified container(s)
|
||||
-w, --workdir="" Working directory inside the container
|
||||
|
|
|
@ -1400,13 +1400,18 @@ The example below mounts an empty tmpfs into the container with the `rw`,
|
|||
### VOLUME (shared filesystems)
|
||||
|
||||
-v, --volume=[host-src:]container-dest[:<options>]: Bind mount a volume.
|
||||
The comma-delimited `options` are [rw|ro], [z|Z], or
|
||||
[[r]shared|[r]slave|[r]private]. The 'host-src' is an absolute path or a
|
||||
name value.
|
||||
The comma-delimited `options` are [rw|ro], [z|Z],
|
||||
[[r]shared|[r]slave|[r]private], and [nocopy].
|
||||
The 'host-src' is an absolute path or a name value.
|
||||
|
||||
If neither 'rw' or 'ro' is specified then the volume is mounted in
|
||||
read-write mode.
|
||||
|
||||
The `nocopy` modes is used to disable automatic copying requested volume
|
||||
path in the container to the volume storage location.
|
||||
For named volumes, `copy` is the default mode. Copy modes are not supported
|
||||
for bind-mounted volumes.
|
||||
|
||||
--volumes-from="": Mount all volumes from the given container(s)
|
||||
|
||||
> **Note**:
|
||||
|
|
|
@ -4249,6 +4249,44 @@ func (s *DockerSuite) TestRunVolumeWithOneCharacter(c *check.C) {
|
|||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "-v", "/tmp/q:/foo", "busybox", "sh", "-c", "find /foo")
|
||||
fmt.Printf("OUTPUT: %+v", out)
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "/foo")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunVolumeCopyFlag(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux) // Windows does not support copying data from image to the volume
|
||||
_, err := buildImage("volumecopy",
|
||||
`FROM busybox
|
||||
RUN mkdir /foo && echo hello > /foo/bar
|
||||
CMD cat /foo/bar`,
|
||||
true,
|
||||
)
|
||||
c.Assert(err, checker.IsNil)
|
||||
|
||||
dockerCmd(c, "volume", "create", "--name=test")
|
||||
|
||||
// test with the nocopy flag
|
||||
out, _, err := dockerCmdWithError("run", "-v", "test:/foo:nocopy", "volumecopy")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
// test default behavior which is to copy for non-binds
|
||||
out, _ = dockerCmd(c, "run", "-v", "test:/foo", "volumecopy")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "hello")
|
||||
// error out when the volume is already populated
|
||||
out, _, err = dockerCmdWithError("run", "-v", "test:/foo:copy", "volumecopy")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
// do not error out when copy isn't explicitly set even though it's already populated
|
||||
out, _ = dockerCmd(c, "run", "-v", "test:/foo", "volumecopy")
|
||||
c.Assert(strings.TrimSpace(out), checker.Equals, "hello")
|
||||
|
||||
// do not allow copy modes on volumes-from
|
||||
dockerCmd(c, "run", "--name=test", "-v", "/foo", "busybox", "true")
|
||||
out, _, err = dockerCmdWithError("run", "--volumes-from=test:copy", "busybox", "true")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
out, _, err = dockerCmdWithError("run", "--volumes-from=test:nocopy", "busybox", "true")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
|
||||
// do not allow copy modes on binds
|
||||
out, _, err = dockerCmdWithError("run", "-v", "/foo:/bar:copy", "busybox", "true")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
out, _, err = dockerCmdWithError("run", "-v", "/foo:/bar:nocopy", "busybox", "true")
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
}
|
||||
|
|
|
@ -434,6 +434,10 @@ change propagation properties of source mount. Say `/` is source mount for
|
|||
> is `slave`, you may not be able to use the `shared` or `rshared` propagation on
|
||||
> a volume.
|
||||
|
||||
|
||||
To disable automatic copying of data from the container path to the volume, use
|
||||
the `nocopy` flag. The `nocopy` flag can be set on bind mounts and named volumes.
|
||||
|
||||
**--volume-driver**=""
|
||||
Container's volume driver. This driver creates volumes specified either from
|
||||
a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag.
|
||||
|
|
|
@ -531,6 +531,7 @@ any options, the systems uses the following options:
|
|||
* [rw|ro]
|
||||
* [z|Z]
|
||||
* [`[r]shared`|`[r]slave`|`[r]private`]
|
||||
* [nocopy]
|
||||
|
||||
The `CONTAINER-DIR` must be an absolute path such as `/src/docs`. The `HOST-DIR`
|
||||
can be an absolute path or a `name` value. A `name` value must start with an
|
||||
|
@ -603,6 +604,9 @@ change propagation properties of source mount. Say `/` is source mount for
|
|||
> is `slave`, you may not be able to use the `shared` or `rshared` propagation on
|
||||
> a volume.
|
||||
|
||||
To disable automatic copying of data from the container path to the volume, use
|
||||
the `nocopy` flag. The `nocopy` flag can be set on bind mounts and named volumes.
|
||||
|
||||
**--volume-driver**=""
|
||||
Container's volume driver. This driver creates volumes specified either from
|
||||
a Dockerfile's `VOLUME` instruction or from the `docker run -v` flag.
|
||||
|
|
|
@ -60,6 +60,11 @@ type MountPoint struct {
|
|||
// Note Propagation is not used on Windows
|
||||
Propagation string // Mount propagation string
|
||||
Named bool // specifies if the mountpoint was specified by name
|
||||
|
||||
// Specifies if data should be copied from the container before the first mount
|
||||
// Use a pointer here so we can tell if the user set this value explicitly
|
||||
// This allows us to error out when the user explicitly enabled copy but we can't copy due to the volume being populated
|
||||
CopyData bool `json:"-"`
|
||||
}
|
||||
|
||||
// Setup sets up a mount point by either mounting the volume if it is
|
||||
|
@ -115,6 +120,10 @@ func ParseVolumesFrom(spec string) (string, string, error) {
|
|||
if HasPropagation(mode) {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
// Do not allow copy modes on volumes-from
|
||||
if _, isSet := getCopyMode(mode); isSet {
|
||||
return "", "", errInvalidMode(mode)
|
||||
}
|
||||
}
|
||||
return id, mode, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package volume
|
||||
|
||||
import "strings"
|
||||
|
||||
const (
|
||||
// DefaultCopyMode is the copy mode used by default for normal/named volumes
|
||||
DefaultCopyMode = true
|
||||
)
|
||||
|
||||
// {<copy mode>=isEnabled}
|
||||
var copyModes = map[string]bool{
|
||||
"nocopy": false,
|
||||
}
|
||||
|
||||
func copyModeExists(mode string) bool {
|
||||
_, exists := copyModes[mode]
|
||||
return exists
|
||||
}
|
||||
|
||||
// GetCopyMode gets the copy mode from the mode string for mounts
|
||||
func getCopyMode(mode string) (bool, bool) {
|
||||
for _, o := range strings.Split(mode, ",") {
|
||||
if isEnabled, exists := copyModes[o]; exists {
|
||||
return isEnabled, true
|
||||
}
|
||||
}
|
||||
return DefaultCopyMode, false
|
||||
}
|
|
@ -110,6 +110,13 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) {
|
|||
mp.Source = filepath.Clean(source)
|
||||
}
|
||||
|
||||
copyData, isSet := getCopyMode(mp.Mode)
|
||||
// do not allow copy modes on binds
|
||||
if len(name) == 0 && isSet {
|
||||
return nil, errInvalidMode(mp.Mode)
|
||||
}
|
||||
|
||||
mp.CopyData = copyData
|
||||
mp.Name = name
|
||||
|
||||
return mp, nil
|
||||
|
@ -137,23 +144,25 @@ func ValidMountMode(mode string) bool {
|
|||
rwModeCount := 0
|
||||
labelModeCount := 0
|
||||
propagationModeCount := 0
|
||||
copyModeCount := 0
|
||||
|
||||
for _, o := range strings.Split(mode, ",") {
|
||||
if rwModes[o] {
|
||||
switch {
|
||||
case rwModes[o]:
|
||||
rwModeCount++
|
||||
continue
|
||||
} else if labelModes[o] {
|
||||
case labelModes[o]:
|
||||
labelModeCount++
|
||||
continue
|
||||
} else if propagationModes[o] {
|
||||
case propagationModes[o]:
|
||||
propagationModeCount++
|
||||
continue
|
||||
case copyModeExists(o):
|
||||
copyModeCount++
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Only one string for each mode is allowed.
|
||||
if rwModeCount > 1 || labelModeCount > 1 || propagationModeCount > 1 {
|
||||
if rwModeCount > 1 || labelModeCount > 1 || propagationModeCount > 1 || copyModeCount > 1 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
Загрузка…
Ссылка в новой задаче