本文是 Docker核心技术 系列文章:Docker原理之Namespace,其他文章快捷链接如下:
- 应用架构演进
- 容器技术要解决哪些问题
- Docker的基本使用
- Docker是如何实现的
- Docker核心技术:Docker原理之Namespace(本文)
- Docker核心技术:Docker原理之Cgroups
- Docker核心技术:Docker原理之Union文件系统
4.1.容器标准
- 发展故事
- 当时Docker特别火热,横扫业界的容器技术,发展迅速。谷歌不甘示弱,接着开源了kubernetes
- 但是kubernetes刚出来,是打不过docker的,所以谷歌采用了标准化的手段来和Docker竞争
- 谷歌提出了容器的标准OCI,让Docker来接入自己,可Docker认为自己是事实标准,不同意接入
- 于是谷歌找到了其他的一些大厂,推进标准化,在kubernetes中支持docker之外的runtime来竞争
- 另一方面,Docker本身也存在一些问题,比如迟迟没有盈利点、发展太快导致管理混乱等
- 随着kubernetes越来越强,Docker不得不服软,同意接入OCI
- Docker的创举主要在第二个规范
- Docker创造性的利用OverlayFS,实现了镜像分层的打包方式。
- 比如一个镜像有4层,在pull image的时候,如果发现前3层没有变化,则直接可以使用本地的缓存
- 这种方式解决了业界非常头疼的 文件分发 的问题,所有公司不需要自己再考虑文件分发,程序拷贝等问题
- 以Docker Repository作为公共的File Server(不需要每个公司自己建一个自己的)
- 以Docker Engine作为公司机器上用于接受指令的Agent
4.2.容器主要特性
- 安全性
- 隔离性:namespace
- 便携性
- 可配额:cgroup
4.3.Namespace:隔离性
4.3.1.Namespace是什么
-
Linux内核中,Namespace的实现
- 无论进程还是线程,在Linux Kernel来看,都是一个Task,每一个Task,都有一个nsproxy的属性
- nsproxy结构中,包含5个namespace:uts_ns、ipc_ns、mnt_ns、pid_ns、net_ns
4.3.2.进程如何分到namespace
-
LinuxOS 第一个进程,一般是systemd,pid=1,会分给它一个默认的namespace
-
启动其他进程时,对namespace的操作方法,包括:
- clone:可以为进程指定新的namespace
- setns:通过系统调用,把进程加入已经存在的namespace
- unshare:通过系统调用,把进程移到新的namespace下
4.3.3.Namespace的类型
-
不同Namespace所支持的Linux Kernel版本如下:
- 现在我们用的Kernel都很新了,一般都是支持的
- 后面演进中,可能还会有新的ns出现,不过现在kubernetes支持的就这些
-
理解不同ns的关系和区别
-
不同ns详解
- Docker本身把这些ns都实现了,不过kubernetes利用这些ns时稍有不同
- 比如namespace本身是不可以嵌套的,但是kubernetes中namespace是可以嵌套的
-
对于进程来说
- 一个进程,有了独立的主机名、独立的ip地址、独立的user namespace用户管理,那么实际上就是拥有了一个虚拟的OS
-
对于应用开发人员来说
- 一个服务,有了独立的网络身份,有独立的ip+port,就达到了微服务的目的
4.3.4.Namespace常用操作
-
lsns:list当前主机上所有的ns
-
lsns -t :list指定类型的ns
-
ls -la /proc//ns/:查看指定进程的ns
-
nsenter -t -n ip adds:进入指定进程的指定ns中,执行指定命令
-
比如这里写的就是,进入指定pid进程的 -n网络ns中,执行 ip addr 命令
-
这条命令非常常用,比如现在容器遇到了问题,但是docker的image非常小,没有各种调试命令,那么你就可以在主机上找到容器对应的pid,进入ns去查看和调试
-
示例:在容器中执行命令---在主机上进入指定ns后执行命令,结果是一样的
-
4.3.5.namespace练习
-
打开两个终端,一个执行命令,一个查看进程信息
-
执行命令之后,这个终端会暂停在这里60s,要抓紧查看,要不就退出来了
-
查看进程信息,pid为15368
-
查看这个进程所在的net ns,果然在一个新的net ns
-
进入该进程的net ns,执行命令 ip a
-
可以看到,这个进程只有一个lo,没有eth0。因为我们只是启动了一个进程,没有人为它配置ip
-
而docker容器之所以有eth0,是因为docker有自己的网络插件,会为容器配ip,比如下面是一个docker容器,docker使用bridge模式为其分配了一个172.17.0.2/16的ip
-
-