先给出答案再来分析过程:

一个完整的 os 应该有:
bootloader + kernel + rootfs + lib + sbin/tools(包管理工具等等) + shell 构成,在此之上才是用户运行自己的 app。
而 Docker 容器中不包含完整的 Client OS,而是 OS 的一部分:rootfs + lib + shell/app 这一部分。

下面来看看 Docker 容器中究竟有些什么:

docker为什么只能启动一个网站 docker version只有client_docker


这个是 docker 和传统虚拟机的官方区别描述,显然官方认为在 docker 容器中是没有 guest os 的。

可是我们在日常 pull 的一个 image 时都表明自己的 ClientOS 类型,或者是先通过 pull 一个 centos 或 ubuntu 等创建一个基础 image,然后加入自己的工作内容,比如安装一个 mysql。

按照上图的理解 mysql 为 App,本机系统为 Host OS,可是我们刚才 pull 回来的 centos 又是图中的哪一层呢?难道是 bins/libs?还是说这种做法就是有一个 client os 存在?

答案是:
这里的 centos 就是 bins/libs 层,只是提供了mysql运行最基本的一个环境,那个容器内部,除了mysql这个应用外就没有别的服务在跑了,可以看成一个独立出来的mysql进程。可以开个容器进去top看看,会看到只有一个 mysql 进程。

比如我用官方的 centos 镜像创建了为基础,创建了一个自己的镜像运行自己的一个程序,当我的程序调用了一个 c 函数时,其实是调用的 centos 提供的 glibc(而不是我的 host os 的 glibc),这个c函数又调用了一个系统函数,此时调用的就是 host os 的系统函数(而不是 centos 中的系统函数)。

因为容器中是不包含 kernel 的。一个完整的 os 应该有:
bootloader + kernel + rootfs + lib + sbin/tools(包管理工具等等) + shell 构成
在此之上才是用户运行自己的 app。而上面 docker 中的 centos(容器) 实际上是没有 bootlaoder 和 kernel 的。在容器中可以发现没有 /boot/ 目录存在(bootloader 和 kernel 都在这个目录下)。同时容器中是有 /lib/,/sbin/,/bin/ 等目录存在的。
在结合上面的 docker 自己官方的说明,容器就是 app + bin/lib 所以可以判断,容器中的 app 访问 c 函数时是调用的容器中的 glibc,而访问系统调用时就是调用的 host os 的 kernel 提供的系统函数。

根据下面的 uname -a 的输入,可以看出在 host、centos-base、alpine-base、busybox-base各个环境下的内核是一个版本,其实都是 host 的内核。

host 上执行: 
$ uname -a: 
Linux localhost.localdomain 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

centos-base 执行: 
$ uname -a:
Linux d9e3c6c4933c 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

alpine-base 执行:
$ uname -a:
Linux 60947a83b80a 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 Linux

busybox-base 执行:$
uname -a:
Linux 3f5a6b025833 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015 x86_64 GNU/Linux