我跑了
unshare -mfp sh -c 'mount -tproc none /proc ; ls /proc'
正如预期的那样,它打印了一个仅包含 PID 1 和 PID 3 目录的 /proc,然后退出,让我回到根命名空间中的旧提示符。
然后我就这么做了
ls /proc
我得到的列表没有任何 PID 目录。我原本以为 /proc 中会充满进程。我不得不再次挂载 proc 来修复这个问题。
为什么会发生这种情况?我该如何修复这个问题,以便我在 PID 命名空间内挂载的 /proc 保持在本地?
我尝试将 --mount-private 传递给 mount,但似乎没有任何效果。
我使用的是带有 util-linux 2.23.2 的 Amazon Linux 2016.03。
答案1
要么是 unshare(1) 坏了,要么就是我太蠢了。
我修改了代码http://crosbymichael.com/creating-containers-part-1.html所以它对我来说确实有效。必须使用 来延迟卸载 /proc umount2
,并使用linux/sched.h
而不是sched.h
。
要编译,请执行以下操作gcc foo.c -ofoo
。
您会注意到,运行后,./foo ls /proc
主机系统上的 /proc 不会被清除。
//
// This compiles and works on Amazon Linux 2016.03 (kernel 4.4.5-15.26.amzn1.x86_64)
//
#include <stdio.h>
#include <stdlib.h>
// was <sched.h>, but wouldn't compile on Amazon Linux
#include <linux/sched.h>
// for umount2()
#include <sys/mount.h>
#include <sys/wait.h>
#include <errno.h>
#define STACKSIZE (1024*1024)
static char child_stack[STACKSIZE];
struct clone_args {
char **argv;
};
static int child_exec(void *stuff) {
struct clone_args *args = (struct clone_args *)stuff;
// the fprintf()s crash. Not sure why.
// changed from umount(), lazy umount succeeds
if (umount2("/proc", MNT_DETACH) != 0) {
fprintf(stderr, "failed to unmount /proc: %s\n", strerror(errno));
exit(-1);
}
if (mount("proc", "/proc", "proc", 0, "") != 0) {
fprintf(stderr, "failed to mount /proc: %s\n", strerror(errno));
exit(-1);
}
if (execvp(args->argv[0], args->argv) != 0) {
fprintf(stderr, "failed to execvp arguments: %s\n", strerror(errno));
exit(-1);
}
// unreachable
exit(EXIT_FAILURE);
}
int main(int argc, char **argv) {
struct clone_args args;
args.argv = &argv[1];
int clone_flags = CLONE_NEWPID | CLONE_NEWNS | SIGCHLD;
pid_t pid = clone(child_exec, child_stack + STACKSIZE, clone_flags, &args);
if (pid < 0) {
fprintf(stderr, "clone failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (waitpid(pid, NULL, 0) == -1) {
fprintf(stderr, "failed to wait pid %d\n", pid);
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
答案2
挂载传播已启用(可能是由 systemd 启用),而您使用的旧版本确实unshare
会改变传播状态,因此新挂载命名空间中的所有挂载操作都会反映在原始命名空间中。