首先,让我们回想,整个docker的安装流程,删除旧版本--》配置安装源--》安装依赖项--》安装docker --》注册成服务--》启动docker。这里我们学习下dockerder的基础框架
docker 采用CS架构,在宿主机器上,docker启用了一个服务端,也即docker的守护进程,服务端与客户端通过一个称为RESET API的网络组件交互,RESET API 基于 UNIX套接字或网络接口实现通讯。服务端接收client端的描述或者指令管理镜像、容器、网络及数据卷等对象,相对于client端,任务更多集中在服务端。docker的客户端和服务端可同时运行在同一设备上,也可运行在不同设备上,默认安装docker-ce / docker 会同时安装服务端和客户端,也可通过仅安装 client端,连接另外一个设备的docker daemon. 具体操作后续再介绍。
这是,docker官网上 docker框架 运行结构图 docker client 通过 RESET API 向docker daemon 发送指令操作进行,当服务端在本地找不到镜像时,服务器从远处仓库中,拉取镜像,然会保存到本地,根据请求实例化镜像或者创建新镜像。那么很多有人好奇,daemon 如何保存管理镜像,启动容器,那么这里需要关注下linux的devicemapper技术,后续有空跟上。
docker daemon,即docker服务端,通过查询可发现监听三个套接字
netstat -ano | grep docker
[root@localhost docker]# netstat -ano | grep docker
unix 2 [ ACC ] STREAM LISTENING 10264084 /var/run/docker.sock
unix 2 [ ACC ] STREAM LISTENING 10360721 /var/run/docker/metrics.sock
unix 2 [ ACC ] STREAM LISTENING 10344608 /run/docker/libnetwork/251d25ccbae459eda47b6edf98222dc34d19a7de94c7321345754082d7ef65e7.sock
[root@localhost docker]#
/var/run/docker.sock 是daemon与容器通讯的套接字,端口是变化的,每次关闭、启动 端口会变化,
/var/run/docker/metrics.sock 用于收集各容器状态信息
/run/docker/libnetwork/.sock 是docker内部用来构建容器网络的
通过查询端口对应的进程我们发现该三个端口对应的启动进程都是 /usr/bin/dockerd
netstat -anp | grep 端口号
查询到具体的进程号后,再查询 启动程序
ps -aux | grep 进程号
[root@localhost hadoop]# netstat -ano | grep docker
unix 2 [ ACC ] STREAM LISTENING 10264084 /var/run/docker.sock
unix 2 [ ACC ] STREAM LISTENING 10360721 /var/run/docker/metrics.sock
unix 2 [ ACC ] STREAM LISTENING 10344608 /run/docker/libnetwork/251d25ccbae459eda47b6edf98222dc34d19a7de94c7321345754082d7ef65e7.sock
[root@localhost hadoop]# netstat -anop | grep 10360721
unix 2 [ ACC ] STREAM LISTENING 10360721 5488/dockerd /var/run/docker/metrics.sock
[root@localhost hadoop]# ps -aux | grep 5488
root 5488 0.0 0.0 2463668 71660 ? Ssl 10:33 0:08 /usr/bin/dockerd -H unix://
root 27808 0.0 0.0 112648 952 pts/1 S+ 14:48 0:00 grep --color=auto 5488
docker daemon 接收 docker API(RESET API 实际上是docker client)的请求,操作docker对象(image container volume network),同时,docker daemon也可与其他daemon交互,协同完成docker服务。docker网络相关问题后续跟进。
docker client 是 与docker服务端交互的客户端,当我们调用 docker run / create pull 等操作指令时,docker client调用API请求daemon, daemon 收到请求后,执行操作, 同一个了docker client 可连接不同宿主设备的daemon。
docker 注册仓库是用于存储docker镜像,例如Docker Hub 、 Docker Cloud 是免费公用镜像库,而且 docker默认在 Docker Hub上查找镜像(当本地未找到镜像时),同样,用户也即可建立私有库,存储镜像。
当用户调用 docker run /pull 时,镜像将被从指定的仓库中拉取下, 当调用 docker push 时,docker将本地镜像推送到指定服务器仓库中。 用户也可以在网络上购买、或者销售镜像,也可免费发布。
在使用docker过程中,docker服务器会创建一些列的对象,这些对象包括镜像、容器、网络、数据卷、插件等。这里简单介绍下镜像、容器与服务。
镜像是 一个具有创建容器的指令的只读模板,简单理解成 一个可执行程序的基础运行环境,通常,镜像是基于一个基础镜像构建而成,例如我们基于的Centos7.5 镜像之上,添加apache web 服务,同时加上自己web程序及依赖库,新建一个新的镜像,那么利用该新建的镜像,创建容器,则可以运行自己的web程序。
我们将将新生成的镜像,和别人的镜像,构建自己的镜像库,同时,我们也可以通过dockerfile创建镜像,一般dockerfile开头文件内容指定基础镜像,然后后续每执行一条语句(RUN),新建一个只读层次,当修改dokerfile,重建镜像时,仅执行修改的那些层,大大增加镜像构建效率。本质上,镜像是多个重叠只读层的同一视角,下一层保存上一层地址。
容器是镜像的实例,可通过调用 docker API 或者 docker cli 创建、停止、启动、删除容器,而且一个容器可以被关联到一个或者多个网络(每个容器之间网络是隔离的,与容器命名空间相关),同时,也可以保存一个容器实时状态(例如添加了一个软件,修改了某个文件,增加了配置等)提交为镜像。
容器可以很好地与其他容器或者宿主机器关联,使用者可控制容器的网络、存储、或者其他潜在的子系统,如何与其他容器、或者宿主机器的关联。这就是后续 docker engine关注的重点,例如kubernetes。
容器状态依赖创建时指定的镜像和启动时的配置参数,一旦容器清除,那么容器在运行过程的一切持久化过程消失。
services 允许用户发布容器到多个docker daemon上,多个docker daemon以集群方式工作,存在多个管理结点和工作结点,结点间通过docker API(前面提到的 RESET API)交互。一个服务在配置时,需要指定服务个数(即在某个结点上服务异常时,集群提供多少个同样服务可替换运行)如此,服务被均衡负载到各工作结点。此时 docker daemon只是一个简单的工作环境,供上层的引擎调度。在docker 1.12及之后版本,集群模块便加入其中。这也是docker engine的核心点。
docker run -t -i ubuntu /bin/bash 语句执行过程
docker run -t -i ubuntu /bin/bash
上述语句,运行一个ubuntu容器,容器接收外部标准输入, 容器内的接收输入的程序为 /bin/bash, 如果需要查看更多参数可d调用docker run --help,每个参数均有解释。
(1) docker 首先检查,本地是否有名为 ubuntu的镜像,如果没有,docker daemon 将从指定的远程仓库拉取,默认远程仓库为Docker Hub, 而且,未指定具体版本情况下将默认获取最新的stable版。拉取镜像。此步骤 类似于手动调用 docker pull ubuntu
(2)docker 创建容器, 对应的 手动指令 docker container create
(3)docker关联一个可读写的文件系统给容器,并将该层作为容器的最后一层,运行用户运行自定义的应用程序,修改容器本地文件或者目录,但是注意,容器一旦通知,该层的数据将删除,不会保存到对应的镜像中。
(4) docker创建一个网络接口,使得容器连接宿主机器网络。此部分工作在libnetwork模块中进行,如此容器可通过宿主机器连接外部网络。
(5) docker 启动容器并运行指定参数 设置的程序 /bin/bash ,由于启动时配置了参数 -t -i 运行容器可宿主终端交互,因此在窗口输入指令,可直接操作docker
(6) 终端输入 exit 或者 组合键盘 Ctrl + d 退出容器,如果未设置参数 --rm 容器默认未删除,可以再次启动,如果设置了,则容器退出,将直接被删除。