当前位置: 首页 > news >正文

Docker 核心技术:Namespace

大家好,我是费益洲。Namespace 作为 Docker 的技术核心之一,主要作用就是对容器的资源进行隔离。容器的本质其实就是 Linux 的一个进程,容器的系统资源隔离其实就是进程的系统资源隔离,本文将从 Linux 内核源码的层面,谈谈进程是如何通过 Namespace 实现系统资源隔离的。

本文中的的内核源码版本为linux-5.10.1,具体的源码可以自行下载查看,本文只列举关键代码。

🔗 内核源码官方地址:www.kernel.org,linux-5.10.1 源码下载地址:linux-5.10.1.tar.xz

概念

Namespace 本质是 Linux 系统内核的一种功能,其主要作用是对进程的系统资源进行全局范围的分装隔离,这些资源包括 User ID、PID(Process ID)、Network 等,这种隔离使得不同 Namespace 下的进程拥有独立的全局系统资源,改变一个 Namespace 中的系统资源只会影响当前 Namespace 中的进程,对其他 Namespace 中的进程没有影响。需要注意的是不同的命名空间是随着内核版本不断加入内核的,具体的 Namespace 的信息如下所示。

类型 系统调用参数 隔离资源 内核版本
Mount Namespace CLONE_NEWNS 文件系统挂载点 2.4.19
UTS Namespace CLONE_NEWUTS 主机名(hostname)和域名 2.6.19
IPC Namespace CLONE_NEWIPC 信号量、消息队列等进程间通信资源 2.6.19
PID Namespace CLONE_NEWPID 进程 ID(各空间独立进程树) 2.6.24
Network Namespace CLONE_NEWNET 网络设备、IP、端口、路由表 2.6.29
User Namespace CLONE_NEWUSER 用户/组 ID 映射 3.8
Cgroup Namespace CLONE_NEWCGROUP Cgroup 文件系统 4.6
Time Namespace CLONE_NEWTIME 时间 5.6

🏷️ Mount Namespace 作为第一个实现的 Namespace,当时的开发人员没有想过后续会有多个 Namespace 出现,所以标识直接定义为 CLONE_NEWNS

Namespace 生命周期和回收策略

Namespace 是随着进程创建而创建的,不存在脱离进程单独存在的 Namespace。而在 Linux 内核源码中,各类 Namespace 也是作为属性存在于进程结构体中。

Namespace 的创建过程

进程结构体task_struct的定义在文件linux-5.10.1/include/linux/sched.h中,如下所示:

struct task_struct {
// ...(省略部分代码)/* Namespaces: */struct nsproxy			*nsproxy;// ...(省略部分代码)
}

具体的nsproxy的定义在文件linux-5.10.1/include/linux/nsproxy.h中,如下所示:

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_for_children;struct net 	     *net_ns;struct time_namespace *time_ns;struct time_namespace *time_ns_for_children;struct cgroup_namespace *cgroup_ns;
};

接下来从进程创建的过程,来说明进程的创建过程中,创建 Namespace 的过程。创建进程的系统调用函数有三个:fork、vfork、clone

具体的函数定义在文件linux-5.10.1/kernel/fork.c中,如下所示:

#ifdef __ARCH_WANT_SYS_FORK
SYSCALL_DEFINE0(fork)
{
#ifdef CONFIG_MMUstruct kernel_clone_args args = {.exit_signal = SIGCHLD,};return kernel_clone(&args);
#else/* can not support in nommu mode */return -EINVAL;
#endif
}
#endif#ifdef __ARCH_WANT_SYS_VFORK
SYSCALL_DEFINE0(vfork)
{struct kernel_clone_args args = {.flags		= CLONE_VFORK | CLONE_VM,.exit_signal	= SIGCHLD,};return kernel_clone(&args);
}
#endif#ifdef __ARCH_WANT_SYS_CLONE
#ifdef CONFIG_CLONE_BACKWARDS
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,int __user *, parent_tidptr,unsigned long, tls,int __user *, child_tidptr)
#elif defined(CONFIG_CLONE_BACKWARDS2)
SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,int __user *, parent_tidptr,int __user *, child_tidptr,unsigned long, tls)
#elif defined(CONFIG_CLONE_BACKWARDS3)
SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,int, stack_size,int __user *, parent_tidptr,int __user *, child_tidptr,unsigned long, tls)
#else
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,int __user *, parent_tidptr,int __user *, child_tidptr,unsigned long, tls)
#endif
{struct kernel_clone_args args = {.flags		= (lower_32_bits(clone_flags) & ~CSIGNAL),.pidfd		= parent_tidptr,.child_tid	= child_tidptr,.parent_tid	= parent_tidptr,.exit_signal	= (lower_32_bits(clone_flags) & CSIGNAL),.stack		= newsp,.tls		= tls,};return kernel_clone(&args);
}
#endif

当调用 fork()、vfork()、clone()时,最终都会调用同一个函数 kernel_clone(),和 Namespace 创建关联的关键函数调用是 copy_process()

pid_t kernel_clone(struct kernel_clone_args *args)
{...(省略部分代码)// line 2456p = copy_process(NULL, trace, NUMA_NO_NODE, args);...(省略部分代码)
}

copy_process()函数和 Namespace 创建关联的关键函数调用是 copy_namespaces()

static __latent_entropy struct task_struct *copy_process(struct pid *pid,int trace,int node,struct kernel_clone_args *args)
{// ...(省略部分代码)// line 2098retval = copy_namespaces(clone_flags, p);// ...(省略部分代码)
}

在文件linux-5.10.1/kernel/nsproxy.c定义的函数 copy_namespaces()中,会根据标识为进程创建新的 Namespace 并进行赋值

int copy_namespaces(unsigned long flags, struct task_struct *tsk)
{struct 
http://www.lryc.cn/news/620463.html

相关文章:

  • 版本更新!FairGuard-Mac加固工具已上线!
  • 银河麒麟系统部署oceanbase社区版
  • 【入门级-C++程序设计:13、STL 模板:栈(stack)、队 列(queue)、 链 表(list)、 向 量(vector) 等容器】
  • 中介者模式和观察者模式的区别是什么
  • mysql——count(*)、count(1)和count(字段)谁更快?有什么区别?
  • 【React】hooks 中的闭包陷阱
  • 某处卖600的【独角仙】尾盘十分钟短线 尾盘短线思路 手机电脑通用无未来函数
  • coze小白-如何用coze上传本地文件?(对话流使用)
  • 《SeeClick: Harnessing GUI Grounding for Advanced Visual GUI Agents》论文精读笔记
  • 云原生俱乐部-k8s知识点归纳(1)
  • 同创永益 IStorM CNBR云原生业务韧性管理平台 v3.3.0重磅发布:告别备份烦恼,云原生数据保护再升级!
  • 【博客系统测试报告】---接口自动化测试
  • toRefs、storeToRefs实际应用
  • 图书商城小程序怎么做?实体书店如何在微信小程序上卖书?
  • 机器学习 - Kaggle项目实践(3)Digit Recognizer 手写数字识别
  • 20道HTML相关前端面试题及答案
  • 如何通过WiFi将文件从安卓设备传输到电脑
  • 点图:数据分布的可视化利器
  • PostgreSQL——视图
  • 读书笔记:《我看见的世界》
  • 为什么Integer缓存-128 ~ 127
  • 【Linux学习|黑马笔记|Day4】IP地址、主机名、网络请求、下载、端口、进程管理、主机状态监控、环境变量、文件的上传和下载、压缩和解压
  • 编排之神-Kubernetes微服务专题--ingress-nginx及金丝雀Canary的演练
  • [Oracle数据库] ORACLE基本DML操作
  • 图论Day2学习心得
  • Pytest本地插件定制及发布指南
  • 代码随想录Day50:图论(图论理论、深度搜索理论、所有可达路径、广度搜索理论)
  • python sqlite3模块
  • 高效解决 pip install 报错 SSLError: EOF occurred in violation of protocol
  • 《贵州棒球百科》体育赛事排名·棒球1号位