donglun1918 2017-08-08 01:14
浏览 152
已采纳

golang mount名称空间:进程退出后是否不清除装入的卷?

code below, I thought if I starts a process with syscall.CLONE_NEWNS, every mount option inside the namespace will be cleared when the process exits.

but it is not?

package main
import (
        "fmt"
        "os"
        "os/exec"
        "syscall"
)

var command string = "/usr/bin/bash"

func container_command() {

        fmt.Printf("starting container command %s
", command)
        cmd := exec.Command(command)
        cmd.SysProcAttr = &syscall.SysProcAttr{Cloneflags: syscall.CLONE_NEWPID |
                syscall.CLONE_NEWNS,
        }
        cmd.Stdin = os.Stdin
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr

        if err := cmd.Run(); err != nil {
                fmt.Println("error", err)
                os.Exit(1)
        }
}

func main() {
        fmt.Printf("starting current process %d
", os.Getpid())
        container_command()
        fmt.Printf("command ended
")

}

run this and mount a directory, this directory still exits after the program exits.

[root@localhost go]# go run namespace-1.go
starting current process 7558
starting container command /usr/bin/bash
[root@ns-process go]# mount --bind /home /mnt
[root@ns-process go]# ls /mnt
vagrant
[root@ns-process go]# exit
exit
command ended
[root@localhost go]# ls /mnt
vagrant
[root@localhost go]#

if this is the desired behavior, how is the proc get mounted in container implementations? because if I mount proc inside the namespace, I will get

[root@ns-process go]# mount -t proc /proc
[root@ns-process go]# exit
exit
command ended
[root@localhost go]# mount
mount: failed to read mtab: No such file or directory
[root@localhost go]#

proc has to be remounted to get it back.

update: doing the same in C also gives the same result, I think this should be a intended behavior.

#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

#define STACK_SIZE (1024 * 1024)
static char container_stack[STACK_SIZE];

char* const container_args[] = {
    "/bin/bash",
    NULL
};

int container_main(void* arg)
{
        printf("Container [%5d] - inside the container!
", getpid());
            sethostname("container",10);
            system("mount -t proc proc /proc");
            execv(container_args[0], container_args);
            printf("Something's wrong!
");
            return 1;
}

int main()
{
    printf("start a container!
");
    int container_pid = clone(container_main, container_stack+STACK_SIZE,
            CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL);
    waitpid(container_pid, NULL, 0);
    printf("container ended!
");
    return 0;
}

command output:

[root@localhost ~]# gcc a.c
[root@localhost ~]# ./a.out
start a container!
Container [    1] - inside the container!
[root@container ~]# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 08:57 pts/0    00:00:00 /bin/bash
root        17     1  0 08:57 pts/0    00:00:00 ps -ef
[root@container ~]# exit
exit
container stopped!
[root@localhost ~]# ps -ef
Error, do this: mount -t proc proc /proc
[root@localhost ~]# cat a.c
  • 写回答

1条回答 默认 最新

  • dongzhan5286 2017-08-14 13:24
    关注

    This happens due to mount events propagation between namespaces. The propagation type of your mount point is MS_SHARED.

    MS_SHARED: This mount point shares mount and unmount events with other mount points that are members of its "peer group". When a mount point is added or removed under this mount point, this change will propagate to the peer group, so that the mount or unmount will also take place under each of the peer mount points. Propagation also occurs in the reverse direction, so that mount and unmount events on a peer mount will also propagate to this mount point.

    Source - https://lwn.net/Articles/689856/

    The shared:N tag in /proc/self/mountinfo indicates that the mount is sharing propagation events with a peer group:

    $ sudo go run namespace-1.go
    [root@localhost]# mount --bind /home/andrii/test /mnt
    # The propagation type is MS_SHARED
    [root@localhost]# grep '/mnt' /proc/self/mountinfo
    264 175 254:0 /home/andrii/test /mnt rw,noatime shared:1 - ext4 
    /dev/mapper/cryptroot rw,data=ordered
    [root@localhost]# exit
    $ ls /mnt
    test_file
    

    On most Linux distributions the default propagation type is MS_SHARED which is set by systemd. See NOTES in man 7 mount_namespaces:

    Notwithstanding the fact that the default propagation type for new mount points is in many cases MS_PRIVATE, MS_SHARED is typically more useful. For this reason, systemd(1) automatically remounts all mount points as MS_SHARED on system startup. Thus, on most modern systems, the default propagation type is in practice MS_SHARED.

    If you want a fully isolated namespace, you can make all mount points private this way:

    $ sudo go run namespace-1.go
    [root@localhost]# mount --make-rprivate /
    [root@localhost]# mount --bind /home/andrii/test /mnt
    # The propagation type is MS_PRIVATE now
    [root@localhost]# grep '/mnt' /proc/self/mountinfo
    264 175 254:0 /home/andrii/test /mnt rw,noatime - ext4 
    /dev/mapper/cryptroot rw,data=ordered
    [root@localhost]# exit
    $ ls /mnt
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度