当前位置: 首页 > 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.dtcms.com/a/331117.html

相关文章:

  • Java毕业设计选题推荐 |基于SpringBoot的健身爱好线上互动与打卡社交平台系统 互动打卡小程序系统
  • 2019 GPT2原文 Language Models are Unsupervised Multitask Learners - Reading Notes
  • [激光原理与应用-274]:理论 - 波动光学 - 光是电磁波,无线电磁波可以通过天线接收和发送,为什么可见光不可以?
  • Visual Studio2019/2022离线安装完整教程(含闪退解决方法)
  • 无人机双目视觉设计要点概述!
  • SOD-YOLO:基于YOLO的无人机图像小目标检测增强方法
  • 值传递+move 优化数据传递
  • torchvision中数据集的使用与DataLoader 小土堆pytorch记录
  • Autoppt-AI驱动的演示文稿生成工具
  • 深入理解 RAG:检索增强生成技术详解
  • 通过机器学习框架实现Android手写识别输入功能
  • 【开源工具】基于硬件指纹的“一机一码”软件授权系统全实现(附完整源码)
  • MapReduce系统架构,颠覆了互联网分层架构的本质?
  • xiaozhi-esp32 仓库分析文档
  • 树莓派 4B 上部署 Minecraft PaperMC 1.20.x 的一键部署脚本
  • [论文阅读] 人工智能 + 软件工程 | 代码变更转自然语言生成中的幻觉问题研究解析
  • 智能家居主控板:智慧家庭的核心大脑
  • 华为实验 链路聚合
  • 实测对比:飞算JavaAI vs 人工编码,谁在效率与质量上更胜一筹?
  • C#WPF实战出真汁03--登录功能实现
  • 本文详细讲解QJson 的用法
  • 带root权限_贝尔RG020ET-CA融合终端S905L处理器当贝纯净版刷机教程
  • Android init.rc详解2
  • 前端vue框架
  • 算法题Day1
  • Ubuntu 22.04 远程桌面设置固定密码的方法
  • 使用colmap自制3DGaussian_Splatting数据集
  • OpenCV 形态学操作
  • spring mvc HttpMessageConverter 消息转换器
  • 性能测试环境的软硬件配置