Docker 核心技术
1 背景
Docker是一种基于GO语言开发的开源应用程序集装箱引擎。 Docker允许开发人员将其应用程序和依赖项打包成轻质,便携式容器,并将其发布到任何流行的Linux机器上,或将其虚拟化。容器完全使用沙盒机制,它们之间将没有接口。更重要的是,容器性能开销非常低。基于Linux内核的Cgroup,命名空间和联合FS等技术,过程被封装和隔离。它们是操作系统级别的虚拟化技术。由于孤立的过程与主机和其他孤立的过程无关,因此它们也称为容器。
最初的实现基于LXC,它开始从0.7中删除LXC,而是使用了自开发的libcontainer。从1.11开始,它进一步发展为使用Runc和Containerd。
Docker已根据容器,从文件系统,网络互连到处理隔离等,进一步封装了容器,从而大大简化了容器的创建和维护,从而使Docker Technology比虚拟机技术更轻,更快。
1.1 Docker 与虚拟机的区别

Docker的抽象层少于虚拟机。由于Docker不需要管理程序来实现硬件资源虚拟化,因此在Docker容器上运行的程序直接使用实际物理机器的硬件资源。因此,Docker将在CPU和内存利用方面具有优势。
Docker使用主机的内核,而无需访客操作系统。因此,当创建新容器时,Docker不需要像虚拟机那样重新加载操作系统内核。启动和加载操作系统内核是一个耗时且资源密集的过程。创建新的虚拟机时,虚拟机软件需要加载访客操作系统。这个新过程是在分钟级别。由于Docker直接使用了主机的操作系统,因此省略了此过程,因此创建一个新的Docker容器只需要几秒钟。此外,现代操作系统是复杂的系统,在物理机器中添加新操作系统的资源开销相对较高。因此,与虚拟机相比,Docker在资源消耗方面的优势也相对较大。实际上,我们可以在物理机器上轻松构建数百个容器,但是只构建了几个虚拟机。
性能比较

容器的主要特征

1.2 容器操作
开始:Docker Run- 它相互作用
-D背景操作
-p端口映射
-v磁盘安装
启动终止容器
Docker Start
停止容器
Docker Stop
查看容器过程
Docker PS
查看容器详细信息
Docker Inspect [ContainerId]
输入容器
Docker附件
pid=$(Docker Inspect -Format'{{.state.pid}}}'[container])
NSENTER-目标$ pid -mount -uts -uts -ipc -net- -pid
1.3 Dockerfile
CAT Dockerfile1
2
3
来自Ubuntu
env my_service_port=80
添加bin /amd64 /httpserver /httpserver入门点/httpserver
将dockerfile包装到镜子里
1
2
docker build -t cncamp/httpserver: $ {tag}。
Docker Push Geekby/httpserver:v1.0
运行容器
1
Docker Run -D Geekby/httpserver:v1.0
1.4 Docker 引擎架构

2 Namespcce
2.1 背景
Linux名称空间是Linux内核提供的资源隔离解决方案。系统可以为过程分配不同的名称空间
它还确保独立分配不同的命名空间资源,并彼此隔离,即不同名称空间下的过程不会彼此干扰。
Linux内核代码中名称空间的实现如下:

2.2 类别

2.2.1 进程编号 - PID
当启动多个容器,然后用每个容器内的PS命令查看它们时,您会发现它们都有一个PID为1的过程。通过PID名称空间隔离了不同用户的过程,并且不同的命名空间可以具有相同的PID。使用PID名称空间,每个名称空间中的PID可以彼此隔离。2.2.2 网络设备 - Network
在每个网络空间中,可以有独立的网络设备(虚拟或真实),IP地址,路由表,防火墙规则等。应用程序限制的端口也是每个名称空间。例如,HTTP默认使用端口80。使用网络空间后,同一主机上的每个容器都可以在内部运行自己的Web服务器。Docker使用VETH将容器中的虚拟网卡与docker bridge: docker0连接到主机上的docker0默认情况下。
2.2.3 进程间通信 - IPC
使用此空间,过程之间的通信(INTERPROCESSC - 通信)仅限于同一空间,也就是说,容器中的过程只能与同一容器中的其他过程进行通信。在主机上的PID名称空间中,容器的过程间交互实际上具有相同的过程间交互,因此在申请IPC资源时有必要添加名称空间信息- 每个IPC资源都有唯一的32位ID。
2.2.4 文件系统 - Mount
MNT命名空间允许具有不同名称空间的进程以查看不同的文件结构,以便隔离每个名称空间中的进程目录。2.2.5 主机域名 - UTS
由于多个容器共享OS内核,因此无法更改UTS中的OS类型和OS释放之类的信息,但是每个容器都可以具有其自己的独立主机名和域名以促进识别和区别(例如,您可以通过主机名中的网络中访问机器)。这就是UTS名称空间所做的。2.2.6 用户控制 - USR
每个容器可以具有不同的用户和组ID,这意味着可以使用容器内的用户而不是主机上的用户执行程序。2.3 linux 对 namespace 的操作方法
克隆创建系统调用新过程时,您可以指定需要通过标志参数创建的名称空间类型。
克隆功能原型:
1
int clone(int( *fn)(void *),void *child_stack,int flags,void *arg)
套
此系统调用允许将调用过程添加到现有名称空间:
1
int setns(int fd,int nstype)
不共产
此系统调用可以将调用过程移至新名称空间下的:
1
int unshare(int标志)
2.4 关于 namespace 的常用操作
查看当前系统的名称空间:LSNS -T [类型]

检查该过程的名称空间:
ls -la/proc/[pid]/ns/

输入一个名称空间以运行命令:
nsenter -t [pid] -n ip addr

3 Cgroup
3.1 背景
CGroups(对照组)是Linux中用于控制和监视一组过程中资源的机制。可以限制CPU使用时间,内存,磁盘I/O等过程所需的资源;
不同资源的特定管理由相应的Cgroup子系统实施;
对于不同类型的资源限制,只需将不同子系统的限制策略关联;
CGROUP以层次结构的方式在不同的系统资源管理子系统中进行组织和管理:每个CGroup都可以包含其他儿童CGroup,因此儿童CGroup可以使用的资源不仅受此CGROUP配置的资源参数的限制,而且还受父母CGROUP设置的资源限制。
Linux内核代码中的CGroups实现:

3.2 类别
CGROUPS实施配额和资源测量BLKIO:此子系统设置限制了每个块设备的输入和输出控制。例如:磁盘,CD,USB,等。
CPU:该子系统使用调度程序来提供对CGroup任务的CPU访问
CPUACCT:生成CGROUP任务的CPU资源报告
CPUSET:如果它是多核CPU,则该子系统将分配单独的CPU和内存为CGroup任务
设备:允许或拒绝通过CGROUP任务访问该设备
冰柜:暂停和恢复CGROUP任务
内存:设置每个cGroup的内存限制,并生成内存资源报告
net_cls:标记每个网络数据包,以便于cgroup使用
NS:名称空间子系统
PID:过程识别子系统
3.2.1 cpu 子系统
CPU.SHARES:可以转移的CPU使用时间的相对值。cpu.cfs_period_us:用于配置时间段长度,单位是美国(微秒)。
cpu.cfs_quota_us:用于配置当前CGROUP可以在CFS_PERIOD_US时间中使用的最大CPU时间数,在美国(微秒)。
CPU.STAT:CGROUP中的过程使用的CPU时间统计信息。
nr_periods:cpu.cfs_period_us传递的时间段。
NR_THROTTLED:经过的周期中有多少次,因为该过程在指定的时间段中消耗了配额时间?
throttled_time:CGROUP中的总时间仅限于在NS(纳秒)中使用CPU。
例子
使用CGROUP CPU子系统来控制资源访问
在CGROUP CPU子系统目录中创建目录结构:
1
2
3
CD/SYS/FS/CGROUP/CPU
mkdir cpudemo
CD CPUDEMO
运行以下代码:
1
2
3
4
5
6
7
8
9
包装主
func main(){
go func(){
为了{
}
}()
为了{
}
}
执行顶部以查看CPU使用情况,CPU占200%:

然后使用CGroup限制CPU:
1
2
3
4
5
6
7
cd/sys/fs/cgroup/cpu/cpudemo
#将过程添加到CGROUP进程配置组
Echo PS -EF | GREP POC | GREP -V GREP | AWK'{print $ 2}'cgroup.procs
#设置cpuquota
echo 10000 cpu.cfs_quota_us

执行顶部以查看CPU使用情况,并且CPU使用率变为10%:

删除分组:
1
CGDELETE -G CPU:CPUDEMO
3.2.2 Memory 子系统
MOMEME.USAGE_IN_BYTES:该过程在CGroup下使用的内存,包括该过程在CGroup和其子组中使用的内存
MOMEME.MAX_USAGE_IN_BYTES:
该进程在CGroup下使用的内存的最大值,包括子cgroup的内存使用量。
memory.limit_in_bytes
设置CGROUP下过程中可以使用的最大内存。如果设置为-1,则意味着对CGroup的内存使用情况没有限制。
memory.oom_control
设置是否在cgroup中使用OOM(不在内存)杀手,默认使用。当属于CGROUP的进程使用的内存超过最大限制时,将立即通过OOM杀手处理。
4 文件系统
4.1 背景
Docker的创新:Union FS应用于文件系统将不同的目录安装到同一虚拟文件系统下的文件系统
支持为每个成员目录设置Readonly,ReadWrite和可白色的权限(类似于GIT分支)
文件系统层次结构,具有读取权限的分支可以在逻辑上修改(逐步影响,它不会影响可读部分)
通常,Union FS有两种用途。一方面,它可以将多个磁盘悬挂到同一目录中。另一方面,它更常用于结合可读的分支和可写的分支。

4.2 Docker 的文件系统
典型的Linux文件系统组成:bootfs(引导文件系统)
引导加载程序- 引导加载程序内核,
内核-Umount Bootfs将内核加载到内存中时。
rootfs(根文件系统)
标准目录和文件,例如/dev, /proc, /bin等。
对于不同的Linux发行版,bootfs基本相同,但是rootfs会不同。

4.2.1 启动过程的差异
Linux 的启动:启动后,首先将rootfs设置为ReadOnly,执行一系列检查,然后将其切换为ReadWrite,供用户使用。Docker 的启动:初始化时,将加载rootfs并在ReadOnly中检查。但是,Union Mount方法用于将ReadWrite文件系统安装在Readonly rootfs上。并允许将下部的FS设置为可读并再次向上叠加。这样的一组可读性和可写的结构形成了容器的运行时态,每个FS称为FS层。
4.2.3 关于写操作
由于镜像具有共享特征,因此容器的写入层的操作需要依靠存储驱动器提供的时间副本和时间分配机制来支持容器的写入层的修改,从而改善了存储和内存资源的利用。复制写作
在写作上复制,也就是说,抄写。镜像可以由多个容器使用,但在内存和磁盘上不需要多个副本。当需要修改镜像提供的文件时,将将文件从图像的文件系统复制到容器的可写层进行修改,并且图像中的文件不会更改。不同的容器都独立修改文件,并且不会互相影响。
时间分配
即按需分配空间,而不是提前分配,也就是说,将在创建文件后分配空间。
4.2.4 容器存储驱动


2.4.5 OverlayFS
Overlayfs也是类似于AUFS的联合文件系统。它还属于文件级存储驱动程序,包括初始覆盖和更新,更稳定的覆盖2。覆盖层只有两层:上层和下层,下层表示镜面,上层表示容器可写的层。

例子
1
2
3
4
5
6
7
8
9
10
11
12
Mkdir上部合并工作
echo'soulter'lower'lower/in_lower.txt
echo'来自上'上/in_upper.txt
回声'来自下部/in_both.txt
echo'来自上'上/in_both.txt
sudo mount -t覆盖层-O lowerdir=
pwd
/persiondir=pwd
/upper,workdir=pwd
/work`pwd`/合并猫合并/in_both.txt
RM合并/in_both.txt
RM合并/in_lower.txt
RM合并/in_upper.txt
5 网络
Docker中提供了各种网络模式:null(–net=无)