mirror of https://github.com/docker/docs.git
Merge pull request #13587 from rhatdan/volume-tmpfs
Add tmpfs as a valid volume source command.
This commit is contained in:
commit
d4be46def4
|
@ -66,6 +66,7 @@ RUN apt-get update && apt-get install -y \
|
||||||
ubuntu-zfs \
|
ubuntu-zfs \
|
||||||
xfsprogs \
|
xfsprogs \
|
||||||
libzfs-dev \
|
libzfs-dev \
|
||||||
|
tar \
|
||||||
--no-install-recommends \
|
--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 \
|
||||||
&& 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
|
--restart
|
||||||
--security-opt
|
--security-opt
|
||||||
--stop-signal
|
--stop-signal
|
||||||
|
--tmpfs
|
||||||
--ulimit
|
--ulimit
|
||||||
--user -u
|
--user -u
|
||||||
--uts
|
--uts
|
||||||
|
@ -1443,7 +1444,7 @@ _docker_run() {
|
||||||
_filedir
|
_filedir
|
||||||
return
|
return
|
||||||
;;
|
;;
|
||||||
--device|--volume|-v)
|
--device|--tmpfs|--volume|-v)
|
||||||
case "$cur" in
|
case "$cur" in
|
||||||
*:*)
|
*:*)
|
||||||
# TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine)
|
# 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' -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 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' -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' -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' -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'
|
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)*--security-opt=[Security options]:security option: "
|
||||||
"($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]"
|
"($help -t --tty)"{-t,--tty}"[Allocate a pseudo-tty]"
|
||||||
"($help -u --user)"{-u=,--user=}"[Username or UID]:user:_users"
|
"($help -u --user)"{-u=,--user=}"[Username or UID]:user:_users"
|
||||||
|
"($help)--tmpfs[mount tmpfs] "
|
||||||
"($help)*-v[Bind mount a volume]:volume: "
|
"($help)*-v[Bind mount a volume]:volume: "
|
||||||
"($help)--volume-driver=[Optional volume driver for the container]:volume driver:(local)"
|
"($help)--volume-driver=[Optional volume driver for the container]:volume driver:(local)"
|
||||||
"($help)*--volumes-from=[Mount volumes from the specified container]:volume: "
|
"($help)*--volumes-from=[Mount volumes from the specified container]:volume: "
|
||||||
|
|
|
@ -1534,3 +1534,15 @@ func (container *Container) unmountVolumes(forceSyscall bool) error {
|
||||||
|
|
||||||
return nil
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (container *Container) tmpfsMounts() []execdriver.Mount {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func getDefaultRouteMtu() (int, error) {
|
func getDefaultRouteMtu() (int, error) {
|
||||||
return -1, errSystemNotSupported
|
return -1, errSystemNotSupported
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,4 +137,5 @@ type CommonCommand struct {
|
||||||
Resources *Resources `json:"resources"`
|
Resources *Resources `json:"resources"`
|
||||||
Rootfs string `json:"rootfs"` // root fs of the container
|
Rootfs string `json:"rootfs"` // root fs of the container
|
||||||
WorkingDir string `json:"working_dir"`
|
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"`
|
Writable bool `json:"writable"`
|
||||||
Private bool `json:"private"`
|
Private bool `json:"private"`
|
||||||
Slave bool `json:"slave"`
|
Slave bool `json:"slave"`
|
||||||
|
Data string `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resources contains all resource configs for a driver.
|
// Resources contains all resource configs for a driver.
|
||||||
|
|
|
@ -4,10 +4,13 @@ package native
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
"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/apparmor"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
|
@ -288,6 +291,36 @@ func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) e
|
||||||
container.Mounts = defaultMounts
|
container.Mounts = defaultMounts
|
||||||
|
|
||||||
for _, m := range c.Mounts {
|
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
|
flags := syscall.MS_BIND | syscall.MS_REC
|
||||||
if !m.Writable {
|
if !m.Writable {
|
||||||
flags |= syscall.MS_RDONLY
|
flags |= syscall.MS_RDONLY
|
||||||
|
|
|
@ -5,6 +5,7 @@ package native
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -128,6 +129,13 @@ type execOutput struct {
|
||||||
// it calls libcontainer APIs to run a container.
|
// it calls libcontainer APIs to run a container.
|
||||||
func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
||||||
destroyed := false
|
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
|
// take the Command and populate the libcontainer.Config from it
|
||||||
container, err := d.createContainer(c, hooks)
|
container, err := d.createContainer(c, hooks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -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
|
return err
|
||||||
}
|
}
|
||||||
mounts = append(mounts, container.ipcMounts()...)
|
mounts = append(mounts, container.ipcMounts()...)
|
||||||
|
mounts = append(mounts, container.tmpfsMounts()...)
|
||||||
|
|
||||||
container.command.Mounts = mounts
|
container.command.Mounts = mounts
|
||||||
if err := daemon.waitForStart(container); err != nil {
|
if err := daemon.waitForStart(container); err != nil {
|
||||||
|
|
|
@ -121,7 +121,7 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
|
||||||
}
|
}
|
||||||
|
|
||||||
if binds[bind.Destination] {
|
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 {
|
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
|
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.
|
`/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)
|
### Mount volume (-v, --read-only)
|
||||||
|
|
||||||
$ docker run -v `pwd`:`pwd` -w `pwd` -i -t ubuntu pwd
|
$ 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`.
|
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)
|
### VOLUME (shared filesystems)
|
||||||
|
|
||||||
-v=[]: Create a bind mount with: [host-src:]container-dest[:<options>], where
|
-v=[]: Create a bind mount with: [host-src:]container-dest[:<options>], where
|
||||||
|
|
|
@ -444,12 +444,12 @@ var (
|
||||||
HTTPStatusCode: http.StatusInternalServerError,
|
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.
|
// to the same path.
|
||||||
ErrorCodeVolumeDup = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
ErrorCodeMountDup = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||||
Value: "VOLUMEDUP",
|
Value: "MOUNTDUP",
|
||||||
Message: "Duplicate bind mount '%s'",
|
Message: "Duplicate mount point '%s'",
|
||||||
Description: "An attempt was made to mount a volume but the specified destination location is already used in a previous mount",
|
Description: "An attempt was made to mount a content but the specified destination location is already used in a previous mount",
|
||||||
HTTPStatusCode: http.StatusInternalServerError,
|
HTTPStatusCode: http.StatusInternalServerError,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,7 @@ func (s *DockerSuite) TestContainerApiStartDupVolumeBinds(c *check.C) {
|
||||||
status, body, err := sockRequest("POST", "/containers/"+name+"/start", config)
|
status, body, err := sockRequest("POST", "/containers/"+name+"/start", config)
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
c.Assert(status, checker.Equals, http.StatusInternalServerError)
|
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) {
|
func (s *DockerSuite) TestContainerApiStartVolumesFrom(c *check.C) {
|
||||||
|
|
|
@ -375,10 +375,10 @@ func (s *DockerSuite) TestRunNoDupVolumes(c *check.C) {
|
||||||
mountstr2 := path2 + someplace
|
mountstr2 := path2 + someplace
|
||||||
|
|
||||||
if out, _, err := dockerCmdWithError("run", "-v", mountstr1, "-v", mountstr2, "busybox", "true"); err == nil {
|
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 {
|
} else {
|
||||||
if !strings.Contains(out, "Duplicate bind mount") {
|
if !strings.Contains(out, "Duplicate mount point") {
|
||||||
c.Fatalf("Expected 'duplicate volume' error, got %v", out)
|
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(err, check.IsNil)
|
||||||
c.Assert(shmSize, check.Equals, "1073741824")
|
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*]]
|
[**--stop-signal**[=*SIGNAL*]]
|
||||||
[**--shm-size**[=*[]*]]
|
[**--shm-size**[=*[]*]]
|
||||||
[**-t**|**--tty**[=*false*]]
|
[**-t**|**--tty**[=*false*]]
|
||||||
|
[**--tmpfs**[=*[CONTAINER-DIR[:<OPTIONS>]*]]
|
||||||
[**-u**|**--user**[=*USER*]]
|
[**-u**|**--user**[=*USER*]]
|
||||||
[**--ulimit**[=*[]*]]
|
[**--ulimit**[=*[]*]]
|
||||||
[**--uts**[=*[]*]]
|
[**--uts**[=*[]*]]
|
||||||
|
@ -271,6 +272,20 @@ This value should always larger than **-m**, so you should always use this with
|
||||||
**-t**, **--tty**=*true*|*false*
|
**-t**, **--tty**=*true*|*false*
|
||||||
Allocate a pseudo-TTY. The default is *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**=""
|
**-u**, **--user**=""
|
||||||
Username or UID
|
Username or UID
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ docker-run - Run a command in a new container
|
||||||
[**--shm-size**[=*[]*]]
|
[**--shm-size**[=*[]*]]
|
||||||
[**--sig-proxy**[=*true*]]
|
[**--sig-proxy**[=*true*]]
|
||||||
[**-t**|**--tty**[=*false*]]
|
[**-t**|**--tty**[=*false*]]
|
||||||
|
[**--tmpfs**[=*[CONTAINER-DIR[:<OPTIONS>]*]]
|
||||||
[**-u**|**--user**[=*USER*]]
|
[**-u**|**--user**[=*USER*]]
|
||||||
[**-v**|**--volume**[=*[]*]]
|
[**-v**|**--volume**[=*[]*]]
|
||||||
[**--ulimit**[=*[]*]]
|
[**--ulimit**[=*[]*]]
|
||||||
|
@ -436,6 +437,20 @@ interactive shell. The default is false.
|
||||||
The **-t** option is incompatible with a redirection of the docker client
|
The **-t** option is incompatible with a redirection of the docker client
|
||||||
standard input.
|
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**=""
|
**-u**, **--user**=""
|
||||||
Sets the username or UID used and optionally the groupname or GID for the specified command.
|
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
|
# 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
|
## 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
|
If you want messages that are logged in your container to show up in the host's
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -67,3 +68,24 @@ func parseOptions(options string) (int, string) {
|
||||||
}
|
}
|
||||||
return flag, strings.Join(data, ",")
|
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
|
PublishAllPorts bool // Should docker publish all exposed port for the container
|
||||||
ReadonlyRootfs bool // Is the container root filesystem in read-only
|
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.
|
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
|
UTSMode UTSMode // UTS namespace to use for the container
|
||||||
ShmSize *int64 // Total shm memory usage
|
ShmSize *int64 // Total shm memory usage
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/opts"
|
"github.com/docker/docker/opts"
|
||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
|
"github.com/docker/docker/pkg/mount"
|
||||||
"github.com/docker/docker/pkg/nat"
|
"github.com/docker/docker/pkg/nat"
|
||||||
"github.com/docker/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
"github.com/docker/docker/pkg/signal"
|
"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?
|
// FIXME: use utils.ListOpts for attach and volumes?
|
||||||
flAttach = opts.NewListOpts(opts.ValidateAttach)
|
flAttach = opts.NewListOpts(opts.ValidateAttach)
|
||||||
flVolumes = opts.NewListOpts(nil)
|
flVolumes = opts.NewListOpts(nil)
|
||||||
|
flTmpfs = opts.NewListOpts(nil)
|
||||||
flBlkioWeightDevice = opts.NewWeightdeviceOpt(opts.ValidateWeightDevice)
|
flBlkioWeightDevice = opts.NewWeightdeviceOpt(opts.ValidateWeightDevice)
|
||||||
flLinks = opts.NewListOpts(opts.ValidateLink)
|
flLinks = opts.NewListOpts(opts.ValidateLink)
|
||||||
flEnv = opts.NewListOpts(opts.ValidateEnv)
|
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(&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(&flBlkioWeightDevice, []string{"-blkio-weight-device"}, "Block IO weight (relative device weight)")
|
||||||
cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume")
|
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(&flLinks, []string{"-link"}, "Add link to another container")
|
||||||
cmd.Var(&flDevices, []string{"-device"}, "Add a host device to the 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")
|
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 (
|
var (
|
||||||
parsedArgs = cmd.Args()
|
parsedArgs = cmd.Args()
|
||||||
runCmd *stringutils.StrSlice
|
runCmd *stringutils.StrSlice
|
||||||
|
@ -396,6 +412,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
|
||||||
Isolation: IsolationLevel(*flIsolation),
|
Isolation: IsolationLevel(*flIsolation),
|
||||||
ShmSize: parsedShm,
|
ShmSize: parsedShm,
|
||||||
Resources: resources,
|
Resources: resources,
|
||||||
|
Tmpfs: tmpfs,
|
||||||
}
|
}
|
||||||
|
|
||||||
// When allocating stdin in attached mode, close stdin at client disconnect
|
// When allocating stdin in attached mode, close stdin at client disconnect
|
||||||
|
|
Loading…
Reference in New Issue