• docker-server(moby)源码窥探


    docker 服务端的代码,已经被单独划分为一个仓库:moby。此文将分析dockerd在启动过程中的重要步骤。为了节省篇幅,突出显示重要部分,在源码的截图中将以…代替次要的逻辑,仅保留重要的信息。

    入口函数main()

    入口函数在/root/go/src/github.com/docker/docker/cmd/dockerd/docker.go中。

    在main() 函数中,除基本的设置外,包含两个重要的函数,分别为newDaemonCommand()和Execute()。newDaemonCommand()返回一个dockerd命令,Execute()则负责执行这个命令。

    在这里插入图片描述

    newDaemonCommand()

    newDaemonCommand() 与 docker-cli中设置命令的方法类似,其中最主要的还是runE字段的对应的函数,后面在执行的过程中,会调用该函数。

    除了runE字段外,还包括一些flag参数设置,这些都不涉及重要的流程。

    在这里插入图片描述

    Execute()

    Execute() 内部直接调用了ExecuteC()

    在这里插入图片描述

    ExecuteC()

    ExecuteC()中先通过Find() 获取解析出实际的命令,此处如果是没有子命令的场景,其实c 和 cmd变量是同样的内容。相当于没有变化。具体的Find()执行过程,与docker-cli项目中的Find()是一样的,详情可以移步至:https://zhh0427.blog.csdn.net/article/details/127796562

    获取到cmd之后,通过execute(), 执行该命令,

    在这里插入图片描述

    execute()

    execute()中主要的就是RunE()的调用,当然还包括一些其他的前置和后置处理,这里就不赘述了。

    在这里插入图片描述

    此处调用的RunE,即是在newDaemonCommand()中设置的RunE字段,可以发现RunE中的runDaemon()其实才是真正开始运行服务,之前的都是为dockerd这个命令做的配置,都是铺垫此处的。

    在这里插入图片描述

    runDaemon()

    runDaemon()的整体逻辑也比较简单,就是先实例化一个DaemonCli(), 接着开启该Cli。

    在这里插入图片描述

    start()

    start()包含对DaemonCli的配置、初始化、以及对操作系统的适配、基础环境的创建、swarm、集群模式的配置等等一系列的操作,这里很难一一讲清楚。不过,其中与日常单机使用最相关的,当属apiServer部分的逻辑。

    这部分逻辑中,主要分为三个步骤:1. 先创建apiServerConfig 配置 2. 根据配置初始化路由,即各个api对应函数 3.路由初始化完成后,通过开启协程开始监听客户端的发来的请求。其中配置部分的逻辑比较简单,更重要的是initRouter()和cli.api.Wait()。

    在这里插入图片描述

    initRouter()

    在initRouter()中,可以发现通过NewRouter()各个模块的实例化路由的动作,包括 容器相关、镜像相关、挂载卷相关的等等。

    在实例化完成后,最终调用InitRouter()对所有的路由作进一步处理。

    在这里插入图片描述

    NewRouter()

    这里仅对container.NewRouter()做分析,其他的模块都是相似的逻辑。NewRouter()中直接调用了initRoutes()。而initRoutes()中包含了大量的url注册,其中值得注意的是/containers/json, 不知道是否还记得,docker ps -a 最终发起的http请求的路径,没错就是该路由(如果不清楚,请移步至:https://zhh0427.blog.csdn.net/article/details/127796562)。

    由此可见,执行docker ps -a 获得的数据,其实是通过此处返回的,getContainersByName()具体的执行逻辑,这里就不赘述了,请自行查阅。
    在这里插入图片描述

    在这里插入图片描述

    InitRouter()

    在InitRouter()中,似乎是仅仅将各个路由赋值给了s.routers,其他啥也没干,其实不然,请记住这里的s.routers。

    在这里插入图片描述

    Wait()

    在Wait()中,通过serverAPI()开启对各个路由的监听。

    在这里插入图片描述

    serveAPI()

    在serverAPI()中,通过createMux() 初始化服务器使用的各个路由,然后通过Server开启监听。

    在这里插入图片描述

    createMux()

    在createMux()中,可以发现前面被赋值的s.routers 在这里发挥了作用。通过遍历每一个routers中的所有route,并为其注册路由。

    在这里插入图片描述

    Serve()

    最终在Server() 中,监听路由,等待客户端发来的请求,并分发到对应的处理器中。

    在这里插入图片描述

    至此,整个docker-server的启动主要过程就结束了。除了上述这些我认为重要的步骤,还有很多很多其他的步骤。很难在短时间内完全搞清楚,也很难一一讲清楚,具体的实现细节,还需要读者自行去查阅源代码。这里提供一个搭建docker源码阅读环境的教程:https://zhh0427.blog.csdn.net/article/details/127797712。

    如果上述有错误的地方,还请评论区指正,谢谢!

  • 相关阅读:
    openfeign异常--NoSuchBeanDefinitionException: No qualifying bean of type
    Jenkins+maven+testng+htmlreport单元自动化测试
    CentOS中使用Docker部署带postgis的postgresql
    小程序开发设计-第一个小程序:创建小程序项目④
    IDEA-插件开发踩坑记录-第四坑-Action介绍与工具栏、弹出菜单中运用
    C语言每日一题(14):有序序列判断
    gson如何序列化子类
    【BUUCTF】roarctf_2019_realloc_magic---从一道题认识realloc函数+stdout泄露libc地址实战
    注解与反射
    【Spring(七)】带你手写一个Spring容器
  • 原文地址:https://blog.csdn.net/hg_zhh/article/details/127876098