虚拟化容器化与docker
- 基本概念
- 虚拟化分类
- 虚拟化实现
- 主机虚拟化实现
- 容器虚拟化实现
- 命名空间namespace
- 空间隔离
- 控制组群cgroup
- 资源隔离
- LXC(Linux Container)
- docker与虚拟机
基本概念
物理机
: 实际的服务器或者计算机。相对于虚拟机而言的对实体计算机的称呼。物理机提供给虚拟机以硬件环境,有时也称为“寄主”或“宿主”。
虚拟化
:是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。
容器化
:容器化是一种虚拟化技术,又称操作系统层虚拟化(Operating system levelvirtualization),这种技术将操作系统内核虚拟化,可以允许用户空间软件实例(instances)被分割成几个独立的单元,在内核中运行,而不是只有一个单一实例运行。这个软件实例,也被称为是一个容器(containers)。对每个实例的拥有者与用户来说,他们使用的服务器程序,看起来就像是自己专用的。容器技术是虚拟化的一种,docker 是现今容器技术的事实标准
容器化与虚拟化的意义:
- 资源利用率高(更少的资源运行更多的业务)
- 环境标准化(docker保证应用运行环境一致)
- 资源弹性伸缩
- 差异化环境提供(比如只有一台物理机,但依赖两种os)
虚拟化分类
应用程序执行环境分层:
- 硬件层:提供硬件抽象,包括指令集架构、硬件设备及硬件访问接口
- 操作系统层 :提供系统调用接口,管理硬件资源
- 函数库层
- 应用程序库层:提供数据结构定义及函数调用接口
分类
- 虚拟机:通过“伪造”一个硬件抽象接口,将一个操作系统以及操作系统层以上的层嫁接到硬件上,实现和真实物理机几乎一样的功能
- 容器:通过“伪造”操作系统的接口,将函数库层以上的功能置于操作系统上
- JVM类虚拟机:在应用层与函数库层之间建立一个抽象层,对下通过不同的版本适应不同的操作系统函数库,对上提供统一的运行环境交给程序和开发者,使开发者能够调用不同操作系统的函数库
虚拟化实现
主机虚拟化实现
有两种Type的Hypervisor
- Type1:Type1 类的 Hypervisor(Hypervisor 是一种系统软件,它充当计算机硬件和虚拟机之间的中介,负责有效地分配和利用由各个虚拟机使用的硬件资源,这些虚拟机在物理主机上单独工作,因此, Hypervisor 也称为虚拟机管理器。 )直接运行在硬件之上,没有宿主机操作系统, Hypervisor 直接控制硬件资源和客户机。典型框架为 Xen、 VmwareESX
- Type2:Type2 类的 Hypervisor 运行在一个宿主机操作系统之上(Vmware Workstation)或者系统里面,Hypervisor 作为宿主机操作系统中的一个应用程序,客户机就是在宿主机操作系统上的一个进程
容器虚拟化实现
操作系统层的虚拟化。通过 namespace 进行各程序的隔离,加上 cgroups 进行资源的控制,以此来进行虚拟化
命名空间namespace
C++中的namespace也是用来隔离,可以类比
namespace 是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程的相关资源指定在同一个 namespace 中,Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前namespace 里的进程,对其他 namespace 中的进程没有影响
namespace API:
- clone()
- setns()
- unshare()
Linux内核主要提供了以下6种namespace隔离系统调用:
namespace 系统调用参数 被隔离的全局系统资源 内核版本 解释 UTS CLONE_NEWUTS 主机名域名 2.6.19 每个容器能看到自己的 hostname,拥有独立的主机名和域名 IPC CLONE_NEWIPC 信号量 消息队列 共享内存 进程间通信 2.6.19 同一个 IPC namespace 的进程之间能互相通讯,不同的 IPC namespace 之间不能通信 PID CLONE_NEWPID 进程编号 2.6.24 每个 PID namespace 中的进程可以有其独立的 PID,每个容器可以有其 PID 为1 的 root 进程 Network CLONE_NEWNET 网络设备 网络栈 端口 2.6.29 每个容器用有其独立的网络设备, IP 地址, IP 路由表, /proc/net 目录,端口号 Mount CLONE_NEWNS 文件系统挂载点 2.4.19 每个容器能看到不同的文件系统层次结构 User CLONE_NEWUSER 用户 用户组 3.8 每个 container 可以有不同的 user 和 group id 隔离两个进程需要实现以上6种隔离,Docker 允许用户在主机和容器间共享文件夹,同时不需要限制容器的访问权限,这就容易让容器突破资源限制。需要借助用户空间来完成用户之间的隔离
空间隔离
/dev/null:所有写入/dev/null文件的内容都会丢失,从/dev/null文件 中也读取不到任何内容,主要用于禁止标准输出,清空日志文件
/dev/zero: 能产生连续不断的null的流(二进制的零流,而不是 ASCII型的),写入/dev/zero的输出会丢失不见,用来创建一个指定长度,主要用于初始化的空文件,它通常都是配合dd命令一起使用的
参考:/dev/null和/dev/zero的用法
隔离不是docker提供的,而是操作系统内核提供的
dd(读取转换并输出):
dd [option]
:
- if=文件名:输入文件名,默认为标准输入。即指定源文件。
- of=文件名:输出文件名,默认为标准输出。即指定目的文件。
- ibs=bytes:一次读入 bytes 个字节,即指定一个块大小为 bytes 个字节
obs=bytes:一次输出 bytes 个字节,即指定一个块大小为 bytes 个字节
bs=bytes:同时设置读入/输出的块大小为 bytes 个字节。- cbs=bytes:一次转换 bytes 个字节,即指定转换缓冲区大小。
- skip=blocks:从输入文件开头跳过 blocks 个块后再开始复制。
- seek=blocks:从输出文件开头跳过 blocks 个块后再开始复制。
- count=blocks:仅拷贝 blocks 个块,块大小等于 ibs 指定的字节数。
- conv=<关键字>,关键字可以有以下 11 种:
▪ conversion:用指定的参数转换文件。
▪ ascii:转换 ebcdic 为 ascii
▪ ebcdic:转换 ascii 为 ebcdic
▪ ibm:转换 ascii 为 alternate ebcdic
▪ block:把每一行转换为长度为 cbs,不足部分用空格填充
▪ unblock:使每一行的长度都为 cbs,不足部分用空格填充
▪ lcase:把大写字符转换为小写字符
▪ ucase:把小写字符转换为大写字符
▪ swap:交换输入的每对字节
▪ noerror:出错时不停止
▪ notrunc:不截短输出文件
▪ sync:将每个输入块填充到 ibs 个字节,不足部分用空(NUL)字符补齐- –help:显示帮助信息
- –version:显示版本信息
创建一个块大小为8k字节的,1024个块名为test.img的镜像文件
转大写
mkfs(创建Linux文件系统 格式化):
mkfs [-V] [-t fstype] [fs-options] filesys [blocks]
- -t fstype:指定要建立何种文件系统;如 ext3, ext4
- filesys :指定要创建的文件系统对应的设备文件名;
- blocks:指定文件系统的磁盘块数
- -V : 详细显示模式
- fs-options:传递给具体的文件系统的参数
将镜像文件格式化为ext4格式
df(显示目前在 Linux 系统上的文件系统磁盘使用情况统计):
df [OPTION]... [FILE]...
- -a, --all 包含所有的具有 0 Blocks 的文件系统
- -h, --human-readable 使用人类可读的格式(预设值是不加这个选项的…)
- -H, --si 很像 -h, 但是用 1000 为单位而不是用 1024
- -t, --type=TYPE 限制列出文件系统的 TYPE
- -T, --print-type 显示文件系统的形式
- FILE:表示文件系统上的文件,如果没有给定 FILE,则默认输出所有已挂载的文件系统的载信息
查看磁盘使用情况
挂载(mounting)
:是指由操作系统使一个存储设备(诸如硬盘、CD-ROM或共享资源)上的计算机文件和目录可供用户通过计算机的文件系统访问的一个过程
mount(加载文件系统到指定的加载点 挂载光盘):mount [-l] mount [-t vfstype] [-o options] device dir
- -l:显示已加载的文件系统列表;
- -t: 加载文件系统类型支持常见系统类型的 ext3,ext4,iso9660,tmpfs,xfs 等,大部分情况可以不指定, mount 可以自己识别
- -o options 主要用来描述设备或档案的挂接方式。
▪ loop:用来把一个文件当成硬盘分区挂接上系统
▪ ro:采用只读方式挂接设备
▪ rw:采用读写方式挂接设备- device: 要挂接(mount)的设备。
- dir: 挂载点的目录
将之前格式化的img文件挂载到目标文件夹,df可以查看挂载点
以只读方式挂载
(当因为软件或硬件出现错误,导致文件系统不一致,也有可能把有问题的文件放入到lost+found目录。它提供了恢复丢失文件的一种方法)
unshare(使用与父程序不共享的名称空间运行程序):
unshare [options] program [arguments]
- -i, --ipc 不共享 IPC 空间
- -m, --mount 不共享 Mount 空间
- -n, --net 不共享 Net 空间
- -p, --pid 不共享 PID 空间
- -u, --uts 不共享 UTS 空间
- -U, --user 不共享用户
- -V, --version 版本查看
- - -fork 执行 unshare 的进程 fork 一个新的子进程,在子进程里执行 unshare 传入的参数
- - -mount-proc[=mountpoint] 执行子进程前,将 proc 优先挂载过去,默认挂载到mountpoint(/proc)
bash UTS隔离(进入一个子进程的命名空间):隔离后修改hostname,复制ssh会话还是原hostname
退出子进程hostname还原
例:
PID隔离:
unshare -p /bin/bash
报错:
原因:没有创建新进程,新的ns会用 unshare的 PID 作为新的空间的父进程,而这个unshare进程并不在新的ns中,所以Cannot allocate memory
解决:加上参数–fork:unshare -p --fork /bin/bash
复制ssh会话,当前bash 和 新的bash中执行ps -ef,发现是一样的,再查看/proc目录发现也是一样的
(ps命令的所有信息都是linux kernel生成,并通过/proc/目录输出给用户空间的,/proc是 一个伪文件,它只存在于系统内存中,而不占用外存空间。它以文件系统的方式为用户提供访问内核数据的操作接口。目录下主要包含进程和状态的信息 参考/proc目录)
加上–mount-proc选项, 执行子进程前,将 proc 优先挂载过去:unshare -p --fork --mount-proc /bin/bash
–mount-proc创建新的mount namespace并自动mount新的proc文件系统
Mount隔离:
unshare -mount --fork /bin/bash
复制ssh会话发现没有mymount2挂载点:想要向mymount2文件中读取写入都会报错
控制组群cgroup
cgroup机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。本质上来说, cgroups 是内核附加在程序上的一系列钩子(hook),通过程序运行时对资源的调度触发相应的钩子以达到资源追踪和限制的目的
cgoup用途:
- Resource limitation: 限制资源使用,例:内存使用上限/cpu 的使用限制
- Prioritization: 优先级控制,例: CPU 利用/磁盘 IO 吞吐
- Accounting: 一些审计或一些统计
- Control: 挂起进程/恢复执行进程
cgroup控制的子系统:
子系统 说明 blkio 对块设备的 IO 进行限制。 cpu 限制 CPU 时间片的分配 cpuacct 生成 cgroup 中的任务占用 CPU 资源的报告,与 cpu 挂载在同一目录。 cpuset 给 cgroup 中的任务分配独立的 CPU(多处理器系统) 和内存节点。 devices 限制设备文件的创建,和对设备文件的读写 freezer 暂停/恢复 cgroup 中的任务。 memory 对 cgroup 中的任务的可用内存进行限制,并自动生成资源占用报告。 perf_event 允许 perf 观测 cgroup 中的 task net_cls cgroup 中的任务创建的数据报文的类别标识符,这让 Linux 流量控制器(tc 指令)可以识别来自特定 cgroup 任务的数据包,并进行网络限制。 hugetlb 限制使用的内存页数量。 pids 限制任务的数量 rdma 限制 RDMA 资源(Remote Direct Memory Access,远程直接数据存取)
资源隔离
pidstat(监控全部或指定进程的 CPU、内存、线程、设备IO 等系统资源的占用情况):
pidstat [option] [<时间间隔>] [<次数>]
- -u:默认参数,显示各进程的 CPU 使用统计
- -r:显示各进程的内存使用统计
- -d:显示各进程的 IO 使用情况
- -p:指定进程号,ALL 表示所有进程
- -C:指定命令
- -l:显示命令名和所有参数
pidstat -r -p ALL -C mysql 1 1000
: 监测内存,指定(ALL所有)进程,指定命令(mysql) 间隔1秒执行1000次
stress压力测试工具:
stress [OPTION [ARG]]
- -c, --cpu N:产生 N 个进程,每个进程都循环调用 sqrt 函数产生 CPU 压力。
PID :某个进程的PID
%usr :用户空间使用的cpu%
%system:内核空间使用的cpu%
%guest :管理程序(hypervisor)为另一个虚拟进程提供服务而等待的虚拟CPU占比
%CPU :整体CPU的使用率
CPU :CPU的编号 #例如总cpu只有4核,那么对应每个CPU的编号为 0,1,2,3
Command:进程的命令名称- -i, --io N:产生 N 个进程,每个进程循环调用 sync 将内存缓冲区内容写到磁盘上,产生 IO 压力。通过系统调用 sync 刷新内存缓冲区数据到磁盘中,以确保同步。如果缓冲区内数据较少,写到磁盘中的数据也较少,不会产生 IO 压力。在 SSD 磁盘环境中尤为明显,很可能 iowait 总是 0,却因为大量调用系统调用 sync,导致系统 CPU 使用率 sys 升高。
PID :进程的PID
kB_rd/s :磁盘每秒读数据(单位:KB)
kB_wr/s :磁盘每秒写数据(单位:KB)
kB_ccwr/s:已被任务取消写入磁盘的数据(单位:KB)
Command :进程的命令名称- -m, --vm N:产生 N 个进程,每个进程循环调用 malloc/free 函数分配和释放内存。
PID :进程的PID
minflt/s:每秒发生的小故障总数 #即不需要从磁盘加载内存页的故障
majflt/s:每秒发生的主要故障总数 #即需要从磁盘加载内存页的故障
VSZ :虚拟内存使用情况(以千字节为单位)
RSS :物理内存使用情况(以千字节为单位)
%MEM :使用总内存占比情况
Command :进程的命令名称- –vm-bytes B:指定分配内存的大小
- –vm-keep:一直占用内存,区别于不断的释放和重新分配(默认是不断释放并重新分配内存)
- -d, --hdd N:产生 N 个不断执行 write 和 unlink 函数的进程(创建文件,写入内容,删除文件)
- –hdd-bytes B:指定文件大小
- -t, --timeout N:在 N 秒后结束程序
- -q, --quiet:程序在运行的过程中不输出信息
pidstst启动监测,stress启动一个进程占用内存10m
cgexec:(cgexec 程序使用给定控制组中的 arguments arguments 执行任务命令)
cgexec [-h] [-g <controllers>:<path>] [--sticky] command [arguments]
- 例:
cgexec -g *:test1 ls
在所有安装的控制器的控制组 test1 中运行命令 ls。
cgexec -g cpu,memory:test1 ls -l
在控制器 cpu 和内存中的控制组 test1 中运行命令 ls -l。
cgexec -g cpu,memory:test1 -g swap:test2 ls -l
在控制器 cpu 和内存中的控制组 test1 中运行命令 ls -l,在控制器交换中运行控制组 test2
cgroup:
查看版本:(支持cgroup v2,)
查看挂载信息:
查看支持的子系统(参考:Docker Cgroup 子系统 CPU/Memory):
- blkio:这个子系统设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及 USB 等(blkio子系统只针对非buffered IO或者read IO起作用)
- cpu:这个子系统使用调度程序为 cgroup 任务提供 CPU 的访问
- cpuacct:产生 cgroup 任务的 CPU 资源报告
- cpuset:如果是多核心的CPU,这个子系统会为 cgroup 任务分配单独的 CPU 和内存(应用进程可以和cpu做绑定关系,比如说希望某些应用就绑在某个核上)(如果是多核的cpu,可以将某个进程绑定到某个cpu核上面,这样就减少进程的切换了,那么它的TLB表和缓存,都是可以永远复用的,那么你这个程序就可以高效)
- devices:允许或拒绝 cgroup 任务对设备的访问
- freezer:暂停和恢复 cgroup 任务
- memory:设置每个 cgroup 的内存限制以及产生内存资源报告
- net_cls:标记每个网络包以供 cgroup 方便使用
- ns:名称空间子系统
- pid: 进程标识子系统
在/sys/fs/cgroup目录下主要子系统的配置 (每一个子系统下都有一个task配置,配置里是cgroup起作用的进程pid):
blkio子系统(这个子系统为块设备设定输入/输出限制,比如物理设备)
配置 功能 blkio.throttle.read_bps_device / blkio.throttle.write_bps_device 设置cgroup在某个设备上的读/写的带宽上限。其格式为 major:minor bytes_per_second blkio.throttle.read_iops_device / blkio.throttle.write_iops_device 设置cgroup在某个设备上的读/写的iops上限。其格式为major:minor operations_per_second blkio.throttle.io_serviced 统计 cgroup 对具体设备的读写操作数。blkio.io_serviced 与blkio.throttle.io_serviced的不同之处在于,CFQ 调度请求队列时,前者不会更新 内容有四个字段:major, minor,operation (read, write, sync, or async)和 number(表示操作的次数) blkio.throttle.io_service_bytes 统计 cgroup对具体设备的读写字节数。blkio.io_service_bytes 与blkio.throttle.io_service_bytes 的不同之处在于,CFQ 调度请求队列时,前者不会更新。内容有四个字段:major, minor, operation (read, write, sync, or async)和 bytes(表示传输的字节数) blkio.weight 设置cgroup 在io 之中所占据的比重,取值为整数,取值范围在 10-1000,默认值为 500 blkio.weight_device 设置cgroup 在某个设备之中所占据的比重。 取值例子:设备号(主次设备号) 整数,取值范围在 10 - 1000 之间 cpu子系统 (这个子系统使用调度程序为 cgroup 任务提供 CPU 的访问)
配置 功能 cpu.shares 相对值 可出让的能获得 CPU 使用时间的相对值。(假设主机上面有3个cpu,定义了两个cgroup,将第一个进程放到第一个cgroup,将第二个进程放到第二个cgroup,将第一个进程里面的cpu设置为512,将第二个进程里面的cpu设置为1024,那么这就是1:2的比例,这样意味着操作系统在调用这些进程的时候对时间的分配是按照1:2去分配的,这是一个相对值,按照cpu占用时间去分配的) cpu.cfs_period_us 绝对值 cfs_period_us 用来配置时间周期长度,单位为 us(微秒)(分母:默认100000) cpu.cfs_quota_us 用来配置当前 Cgroup 在 cfs_period_us 时间内最多能使用的 CPU时间数,单位为 us(微秒)。(绝对值是按照两个文件去配置的,一个文件叫做cpu.cfs_period_us,另外一个叫做cpu.cfs_quota_us,在10w的cpu时间片里面,可以使用多少个时间片(默认-1表示无限制,分子:30000就是30%) cpu.stat Cgroup 内的进程使用的 CPU 时间统计 nr_periods 经过 cpu.cfs_period_us 的时间周期数量 nr_throttled 在经过的周期内,有多少次因为进程在指定的时间周期内用光了配额时间而受到限制 throttled_time Cgroup 中的进程被限制使用 CPU 的总用时,单位是 ns(纳秒) memory子系统(设置每个 cgroup 的内存限制以及产生内存资源报告)
配置 功能 memory.usage_in_bytes cgroup 下进程使用的内存,包含cgroup 及其子 cgroup下的进程使用的内存 memory.max_usage_in_bytes Cgroup下进程使用内存的最大值,包含子cgroup 的内存使用量。 memory.limit_in_bytes 设置Cgroup 下进程最多能使用的内存。如果设置为-1,表示对该cgroup 的内存使用不做限制 memory.oom_Control 设置是否在 Cgroup中使用 OOM(Out of Memory)Killer,默认为使用。当属于该cgroup的进程使用的内存超过最大的限定值时,会立刻被 OOM Killer 处理 在子系统目录下创建目录会自动生成上面提到的一系列配置文件
例1:对内存进行限制
原默认限制
更改limit为20m左右
新开ssh会话,进行stress压力测试
一旦写入pid到tasks文件,stress进程会被立马终止
例2:对CPU进行限制
- 同理在memory目录下创建新测试目录,目录下会自动生成相关配置文件,同理使用streaa压力测试cpu,再更改cpu相关配置文件设置cpu占用为30%,pidstat监控
例3:对磁盘进行带宽限制
- 设置写上限后
cgexec -g blkio:blkiolimit_test dd if=/dev/zero of=test.txt oflag=direct bs=2M count=1023
在控制器blkio中的控制组blkiolimit_test 中运行dd命令
设置上限前后对比:
fio测试??
LXC(Linux Container)
LXC(LinuX Containers) Linux 容器,一种操作系统层虚拟化技术,为 Linux 内核容器功能的一个用户空间接口。它将应用软件系统打包成一个软件容器(Container),内含应用软件本身的代码,以及所需要的操作系统核心和库。透过统一的名字空间和共享 API 来分配不同软件容器的可用硬件资源,创造出应用程序的独立沙箱运行环境,使得 Linux 用户可以容易的创建和管理系统或应用容器
配置源:
yum install epel-release
lxc安装:(yum -y install lxc lxc-templates bridge-utils lxc-libs libcgroup libvirt lxc-extra debootstrap
)
- lxc 主程序包
- lxc-templates lxc 的配置模板
(注意:lxc3.0.0后仅保留了 lxc-download、lxc-local、lxc-oci、lxc-busybox 4 个模板
)
- bridge-utils 网桥管理工具
- lxc-libs lxc 所需的库文件
- libcgroup cgroup 安装包
- libvirt 管理 Linux 的虚拟化功能所需的服务器端守护程序。 需要针对特定驱动程序的管理程序
- debootstrap debootstrap 是 Debian 引导程序,它允许您将 Debian 基本系统(例如 Debian 或 Ubuntu)安装到当前正在运行的系统的目录中
lxc常用命令:
lxc-checkconfig
检查系统环境是否满足容器使用要求;格式: lxc-checkconfiglxc-create
创建 lxc 容器; 格式: lxc-create -n NAME -t TEMPLATE_NAME [-- template-options]lxc-start
启动容器; 格式: lxc-start -n NAME -dlxc-ls
列出所有容器,-f 表示打印常用的信息 ;格式: lxc-ls -flxc-info
查看容器相关的信息;格式: lxc-info -n NAMElxc-attach
进入容器执行命令; 格式: lxc-attach --name=NAME [-- COMMAND]lxc-stop
停止容器;格式: lxc-stop -n NAMElxc-destory
删除处于停机状态的容器;格式: lxc-destory -n NAME
操作:
- 创建lxc容器(注意这里没lxc-cenos模板,只能使用lxc-download模板):
lxc-create -n centos2 -t download
输入后选择对应的系统 版本 架构
这里出现ERROR
貌似是大多数发行版都少了配置文件 暂时搁置,issue详见GitHub:LXC BROKEN - Container configs missing for most distributions #4325
- 容器创建后都放在/var/lib/lxc/下,容器的根文件系统放在/var/lib/lxc/<容器名>/rootfs 目录下,创建过程中下载的软件包保存在 /var/cache/lxc 目录下
- 查看容器详细信息:
lxc-info -n [container name]
, 查看容器ip,通过 ssh 进入容器:ssh centos@[ip]
docker与虚拟机
概念背景
- Docker 本质:Docker 本质是LXC 之类的增强版,它本身不是容器,而是容器的易用工具。容器是 linux 内核中的技术, Docker 只是把这种技术在使用上简易普及了。 Docker 在早期的版本其核心就是 LXC 的二次封装发行版
- 早期 Docker 利用 LXC 做容器管理引擎,但是在创建容器时,不再使用模板去安装生成,而是通过镜像技术(把一个操作系统用户空间所需要使用到的组件事先编排好,并整体打包成一个文件, image 文件),镜像文件集中放在一个仓库中。当需要创建容器时, Docker 调用 LXC 的工具 lxc-create,但不再通过 lxc 的模板去安装,而是连接到镜像服务器上下载匹配的镜像文件,而后基于镜像启动容器。所以, Docker 极大的简化了容器的使用难度。以后我们创建启动容器,只需要一个命令, docker-run,docker-stop 就可以启动停止一个容器了
- 引擎迭代:Docker 早期是基于 LXC 容器管理引擎实现,当后来成熟之后, Docker 自建了一个容器引擎叫 libcontainer,后来 CNCF 的介入, Docker 又研发了一个工业化标准的容器引擎 runC,目前所使用的新版 Docker,所使用的容器引擎就是 RunC
docker vs 传统虚拟机
传统虚拟机 Docker 容器 磁盘占用 几个 GB 到几十个 GB左右 几十 MB 到几百 MB 左右 CPU内存占用 虚拟操作系统非常占用CPU 和内存,需要通过虚拟层调用占用率高 Docker 引擎占用资源极低,直接作用于硬件资源占用少 启动速度 (从开机到运行项目)几分钟 (从开启容器到运行项目)几秒 安装管理 需要专门的运维技术 安装、管理方便 应用部署 手动部署,速度慢 体系化部署,可以自动化,速度快 隔离性 系统级别 进程级别 封装程度 打包整个操作系统 打包项目代码和依赖信息
问
:Docker 为什么比虚拟机资源利用率高,启动快?
答
:docker 有比虚拟机更少的抽象层。 docker 不需要 Hypervisor 实现硬件资源虚拟化,运行在 docker 容器上的程序直接使用的是实际物理机的硬件资源。因此在 cpu、内存利用率上 docker 将会在效率上有明显的优势。 docker 利用的是宿主机的内核,而不需要Guest OS(子操作系统),节省了 Guest OS 占用的资源。docker 不需要 Guest OS,创建一个容器时,不需要和虚拟机一样重新加载一个操作系统内核。从而避免引寻、加载操作系统内核返回时耗时耗资源的过程,当新建一个虚拟机时,虚拟机软件需要加载 Guest OS,返回新建过程是分钟级别的。而新建一个docker 容器只需要几秒钟 (图片来源网络)