C++实现简易Docker容器——第一讲基础入门
Docker 的本质是使用 LXC 实现类似虚拟机的功能,进而节省的硬件资源提供给用户更多的计算资源。本项目将 C++ 与 Linux 的 Namespace 及 Control Group 技术相结合,实现一个简易 Docker 容器。
|
1、独立的文件系统
2、网络访问的支持
3、容器资源的限制
本期目录
一、Linux Namespace技术
二、Clone系统调用
三、其他函数
一、Linux Namespace技术
-
在 C++ 中,我们知道有 namespace 这个关键字。在 C++ 中,每一个 namespace 对不同代码的相同名称进行了隔离,只要 namespace 的名称不同,就能够让 namespace 中的代码名称相同,从而解决了代码名称冲突的问题。
-
而 Linux Namespace 则是 Linux 内核提供的一种技术,它为应用程序提供了一种资源隔离的方案,和 C++ 中的 namespace 有异曲同工之妙。我们知道,PID、IPC、网络等系统资源本应该属于操作系统本身进行管理,但 Linux Namespace 则可以让这些资源的全局性消失,让一部分属于某个特定的 Namespace。
-
在 Docker 技术中,我们时常听说 LXC、操作系统级虚拟化这些名词,而 LXC 就是利用了 Namespace 这种技术实现了不同容器之前的资源隔离。利用 Namespace 技术,不同的容器内进程属于不同的 Namespace,彼此不相干扰。总的来说,Namespace 技术,提供了虚拟化的一种轻量级形式,使我们可以从不同方面来运行系统全局属性。
-
在 Linux 中,和 Namespace 相关的系统调用最重要的就是 clone()。 clone() 的作用是在创建进程时,将线程限制在某个 Namespace 中。
返回顶部目录
二、Clone系统调用
* clone 的函数原型如下:int clone(int (*fn)(void *), void *child_stack, int flags, void *arg);
fork 在创建一个进程的时候,子进程会完全复制父进程的资源。而 clone 则比 fork 更加强大,因为 clone 可以有选择性的将父进程的资源复制给子进程,而没有复制的数据结构则通过指针的复制让子进程共享(arg),具体要复制的资源,则可以通过 flags 进行指定,并返回子进程的 PID。
-
进程四大要素:
1、一段需要执行的程序
2、进程自己的专用堆栈空间
3、进程控制块(PCB)
4、进程专有的 Namespace
前两点要素在 clone 中对应的参数很明显,分别为 fn 和 child_stack。而对于进程控制块来说,由内核控制我们不需要关心,因此,Namespace 就落在了 flags 的身上。我们要实现一个满足我们之前所定目标的 Docker 容器,需要的主要参数如下:Namespace 分类 系统调用参数 备注 UTS CLONE_NEWUTS 供了主机名相关的设置 Mount CLONE_NEWNS 提供了文件系统相关的挂载,用于复制和文件系统相关的资源 PID CLONE_NEWPID 提供了独立的进程空间支持 Network CLONE_NEWNET 提供了网络相关支持
返回顶部目录
三、其他函数
-
execv()
int execv(const char *path, char *const argv[]);
execv 可以通过传入一个 path 来执行 path 中的执行文件,这个系统调用可以让我们的子进程执行 /bin/bash 从而让整个容器保持运行。
-
sethostname
int sethostname(const char *name, size_t len);
从名字不难看出,这个系统调用能够设置我们的主机名,值得一提的是,由于 C 风格的字符串使用的是指针,不指定长度是无法直接从内部得知字符串长度的,这里 len 起到了获得字符串长度的作用。
-
chdir
int chdir(const char *path);
我们知道,任何一个程序,都会在某个特定的目录下运行。当我们需要访问资源时,就可以通过相对路径而不是绝对路径来访问相关资源。而 chdir 恰好提供给了我们一个便利之处,那就是可以改变我们程序的运行目录,从而达到某些不可描述的目的。
-
chroot
int chroot(const char *path);
这个系统调用能够用于设置根目录
-
mount
int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
这个系统调用用于挂载文件系统,和 mount 这个命令能够达到相同的目的。
返回顶部目录
下期预告:使用namespace进行资源隔离