《Docker技术入门与实战》-第17章-dokcer核心实现技术

0x01 基础架构

docker目前采用了标准的c/s架构,包括客户端、服务端两大核心组件,同时通过镜像仓库来存储镜像。客户端和服务端既可以运行在一个机器上,也可通过socket或者RESTful API来进行通信。
《Docker技术入门与实战》-第17章-dokcer核心实现技术

服务端

docker服务端一般在宿主机后台运行,用来处理来自客户客户端的请求,主要包括四个组件。

  • dockered,为客户端提供RESTful API,响应来自客户端的请求,采用模块化的架构,通过专门的Engine模块来分发管理各个来自客户端的任务。
  • docker-proxy,是dockered的子进程,当容器需要使用端口映射时,它就会完成网络映射配置
  • containerddockered的子进程 ,提供gRPC接口响应来自dockered的请求,对下管理runC镜像和容器环境。
  • containerd-shimcontainerd的子进程 ,为runC容器提供支持,同时作为容器内进程的根进程。

经过 Server Version: 20.10.3测试,上述中的子进程均不正确,因为于2016年,Docker分拆了 containerd,并将其捐赠给了社区。将这个组件分解为一个单独的项目,使得 docker 将容器的管理功能移出docker的核心引擎并移入一个单独的守护进程(即containerd)

客户端

Docker客户端为用户提供一系列可执行命令,使用这些命令可实现与Docker服务端交互。

客户端程序在发送命令后,等待服务端返回,一旦收到返回后,客户端立刻执行结束并退出,当执行新的命令时,需要再次调用客户端命令。

镜像仓库

镜像是使用容器的基础,docker使用镜像仓库registry在大规模场景下存储和分发docker镜像。


0x02 命名空间

命名空间namespacelinux内核的一个强大特性,为容器虚拟化的实现带来极大便利。利用这一特性,每个容器都可以拥有自己单独的命名空间,运行在其中的应用都像在独立的操作系统环境一样。

命名空间机制了容器之间彼此互不影响!

在操作系统中,包括内核、文件系统、网络、进程号、用户号、进程间通信IPC等资源,所有的资源都是应用进程直接共享的。想要实现虚拟化,除了要对内存、CPU、网络IO、存储空间等的限制外,还要实现文件系统、网络、PID、UID、IPC等的相互隔离。前者相对容易实现,后者则需要宿主主机系统的深入支持。

docker窗口启动时,都通过调用func setNamespaces(daemon *Daemon,s *specs.Spec,c *container.Container) error方法来完成对各个命名空间的配置

进程命名空间

目前docker上只运行了一个容器

[root@localhost ~]docker container ls -a
CONTAINER ID   IMAGE     COMMAND              CREATED        STATUS        PORTS                   NAMES
b42e6f99cfce   lamp      "/bin/bash run.sh"   39 hours ago   Up 39 hours   0.0.0.0:49230->80/tcp   lamp

《Docker技术入门与实战》-第17章-dokcer核心实现技术
再开一个容器

[root@localhost ~]docker container ls -a
CONTAINER ID   IMAGE     COMMAND              CREATED         STATUS         PORTS                   NAMES
66dd5c696607   lamp      "/bin/bash run.sh"   9 seconds ago   Up 7 seconds   0.0.0.0:49231->80/tcp   lamp2
b42e6f99cfce   lamp      "/bin/bash run.sh"   39 hours ago    Up 39 hours    0.0.0.0:49230->80/tcp   lamp

《Docker技术入门与实战》-第17章-dokcer核心实现技术
明显看到多出一个进程,如果使用pstree -p效果明显,篇幅受限,可以自行查看。

IPC命名空间

容器中的进程交互还是采用了Linux常见的进程间交互方法( Interprocess Communication,IPC),包括信号量、消息队列和共享内存等方式。PID命名空间和IPC命名空间可以组合起来一起使用,同一个IPC命名空间内的进程可以彼此可见,允许进行交互,不同空间的进程则无法交互。

网络命名空间

Docker采用虚拟网络设备VND的方式,将不同命名空间的网络设备连接到一起。默认情况下,Docker在宿主机上创建多个虚拟网桥,容器中的虚拟网卡通过网桥进行桥接。
《Docker技术入门与实战》-第17章-dokcer核心实现技术
通过docker network可以观察情况,还可以通过brctl工具看到更具体的信息。

[root@localhost ~]brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.024265dd7da1       no              veth68f987e
                                                        vetha7abc41

通过这下面案例进行对比,在本地上查看网卡信息
《Docker技术入门与实战》-第17章-dokcer核心实现技术
接着在其中一个容器中进行查看网卡信息
《Docker技术入门与实战》-第17章-dokcer核心实现技术
会发现很有规律,这两个网卡其实是一对出现的,称为veth-peer,也就是说每产生一个容器,都会产生这样一对网卡,主机和容器之间通信就通过这对网卡走,但是容器和容器之前通信,即使也是同一个网段的,仍然也需要借助docker0这块虚拟网卡走。

挂载命名空间

类似于chroot,挂载(Mount,MNT)命名空间可以将一个进程的根文件系统限制到一个特定的目录下。

挂载命名空间允许不同命名空间的进程看到的本地文件位于宿主机中不同路径下,每个命名空间中的进程所看到的文件目录彼此是隔离的。例如,不同命名空间中的进程,都认为自己独占了一个完整的根文件系统(rootfs),但实际上,不同命名空间中的文件彼此隔离,不会造成相互影响,同时也无法影响宿主机文件系统中的其他路径。

UTS命名空间

UTS (UNIX Time-sharing System)命名空间允许每个容器拥有独立的主机名和域名从而可以虚拟出一个有独立主机名和网络空间的环境,就跟网络上一*立的主机一样。

如果没有手动指定主机名称,Docker容器的主机名就是返回的容器ID的前6字节前缀,否则为指定的用户名:

[root@localhost ~]docker container inspect -f  {{".Config.Hostname"}}  lamp 
b42e6f99cfce

用户命名空间

每个容器可以有不同的用户和组id,也就是说,可以在容器内使用特定的内部用户执行程序,而非本地系统上存在的用户。

每个容器内部都可以有最高权限的root帐号,但跟宿主主机不在一个命名空间。通过使用隔离的用户命名空间,可以提高安全性,避免容器内的进程获取到额外的权限;同时通过使用不同用户也可以进一步在容器内控制权限。


0x03 控制组

控制组(CGroups)Linux内核的一个特性,主要用来对共享资源进行隔离、限制、审计等。只有将分配到容器的资源进行控制,才能避免多个容器同时运行时对宿主机系统的资源竞争。每个控制组是一组对资源的限制,支持层级化结构。

具体来看,CGroups提供如下功能

  • 资源限制( resource limiting):可将组设置一定的内存限制。比如:内存子系统可以为进程组设定一个内存使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发Out of Memory警告。
  • 优先级(prioritization):通过优先级让一些组优先得到更多的CPU等资源。
  • 资源审计( accounting):用来统计系统实际上把多少资源用到适合的目的上,可以使用cpuacct子系统记录某个进程组使用的CPU时间。
  • 隔离(isolation):为组隔离命名空间,这样使得一个组不会看到另一个组的进程、网络连接和文件系统。
  • 控制(control):执行挂起、恢复和重启动等操作。

可以在目录/sys/fs/cgroup/memory/docker/下看到对容器各方面的限制

[root@localhost ~]ls /sys/fs/cgroup/memory/docker/6873e4943c9f295c6bd2b4b177dd9466a0e698b0309da400083839a231b02623/
cgroup.clone_children           memory.kmem.slabinfo                memory.memsw.failcnt             memory.soft_limit_in_bytes
cgroup.event_control            memory.kmem.tcp.failcnt             memory.memsw.limit_in_bytes      memory.stat
cgroup.procs                    memory.kmem.tcp.limit_in_bytes      memory.memsw.max_usage_in_bytes  memory.swappiness
memory.failcnt                  memory.kmem.tcp.max_usage_in_bytes  memory.memsw.usage_in_bytes      memory.usage_in_bytes
memory.force_empty              memory.kmem.tcp.usage_in_bytes      memory.move_charge_at_immigrate  memory.use_hierarchy
memory.kmem.failcnt             memory.kmem.usage_in_bytes          memory.numa_stat                 notify_on_release
memory.kmem.limit_in_bytes      memory.limit_in_bytes               memory.oom_control               tasks
memory.kmem.max_usage_in_bytes  memory.max_usage_in_bytes           memory.pressure_level

0x04 联合文件系统

联合文件系统(UnionFS)是一种轻量级的高性能分层文件系统,它支持将文件系统中的修改信息作为一次提交,并层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,应用看到的是挂载的最终结果。联合文件系统是实现Docker镜像的技术基础。

Docker镜像可以通过分层来继承,当用户分发镜像时,只需要分发有改动那一部分,使得镜像管理变得十分轻盈和快速。

具体可以看之前学习的文章,overlayFS文件系统

也可参照书上的总结
《Docker技术入门与实战》-第17章-dokcer核心实现技术


0x05 网络虚拟化

之前在网络命名空间里面也简单介绍了下,应该也有一定了解了,看下图。
《Docker技术入门与实战》-第17章-dokcer核心实现技术
网络创建过程如下:

  1. 创建一对虚拟接口,分别放到本地主机和新容器的命名空间中;
  2. 本地主机一端的虚拟接口连接到默认的docker0网桥或指定网桥上,并具有一个以veth开头的唯一名字,如veth1234;
  3. 容器一端的虚拟接口将放到新创建的容器中,并修改名字作为eth0。这个接口只在容器的命名空间可见;
  4. 从网桥可用地址段中获取一个空闲地址分配给容器的eth0,并配置默认路由网关为docker0网卡的内部接口的IP地址。

现在理解起来是不是更加深刻了,如果有问题,再去看看命名空间那一块吧!

[root@localhost ~]docker container run --network 
bridge      container:  host        ipvlan      macvlan     none        null        overlay  

在目前来看,支持的网络类型还是非常多的

  • bridge,默认就是这个网卡,也就是docker0
  • container:,指的是将新建容器的网卡放去一个已有容器的网络栈中。
  • host,容器使用本地的网络,权限比较大,如果加了--privileged则可以修改主机的网络栈。
  • macvlan,和bridge类似,也是起子接口,但是省去了bridge的过程,效率更高。
  • ipvlan,暂时没找到合适的资料。。。。docker macvlan实战
  • none,放入新的网络栈上,但是不进行网络配置,一般用户自行配置。
  • null,禁用容器的网络
  • overlayoverlay网络模型在docker集群节点间的加入了一层虚拟网络,它有独立的虚拟网段,意味着docker容器发送的内容,会先发送到虚拟子网,再由虚拟子网包装为宿主机的真实网址进行发送。
    《Docker技术入门与实战》-第17章-dokcer核心实现技术

其实除了上述的种类外,docker还可以支持自定义网络,也是非常常用的一种方式,后面章节还有讲,这里就不详细说明了。

上一篇:CentOS6.5安装python3.7


下一篇:docker 容器使用 systemctl 命令是报错