Jelajahi Sumber

Add support for sharing /dev/shm/ and /dev/mqueue between containers

This changeset creates /dev/shm and /dev/mqueue mounts for each container under
/var/lib/containers/<id>/ and bind mounts them into the container. When --ipc:container<id/name>
is used, then the /dev/shm and /dev/mqueue of the ipc container are used instead of creating
new ones for the container.

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan)

(cherry picked from commit d88fe447df0e87b3a57f9d08b108b141dd72678c)
Mrunal Patel 10 tahun lalu
induk
melakukan
c8291f7107

+ 11 - 0
daemon/container.go

@@ -296,10 +296,17 @@ func (container *Container) Start() (err error) {
 		return err
 		return err
 	}
 	}
 
 
+	if !(container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost()) {
+		if err := container.setupIpcDirs(); err != nil {
+			return err
+		}
+	}
+
 	mounts, err := container.setupMounts()
 	mounts, err := container.setupMounts()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
+	mounts = append(mounts, container.ipcMounts()...)
 
 
 	container.command.Mounts = mounts
 	container.command.Mounts = mounts
 	return container.waitForStart()
 	return container.waitForStart()
@@ -358,6 +365,10 @@ func (container *Container) isNetworkAllocated() bool {
 func (container *Container) cleanup() {
 func (container *Container) cleanup() {
 	container.releaseNetwork()
 	container.releaseNetwork()
 
 
+	if err := container.unmountIpcMounts(); err != nil {
+		logrus.Errorf("%v: Failed to umount ipc filesystems: %v", container.ID, err)
+	}
+
 	if err := container.Unmount(); err != nil {
 	if err := container.Unmount(); err != nil {
 		logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
 		logrus.Errorf("%v: Failed to umount filesystem: %v", container.ID, err)
 	}
 	}

+ 100 - 0
daemon/container_unix.go

@@ -50,6 +50,8 @@ type Container struct {
 	AppArmorProfile string
 	AppArmorProfile string
 	HostnamePath    string
 	HostnamePath    string
 	HostsPath       string
 	HostsPath       string
+	ShmPath         string
+	MqueuePath      string
 	MountPoints     map[string]*mountPoint
 	MountPoints     map[string]*mountPoint
 	ResolvConfPath  string
 	ResolvConfPath  string
 
 
@@ -189,6 +191,16 @@ func populateCommand(c *Container, env []string) error {
 	}
 	}
 
 
 	ipc := &execdriver.Ipc{}
 	ipc := &execdriver.Ipc{}
+	var err error
+	c.ShmPath, err = c.shmPath()
+	if err != nil {
+		return err
+	}
+
+	c.MqueuePath, err = c.mqueuePath()
+	if err != nil {
+		return err
+	}
 
 
 	if c.hostConfig.IpcMode.IsContainer() {
 	if c.hostConfig.IpcMode.IsContainer() {
 		ic, err := c.getIpcContainer()
 		ic, err := c.getIpcContainer()
@@ -196,8 +208,14 @@ func populateCommand(c *Container, env []string) error {
 			return err
 			return err
 		}
 		}
 		ipc.ContainerID = ic.ID
 		ipc.ContainerID = ic.ID
+		c.ShmPath = ic.ShmPath
+		c.MqueuePath = ic.MqueuePath
 	} else {
 	} else {
 		ipc.HostIpc = c.hostConfig.IpcMode.IsHost()
 		ipc.HostIpc = c.hostConfig.IpcMode.IsHost()
+		if ipc.HostIpc {
+			c.ShmPath = "/dev/shm"
+			c.MqueuePath = "/dev/mqueue"
+		}
 	}
 	}
 
 
 	pid := &execdriver.Pid{}
 	pid := &execdriver.Pid{}
@@ -1222,3 +1240,85 @@ func (container *Container) removeMountPoints(rm bool) error {
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+func (container *Container) shmPath() (string, error) {
+	return container.GetRootResourcePath("shm")
+}
+func (container *Container) mqueuePath() (string, error) {
+	return container.GetRootResourcePath("mqueue")
+}
+
+func (container *Container) setupIpcDirs() error {
+	shmPath, err := container.shmPath()
+	if err != nil {
+		return err
+	}
+
+	if err := os.MkdirAll(shmPath, 0700); err != nil {
+		return err
+	}
+
+	if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel("mode=1777,size=65536k", container.GetMountLabel())); err != nil {
+		return fmt.Errorf("mounting shm tmpfs: %s", err)
+	}
+
+	mqueuePath, err := container.mqueuePath()
+	if err != nil {
+		return err
+	}
+
+	if err := os.MkdirAll(mqueuePath, 0700); err != nil {
+		return err
+	}
+
+	if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil {
+		return fmt.Errorf("mounting mqueue mqueue : %s", err)
+	}
+
+	return nil
+}
+
+func (container *Container) unmountIpcMounts() error {
+	if container.hostConfig.IpcMode.IsContainer() || container.hostConfig.IpcMode.IsHost() {
+		return nil
+	}
+
+	shmPath, err := container.shmPath()
+	if err != nil {
+		return fmt.Errorf("shm path does not exist %v", err)
+	}
+
+	if err := syscall.Unmount(shmPath, syscall.MNT_DETACH); err != nil {
+		return fmt.Errorf("failed to umount %s filesystem %v", shmPath, err)
+	}
+
+	mqueuePath, err := container.mqueuePath()
+	if err != nil {
+		return fmt.Errorf("mqueue path does not exist %v", err)
+	}
+
+	if err := syscall.Unmount(mqueuePath, syscall.MNT_DETACH); err != nil {
+		return fmt.Errorf("failed to umount %s filesystem %v", mqueuePath, err)
+	}
+
+	return nil
+}
+
+func (container *Container) ipcMounts() []execdriver.Mount {
+	var mounts []execdriver.Mount
+	label.SetFileLabel(container.ShmPath, container.MountLabel)
+	mounts = append(mounts, execdriver.Mount{
+		Source:      container.ShmPath,
+		Destination: "/dev/shm",
+		Writable:    true,
+		Private:     true,
+	})
+	label.SetFileLabel(container.MqueuePath, container.MountLabel)
+	mounts = append(mounts, execdriver.Mount{
+		Source:      container.MqueuePath,
+		Destination: "/dev/mqueue",
+		Writable:    true,
+		Private:     true,
+	})
+	return mounts
+}

+ 12 - 0
daemon/container_windows.go

@@ -163,3 +163,15 @@ func (container *Container) prepareMountPoints() error {
 func (container *Container) removeMountPoints(_ bool) error {
 func (container *Container) removeMountPoints(_ bool) error {
 	return nil
 	return nil
 }
 }
+
+func (container *Container) setupIpcDirs() error {
+	return nil
+}
+
+func (container *Container) unmountIpcMounts() error {
+	return nil
+}
+
+func (container *Container) ipcMounts() []execdriver.Mount {
+	return nil
+}

+ 8 - 0
daemon/daemon.go

@@ -762,6 +762,10 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
 		return nil, err
 		return nil, err
 	}
 	}
 
 
+	if err := d.cleanupMounts(); err != nil {
+		return nil, err
+	}
+
 	return d, nil
 	return d, nil
 }
 }
 
 
@@ -838,6 +842,10 @@ func (daemon *Daemon) Shutdown() error {
 		}
 		}
 	}
 	}
 
 
+	if err := daemon.cleanupMounts(); err != nil {
+		return err
+	}
+
 	return nil
 	return nil
 }
 }
 
 

+ 44 - 0
daemon/daemon_linux.go

@@ -0,0 +1,44 @@
+package daemon
+
+import (
+	"bufio"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/Sirupsen/logrus"
+	"github.com/docker/docker/pkg/mount"
+)
+
+// cleanupMounts umounts shm/mqueue mounts for old containers
+func (daemon *Daemon) cleanupMounts() error {
+	logrus.Debugf("Cleaning up old shm/mqueue mounts: start.")
+	f, err := os.Open("/proc/self/mountinfo")
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	sc := bufio.NewScanner(f)
+	for sc.Scan() {
+		line := sc.Text()
+		fields := strings.Split(line, " ")
+		if strings.HasPrefix(fields[4], daemon.repository) {
+			mnt := fields[4]
+			mountBase := filepath.Base(mnt)
+			if mountBase == "mqueue" || mountBase == "shm" {
+				logrus.Debugf("Unmounting %+v", mnt)
+				if err := mount.Unmount(mnt); err != nil {
+					return err
+				}
+			}
+		}
+	}
+
+	if err := sc.Err(); err != nil {
+		return err
+	}
+
+	logrus.Debugf("Cleaning up old shm/mqueue mounts: done.")
+	return nil
+}

+ 4 - 0
daemon/daemon_windows.go

@@ -141,3 +141,7 @@ func (daemon *Daemon) newBaseContainer(id string) Container {
 		},
 		},
 	}
 	}
 }
 }
+
+func (daemon *Daemon) cleanupMounts() error {
+	return nil
+}

+ 0 - 13
daemon/execdriver/native/template/default_template.go

@@ -61,19 +61,6 @@ func New() *configs.Config {
 				Flags:       syscall.MS_NOSUID | syscall.MS_NOEXEC,
 				Flags:       syscall.MS_NOSUID | syscall.MS_NOEXEC,
 				Data:        "newinstance,ptmxmode=0666,mode=0620,gid=5",
 				Data:        "newinstance,ptmxmode=0666,mode=0620,gid=5",
 			},
 			},
-			{
-				Device:      "tmpfs",
-				Source:      "shm",
-				Destination: "/dev/shm",
-				Data:        "mode=1777,size=65536k",
-				Flags:       defaultMountFlags,
-			},
-			{
-				Source:      "mqueue",
-				Destination: "/dev/mqueue",
-				Device:      "mqueue",
-				Flags:       defaultMountFlags,
-			},
 			{
 			{
 				Source:      "sysfs",
 				Source:      "sysfs",
 				Destination: "/sys",
 				Destination: "/sys",