前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux Namespace机制简介

Linux Namespace机制简介

作者头像
sean.liu
发布2022-09-29 11:41:47
1.9K0
发布2022-09-29 11:41:47
举报

最近Docker技术越来越受到关注,作为Docker中很重要的一项技术,Namespace也就经常在Docker的简介里面看到。 在这里总结一下它的内部机制。也解决一下自己原来的一些疑惑。

Namespace是什么

C++中的Namespace

首先,先提一下Namespace是什么。最早知道这个名词是在学习C++语言的时候。由于现在的系统越来越复杂,代码中不同的模块就可能使用相同变量,于是就出现了Namespace,来对全局作用域进行划分。

比如C++的标注库都定义在STD Namespace中,需要使用时,就可以指定STD Namespace。当我们写一个类,类函数也需要使用namespace来指明这是属于哪一个类的函数。

Linux的Namespasce

Linux Namespaces是一种轻量级的虚拟化形式。操作系统在内存,CPU上,已经使用了虚拟化的技术,让每个进程都认为是自己独占了内存和CPU。但像存储,磁盘,信号等,一些资源,操作系统并没有将其隔离开。

namespace则是将这类资源也隔离开来。使得进程只能看到自己的资源视图。这个功能加上Cgroup,就可以实现一个轻量级的虚拟机。这对于提高主机资源利用率很有用。如果说KVM这类虚拟机是为了隔离,而容器技术更多是为了共享。

Linux Namespace原理

对于内核来说,进程是由task_struct结构体来控制。所以Namespace肯定会和task_struct有关联。在task_struct中,定义了一个nsproxy的结构体指针。

代码语言:javascript
复制
struct task_struct {
......
/* namespaces */
    struct nsproxy *nsproxy;
......
}

nsproxy结构体

nsproxy是定义namespace的结构体。

代码语言:javascript
复制
struct nsproxy {
    atomic_t count;
    struct uts_namespace *uts_ns;
    struct ipc_namespace *ipc_ns;
    struct mnt_namespace *mnt_ns;
    struct pid_namespace *pid_ns;
    <strong>struct</strong> user_namespace *user_ns;
    struct net             *net_ns;
};
  • 'count' 是task引用namspace的计数,这是通过nsproxy指向的计数。
  • nsproxy被共用所有namespace的tasks所共享。只要一个namespace被clone或者不被使用,那么nsproxy就会被copy。
  • uts_namespace结构体主要是包含了运行内核的名称、版本、底层体系结构类型等信息。UTS是UNIX Timesharing System的简称。
  • *ipc_namespace指向保存在struct ipc_namespace中的所有与进程间通信(IPC)有关的信息。
  • *mnt_namespace指向的是已经装载的文件系统的视图,在struct mnt_namespace中给出。
  • *pid_ns_for_children指向有关进程ID的信息,由struct pid_namespace提供。
  • user_ns 这个在新的3.8内核中实现。
  • struct net_ns包含所有网络相关的命名空间参数。
nsproxy 结构图

默认nsproxy:

init_nsproxy是和task一起初始化的。除了mnt_ns 没有进行初始化,其余的namespace都进行了系统默认初始化。

创建新的Namspace:

如果要进程有独立的Namespace,可以使用系统调用clone().使用flag标记来设置

代码语言:javascript
复制
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg)
  • fn 是指向函数的指针。
  • child_stack是运行的栈。需要传尾指针,因为栈是反着的。
  • flag 就是设置namespace的地方。
  • arg 是函数运行的参数。

当然,这个函数并非系统调用,这是glibc的函数。内核中真正工作的是do_fork函数。 do_fork函数会调用copy_process函数,在进行flag检查之后,里面会调用copy_namespaces. 这个函数会给task初始化一个新的nsproxy,然后对nsproxy里面的每个namespace结构体进行创建。

Namespace的复制

代码语言:javascript
复制
int copy_namespaces(unsigned long flags, struct task_struct *tsk);
copy_namespaces 调用关系图

进入存在的Namespace

在刚开始用docker时,发现可以使用docker exec 来进入一个运行中的容器,对其操作。 如果是Cgroup,只需要找到对应挂在目录,echo进程pid到tasks里即可。但Namespace现在还没有这种设计。 另外,要进入一个已知的namespace还需要一个标识。不然,进入哪个Namespace呢。

代码语言:javascript
复制
/proc/[pid]/ns

这个时候,Linux一切皆文件的设计就体现出了它的优势。我们可以直接通过proc中的ns文件来获取这个Namespa的标示。Cgroup的设置也能通过proc中的文件看出。

代码语言:javascript
复制
int setns(int fd, int nstype);
  • 参数fd表示我们要加入的namespace的文件描述符。
  • nstype是用于校验的,传入0就是不校验。
  • setns之后,就可以通过exec系列的函数来运行需要的程序了。for会继承其父进程的Namespace。

参考

Linux内核的namespace机制分析 Namespaces in operation, part 1: namespaces overview Docker基础技术:Linux Namespace(上) Docker基础技术:Linux Namespace(下)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022年9月18日2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Namespace是什么
    • C++中的Namespace
      • Linux的Namespasce
      • Linux Namespace原理
        • nsproxy结构体
          • nsproxy 结构图
        • 默认nsproxy:
          • 创建新的Namspace:
            • Namespace的复制
              • copy_namespaces 调用关系图
            • 进入存在的Namespace
            • 参考
            相关产品与服务
            容器镜像服务
            容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档