2017年11月

请各位思考以下问题:在你阅读本文的这段时间内,计算机中的操作系统在运行吗?又或者仅仅是 Web 浏览器在运行?又或者它们也许均处于空闲状态,等待着你的指示?

这些问题并不复杂,但它们深入涉及到系统软件工作的本质。为了准确回答这些问题,我们需要透彻理解操作系统的行为模型,包括性能、安全和除错等方面。在该系列文章中,我们将以 Linux 为主举例来帮助你建立操作系统的行为模型,OS X 和 Windows 在必要的时候也会有所涉及。对那些深度探索者,我会在适当的时候给出 Linux 内核源码的链接。

这里有一个基本认知,就是,在任意给定时刻,某个 CPU 上仅有一个任务处于活动状态。大多数情形下这个任务是某个用户程序,例如你的 Web 浏览器或音乐播放器,但它也可能是一个操作系统线程。可以确信的是,它是一个任务,不是两个或更多,也不是零个,对,永远是一个。

这听上去可能会有些问题。比如,你的音乐播放器是否会独占 CPU 而阻止其它任务运行?从而使你不能打开任务管理工具去杀死音乐播放器,甚至让鼠标点击也失效,因为操作系统没有机会去处理这些事件。你可能会愤而喊出,“它究竟在搞什么鬼?”,并引发骚乱。

此时便轮到中断大显身手了。中断就好比,一声巨响或一次拍肩后,神经系统通知大脑去感知外部刺激一般。计算机主板上的芯片组同样会中断 CPU 运行以传递新的外部事件,例如键盘上的某个键被按下、网络数据包的到达、一次硬盘读取的完成,等等。硬件外设、主板上的中断控制器和 CPU 本身,它们共同协作实现了中断机制。

中断对于记录我们最珍视的资源——时间——也至关重要。计算机启动过程中,操作系统内核会设置一个硬件计时器以让其产生周期性计时中断,例如每隔 10 毫秒触发一次。每当计时中断到来,内核便会收到通知以更新系统统计信息和盘点如下事项:当前用户程序是否已运行了足够长时间?是否有某个 TCP 定时器超时了?中断给予了内核一个处理这些问题并采取合适措施的机会。这就好像你给自己设置了整天的周期闹铃并把它们用作检查点:我是否应该去做我正在进行的工作?是否存在更紧急的事项?直到你发现 10 年时间已逝去……

这些内核对 CPU 周期性的劫持被称为 滴答 tick ,也就是说,是中断让你的操作系统滴答了一下。不止如此,中断也被用作处理一些软件事件,如整数溢出和页错误,其中未涉及外部硬件。中断是进入操作系统内核最频繁也是最重要的入口。对于学习电子工程的人而言,这些并无古怪,它们是操作系统赖以运行的机制。

说到这里,让我们再来看一些实际情形。下图示意了 Intel Core i5 系统中的一个网卡中断。图片中的部分元素设置了超链,你可以点击它们以获取更为详细的信息,例如每个设备均被链接到了对应的 Linux 驱动源码。

链接如下:

让我们来仔细研究下。首先,由于系统中存在众多中断源,如果硬件只是通知 CPU “嘿,这里发生了一些事情”然后什么也不做,则不太行得通。这会带来难以忍受的冗长等待。因此,计算机上电时,每个设备都被授予了一根中断线,或者称为 IRQ。这些 IRQ 然后被系统中的中断控制器映射成值介于 0 到 255 之间的中断向量。等到中断到达 CPU,它便具备了一个完好定义的数值,异于硬件的某些其它诡异行为。

相应地,CPU 中还存有一个由内核维护的指针,指向一个包含 255 个函数指针的数组,其中每个函数被用来处理某个特定的中断向量。后文中,我们将继续深入探讨这个数组,它也被称作中断描述符表(IDT)。

每当中断到来,CPU 会用中断向量的值去索引中断描述符表,并执行相应处理函数。这相当于,在当前正在执行任务的上下文中,发生了一个特殊函数调用,从而允许操作系统以较小开销快速对外部事件作出反应。考虑下述场景,Web 服务器在发送数据时,CPU 却间接调用了操作系统函数,这听上去要么很炫酷要么令人惊恐。下图展示了 Vim 编辑器运行过程中一个中断到来的情形。

此处请留意,中断的到来是如何触发 CPU 到 Ring 0 内核模式的切换而未有改变当前活跃的任务。这看上去就像,Vim 编辑器直接面向操作系统内核产生了一次神奇的函数调用,但 Vim 还在那里,它的地址空间原封未动,等待着执行流返回。

这很令人振奋,不是么?不过让我们暂且告一段落吧,我需要合理控制篇幅。我知道还没有回答完这个开放式问题,甚至还实质上翻开了新的问题,但你至少知道了在你读这个句子的同时滴答正在发生。我们将在充实了对操作系统动态行为模型的理解之后再回来寻求问题的答案,对 Web 浏览器情形的理解也会变得清晰。如果你仍有问题,尤其是在这篇文章公诸于众后,请尽管提出。我将会在文章或后续评论中回答它们。下篇文章将于明天在 RSS 和 Twitter 上发布。


via: http://duartes.org/gustavo/blog/post/when-does-your-os-run/

作者:gustavo 译者:Cwndmiao 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Linux 新手往往对命令行心存畏惧。部分原因是因为需要记忆大量的命令,毕竟掌握命令是高效使用命令行的前提。

不幸的是,学习这些命令并无捷径,然而在你开始学习命令之初,有些工具还是可以帮到你的。

history

Linux Bash History 命令

首先要介绍的是命令行工具 history,它能帮你记住那些你曾经用过的命令。包括应用最广泛的 Bash 在内的大多数 Linux shell,都会创建一个历史文件来包含那些你输入过的命令。如果你用的是 Bash,这个历史文件就是 /home/<username>/.bash_history

这个历史文件是纯文本格式的,你可以用任意的文本编辑器打开来浏览和搜索。

apropos

确实存在一个可以帮你找到其他命令的命令。这个命令就是 apropos,它能帮你找出合适的命令来完成你的搜索。比如,假设你需要知道哪个命令可以列出目录的内容,你可以运行下面命令:

apropos "list directory"

Linux Apropos

这就搜索出结果了,非常直接。给 “directory” 加上复数后再试一下。

apropos "list directories"

这次没用了。apropos 所作的其实就是搜索一系列命令的描述。描述不匹配的命令不会纳入结果中。

还有其他的用法。通过 -a 标志,你可以以更灵活的方式来增加搜索关键字。试试这条命令:

apropos "match pattern"

Linux Apropos -a Flag

你会觉得应该会有一些匹配的内容出现,比如 grep 对吗? 然而,实际上并没有匹配出任何结果。再说一次,apropos 只会根据字面内容进行搜索。

现在让我们试着用 -a 标志来把单词分割开来。(LCTT 译注:该选项的意思是“and”,即多个关键字都存在,但是不需要正好是连在一起的字符串。)

apropos "match" -a "pattern"

这一下,你可以看到很多期望的结果了。

apropos 是一个很棒的工具,不过你需要留意它的缺陷。

ZSH

Linux ZSH Autocomplete

ZSH 其实并不是用于记忆命令的工具。它其实是一种 shell。你可以用 ZSH 来替代 Bash 作为你的命令行 shell。ZSH 包含了自动纠错机制,能在你输入命令的时候给你予提示。开启该功能后,它会提示你相近的选择。在 ZSH 中你可以像往常一样使用命令行,同时你还能享受到极度安全的网络以及其他一些非常好用的特性。充分利用 ZSH 的最简单方法就是使用 Oh-My-ZSH

速记表

最后,也可能是最间的方法就是使用 速记表

有很多在线的速记表,比如这个 可以帮助你快速查询命令。

linux-commandline-cheatsheet

为了快速查询,你可以寻找图片格式的速记表,然后将它设置为你的桌面墙纸。

这并不是记忆命令的最好方法,但是这么做可以帮你节省在线搜索遗忘命令的时间。

在学习时依赖这些方法,最终你会发现你会越来越少地使用这些工具。没有人能够记住所有的事情,因此偶尔遗忘掉某些东西或者遇到某些没有见过的东西也很正常。这也是这些工具以及因特网存在的意义。


via: https://www.maketecheasier.com/remember-linux-commands/

作者:Nick Congleton 译者:lujun9972 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在显示你的数据和工作方面我发现了几个科学软件,但是我不会涉及太多方面。因此在这篇文章中,我将谈到一款叫 ImageJ 的热门图像处理软件。特别的,我会介绍 Fiji,这是一款绑定了一系列用于科学图像处理插件的 ImageJ 软件。

Fiji 这个名字是一个循环缩略词,很像 GNU 。代表着 “Fiji Is Just ImageJ”。 ImageJ 是科学研究领域进行图像分析的实用工具 —— 例如你可以用它来辨认航拍风景图中树的种类。 ImageJ 能划分物品种类。它以插件架构制成,海量插件可供选择以提升使用灵活度。

首先是安装 ImageJ (或 Fiji)。大多数的 ImageJ 发行版都可有该软件包。你愿意的话,可以以这种方式安装它,然后根据你的研究安装所需的独立插件。另一种选择是安装 Fiji 的同时获取最常用的插件。不幸的是,大多数 Linux 发行版的软件中心不会有可用的 Fiji 安装包。幸而,官网上的简单安装文件是可以使用的。这是一个 zip 文件,包含了运行 Fiji 需要的所有文件目录。第一次启动时,你只会看到一个列出了菜单项的工具栏。(图 1)

图 1. 第一次打开 Fiji 有一个最小化的界面。

如果你没有备好图片来练习使用 ImageJ ,Fiji 安装包包含了一些示例图片。点击“File”->“Open Samples”的下拉菜单选项(图 2)。这些示例包含了许多你可能有兴趣做的任务。

图 2. 案例图片可供学习使用 ImageJ。

如果你安装了 Fiji,而不是单纯的 ImageJ ,那么大量插件也会被安装。首先要注意的是自动更新器插件。每次打开 ImageJ ,该插件将联网检验 ImageJ 和已安装插件的更新。

所有已安装的插件都在“插件”菜单项中可选。一旦你安装了很多插件,列表会变得冗杂,所以需要精简你选择的插件。你想手动更新的话,点击“Help”->“Update Fiji” 菜单项强制检测并获取可用更新的列表(图 3)。

图 3. 强制手动检测可用更新。

那么,现在,用 Fiji/ImageJ 可以做什么呢?举一例,统计图片中的物品数。你可以通过点击“File”->“Open Samples”->“Embryos”来载入示例。

图 4. 用 ImageJ 算出图中的物品数。

第一步给图片设定比例,这样你可以告诉 ImageJ 如何判别物品。首先,选择在工具栏选择线条按钮。然后选择“Analyze”->“Set Scale”,然后就会设置比例尺包含的像素点个数(图 5)。你可以设置“known distance ”为 100,单元为“um”。

图 5. 很多图片分析任务需要对图片设定一个范围。

接下来的步骤是简化图片内的信息。点击“Image”->“Type”->“8-bit”来减少信息量到 8 比特灰度图片。要分隔独立物体点击“Process”->“Binary”->“Make Binary”以自动设置图片门限。(图 6)。

图 6. 有些工具可以自动完成像门限一样的任务。

图片内的物品计数前,你需要移除像比例尺之类的人工操作。可以用矩形选择工具来选中它并点击“Edit”->“Clear”来完成这项操作。现在你可以分析图片看看这里是啥物体。

确保图中没有区域被选中,点击“Analyze”->“Analyze Particles”来弹出窗口来选择最小尺寸,这决定了最后的图片会展示什么(图 7)。

*图 7. 你可以通过确定最小尺寸生成一个缩减过的图片。 *

图 8 在总结窗口展示了一个概览。每个最小点也有独立的细节窗口。

图 8. 包含了已知最小点总览清单的输出结果。

当你有一个分析程序可以工作于给定图片类型,你通常需要将相同的步骤应用到一系列图片当中。这可能数以千计,你当然不会想对每张图片手动重复操作。这时候,你可以集中必要步骤到宏,这样它们可以被应用多次。点击插件->“Macros”->“Record”,弹出一个新的窗口记录你随后的所有命令。所有步骤完成,你可以将之保存为一个宏文件,并且通过点击“Plugins”->“Macros”->“Run”来在其它图片上重复运行。

如果你有非常特定的工作步骤,你可以简单地打开宏文件并手动编辑它,因为它是一个简单的文本文件。事实上有一套完整的宏语言可供你更加充分地控制图片处理过程。

然而,如果你有真的有非常多的系列图片需要处理,这也将是冗长乏味的工作。这种情况下,前往“Process”->“Batch”->“Macro”,会弹出一个你可以设置批量处理工作的新窗口(图 9)。

图 9. 对批量输入的图片用单一命令运行宏。

这个窗口中,你能选择应用哪个宏文件、输入图片所在的源目录和你想写入输出图片的输出目录。也可以设置输出文件格式,及通过文件名筛选输入图片中需要使用的。万事具备之后,点击窗口下方的的“Process”按钮开始批量操作。

若这是会重复多次的工作,你可以点击窗口底部的“Save”按钮保存批量处理到一个文本文件。点击也在窗口底部的“Open”按钮重新加载相同的工作。这个功能可以使得研究中最冗余部分自动化,这样你就可以在重点放在实际的科学研究中。

考虑到单单是 ImageJ 主页就有超过 500 个插件和超过 300 种宏可供使用,简短起见,我只能在这篇短文中提出最基本的话题。幸运的是,还有很多专业领域的教程可供使用,项目主页上还有关于 ImageJ 核心的非常棒的文档。如果你觉得这个工具对研究有用,你研究的专业领域也会有很多信息指引你。


作者简介:

Joey Bernard 有物理学和计算机科学的相关背景。这对他在新不伦瑞克大学当计算研究顾问的日常工作大有裨益。他也教计算物理和并行程序规划。


via: https://www.linuxjournal.com/content/image-processing-linux

作者:Joey Bernard 译者:XYenChi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Moby Project

自从 Docker 四年前将软件容器推向大众化以来,整个生态系统都围绕着容器化而发展,在这段这么短的时期内,它经历了两个不同的增长阶段。在这每一个阶段,生产容器系统的模式已经随着项目和不断增长的容器生态系统而演变适应用户群体的规模和需求。

Moby 是一个新的开源项目,旨在推进软件容器化运动,帮助生态系统将容器作为主流。它提供了一个组件库,一个将它们组装到定制的基于容器的系统的框架,也是所有容器爱好者进行实验和交换想法的地方。

让我们来回顾一下我们如何走到今天。在 2013-2014 年,开拓者开始使用容器,并在一个单一的开源代码库,Docker 和其他一些项目中进行协作,以帮助工具成熟。

Docker Open Source

然后在 2015-2016 年,云原生应用中大量采用容器用于生产环境。在这个阶段,用户社区已经发展到支持成千上万个部署,由数百个生态系统项目和成千上万的贡献者支持。正是在这个阶段,Docker 将其产品模式演变为基于开放式组件的方法。这样,它使我们能够增加创新和合作的方面。

涌现出来的新独立的 Docker 组件项目帮助促进了合作伙伴生态系统和用户社区的发展。在此期间,我们从 Docker 代码库中提取并快速创新组件,以便系统制造商可以在构建自己的容器系统时独立重用它们:runcHyperKitVPNKitSwarmKitInfraKitcontainerd 等。

Docker Open Components

站在容器浪潮的最前沿,我们看到 2017 年出现的一个趋势是容器将成为主流,传播到计算、服务器、数据中心、云、桌面、物联网和移动的各个领域。每个行业和垂直市场,金融、医疗、政府、旅游、制造。以及每一个使用案例,现代网络应用、传统服务器应用、机器学习、工业控制系统、机器人技术。容器生态系统中许多新进入者的共同点是,它们建立专门的系统,针对特定的基础设施、行业或使用案例。

作为一家公司,Docker 使用开源作为我们的创新实验室,而与整个生态系统合作。Docker 的成功取决于容器生态系统的成功:如果生态系统成功,我们就成功了。因此,我们一直在计划下一阶段的容器生态系统增长:什么样的产品模式将帮助我们扩大容器生态系统,以实现容器成为主流的承诺?

去年,我们的客户开始在 Linux 以外的许多平台上要求有 Docker:Mac 和 Windows 桌面、Windows Server、云平台(如亚马逊网络服务(AWS)、Microsoft Azure 或 Google 云平台),并且我们专门为这些平台创建了许多 Docker 版本。为了在一个相对较短的时间和更小的团队中,以可扩展的方式构建和发布这些专业版本,而不必重新发明轮子,很明显,我们需要一个新的方式。我们需要我们的团队不仅在组件上进行协作,而且还在组件组合上进行协作,这借用来自汽车行业的想法,其中组件被重用于构建完全不同的汽车。

Docker production model

我们认为将容器生态系统提升到一个新的水平以让容器成为主流的最佳方式是在生态系统层面上进行协作。

Moby Project

为了实现这种新的合作高度,今天(2017 年 4 月 18 日)我们宣布推出软件容器化运动的新开源项目 Moby。它是提供了数十个组件的“乐高组件”,一个将它们组合成定制容器系统的框架,以及所有容器爱好者进行试验和交换意见的场所。可以把 Moby 认为是容器系统的“乐高俱乐部”。

Moby 包括:

  1. 容器化后端组件(例如,低层构建器、日志记录设备、卷管理、网络、镜像管理、containerd、SwarmKit 等)
  2. 将组件组合到独立容器平台中的框架,以及为这些组件构建、测试和部署构件的工具。
  3. 一个名为 “Moby Origin” 的引用组件,它是 Docker 容器平台的开放基础,以及使用 Moby 库或其他项目的各种组件的容器系统示例。

Moby 专为系统构建者而设计,他们想要构建自己的基于容器的系统,而不是可以使用 Docker 或其他容器平台的应用程序开发人员。Moby 的参与者可以从源自 Docker 的组件库中进行选择,或者可以选择将“自己的组件”(BYOC)打包为容器,以便在所有组件之间进行混合和匹配以创建定制的容器系统。

Docker 将 Moby 作为一个开放的研发实验室来试验、开发新的组件,并与容器技术的未来生态系统进行协作。我们所有的开源协作都将转向 Moby。Docker 现在并且将来仍然是一个开源产品,可以让你创建、发布和运行容器。从用户的角度来看,它是完全一样的。用户可以继续从 docker.com 下载 Docker。请在 Moby 网站上参阅有关 Docker 和 Moby 各自角色的更多信息

请加入我们,帮助软件容器成为主流,并通过在组件和组合上进行协作,将我们的生态系统和用户社区发展到下一个高度。


via: https://blog.docker.com/2017/04/introducing-the-moby-project/

作者:Solomon Hykes 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

一个不幸的事实是,所有的软件都有 bug,一些 bug 会导致系统崩溃。当它出现的时候,它经常会在磁盘上留下一个被称为“ 核心转储 core dump ”的数据文件。该文件包含有关系统崩溃时的相关数据,可能有助于确定发生崩溃的原因。通常开发者要求提供 “ 回溯 backtrace ” 形式的数据,以显示导致崩溃的指令流。开发人员可以使用它来修复 bug 以改进系统。如果系统发生了崩溃,以下是如何轻松生成 回溯 backtrace 的方法。

从使用 coredumpctl 开始

大多数 Fedora 系统使用自动错误报告工具(ABRT)来自动捕获崩溃文件并记录 bug。但是,如果你禁用了此服务或删除了该软件包,则此方法可能会有所帮助。

如果你遇到系统崩溃,请首先确保你运行的是最新的软件。更新通常包含修复程序,这些更新通常含有已经发现的会导致严重错误和崩溃的错误的修复。当你更新后,请尝试重现导致错误的情况。

如果崩溃仍然发生,或者你已经在运行最新的软件,那么可以使用有用的 coredumpctl 工具。此程序可帮助查找和处理崩溃。要查看系统上所有核心转储列表,请运行以下命令:

coredumpctl list

如果你看到比预期长的列表,请不要感到惊讶。有时系统组件在后台默默地崩溃,并自行恢复。快速查找今天的转储的简单方法是使用 -since 选项:

coredumpctl list --since=today

“PID” 列包含用于标识转储的进程 ID。请注意这个数字,因为你会之后再用到它。或者,如果你不想记住它,使用下面的命令将它赋值给一个变量:

MYPID=<PID>

要查看关于核心转储的信息,请使用此命令(使用 $MYPID 变量或替换 PID 编号):

coredumpctl info $MYPID

安装 debuginfo 包

在核心转储中的数据以及原始代码中的指令之间调试符号转义。这个符号数据可能相当大。与大多数用户运行在 Fedora 系统上的软件包不同,符号以 “debuginfo” 软件包的形式安装。要确定你必须安装哪些 debuginfo 包,请先运行以下命令:

coredumpctl gdb $MYPID

这可能会在屏幕上显示大量信息。最后一行可能会告诉你使用 dnf 安装更多的 debuginfo 软件包。用 sudo 运行该命令以安装:

sudo dnf debuginfo-install <packages...>

然后再次尝试 coredumpctl gdb $MYPID 命令。你可能需要重复执行此操作,因为其他符号会在回溯中展开。

捕获回溯

在调试器中运行以下命令以记录信息:

set logging file mybacktrace.txt
set logging on

你可能会发现关闭分页有帮助。对于长的回溯,这可以节省时间。

set pagination off

现在运行回溯:

thread apply all bt full

现在你可以输入 quit 来退出调试器。mybacktrace.txt 包含可附加到 bug 或问题的追踪信息。或者,如果你正在与某人实时合作,则可以将文本上传到 pastebin。无论哪种方式,你现在可以向开发人员提供更多的帮助来解决问题。


作者简介:

Paul W. Frields

Paul W. Frields 自 1997 年以来一直是 Linux 用户和爱好者,并于 2003 年在 Fedora 发布不久后加入 Fedora。他是 Fedora 项目委员会的创始成员之一,从事文档、网站发布、宣传、工具链开发和维护软件。他于 2008 年 2 月至 2010 年 7 月加入 Red Hat,担任 Fedora 项目负责人,现任红帽公司工程部经理。他目前和妻子和两个孩子住在弗吉尼亚州。


via: https://fedoramagazine.org/file-better-bugs-coredumpctl/

作者:Paul W. Frields 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

让我们来探讨一下“容器主机”和“容器操作系统”之间的关系,以及它们在 Linux 和 Windows 容器之间的区别。

一些定义

  • 容器主机 Container Host :也称为 主机操作系统 Host OS 。主机操作系统是 Docker 客户端和 Docker 守护程序在其上运行的操作系统。在 Linux 和非 Hyper-V 容器的情况下,主机操作系统与运行中的 Docker 容器共享内核。对于 Hyper-V,每个容器都有自己的 Hyper-V 内核。
  • 容器操作系统 Container OS :也被称为 基础操作系统 Base OS 。基础操作系统是指包含操作系统如 Ubuntu、CentOS 或 windowsservercore 的镜像。通常情况下,你将在基础操作系统镜像之上构建自己的镜像,以便可以利用该操作系统的部分功能。请注意,Windows 容器需要一个基础操作系统,而 Linux 容器不需要。
  • 操作系统内核 Operating System Kernel :内核管理诸如内存、文件系统、网络和进程调度等底层功能。

如下的一些图

Linux Containers

在上面的例子中:

  • 主机操作系统是 Ubuntu。
  • Docker 客户端和 Docker 守护进程(一起被称为 Docker 引擎)正在主机操作系统上运行。
  • 每个容器共享主机操作系统内核。
  • CentOS 和 BusyBox 是 Linux 基础操作系统镜像。
  • “No OS” 容器表明你不需要基础操作系统以在 Linux 中运行一个容器。你可以创建一个含有 scratch 基础镜像的 Docker 文件,然后运行直接使用内核的二进制文件。
  • 查看这篇文章来比较基础 OS 的大小。

Windows Containers - Non Hyper-V

在上面的例子中:

  • 主机操作系统是 Windows 10 或 Windows Server。
  • 每个容器共享主机操作系统内核。
  • 所有 Windows 容器都需要 nanoserverwindowsservercore 的基础操作系统。

Windows Containers - Hyper-V

在上面的例子中:

  • 主机操作系统是 Windows 10 或 Windows Server。
  • 每个容器都托管在自己的轻量级 Hyper-V 虚拟机中。
  • 每个容器使用 Hyper-V 虚拟机内的内核,它在容器之间提供额外的分离层。
  • 所有 Windows 容器都需要 nanoserverwindowsservercore 的基础操作系统。

几个好的链接


via: http://floydhilton.com/docker/2017/03/31/Docker-ContainerHost-vs-ContainerOS-Linux-Windows.html

作者:Floyd Hilton 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出