深入刨析容器(二):容器的进程

这章节主要是从容器的技术概念入手,说一下容器的基础,有了好的基础才能更好的理解容器这门技术,先说一下容器和进程的关系,后续的文章会说进程的隔离与限制资源以及容器的内部灵魂,来一点点深入容器,话不多说,那么开始把!

1.从进程说开去

之前的章节说过容器就是一个“沙盒”,把一个个应用存储在里面,看似是隔离的,那么我们接下来就要讲怎么塑造这样的一个盒子将我们的应用隔离限制起来,那么第一个要说的就是进程,我们运行应用就需要用到进程。

我们的程序都是运行在进程里的,进程的静态表现就是程序,平常都安安静静地待在磁盘上,但是一旦运行起来就变成计算机里的数据和状态的总和,这就是它的动态表现。容器核心的技术实现就是约束和修改进程的动态表现,为其创造出一个“边界”。对于Docker和大部分的linux容器来说,Cgroups技术用来制造约束的手段,Namespace技术则用来修改进程视图的主要方法(后文会讲)。

Linux Cgroups的全称是linux controller group:它最主要的作用就是限制一个进程组能够使用的资源上线,包括CPU、内存、磁盘、网络带宽等等。

1.1 Namespace

动手实践一下理解Namespace,咱们先创建容器试试,

$ docker run -it busybox /bin/sh
/ #

docker run 我们需要启动一个容器,-it 则是容器启动后分配一个文本输入/输出环境,/bin/sh 就是我们要在 docker 容器里运行的程序。

busybox:linux里的命令软件,如ls,cat等等。

上面的命令的意思是:请帮我启动一个容器,在容器里执行 /bin/sh,并且给我分配一个命令行终端跟这个容器交互,这样,Ubuntu 16.04 机器就变成了一个宿主机,而一个运行着 /bin/sh 的容器,就跑在了这个宿主机里面。

此时,如果我们在容器里执行一下 ps 指令,就会发现一些更有趣的事情:

/ # ps
PID  USER   TIME COMMAND
  1 root   0:00 /bin/sh
  10 root   0:00 ps

我们发现第一行的PID是1,运行着/bin/sh,正常情况下我们这个进程肯定不是1,因为我们宿主机运行着大量的进程,也许正常这个PID=100也说不定,那说明已经被 Docker 隔离在了一个跟宿主机完全不同的世界当中,而这种技术就是Linux的Namespace机制

Namespace机制:

Linux的Namespace主要是通过调用系统的Clone()创建进程时指定进程号,比如:

系统调用就会为我们创建一个新的进程,并且返回它的进程号 pid

int pid = clone(main_function, stack_size, SIGCHLD, NULL); 

我们用 clone() 系统调用创建一个新进程时,就可以在参数中指定 CLONE_NEWPID 参数,比如:

int pid = clone(main_function, stack_size, CLONE_NEWPID | SIGCHLD, NULL); 

这时,新创建的这个进程将会“看到”一个全新的进程空间,使其看不到其他的宿主机的进程,当然,我们还可以多次执行上面的 clone() 调用,这样就会创建多个 PID Namespace,而每个 Namespace 里的应用进程,都会认为自己是当前容器里的第 1 号进程,它们既看不到宿主机里真正的进程空间,也看不到其他 PID Namespace 里的具体情况,使其看似隔离,这种技术就是linux的Namespace机制。

其实上述的操作实践也叫PID Namespace,Linux除了给予这样的Namespace方式,Linux 操作系统还提供了 Mount、UTS、IPC、Network 和 User 这些 Namespace,用来对各种不同的进程上下文进行“障眼法”操作。

如:Mount Namespace :用于让被隔离进程只看到当前 Namespace 里的挂载点信息,Network  Namespace:用于让被隔离进程看到当前 Namespace 里的网络设备和配置。

这就是Linux容器的基本实现原理,

Docker 容器的概念,实际上是在创建容器进程时,指定了这个进程所需要启用的一组 Namespace 参数。这样,容器就只能“看”到当前 Namespace 所限定的资源、文件、设备、状态,或者配置。而对于宿主机以及其他不相关的程序,它就完全看不到了。

容器,只是特殊的一种进程而已。

看完本章节你会发现容器不是真正的虚拟机,还是运用着Linux内核来运行程序,只不过通过了Namespace的手段给屏蔽了,那么既然还是共享着内核,那么就会衍生很多问题,所以下一节会给大家说下容器的隔离与限制。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
map容器和unordered_map容器的主要区别在于底层实现和性能特征。 1. 底层实现: - map容器是基于红黑树(一种平衡叉搜索树)实现的有序映射容器。红黑树的特点是插入、删除和查找操作的时间复杂度都是O(log n),并且元素按照键的顺序进行排序。 - unordered_map容器是基于哈希表实现的无序映射容器。哈希表的特点是插入、删除和查找操作的平均时间复杂度是O(1),但是最坏情况下的时间复杂度是O(n)。 2. 性能特征: - map容器适用于需要有序访问元素的场景,例如需要按照键的顺序进行遍历或查找元素。 - unordered_map容器适用于不需要有序访问元素的场景,例如需要快速插入、删除和查找元素。 下面是一个示例演示map容器和unordered_map容器的使用: ```cpp #include <iostream> #include <map> #include <unordered_map> int main() { // 使用map容器 std::map<int, std::string> mapContainer; mapContainer[1] = "apple"; mapContainer[2] = "banana"; mapContainer[3] = "orange"; std::cout << "map容器中的元素:" << std::endl; for (const auto& pair : mapContainer) { std::cout << pair.first << ": " << pair.second << std::endl; } // 使用unordered_map容器 std::unordered_map<int, std::string> unorderedMapContainer; unorderedMapContainer[1] = "apple"; unorderedMapContainer[2] = "banana"; unorderedMapContainer[3] = "orange"; std::cout << "unordered_map容器中的元素:" << std::endl; for (const auto& pair : unorderedMapContainer) { std::cout << pair.first << ": " << pair.second << std::endl; } return 0; } ``` 输出结果: ``` map容器中的元素: 1: apple 2: banana 3: orange unordered_map容器中的元素: 2: banana 1: apple 3: orange ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值