docker核心原理-框架结构

框架结构

  • docker是基于 C/S架构的服务
  • 一个完整的docker程序是由client和server两个组成,客户端和服务端会在本地安装好,不过生产环境中,client和server是可以分离的

docker 客户端和服务端分离

  • docker默认没有监听端口,没有监听端口之前是不可以将client和server分离的。所以添加监听端口就可以将server与client分离了

修改docker监听地址

[root@localhost ~]# vim /usr/lib/systemd/system/docker.service 
# 14行的ExecStart添加 -H tcp://0.0.0.0,监听所有ip
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0 --containerd=/run/containerd/containerd.sock

重启docker

[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker

查看docker的状态

[root@localhost ~]# netstat -anput | grep docker
tcp6       0      0 :::2375                 :::*           LISTEN      79211/dockerd

打开另一台有docker的主机

docker -H 192.168.100.211 images # 查看100.211主机docker的本地镜像
docker -H 192.168.100.211 info # 查看100.211的docker信息
  • 现在就可以通过客户端操作server了,不过一般不用这个,而是通过ssh或者ansible等程序进行管理

docker框架结构

  • Docker的后端是一个非常松耦合的架构,模块各司其职,并有机组合,支撑Docker的运行。

松耦合:Docker的每个模块中的依赖性不是特别强
紧耦合:程序的每个模块有这紧密相关的联系,同时性能也是较强的

  • 下面来逐个讲解模块
  1. 用户使用Docker_Client 与 Docker_Daemon建立通信,并发送请求给Server
  2. Daemon为docker架构的主体部分,首先提供了一个Server功能,可以接收Client的请求,然后交给Engine执行Docker内部的一些工作,每一项工作都是以一个JOB的形式存在的
  3. JOB运行过程中,如果容器需要镜像,则从Registry中下载镜像,并通过管理驱动的graphdriver将下载的镜像以Graph的形式存储
  4. JOB运行过程中,当需要为docker创建网络环境的时候,通过网络管理驱动networkdriver创建并配置docker容器的网络环境(通过调用libcontainer的 netlink来创建网络环境)
  5. JOB运行过程中,当需要限制容器的运行资源或者执行的用户指令等操作,则通过execdriver来调用 libcontaine中的namespace 和 cgroup 对容器进行一个限制
  6. libcontainer是一项独立的容器管理包, networkdriver和execdriver都是通过libcontainer来实现对容器的具体操作,当执行完容器的命令后,docker容器就处于一个运行状态了,该容器拥有独立的文件系统,独立的运行环境等
  • 说一下容器是怎么找到镜像的

    job运行过程中,如果需要pull镜像则从镜像仓库下载,将下载好的镜像交给graphdriver,然后driver把下载好的镜像的信息存储到 GraphDB这个非常小的数据库中,将镜像的内容存储到Repository本地镜像仓库,如果需要读取镜像时则会先通过GraphDB查询镜像信息,得到镜像的位置后,在通过本地镜像仓库(reository)来找到镜像主体,从而 通过run命令开启容器

框架结构中的名词

  • Docker Client

    是Docker架构中用户用来和Docker Daemon建立通信的客户端。用户使用的可执行文件docker,通过docker命令行工具可以发起众多管理container(容器)的请求。

  • Docker Client可以通过三种方式和Docker Daemon建立通信:

    tcp://host:port
    unix://path_to_socket
    fd://socketfd
    一般Client和Server是不会分开的,一律使用第一种方法tcp://host:port进行通信。

  • Docker Daemon

    Docker Daemon是Docker架构中一个常驻在后台的系统进程,功能是:接受并处理Docker Client发送的请求。
    该守护进程在后台启动了一个Server,Server负责接受Docker Client发送的请求;接收请求后,Server通过路由与分发调度,找到相应的处理者(Handler)来执行请求。

    • Docker Daemon的架构,大致可以分为三个部分:Docker Server、Engine和Job
  • Docker Server

    Docker Server在Docker架构中是专门服务于Docker Client的server。该server的功能是:接收并调度分发Docker Client发送的请求

  • Engine

    Engine是Docker架构中的运行引擎,同时也是Docker运行的核心模块。它扮演Docker container存储仓库的角色,并且通过执行job的方式来操纵管理这些容器。

  • Job

    一个Job可以认为是Docker架构中Engine内部最基本的工作执行单元。Docker可以做的每一项工作,都可以抽象为一个job。
    例如 docker run,docker push,docker pull等 就是一个job

    • Job的设计者,把Job设计得与Unix进程相仿。比如说:Job有一个名称,有参数,有环境变量,有标准的输入输出,有错误处理,有返回状态等。
  • Docker Registry

    是一个存储容器镜像的仓库。而容器镜像是在容器被创建时,被加载用来初始化容器的文件架构与目录。

    • 通常Docker仓库分为网络端和本地端,网络端是docker官方的仓库或者阿里云的缓存仓库等。本地端是docker私有仓库,自己搭建的。
    • Docker的运行过程中,Docker Daemon会与Docker Registry通信,并实现搜索镜像、下载镜像、上传镜像三个功能,这三个功能对应的job名称分别为”search”,”pull” 与 “push”。
  • Graph

    Graph在Docker架构中扮演已下载容器镜像的保管者,以及已下载容器镜像之间关系的记录者。
    也就是说通过pull下载到的镜像,可以进行重复使用是因为它已经被保存到了Graph中。

    • GraphDB是一个构建在SQLite之上的小型图数据库,SQLite是一个特别小的数据库,实现了节点的命名以及节点之间关联关系的记录。所有的镜像是按照分层结构来的
    • 比如下载一个镜像,下载完成后,又下载另一个镜像,这一个镜像中有和上一个镜像相同的数据,则就不用下载了,直接从GraphDB获取出信息,然后找到该数据就可以了
  • Driver

    Driver是Docker架构中的驱动模块。通过Driver驱动,Docker可以实现对Docker容器执行环境的定制。

    • 在Docker Driver的实现中,可以分为以下三类驱动:graphdriver、networkdriver和execdriver。

    • graphdriver

      主要用于完成容器镜像的管理,包括存储与获取。即当用户需要下载指定的容器镜像时,graphdriver将容器镜像存储在本地的指定目录;同时当用户需要使用指定的容器镜像来创建容器的rootfs时,graphdriver从本地镜像存储目录中获取指定的容器镜像。

    • graphdirver在初始化之前,有4中文件系统,分别是 aufs btrfs vfs overlay

    • 当docker初始化时,通过读取系统的环境变量 DOCKER_DRIVER 来获取driver的指定类型,而之后的所有graph操作都使用该driver(文件系统)来执

    • 例如 centos_docker的文件系统是 voerlay 而 ubuntu_docker的文件系统是 aufs

    • 使用docker info命令可以找到以下关键信息,就是基于系统的docker使用什么样的存储驱动

    • networkdriver

      networkdriver的用途是完成Docker容器网络环境的配置,其中包括Docker启动时为Docker环境创建网桥;Docker容器创建时为其创建专属虚拟网卡设备;以及为Docker容器分配IP、端口并与宿主机做端口映射,设置容器防火墙策略等。

    • execdriver

      作为Docker容器的执行驱动,负责创建容器运行命名空间(namespace),负责容器资源使用的统计与限制(cgroup),负责容器内部进程的真正运行等

      • 在执行docker exec命令时就是在这个驱动中来执行的
    • libcontainer

      是Docker架构中一个使用python设计实现的库,设计初衷是希望该库可以不依靠任何依赖,直接访问内核中与容器相关的API。

      • 正是由于libcontainer的存在,Docker可以直接调用libcontainer,而最终操纵容器的namespace、cgroups、网络设备以及防火墙规则等。这一系列操作的完成都不需要依赖LXC或者其他包
  • Docker container

    Docker container(Docker容器)是Docker架构中服务交付的最终体现形式。

    • 用户通过指定容器镜像,使得Docker容器可以自定义rootfs等文件系统; - 用户通过指定计算资源的配额,使得Docker容器使用指定的计算资源;
    • 用户通过配置网络及其安全策略,使得Docker容器拥有独立且安全的网络环境;
    • 用户通过指定运行的命令,使得Docker容器执行指定的工作。
  • Rootfs

  • 当镜像操作完成后,overlay2会启动镜像中的rootfs。实际上,镜像中只存在两个东西,一个是rootfs,一个是bootfs

  • bootfs用来引导镜像实例化后的容器启动,rootfs是镜像中所有的目录结构(如:./bin、/root/、/dev/、/proc/、/tmp/….)和数据结构,也就是系统所需的运行必要的目录

  • bootfs引导操作系统启动,用来加载内核和rootfs提供的文件系统,等加载完rootfs后bootfs会被卸载

  • rootfs是从镜像中抽离出来启动实例化后的容器的,用于将目录等结构加载到内存中,完成之后,就会去启动容器

小结


本博客所有文章是以学习为目的,如果有不对的地方可以一起交流沟通共同学习 邮箱:1248287831@qq.com!