mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #13587 from rhatdan/volume-tmpfs
Add tmpfs as a valid volume source command.
This commit is contained in:
commit
d4be46def4
24 changed files with 248 additions and 11 deletions
|
@ -66,6 +66,7 @@ RUN apt-get update && apt-get install -y \
|
|||
ubuntu-zfs \
|
||||
xfsprogs \
|
||||
libzfs-dev \
|
||||
tar \
|
||||
--no-install-recommends \
|
||||
&& ln -snf /usr/bin/clang-3.8 /usr/local/bin/clang \
|
||||
&& ln -snf /usr/bin/clang++-3.8 /usr/local/bin/clang++
|
||||
|
|
|
@ -1394,6 +1394,7 @@ _docker_run() {
|
|||
--restart
|
||||
--security-opt
|
||||
--stop-signal
|
||||
--tmpfs
|
||||
--ulimit
|
||||
--user -u
|
||||
--uts
|
||||
|
@ -1443,7 +1444,7 @@ _docker_run() {
|
|||
_filedir
|
||||
return
|
||||
;;
|
||||
--device|--volume|-v)
|
||||
--device|--tmpfs|--volume|-v)
|
||||
case "$cur" in
|
||||
*:*)
|
||||
# TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine)
|
||||
|
|
|
@ -339,6 +339,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l sig-proxy -d 'P
|
|||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l stop-signal -d 'Signal to kill a container'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s t -l tty -d 'Allocate a pseudo-TTY'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s u -l user -d 'Username or UID'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l tmpfs -d 'Mount tmpfs on a directory'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s v -l volume -d 'Bind mount a volume (e.g., from the host: -v /host:/container, from Docker: -v /container)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l volumes-from -d 'Mount volumes from the specified container(s)'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s w -l workdir -d 'Working directory inside the container'
|
||||
|
|
|
@ -491,6 +491,7 @@ __docker_subcommand() {
|
|||
"($help)*--security-opt=[Security options]:security option: "
|
||||
"($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]"
|
||||
"($help -u --user)"{-u=,--user=}"[Username or UID]:user:_users"
|
||||
"($help)--tmpfs[mount tmpfs] "
|
||||
"($help)*-v[Bind mount a volume]:volume: "
|
||||
"($help)--volume-driver=[Optional volume driver for the container]:volume driver:(local)"
|
||||
"($help)*--volumes-from=[Mount volumes from the specified container]:volume: "
|
||||
|
|
|
@ -1534,3 +1534,15 @@ func (container *Container) unmountVolumes(forceSyscall bool) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) tmpfsMounts() []execdriver.Mount {
|
||||
var mounts []execdriver.Mount
|
||||
for dest, data := range container.hostConfig.Tmpfs {
|
||||
mounts = append(mounts, execdriver.Mount{
|
||||
Source: "tmpfs",
|
||||
Destination: dest,
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
return mounts
|
||||
}
|
||||
|
|
|
@ -191,6 +191,10 @@ func (container *Container) ipcMounts() []execdriver.Mount {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (container *Container) tmpfsMounts() []execdriver.Mount {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDefaultRouteMtu() (int, error) {
|
||||
return -1, errSystemNotSupported
|
||||
}
|
||||
|
|
|
@ -137,4 +137,5 @@ type CommonCommand struct {
|
|||
Resources *Resources `json:"resources"`
|
||||
Rootfs string `json:"rootfs"` // root fs of the container
|
||||
WorkingDir string `json:"working_dir"`
|
||||
TmpDir string `json:"tmpdir"` // Directory used to store docker tmpdirs.
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ type Mount struct {
|
|||
Writable bool `json:"writable"`
|
||||
Private bool `json:"private"`
|
||||
Slave bool `json:"slave"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
// Resources contains all resource configs for a driver.
|
||||
|
|
|
@ -4,10 +4,13 @@ package native
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
derr "github.com/docker/docker/errors"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/apparmor"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
|
@ -288,6 +291,36 @@ func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) e
|
|||
container.Mounts = defaultMounts
|
||||
|
||||
for _, m := range c.Mounts {
|
||||
for _, cm := range container.Mounts {
|
||||
if cm.Destination == m.Destination {
|
||||
return derr.ErrorCodeMountDup.WithArgs(m.Destination)
|
||||
}
|
||||
}
|
||||
|
||||
if m.Source == "tmpfs" {
|
||||
var (
|
||||
data = "size=65536k"
|
||||
flags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
|
||||
err error
|
||||
)
|
||||
fulldest := filepath.Join(c.Rootfs, m.Destination)
|
||||
if m.Data != "" {
|
||||
flags, data, err = mount.ParseTmpfsOptions(m.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
container.Mounts = append(container.Mounts, &configs.Mount{
|
||||
Source: m.Source,
|
||||
Destination: m.Destination,
|
||||
Data: data,
|
||||
Device: "tmpfs",
|
||||
Flags: flags,
|
||||
PremountCmds: genTmpfsPremountCmd(c.TmpDir, fulldest, m.Destination),
|
||||
PostmountCmds: genTmpfsPostmountCmd(c.TmpDir, fulldest, m.Destination),
|
||||
})
|
||||
continue
|
||||
}
|
||||
flags := syscall.MS_BIND | syscall.MS_REC
|
||||
if !m.Writable {
|
||||
flags |= syscall.MS_RDONLY
|
||||
|
|
|
@ -5,6 +5,7 @@ package native
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
@ -128,6 +129,13 @@ type execOutput struct {
|
|||
// it calls libcontainer APIs to run a container.
|
||||
func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
||||
destroyed := false
|
||||
var err error
|
||||
c.TmpDir, err = ioutil.TempDir("", c.ID)
|
||||
if err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
defer os.RemoveAll(c.TmpDir)
|
||||
|
||||
// take the Command and populate the libcontainer.Config from it
|
||||
container, err := d.createContainer(c, hooks)
|
||||
if err != nil {
|
||||
|
|
56
daemon/execdriver/native/tmpfs.go
Normal file
56
daemon/execdriver/native/tmpfs.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
func genTmpfsPremountCmd(tmpDir string, fullDest string, dest string) []configs.Command {
|
||||
var premount []configs.Command
|
||||
tarPath, err := exec.LookPath("tar")
|
||||
if err != nil {
|
||||
logrus.Warn("tar command is not available for tmpfs mount: %s", err)
|
||||
return premount
|
||||
}
|
||||
if _, err = exec.LookPath("rm"); err != nil {
|
||||
logrus.Warn("rm command is not available for tmpfs mount: %s", err)
|
||||
return premount
|
||||
}
|
||||
tarFile := fmt.Sprintf("%s/%s.tar", tmpDir, strings.Replace(dest, "/", "_", -1))
|
||||
if _, err := os.Stat(fullDest); err == nil {
|
||||
premount = append(premount, configs.Command{
|
||||
Path: tarPath,
|
||||
Args: []string{"-cf", tarFile, "-C", fullDest, "."},
|
||||
})
|
||||
}
|
||||
return premount
|
||||
}
|
||||
|
||||
func genTmpfsPostmountCmd(tmpDir string, fullDest string, dest string) []configs.Command {
|
||||
var postmount []configs.Command
|
||||
tarPath, err := exec.LookPath("tar")
|
||||
if err != nil {
|
||||
return postmount
|
||||
}
|
||||
rmPath, err := exec.LookPath("rm")
|
||||
if err != nil {
|
||||
return postmount
|
||||
}
|
||||
if _, err := os.Stat(fullDest); os.IsNotExist(err) {
|
||||
return postmount
|
||||
}
|
||||
tarFile := fmt.Sprintf("%s/%s.tar", tmpDir, strings.Replace(dest, "/", "_", -1))
|
||||
postmount = append(postmount, configs.Command{
|
||||
Path: tarPath,
|
||||
Args: []string{"-xf", tarFile, "-C", fullDest, "."},
|
||||
})
|
||||
return append(postmount, configs.Command{
|
||||
Path: rmPath,
|
||||
Args: []string{"-f", tarFile},
|
||||
})
|
||||
}
|
|
@ -130,6 +130,7 @@ func (daemon *Daemon) containerStart(container *Container) (err error) {
|
|||
return err
|
||||
}
|
||||
mounts = append(mounts, container.ipcMounts()...)
|
||||
mounts = append(mounts, container.tmpfsMounts()...)
|
||||
|
||||
container.command.Mounts = mounts
|
||||
if err := daemon.waitForStart(container); err != nil {
|
||||
|
|
|
@ -121,7 +121,7 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
|
|||
}
|
||||
|
||||
if binds[bind.Destination] {
|
||||
return derr.ErrorCodeVolumeDup.WithArgs(bind.Destination)
|
||||
return derr.ErrorCodeMountDup.WithArgs(bind.Destination)
|
||||
}
|
||||
|
||||
if len(bind.Name) > 0 && len(bind.Driver) > 0 {
|
||||
|
|
|
@ -153,6 +153,14 @@ flag exists to allow special use-cases, like running Docker within Docker.
|
|||
The `-w` lets the command being executed inside directory given, here
|
||||
`/path/to/dir/`. If the path does not exists it is created inside the container.
|
||||
|
||||
### mount tmpfs (--tmpfs)
|
||||
|
||||
$ docker run -d --tmpfs /run:rw,noexec,nosuid,size=65536k my_image
|
||||
|
||||
The --tmpfs flag mounts a tmpfs into the container with the rw,noexec,nosuid,size=65536k options.
|
||||
|
||||
Underlying content from the /run in the my_image image is copied into tmpfs.
|
||||
|
||||
### Mount volume (-v, --read-only)
|
||||
|
||||
$ docker run -v `pwd`:`pwd` -w `pwd` -i -t ubuntu pwd
|
||||
|
|
|
@ -1298,6 +1298,14 @@ above, or already defined by the developer with a Dockerfile `ENV`:
|
|||
|
||||
Similarly the operator can set the **hostname** with `-h`.
|
||||
|
||||
### TMPFS (mount tmpfs filesystems)
|
||||
|
||||
--tmpfs=[]: Create a tmpfs mount with: container-dir[:<options>], where the options are identical to the Linux `mount -t tmpfs -o` command.
|
||||
|
||||
Underlying content from the "container-dir" is copied into tmpfs.
|
||||
|
||||
$ docker run -d --tmpfs /run:rw,noexec,nosuid,size=65536k my_image
|
||||
|
||||
### VOLUME (shared filesystems)
|
||||
|
||||
-v=[]: Create a bind mount with: [host-src:]container-dest[:<options>], where
|
||||
|
|
|
@ -444,12 +444,12 @@ var (
|
|||
HTTPStatusCode: http.StatusInternalServerError,
|
||||
})
|
||||
|
||||
// ErrorCodeVolumeDup is generated when we try to mount two volumes
|
||||
// ErrorCodeMountDup is generated when we try to mount two mounts points
|
||||
// to the same path.
|
||||
ErrorCodeVolumeDup = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "VOLUMEDUP",
|
||||
Message: "Duplicate bind mount '%s'",
|
||||
Description: "An attempt was made to mount a volume but the specified destination location is already used in a previous mount",
|
||||
ErrorCodeMountDup = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||
Value: "MOUNTDUP",
|
||||
Message: "Duplicate mount point '%s'",
|
||||
Description: "An attempt was made to mount a content but the specified destination location is already used in a previous mount",
|
||||
HTTPStatusCode: http.StatusInternalServerError,
|
||||
})
|
||||
|
||||
|
|
|
@ -212,7 +212,7 @@ func (s *DockerSuite) TestContainerApiStartDupVolumeBinds(c *check.C) {
|
|||
status, body, err := sockRequest("POST", "/containers/"+name+"/start", config)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(status, checker.Equals, http.StatusInternalServerError)
|
||||
c.Assert(string(body), checker.Contains, "Duplicate bind", check.Commentf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err))
|
||||
c.Assert(string(body), checker.Contains, "Duplicate mount point", check.Commentf("Expected failure due to duplicate bind mounts to same path, instead got: %q with error: %v", string(body), err))
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) {
|
||||
|
|
|
@ -375,10 +375,10 @@ func (s *DockerSuite) TestRunNoDupVolumes(c *check.C) {
|
|||
mountstr2 := path2 + someplace
|
||||
|
||||
if out, _, err := dockerCmdWithError("run", "-v", mountstr1, "-v", mountstr2, "busybox", "true"); err == nil {
|
||||
c.Fatal("Expected error about duplicate volume definitions")
|
||||
c.Fatal("Expected error about duplicate mount definitions")
|
||||
} else {
|
||||
if !strings.Contains(out, "Duplicate bind mount") {
|
||||
c.Fatalf("Expected 'duplicate volume' error, got %v", out)
|
||||
if !strings.Contains(out, "Duplicate mount point") {
|
||||
c.Fatalf("Expected 'duplicate mount point' error, got %v", out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -438,3 +438,21 @@ func (s *DockerSuite) TestRunWithShmSize(c *check.C) {
|
|||
c.Assert(err, check.IsNil)
|
||||
c.Assert(shmSize, check.Equals, "1073741824")
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestRunTmpfsMounts(c *check.C) {
|
||||
// TODO Windows (Post TP4): This test cannot run on a Windows daemon as
|
||||
// Windows does not support tmpfs mounts.
|
||||
testRequires(c, DaemonIsLinux)
|
||||
if out, _, err := dockerCmdWithError("run", "--tmpfs", "/run", "busybox", "touch", "/run/somefile"); err != nil {
|
||||
c.Fatalf("/run directory not mounted on tmpfs %q %s", err, out)
|
||||
}
|
||||
if out, _, err := dockerCmdWithError("run", "--tmpfs", "/run:noexec,nosuid,rw,size=5k,mode=700", "busybox", "touch", "/run/somefile"); err != nil {
|
||||
c.Fatalf("/run failed to mount on tmpfs with valid options %q %s", err, out)
|
||||
}
|
||||
if _, _, err := dockerCmdWithError("run", "--tmpfs", "/run:foobar", "busybox", "touch", "/run/somefile"); err == nil {
|
||||
c.Fatalf("/run mounted on tmpfs when it should have vailed within invalid mount option")
|
||||
}
|
||||
if _, _, err := dockerCmdWithError("run", "--tmpfs", "/run", "-v", "/run:/run", "busybox", "touch", "/run/somefile"); err == nil {
|
||||
c.Fatalf("Should have generated an error saying Duplicate mount points")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ docker-create - Create a new container
|
|||
[**--stop-signal**[=*SIGNAL*]]
|
||||
[**--shm-size**[=*[]*]]
|
||||
[**-t**|**--tty**[=*false*]]
|
||||
[**--tmpfs**[=*[CONTAINER-DIR[:<OPTIONS>]*]]
|
||||
[**-u**|**--user**[=*USER*]]
|
||||
[**--ulimit**[=*[]*]]
|
||||
[**--uts**[=*[]*]]
|
||||
|
@ -271,6 +272,20 @@ This value should always larger than **-m**, so you should always use this with
|
|||
**-t**, **--tty**=*true*|*false*
|
||||
Allocate a pseudo-TTY. The default is *false*.
|
||||
|
||||
**--tmpfs**=[] Create a tmpfs mount
|
||||
|
||||
Mount a temporary filesystem (`tmpfs`) mount into a container, for example:
|
||||
|
||||
$ docker run -d --tmpfs /tmp:rw,size=787448k,mode=1777 my_image
|
||||
|
||||
This command mounts a `tmpfs` at `/tmp` within the container. The mount copies
|
||||
the underlying content of `my_image` into `/tmp`. For example if there was a
|
||||
directory `/tmp/content` in the base image, docker will copy this directory and
|
||||
all of its content on top of the tmpfs mounted on `/tmp`. The supported mount
|
||||
options are the same as the Linux default `mount` flags. If you do not specify
|
||||
any options, the systems uses the following options:
|
||||
`rw,noexec,nosuid,nodev,size=65536k`.
|
||||
|
||||
**-u**, **--user**=""
|
||||
Username or UID
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ docker-run - Run a command in a new container
|
|||
[**--shm-size**[=*[]*]]
|
||||
[**--sig-proxy**[=*true*]]
|
||||
[**-t**|**--tty**[=*false*]]
|
||||
[**--tmpfs**[=*[CONTAINER-DIR[:<OPTIONS>]*]]
|
||||
[**-u**|**--user**[=*USER*]]
|
||||
[**-v**|**--volume**[=*[]*]]
|
||||
[**--ulimit**[=*[]*]]
|
||||
|
@ -436,6 +437,20 @@ interactive shell. The default is false.
|
|||
The **-t** option is incompatible with a redirection of the docker client
|
||||
standard input.
|
||||
|
||||
**--tmpfs**=[] Create a tmpfs mount
|
||||
|
||||
Mount a temporary filesystem (`tmpfs`) mount into a container, for example:
|
||||
|
||||
$ docker run -d --tmpfs /tmp:rw,size=787448k,mode=1777 my_image
|
||||
|
||||
This command mounts a `tmpfs` at `/tmp` within the container. The mount copies
|
||||
the underlying content of `my_image` into `/tmp`. For example if there was a
|
||||
directory `/tmp/content` in the base image, docker will copy this directory and
|
||||
all of its content on top of the tmpfs mounted on `/tmp`. The supported mount
|
||||
options are the same as the Linux default `mount` flags. If you do not specify
|
||||
any options, the systems uses the following options:
|
||||
`rw,noexec,nosuid,nodev,size=65536k`.
|
||||
|
||||
**-u**, **--user**=""
|
||||
Sets the username or UID used and optionally the groupname or GID for the specified command.
|
||||
|
||||
|
@ -552,6 +567,19 @@ the exit codes follow the `chroot` standard, see below:
|
|||
|
||||
# EXAMPLES
|
||||
|
||||
## Running container in read-only mode
|
||||
|
||||
During container image development, containers often need to write to the image
|
||||
content. Installing packages into /usr, for example. In production,
|
||||
applications seldom need to write to the image. Container applications write
|
||||
to volumes if they need to write to file systems at all. Applications can be
|
||||
made more secure by running them in read-only mode using the --read-only switch.
|
||||
This protects the containers image from modification. Read only containers may
|
||||
still need to write temporary data. The best way to handle this is to mount
|
||||
tmpfs directories on /run and /tmp.
|
||||
|
||||
# docker run --read-only --tmpfs /run --tmpfs /tmp -i -t fedora /bin/bash
|
||||
|
||||
## Exposing log messages from the container to the host's log
|
||||
|
||||
If you want messages that are logged in your container to show up in the host's
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -67,3 +68,24 @@ func parseOptions(options string) (int, string) {
|
|||
}
|
||||
return flag, strings.Join(data, ",")
|
||||
}
|
||||
|
||||
// ParseTmpfsOptions parse fstab type mount options into flags and data
|
||||
func ParseTmpfsOptions(options string) (int, string, error) {
|
||||
flags, data := parseOptions(options)
|
||||
validFlags := map[string]bool{
|
||||
"size": true,
|
||||
"mode": true,
|
||||
"uid": true,
|
||||
"gid": true,
|
||||
"nr_inodes": true,
|
||||
"nr_blocks": true,
|
||||
"mpol": true,
|
||||
}
|
||||
for _, o := range strings.Split(data, ",") {
|
||||
opt := strings.SplitN(o, "=", 2)
|
||||
if !validFlags[opt[0]] {
|
||||
return 0, "", fmt.Errorf("Invalid tmpfs option %q", opt)
|
||||
}
|
||||
}
|
||||
return flags, data, nil
|
||||
}
|
||||
|
|
|
@ -217,6 +217,7 @@ type HostConfig struct {
|
|||
PublishAllPorts bool // Should docker publish all exposed port for the container
|
||||
ReadonlyRootfs bool // Is the container root filesystem in read-only
|
||||
SecurityOpt []string // List of string values to customize labels for MLS systems, such as SELinux.
|
||||
Tmpfs map[string]string `json:",omitempty"` // List of tmpfs (mounts) used for the container
|
||||
UTSMode UTSMode // UTS namespace to use for the container
|
||||
ShmSize *int64 // Total shm memory usage
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/docker/docker/opts"
|
||||
flag "github.com/docker/docker/pkg/mflag"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/docker/pkg/nat"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/signal"
|
||||
|
@ -50,6 +51,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
|||
// FIXME: use utils.ListOpts for attach and volumes?
|
||||
flAttach = opts.NewListOpts(opts.ValidateAttach)
|
||||
flVolumes = opts.NewListOpts(nil)
|
||||
flTmpfs = opts.NewListOpts(nil)
|
||||
flBlkioWeightDevice = opts.NewWeightdeviceOpt(opts.ValidateWeightDevice)
|
||||
flLinks = opts.NewListOpts(opts.ValidateLink)
|
||||
flEnv = opts.NewListOpts(opts.ValidateEnv)
|
||||
|
@ -111,6 +113,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
|||
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR")
|
||||
cmd.Var(&flBlkioWeightDevice, []string{"-blkio-weight-device"}, "Block IO weight (relative device weight)")
|
||||
cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume")
|
||||
cmd.Var(&flTmpfs, []string{"-tmpfs"}, "Mount a tmpfs directory")
|
||||
cmd.Var(&flLinks, []string{"-link"}, "Add link to another container")
|
||||
cmd.Var(&flDevices, []string{"-device"}, "Add a host device to the container")
|
||||
cmd.Var(&flLabels, []string{"l", "-label"}, "Set meta data on a container")
|
||||
|
@ -221,6 +224,19 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
|||
}
|
||||
}
|
||||
|
||||
// Can't evalute options passed into --tmpfs until we actually mount
|
||||
tmpfs := make(map[string]string)
|
||||
for _, t := range flTmpfs.GetAll() {
|
||||
if arr := strings.SplitN(t, ":", 2); len(arr) > 1 {
|
||||
if _, _, err := mount.ParseTmpfsOptions(arr[1]); err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
tmpfs[arr[0]] = arr[1]
|
||||
} else {
|
||||
tmpfs[arr[0]] = ""
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
parsedArgs = cmd.Args()
|
||||
runCmd *stringutils.StrSlice
|
||||
|
@ -396,6 +412,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
|||
Isolation: IsolationLevel(*flIsolation),
|
||||
ShmSize: parsedShm,
|
||||
Resources: resources,
|
||||
Tmpfs: tmpfs,
|
||||
}
|
||||
|
||||
// When allocating stdin in attached mode, close stdin at client disconnect
|
||||
|
|
Loading…
Add table
Reference in a new issue