https://www.junmajinlong.com/virtual/namespace/mount_namespace/
root@cloud:~# ls -1 /proc/$$/mount* /proc/3374/mountinfo /proc/3374/mounts /proc/3374/mountstats root@cloud:~# mkdir iso root@cloud:~# cd iso/ root@cloud:~/iso# ls root@cloud:~/iso# mkdir -p iso1/dir root@cloud:~/iso# mkdir -p iso2/dir2 root@cloud:~/iso# ls iso1 iso2 root@cloud:~/iso# ls iso1 dir
root@cloud:~/iso# mkisofs -o 1.iso iso1 I: -input-charset not specified, using utf-8 (detected in locale settings) Total translation table size: 0 Total rockridge attributes bytes: 0 Total directory bytes: 2152 Path table size(bytes): 22 Max brk space used 0 175 extents written (0 MB) root@cloud:~/iso# ls 1.iso iso1 iso2 root@cloud:~/iso# mkisofs -o 2.iso iso2 I: -input-charset not specified, using utf-8 (detected in locale settings) Total translation table size: 0 Total rockridge attributes bytes: 0 Total directory bytes: 2154 Path table size(bytes): 22 Max brk space used 0 175 extents written (0 MB) root@cloud:~/iso# ls 1.iso 2.iso iso1 iso2 root@cloud:~/iso#
root@cloud:~/iso# ls -1 /proc/$$/mount* /proc/3374/mountinfo /proc/3374/mounts /proc/3374/mountstats root@cloud:~/iso# ls -l /proc/$$/ns/mnt lrwxrwxrwx 1 root root 0 Dec 4 10:27 /proc/3374/ns/mnt -> 'mnt:[4026531840]' root@cloud:~/iso#
root@cloud:~/iso# ls -1 /proc/$$/mount* /proc/3374/mountinfo /proc/3374/mounts /proc/3374/mountstats root@cloud:~/iso# ls -l /proc/$$/ns/mnt lrwxrwxrwx 1 root root 0 Dec 4 10:27 /proc/3374/ns/mnt -> 'mnt:[4026531840]' root@cloud:~/iso# mount 1.iso /mnt/iso1 mount: /mnt/iso1: WARNING: device write-protected, mounted read-only. root@cloud:~/iso# mount | grep iso1 /root/iso/1.iso on /mnt/iso1 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048) root@cloud:~/iso# unshare -m -u /bin/bash root@cloud:~/iso# ls -l /proc/$$/ns total 0 lrwxrwxrwx 1 root root 0 Dec 4 10:29 cgroup -> 'cgroup:[4026531835]' lrwxrwxrwx 1 root root 0 Dec 4 10:29 ipc -> 'ipc:[4026531839]' lrwxrwxrwx 1 root root 0 Dec 4 10:29 mnt -> 'mnt:[4026533784]' lrwxrwxrwx 1 root root 0 Dec 4 10:29 net -> 'net:[4026531896]' lrwxrwxrwx 1 root root 0 Dec 4 10:29 pid -> 'pid:[4026531836]' lrwxrwxrwx 1 root root 0 Dec 4 10:29 pid_for_children -> 'pid:[4026531836]' lrwxrwxrwx 1 root root 0 Dec 4 10:29 user -> 'user:[4026531837]' lrwxrwxrwx 1 root root 0 Dec 4 10:29 uts -> 'uts:[4026533786]' root@cloud:~/iso#
root@cloud:~/iso# mount 2.iso /mnt/iso2/ mount: /mnt/iso2: WARNING: device write-protected, mounted read-only. root@cloud:~/iso# mount | grep 'iso[12]' /root/iso/1.iso on /mnt/iso1 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048) /root/iso/2.iso on /mnt/iso2 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048) root@cloud:~/iso#
root@cloud:~/iso# ls /mnt/iso1/ dir root@cloud:~/iso# ls /mnt/iso2/ dir2 root@cloud:~/iso#
重新打开一个shell
root@cloud:~# mount | grep 'iso[12]' /root/iso/1.iso on /mnt/iso1 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048) root@cloud:~#
root@cloud:~/iso# ls /mnt/iso1/ dir root@cloud:~/iso# ls /mnt/iso2/ dir2 root@cloud:~/iso# umount /mnt/iso1/ root@cloud:~/iso# mount | grep 'iso[12]' /root/iso/2.iso on /mnt/iso2 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048) root@cloud:~/iso# ls /mnt/iso1/ root@cloud:~/iso# ls /mnt/iso2/ dir2 root@cloud:~/iso#
重新打开一个shell
root@cloud:~# mount | grep 'iso[12]' /root/iso/1.iso on /mnt/iso1 type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048) root@cloud:~# ls /mnt/iso1/ dir root@cloud:~#
mnt namespace: shared subtrees
root@cloud:~/iso# ls 1.iso 2.iso iso1 iso2 root@cloud:~/iso# mount --bind iso1 iso2 root@cloud:~/iso# ls iso2/ dir root@cloud:~/iso# mount --make-shared iso2 root@cloud:~/iso# unshare -m -u --propagation unchanged /bin/bash root@cloud:~/iso# grep 'iso1' /proc/self/mountinfo 563 513 7:0 / /mnt/iso1 ro,relatime shared:228 - iso9660 /dev/loop0 ro,nojoliet,check=s,map=n,blocksize=2048 564 513 8:34 /root/iso/iso1 /root/iso/iso2 rw,relatime shared:1 - ext4 /dev/sdc2 rw,errors=remount-ro,stripe=64 root@cloud:~/iso# mkdir sub root@cloud:~/iso# ls 1.iso 2.iso iso1 iso2 sub root@cloud:~/iso# mount --bind sub iso2/subfoo mount: iso2/subfoo: mount point does not exist. root@cloud:~/iso# mkdir -p iso2/subfoo root@cloud:~/iso# mount --bind sub iso2/subfoo
root@cloud:~/iso# tree iso2 iso2 ├── dir └── subfoo 2 directories, 0 files root@cloud:~/iso# tree iso1 iso1 ├── dir └── subfoo 2 directories, 0 files root@cloud:~/iso#
root@cloud:~/iso# tree iso2 iso2 ├── dir └── subfoo 2 directories, 0 files root@cloud:~/iso# tree iso1 iso1 ├── dir └── subfoo 2 directories, 0 files root@cloud:~/iso#
syscall.MS_PRIVATE
// Get the parent mount point of directory passed in as argument. Also return // optional fields. func getParentMount(rootfs string) (string, string, error) { var path string mountinfos, err := mount.GetMounts() if err != nil { return "", "", err } mountinfo := getMountInfo(mountinfos, rootfs) if mountinfo != nil { return rootfs, mountinfo.Optional, nil } path = rootfs for { path = filepath.Dir(path) mountinfo = getMountInfo(mountinfos, path) if mountinfo != nil { return path, mountinfo.Optional, nil } if path == "/" { break } } // If we are here, we did not find parent mount. Something is wrong. return "", "", fmt.Errorf("Could not find parent mount of %s", rootfs) } // Make parent mount private if it was shared func rootfsParentMountPrivate(config *configs.Config) error { sharedMount := false parentMount, optionalOpts, err := getParentMount(config.Rootfs) if err != nil { return err } optsSplit := strings.Split(optionalOpts, " ") for _, opt := range optsSplit { if strings.HasPrefix(opt, "shared:") { sharedMount = true break } } // Make parent mount PRIVATE if it was shared. It is needed for two // reasons. First of all pivot_root() will fail if parent mount is // shared. Secondly when we bind mount rootfs it will propagate to // parent namespace and we don't want that to happen. if sharedMount { return syscall.Mount("", parentMount, "", syscall.MS_PRIVATE, "") } return nil }
func prepareRoot(config *configs.Config) error { flag := syscall.MS_SLAVE | syscall.MS_REC if config.RootPropagation != 0 { flag = config.RootPropagation } if err := syscall.Mount("", "/", "", uintptr(flag), ""); err != nil { return err } if err := rootfsParentMountPrivate(config); err != nil { return err } return syscall.Mount(config.Rootfs, config.Rootfs, "bind", syscall.MS_BIND|syscall.MS_REC, "") }
Hands on Docker Hack Now, a bit hack will change the container’s mount namespace from slave/private to shared, and making container-initiated filesystem mount event propagate to the host. diff –git a/contrib/init/systemd/docker.service b/contrib/init/systemd/docker.service index bc73448..ee1b43b 100644 — a/contrib/init/systemd/docker.service +++ b/contrib/init/systemd/docker.service @@ -6,7 +6,7 @@ Requires=docker.socket [Service] ExecStart=/usr/bin/docker -d -H fd:// -MountFlags=slave +MountFlags=shared LimitNOFILE=1048576 LimitNPROC=1048576 LimitCORE=infinity diff –git a/vendor/src/github.com/docker/libcontainer/standard_init_linux.go b/vendor/src/github.com/docker/libcontainer/standard_init_linux.go index 282832b..652f278 100644 — a/vendor/src/github.com/docker/libcontainer/standard_init_linux.go +++ b/vendor/src/github.com/docker/libcontainer/standard_init_linux.go @@ -48,7 +48,7 @@ func (l *linuxStandardInit) Init() error { } label.Init() // InitializeMountNamespace() can be executed only for a new mount namespace – if l.config.Config.Namespaces.Contains(configs.NEWNS) { + if !l.config.Config.Namespaces.Contains(configs.NEWNS) { if err := setupRootfs(l.config.Config, console); err != nil { return err }
// Finish the rootfs setup. if l.config.Config.Namespaces.Contains(configs.NEWNS) { if err := finalizeRootfs(l.config.Config); err != nil { return err } }
// finalizeRootfs sets anything to ro if necessary. You must call // prepareRootfs first. func finalizeRootfs(config *configs.Config) (err error) { // remount dev as ro if specified for _, m := range config.Mounts { if libcontainerUtils.CleanPath(m.Destination) == "/dev" { if m.Flags&unix.MS_RDONLY == unix.MS_RDONLY { if err := remountReadonly(m); err != nil { return newSystemErrorWithCausef(err, "remounting %q as readonly", m.Destination) } } break } } // set rootfs ( / ) as readonly if config.Readonlyfs { if err := setReadonly(); err != nil { return newSystemErrorWithCause(err, "setting rootfs as readonly") } } unix.Umask(0022) return nil }