容器Namespace - 2

      容器通过namespace建立属于自己的一个相对隔离的环境,从上一篇《容器Namespace - 1》我们知道centos7默认没有启用user namespace。

      

      上图显示容器的user namespace与宿主机是同一个ID:4026531837,接下来简单分析下docker创建namespace的代码。

 

vendor/github.com/containerd/containerd/oci/spec_unix.go,这个文件定义了缺省的namespace以及capability。

func defaultCaps() []string {

        return []string{

                "CAP_CHOWN",

                "CAP_DAC_OVERRIDE",

                "CAP_FSETID",

                "CAP_FOWNER",

                "CAP_MKNOD",

                "CAP_NET_RAW",

                "CAP_SETGID",

                "CAP_SETUID",

                "CAP_SETFCAP",

                "CAP_SETPCAP",

                "CAP_NET_BIND_SERVICE",

                "CAP_SYS_CHROOT",

                "CAP_KILL",

                "CAP_AUDIT_WRITE",

        }

}



func defaultNamespaces() []specs.LinuxNamespace {

        return []specs.LinuxNamespace{

                {

                        Type: specs.PIDNamespace,

                },

                {

                        Type: specs.IPCNamespace,

                },

                {

                        Type: specs.UTSNamespace,

                },

                {

                        Type: specs.MountNamespace,

                },

                {

                        Type: specs.NetworkNamespace,

                },

        }

}

创建启动容器过程中,会在下面的目录下生成run-time的config.json

/run/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby/容器id/config.json

解析下这个文件(jq is a tool for processing JSON inputs):

cat config.json | jq . > /opt/config.json

/opt/config.json文件相关的namespace配置

  "namespaces": [

      {

        "type": "mount"

      },

      {

        "type": "network"

      },

      {

        "type": "uts"

      },

      {

        "type": "pid"

      },

      {

        "type": "ipc"

      }

    ],

 

创建容器namespace的逻辑在:

vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c

 if (config.namespaces)

       join_namespaces(config.namespaces);



void join_namespaces(char *nslist)

{

        struct namespace_t {

                int fd;

                int ns;

                char type[PATH_MAX];

                char path[PATH_MAX];

        } *namespaces = NULL;



      //准备namespace

                fd = open(path, O_RDONLY);

                if (fd < 0)

                        bail("failed to open %s", path);



                ns->fd = fd;

                ns->ns = nsflag(namespace);

                strncpy(ns->path, path, PATH_MAX - 1);





        for (i = 0; i < num; i++) {

                struct namespace_t ns = namespaces[i];


                // 通过setns设置
                if (setns(ns.fd, ns.ns) < 0)

                        bail("failed to setns to %s", ns.path);



                close(ns.fd);

        }



        free(namespaces);



}

详细的代码分析逻辑需要仔细再看看,这里只是个大概过程。

 

既然docker容器user namespace的管理员root是“map root to root”,它应该就具备super priviledge权限,我们来看看。

[root@centos opt]# unshare -m --mount-proc -u -i -n -p -U -r -f  /bin/bash

[root@centos opt]# ip link show

1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT

    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

[root@centos opt]# ip link set dev lo down

[root@centos opt]# ip link set dev lo up

 

[root@centos opt]#docker run -ti centos /bin/bash

[root@f45f03e236ec /]#ip link set lo down

RTNETLINK answers: Operation not permitted

为什么docker容器在设置loop接口状态时提示:“RTNETLINK answers: Operation not permitted”?

[root@f45f03e236ec /]# mount -t tmpfs -o size=20m tmpfs /tmp1

mount: permission denied       // mount 也不允许

这个super user的权限是怎么限制的呢?

 

这个就需要讲讲linux系统的capability了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值