简体   繁体   English

创建和使用 Linux 命名空间的问题

[英]Problems with creating and using Linux namespaces

I'm making a go library wrapper on namespaces.我正在命名空间上制作一个 go 库包装器。 There were no problems with the.net ns, with ips ns and with uts ns, but there are problems with the others: .net ns、ips ns 和 uts ns 没有问题,但其他的有问题:

UserNs:用户名:

  • When trying to create, I get "invalid argument"(syscall error).尝试创建时,出现“无效参数”(系统调用错误)。

MntNS: MntNS:

  • mnt ns is being created, but doesn't work, I checked using mount proc. mnt ns 正在创建,但不起作用,我使用 mount proc 检查过。

ProcNS:进程:

  • proc ns is also created, but shows host processes, mounting does not work. proc ns 也已创建,但显示主机进程,挂载不起作用。

TimeNS:时间NS:

  • time ns is not created with the error "too many users"(syscall error). time ns 没有创建错误“太多用户”(系统调用错误)。

Create Namespace code:创建命名空间代码:

func NewNamespace(NSs []string) (*Namespace, error) {
    var flag int = 0
    for _, ns := range NSs {
        if val, ok := CloneFlags[ns]; ok == true {
            flag = flag | val
            continue
        }
        return nil, errors.New("unsupported ns " + ns)
    }
    if err := unix.Unshare(flag); err != nil {
        return nil, err
    }
    return GetCurrent()
}

Get Current NS Code:获取当前 NS 代码:

func GetCurrent() (*Namespace, error) {
    return GetFromThread(os.Getpid(), unix.Gettid())
}

func GetFromThread(pid, tid int) (*Namespace, error) {
    ns := newNamespace()
    for _, n := range NSs {
        if entry, ok := ns.ns[n]; ok {
            entry.path = fmt.Sprintf("/proc/%d/task/%d/ns/%s", pid, tid, n)
            fd, err := OpenNS(entry.path)
            if err != nil {
                return nil, err
            }
            entry.fd = fd
            ns.ns[n] = entry
        }
    }
    return ns, nil
}

Set NS Code:设置 NS 代码:

func SetNamespace(ns *Namespace, NSs []string) error {
    for _, n := range NSs {
        if entry, ok := ns.ns[n]; ok {
            entry.share = true

            ns.ns[n] = entry
        }
    }
    for key, val := range ns.ns {
        if !val.share {
            continue
        }
        fmt.Printf("Preparing %s...\n", key)
        err := unix.Setns(val.fd, CloneFlags[key])
        if err != nil {
            return err
        }
        fmt.Printf("Set %s\n", key)
    }
    return nil
}

Mount proc code:挂载过程代码:

func mountProc() error {
    if err := syscall.Mount("proc", "/proc", "proc", 0, ""); err != nil {
        return err
    }
    return nil
}

Flags:标志:

const (
    CLONE_NEWUTS    = unix.CLONE_NEWUTS //Work
    CLONE_NEWNS     = unix.CLONE_NEWNS
    CLONE_NEWCGROUP = unix.CLONE_NEWCGROUP
    CLONE_NEWTIME   = unix.CLONE_NEWTIME
    CLONE_NEWIPC    = unix.CLONE_NEWIPC //Work
    CLONE_NEWUSER   = unix.CLONE_NEWUSER
    CLONE_NEWPID    = unix.CLONE_NEWPID
    CLONE_NEWNET    = unix.CLONE_NEWNET //Work
    CLONE_IO        = unix.CLONE_IO
)

I think I'm missing something but I can't figure out what, perhaps a combination of ns is needed.我想我遗漏了一些东西,但我不知道是什么,也许需要 ns 的组合。

UserNs:用户名:

  • When trying to create, I get "invalid argument"(syscall error).尝试创建时,出现“无效参数”(系统调用错误)。

Per man 2 unshare , " CLONE_NEWUSER requires that the calling process is not threaded", but your process is threaded, as you can tell by the clone syscall with CLONE_THREAD in your strace output.根据man 2 unshare ,“ CLONE_NEWUSER要求调用进程不是线程化的”,但是您的进程是线程化的,正如您可以通过 strace output 中带有CLONE_THREADclone系统调用来判断的那样。

MntNS: MntNS:

  • mnt ns is being created, but doesn't work, I checked using mount proc. mnt ns 正在创建,但不起作用,我使用 mount proc 检查过。

I don't know exactly without knowing what you checked, but I'm guessing what you're running into is that systemd changes the default mount propagation in a way that makes mount namespaces effectively not work , so every time you make one, the first thing you need to do immediately afterwards is to change it back.我不知道你检查了什么,但我猜你遇到了什么之后您需要立即做的第一件事就是将其改回。 See if doing something like syscall.Mount("none", "/", nil, syscall.MS_REC | syscall.MS_PRIVATE, "") right after creating the mount namespace helps.看看在创建挂载命名空间后立即执行类似syscall.Mount("none", "/", nil, syscall.MS_REC | syscall.MS_PRIVATE, "")操作是否有帮助。

ProcNS:进程:

  • proc ns is also created, but shows host processes, mounting does not work. proc ns 也已创建,但显示主机进程,挂载不起作用。

I assume you mean PID namespace, since there's no such thing as a proc namespace.我假设你的意思是 PID 命名空间,因为没有 proc 命名空间这样的东西。 This time, I can think of two reasons things could be going wrong.这一次,我可以想到两个可能出错的原因。 First, again per man 2 unshare , "the calling process has a new PID namespace for its children" and "The calling process is not moved into the new namespace."首先,再次根据man 2 unshare ,“调用进程为其子进程有一个新的 PID 命名空间”和“调用进程未移入新的命名空间。” So that won't affect your process, and for it to do anything, you need to start a child process.因此,这不会影响您的流程,并且要使其执行任何操作,您需要启动一个子流程。 Second, per man 7 pid_namespaces , you need to mount a new instance of the proc filesystem from within the PID namespace to see the PIDs within it.其次,根据man 7 pid_namespaces ,您需要从 PID 命名空间内挂载 proc 文件系统的新实例,以查看其中的 PID。

TimeNS:时间NS:

  • time ns is not created with the error "too many users"(syscall error). time ns 没有创建错误“太多用户”(系统调用错误)。

It looks like this is being created and is just failing to set.看起来这是正在创建,只是未能设置。 It's hard to find documentation that explicitly says this, but by reading kernel source code, it looks like as with user namespaces, you can't set time namespaces on a multithreaded process, but as with PID namespaces, if you spawn a child process, it should have it set.很难找到明确说明这一点的文档,但通过阅读 kernel 源代码,它看起来与用户命名空间一样,您不能在多线程进程上设置时间命名空间,但与 PID 命名空间一样,如果您生成子进程,它应该有它设置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM