为像 Docker 这样流行的开源项目做贡献有很多好处
- 您会因改进一个被很多人使用的项目而获得认可。
- 您将有机会与开源社区中其他非常聪明的人合作。
- 通过理解和改进一个重要的系统,您自己也会成为更优秀的程序员。
但是,着手一个新的代码库可能会让人望而生畏。Docker 有非常非常多的代码行。即使是修复最小的问题也可能需要阅读大量代码,并理解各个部分是如何组合在一起的。
但它也没有您想象的那么困难。您可以按照 Docker 的贡献者指南 来设置开发环境。然后按照这 5 个简单步骤 深入了解新的代码库(带有交互式代码片段来指导您)。您在此过程中磨练的技能将在您编程生涯中遇到的每个新项目中派上用场。还在等什么?步骤如下:
步骤 1:从 ‘func main()’ 开始
俗话说,从你所知道的开始。如果您像大多数 Docker 用户一样,您可能主要使用 Docker CLI。那么,让我们从该程序的入口点开始:‘main’ 函数。
在本文的剩余部分,我们将使用一个名为 Sourcegraph 的网站,Docker 团队使用它在 Web 上搜索和浏览代码,就像在智能 IDE 中一样。为了方便跟进,最好 打开第二个浏览器窗口访问 Sourcegraph,并在该窗口和这篇文章之间来回切换。
在 Sourcegraph 上,让我们在 Docker 仓库 中 搜索 ‘func main()’。

我们正在寻找与 ‘docker’ 命令对应的 ‘main’ 函数,它位于 ‘docker/docker/docker.go’ 文件中。点击该搜索结果,我们跳转到它的定义(如下所示)。花一些时间阅读这个函数
在 ‘main’ 函数的顶部,我们看到很多与设置日志记录、读取命令标志和初始化默认值相关的代码。在底部,我们找到了对 ‘client.NewDockerCli’ 的调用,它似乎负责创建结构体,而该结构体的方法完成了所有实际工作。让我们 发出一个针对 ‘NewDockerCli’ 的搜索查询。
步骤 2:深入核心
在许多应用程序和库中,都有一两个关键接口描述了核心功能或本质。让我们尝试从我们现在的位置到达那里。
点击 ‘NewDockerCli’ 搜索结果,我们到达该函数的定义。由于我们感兴趣的是该函数返回的结构体 ‘DockerCli’,让我们点击返回类型以跳转到其定义。
点击 ‘DockerCli’ 将我们带到 它的定义。向下滚动浏览此文件,我们看到它的方法 ‘getMethod’、‘Cmd’、‘Subcmd’ 和 ‘LoadConfigFile’。‘Cmd’ 看起来值得注意。它是唯一一个带有文档字符串的方法,并且文档字符串表明它是执行每个 Docker 命令的核心方法。
步骤 3:深入挖掘
现在我们已经找到了 ‘DockerCli’,Docker 客户端的核心 “控制器”,让我们深入了解其中一个具体的 Docker 命令是如何工作的。让我们聚焦 ‘docker build’。
阅读 ‘DockerCli.Cmd’ 的实现表明,它调用 ‘DockerCli.getMethod’ 来调用与每个 Docker 命令对应的函数。
在 ‘DockerCli.getMethod’ 中,我们看到这是通过动态调用一个方法来实现的,该方法的名称是字符串 ‘“Cmd”’ 前置于 Docker 命令的名称。因此,在 ‘docker build’ 的情况下,我们正在寻找 ‘DockerCli.CmdBuild’。在此文件中没有定义这样的方法,所以让我们 搜索 ‘CmdBuild’。
实际上,搜索结果显示 ‘DockerCli’ 上确实存在 ‘CmdBuild’ 方法,所以让我们选择结果跳转到它的定义。‘DockerCli.CmdBuild’ 方法体相当长,不适合在此博客文章中内联显示,但 这里提供了参考。
这里有很多事情正在发生。在该方法的顶部,我们看到了处理 Dockerfile 和配置的各种输入方法的代码。通常,阅读长方法的一个好策略是倒着工作。从底部开始,看看该方法在最后做了什么。在许多情况下,那是该方法的核心,之前的一切都只是为完成该核心操作而进行的设置。
在 ‘CmdBuild’ 的底部,我们看到通过 ‘cli.stream’ 发出的 ‘POST’ 请求。跳转到更多定义后,我们到达 ‘DockerCli.clientRequest’,它构建了一个 HTTP 请求,其中包含您通过 ‘docker build’ 传递给 Docker 的信息。因此,归根结底,所有 ‘docker build’ 所做的只是向 Docker 守护进程发出一个花哨的 ‘POST’ 请求。如果您真的想,可以尝试使用 ‘curl’ 复制它的行为。
现在我们已经彻底理解了一个 Docker 客户端命令,您可能会有兴趣更深入地挖掘,找到守护进程接收请求的位置,并一直跟踪到它与 LXC 和内核的交互。这当然是一条有效的途径,但我们现在将其留给读者作为练习。相反,让我们更广泛地了解客户端的关键组件。
步骤 4:查看使用示例
更好理解一段代码的一种方法是查看该代码的使用示例。让我们回到 ‘DockerCli.clientRequest’ 方法。在 Sourcegraph 右侧的面板中,我们可以翻阅此方法的使用示例。事实证明,此方法在多个地方被使用,因为大多数 Docker 客户端命令都会导致向守护进程发出 HTTP 请求。

为了完全理解一段代码,您需要同时理解它的工作原理和它的使用方式。跳转到定义使我们能够通过沿着代码图向前走来理解前者,而查看使用示例则通过向后走来涵盖后者。
为更多的函数和方法尝试一下,以了解它们是如何相互关联的。如果对您有帮助,可以画一张图,说明应用程序的各个组件是如何相互作用的。
步骤 5:选择一个问题并开始编码!
现在您已经对整个 Docker 代码库有了一个大致的了解,请查看 问题跟踪器,看看有哪些需要处理的问题,并向 Docker 社区的成员寻求您无法自行回答的问题的帮助。因为您已经花时间探索和理解了代码,所以您将能够更好地提出明智的问题,并知道具体问题在更广泛的图中处于什么位置。
如果您觉得可以胜任,请沿途做笔记,记录您的经验,并像这篇文章一样撰写成博客文章。Docker 团队很乐意了解您深入研究他们代码的经历。
有效贡献
常常阻止人们参与项目的一个误解是,被跳入一个庞大的、陌生的代码库的任务吓倒。作为程序员,我们常常认为,艰苦的工作在于编写代码,但通常,阅读和理解别人的代码才是关键的第一步。认识到这一点,并以有原则的方式处理这项任务,并配备好的工具来做到这一点,将帮助您克服深入研究代码的心理障碍。
所以,迈出一步,今天就查看 Docker 的源代码。一个充满活力的开源社区和代码库在等着您!
1 条评论