虚拟化/容器化
概念
虚拟化:通过虚拟化技术将一台物理机虚拟为多台逻辑计算机。
虚拟化常见类别:
虚拟机:硬件层面的虚拟化,实现和真实物理机几乎一样的功能
容器:操作系统层的虚拟化
JVM 之类的虚拟机:存在于函数库层和应用程序之间的虚拟化技术,为程序员提供一个提供统一的运行环境
容器化:一种虚拟化技术,又称操作系统层虚拟化,将操作系统内核虚拟化,容器之间共享操作系统内核,每个容器可以配置自己的运行时环境,有独立的文件系统。相当于在一个房子里面开辟出一个个胶囊公寓,每个胶囊共享房子的洗手间,WiFi。胶囊内部又是一个独立的空间
原因
- 资源利用率高,用较少成本管理多台服务器
- 环境标准化,镜像提供除内核外完整的运行时环境
- 沙箱安全,容器内部的操作不会影响到容器外部
- 容器比虚拟机更加轻量,前者直接运行与宿主内核,无需启动完整的操作系统。
容器虚拟化实现
通过namespace进行各程序的隔离,加上cgroups进行资源控制以进行虚拟化,以下操作使用cgroup v1 实现
namespace
namespace是Linux内核用来隔离内核资源的一种方式。通过namespace可以让一些进程只能看到与自己相关的一些资源,不同namespace进程拥有独立的全集资源,相互之间无法感应,改变一个namespace的系统资源只会影响当前namespace的进程
| Namespace 类型 | 隔离内容 | Docker 对应能力 |
|---|---|---|
| PID | 进程号空间,容器内 PID 从 1 开始 | 容器进程隔离,看不到宿主机进程 |
| Mount | 文件系统挂载点视图 | 容器独立根目录、数据卷挂载隔离 |
| Network | 网卡、端口 | 容器独立 IP、端口、网络栈 |
| UTS | 主机名与域名 | 容器可设置独立 hostname |
| IPC | 进程间通信(信号量、共享内存等) | 容器间 IPC 隔离 |
| User | 用户 / 用户组 ID 映射 | 容器内 root 映射为宿主机普通用户,降权 |
实现PID隔离:
unshare --fork --pid --mount-proc /bin/bash--fork:创建一个子进程
--pid:隔离进程命名空间,/bin/bash为一号进程
--mount-proc:在新的PID空间里重新生成一份只包含当前环境进程的/proc文件,防止ps命令读取宿主机的/proc文件
实现mount隔离:
文件系统隔离,在隔离空间内挂载目录,宿主机不可见
shell窗口1 unshare --mount --fork /bin/bash mkdir -p /data/tmpmount dd if=/dev/zero of=fdimage.img bs=8k count=10240 在目录下生成一个全0空白文件fdimage.img,大小为80mb mkfs -t ext4 ./fdimage.img 将fdimage.img格式化为ext4文件系统 mount ./fdimage.img /data/tmpmount 将fdimage.img挂载到/data/tmpmount目录下,成功后进入/data/tmpmount写入的任何数据,都会添加到fdimage.img shell窗口2在窗口2无法感知/data/tmpmount有镜像挂载,窗口1对镜像进行操作,窗口2也无法感知
cgroups
cgroups是Linux内核提供的一种机制,这种机制可以根据需求把一系列进程及其子进程按照所需资源不同划分到不同的组内,每组有单独的资源划分方案,以实现对容器的cpu,内存等实现精细化控制
实现对CPU进行控制:
进入cgroup的cpu控制目录,创建一个CPU控制组
启动stress进程,将CPU打满,
stress -c 1设置控制组CPU占用上限,cfs_quota_us存储Cgroup可以使用的cpu带宽,单位是微秒
echo 20000 > cpu.cfs_quota_us将stress进程PID放入控制组
echo 38578 > tasksCPU占用率降低
UnionFS
联合文件系统,docker镜像由一层层只读层堆叠而成,不同镜像之间可以共享底层基础镜像。当容器启动时,docker只会在只读的镜像层之上增加一个容器层(可读写层)。容器内的所有修改都在这一层执行,一旦容器被删除,这一层的数据也会丢失
LXC
Linux Containers Linus容器,容器化技术的具体实现,上层将应用软件打包成一个软件容器。内部存放了软件本身的代码以及所需要的操作系统核心和动态链接库,下层通过namespace技术实现文件系统的隔离,通过cgroup技术实现对系统资源的精细化控制
Docker
概念
早期Docker是LXC的增强版,它本身不是容器,并没有单独实现一个容器,而是一个容器的易用工具。底层是对LXC的二次封装,但是创建容器时不再使用模板进行生成,而是通过镜像技术(将一个操作系统的用户空间所使用的组件,编排好并打包成一个镜像文件),镜像文件集中放在镜像仓库。当需要创建容器时,docker连接到镜像服务器上下载匹配的文件。
docker的主要目标就是通过对组建的封装,分发,部署,运行等声明周期的管理,实现"一次构建,到处运行"
Docker 的引擎迭代
Docker早期是基于LXC容器管理引擎实现,当后来成熟之后,Docker自建了一个叫做libcontainer的引擎。之后Docker又研发了一个工业化标准的容器引擎 runC
Docker和虚拟机的区别

- 共享操作系统内核,磁盘占用低
- 安装管理比虚拟机方便,能够实现自动化部署
- 虚拟机通过虚拟层实现与硬件的交互,容器则直接与硬件交互,资源利用率高
- 虚拟机隔离性是系统级别,Docker是进程级别
- docker启动更快,不需要像虚拟机一样加载整个操作系统内核
架构
docker采用客户端-服务器架构,现代调用链:Docker Client -> daemon -> containerd -> containerd-shim -> runC

Docker Registry:docker仓库,用来保存镜像
Docker daemon;服务器组件,docker最核心的后台进程,称为守护进程
Docker Client:使用命令行或其他工具通过docker api与守护进程进行通信
Docker Host:用于执行docker守护进程
Docke Images;docker容器的模板
Docker Container:模板启动后,就成为docker容器,独立运行一个或一组应用

