Docker基础知识之Linux namespace图文详解

 更新时间:2018年03月14日 10:22:23   作者:bakari  
这篇文章主要给大家介绍了关于Docker基础知识之Linux namespace的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。

前言

Docker 是“新瓶装旧酒”的产物,依赖于 Linux 内核技术 chroot 、namespace 和 cgroup。本篇先来看 namespace 技术。

Docker 和虚拟机技术一样,从操作系统级上实现了资源的隔离,它本质上是宿主机上的进程(容器进程),所以资源隔离主要就是指进程资源的隔离。实现资源隔离的核心技术就是 Linux namespace。这技术和很多语言的命名空间的设计思想是一致的(如 C++ 的 namespace)。

隔离意味着可以抽象出多个轻量级的内核(容器进程),这些进程可以充分利用宿主机的资源,宿主机有的资源容器进程都可以享有,但彼此之间是隔离的,同样,不同容器进程之间使用资源也是隔离的,这样,彼此之间进行相同的操作,都不会互相干扰,安全性得到保障。

为了支持这些特性,Linux namespace 实现了 6 项资源隔离,基本上涵盖了一个小型操作系统的运行要素,包括主机名、用户权限、文件系统、网络、进程号、进程间通信。

这 6 项资源隔离分别对应 6 种系统调用,通过传入上表中的参数,调用 clone() 函数来完成。

int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);

clone() 函数相信大家都不陌生了,它是 fork() 函数更通用的实现方式,通过调用 clone() ,并传入需要隔离资源对应的参数,就可以建立一个容器了(隔离什么我们自己控制)。

一个容器进程也可以再 clone() 出一个容器进程,这是容器的嵌套。

如果想要查看当前进程下有哪些 namespace 隔离,可以查看文件 /proc/[pid]/ns (注:该方法仅限于 3.8 版本以后的内核)。

可以看到,每一项 namespace 都附带一个编号,这是唯一标识 namespace 的,如果两个进程指向的 namespace 编号相同,则表示它们同在该 namespace 下。同时也注意到,多了一个 cgroup,这个 namespace 是 4.6 版本的内核才支持的。Docker 目前对它的支持普及度还不高。所以我们暂时先不考虑它。

下面通过简单的代码来实现 6 种 namespace 的隔离效果,让大家有个直观的印象。

UTS namespace

UTS namespace 提供了主机名和域名的隔离,这样每个容器就拥有独立的主机名和域名了,在网络上就可以被视为一个独立的节点,在容器中对 hostname 的命名不会对宿主机造成任何影响。

首先,先看总体的代码骨架:

#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#define STACK_SIZE (1024 * 1024)

static char container_stack[STACK_SIZE];
char* const container_args[] = {
 "/bin/bash",
 NULL
};

// 容器进程运行的程序主函数
int container_main(void *args)
{
 printf("在容器进程中!\n");
 execv(container_args[0], container_args); // 执行/bin/bash return 1;
}

int main(int args, char *argv[])
{
 printf("程序开始\n");
 // clone 容器进程
 int container_pid = clone(container_main, container_stack + STACK_SIZE, SIGCHLD, NULL);
 // 等待容器进程结束
 waitpid(container_pid, NULL, 0);
 return 0;
}

该程序骨架调用 clone() 函数实现了子进程的创建工作,并定义子进程的执行函数,clone() 第二个参数指定了子进程运行的栈空间大小,第三个参数即为创建不同 namespace 隔离的关键。

对于 UTS namespace,传入 CLONE_NEWUTS,如下:

int container_pid = clone(container_main, container_stack + STACK_SIZE, SIGCHLD | CLONE_NEWUTS, NULL);

为了能够看出容器内和容器外主机名的变化,我们子进程执行函数中加入:

sethostname("container", 9);

最终运行可以看到效果如下:

IPC namespace

IPC namespace 实现了进程间通信的隔离,包括常见的几种进程间通信机制,如信号量,消息队列和共享内存。我们知道,要完成 IPC,需要申请一个全局唯一的标识符,即 IPC 标识符,所以 IPC 资源隔离主要完成的就是隔离 IPC 标识符。

同样,代码修改仅需要加入参数 CLONE_NEWIPC 即可,如下:

int container_pid = clone(container_main, container_stack + STACK_SIZE, SIGCHLD | CLONE_NEWUTS | CLONE_NEWIPC, NULL);

为了看出变化,首先在宿主机上建立一个消息队列:

然后运行程序,进入容器查看 IPC,没有找到原先建立的 IPC 标识,达到了 IPC 隔离。

PID namespace

PID namespace 完成的是进程号的隔离,同样在 clone() 中加入 CLONE_NEWPID 参数,如:

int container_pid = clone(container_main, container_stack + STACK_SIZE, SIGCHLD | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID, NULL);

效果如下,echo $$ 输出 shell 的 PID 号,发生了变化。

但是对于 ps/top 之类命令却没有改变:

具体的原因和接下来的内容(包括 mount namespace,network namespace 和 user namespace),大家可以关注我的公众号阅读,那里的阅读体验会更好一些。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • docker system prune命令使用示例详解

    docker system prune命令使用示例详解

    docker system prune是一个用于清理Docker系统资源的命令,它用于删除未使用的数据(如未使用的镜像、容器、网络和存储卷)以释放磁盘空间,下面这篇文章主要给大家介绍了关于docker system prune命令使用示例的相关资料,需要的朋友可以参考下
    2024-04-04
  • docker配置修改阿里云镜像仓库的实现

    docker配置修改阿里云镜像仓库的实现

    这篇文章主要介绍了docker配置修改阿里云镜像仓库的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • docker获取Let''s Encrypt永久免费SSL证书的方法

    docker获取Let''s Encrypt永久免费SSL证书的方法

    在本篇文章里小编给大家分享了一篇关于docker获取Let's Encrypt永久免费SSL证书的方法,以后需要的朋友们可以参考下。
    2021-01-01
  • Docker挂载的三种方法及使用场景分析

    Docker挂载的三种方法及使用场景分析

    在Docker容器中,持久化存储和数据共享是非常重要的功能,Docker提供了三种主要的方法来实现宿主机和容器之间的数据挂载,本文将详细介绍这三种方法的基本语法,并探讨它们各自的使用场景,需要的朋友可以参考下
    2024-05-05
  • Docker 部署Django项目的方法示例

    Docker 部署Django项目的方法示例

    这篇文章主要介绍了Docker 部署Django项目的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • 关于docker启动jenkins环境的问题

    关于docker启动jenkins环境的问题

    这篇文章主要介绍了docker启动jenkins环境的问题,文中提到了jenkins基本工作原理及管理员密码获取方法,对docker启动jenkins环境相关知识感兴趣的朋友一起看看吧
    2022-04-04
  • docker常用命令整理汇总(新手必备!)

    docker常用命令整理汇总(新手必备!)

    这篇文章主要给大家介绍了关于docker常用命令的相关资料,包括docker的启动、停止、重启、创建、查看等等,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • docker-entrypoint.sh文件的用处详解

    docker-entrypoint.sh文件的用处详解

    这篇文章主要介绍了docker-entrypoint.sh文件的用处,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • 两小时入门Docker教程实践

    两小时入门Docker教程实践

    这篇文章主要介绍了两小时入门Docker教程实践,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • 虚拟机如何安装指定版本的Docker举例详解

    虚拟机如何安装指定版本的Docker举例详解

    这篇文章主要介绍了虚拟机如何安装指定版本的Docker的相关资料,包括配置yum源、查看可用版本、安装指定版本、卸载旧版本、解决冲突、再次安装以及最后验证安装,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2024-12-12

最新评论