- 容器只能使用宿主机的kernel版本,且不能修改
- 如果某一应用只能在特定的kernel版本下运行,应该使用虚拟机
- 所谓的“应用依赖内核”是指程序直接进行内核调用,而不是仅仅使用c运行库
- 如果你要在 Windows 宿主机上运行 Linux 容器,或者在低版本的 Linux 宿主机上运行高版本的 Linux 容器,都是行不通的
- namespace技术实现了容器的资源隔离
- 包括mount, UTS, IPC, PID, Network, User
- 本地docker客户端(CLI)与docker服务器使用HTTP协议通信
- docker底层实现原理
- cgorups
- namespace
- UionFS
- Docker最核心的原理就是为待创建的用户进程做以下三件事
- 启用 Linux Namespace 配置
- 设置指定的 Cgroups 参数
- 切换进程的根目录(Change Root)
隔离
- docker中运行的程序通过namespace技术使其看不到其余进程,所以在docker中会重新计算进程号,但是实际上在原来的宿主机中,这个程序仍然有个原本分配的进程号
- 每一个进程都有一个
namespace
,可以在/proc/<pid_num>/ns
目录下查看 docker exec
就是通过加入容器的namespace·
中进入容器的- 也就是会创建一个和容器共享
namespace
的新进程
- 也就是会创建一个和容器共享
- 每一个进程都有一个
- 使用虚拟化技术作为应用沙盒,就必须要由 Hypervisor 来负责创建虚拟机,这个虚拟机是真实存在的,并且它里面必须运行一个完整的 Guest OS 才能执行用户的应用进程。这就不可避免地带来了额外的资源消耗和占用
- 跟真实存在的虚拟机不同,在使用 Docker 的时候,并没有一个真正的“Docker 容器”运行在宿主机里面。Docker 项目帮助用户启动的,还是原来的应用进程,只不过在创建这些进程时,Docker 为它们加上了各种各样的 Namespace 参数
- 容器本质上就是一个加了限定参数的进程
- docker engine 只是一种启动时用,运行时并不需要,真实进程(容器)是直接run在host os上
- 宿主机可以直接控制容器内的进程,包括kill
- 容器化后的用户应用,却依然还是一个宿主机上的普通进程,这就意味着这些因为虚拟化而带来的性能损耗都是不存在的;而另一方面,使用 Namespace 作为隔离手段的容器并不需要单独的 Guest OS,这就使得容器额外的资源占用几乎可以忽略不计
- 在容器内,除了pid=1的进程,其他进程是不受docker控制的
- 通过exec进去之后启动的后台进程,不受控制。控制指的是它们的回收和生命周期管理
- 其他进程挂掉了docker也感知不到
- 使用
-link
选项关联容器,不但可以避免容器IP和端口暴露到外部导致的安全问题,还能避免容器在重启后IP地址变动导致的访问失败- 原理类似DNS的IP和域名映射
限制
- 虽然容器内的第 1 号进程在“障眼法”的干扰下只能看到容器里的情况,但是宿主机上,它作为第 100 号进程与其他所有进程之间依然是平等的竞争关系。这就意味着,虽然第 100 号进程表面上被隔离了起来,但是它所能够使用到的资源(比如 CPU、内存),却是可以随时被宿主机上的其他进程(或者其他容器)占用的
- Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等
- cgroups只能限制上限,不能限制下限,所以需要k8s等应用的调度
文件系统
- 容器进程在启动前会挂载根目录到镜像提供的文件系统
- 修改iNode
- 镜像只是提供了一套镜像文件系统中的各种文件,而各种内核相关的模块或者特性支持,完全依赖于宿主机
- 不同版本的linux OS公用相同的kernel,主要不同在于rootfs文件系统
- rootfs 只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在 Linux 操作系统中,这两部分是分开存放的
- 由于 rootfs 里打包的不只是应用,而是整个操作系统的文件和目录,也就意味着,应用以及它运行所需要的所有依赖,都被封装在了一起
- 这就赋予了容器所谓的一致性:无论在本地、云端,还是在一台任何地方的机器上,用户只需要解压打包好的容器镜像,那么这个应用运行所需要的完整的执行环境就被重现出来了
- 使用联合文件系统对rootfs进行增量修改
- 不同镜像的底层可以共用 (只读层)
- 在容器内对只读层的任何修改,都会被操作系统把相应内容复制到可读写层,然后再修改
- 为了实现删除操作,AuFS 会在可读写层创建一个 whiteout 文件,把只读层里的文件“遮挡”起来
- 所以删除一些文件后镜像体积反而变大
- 所以删除一些文件后镜像体积反而变大