分类 观点 下的文章

本文由高级咨询师薛亮据自由软件基金会(FSF)的英文原文翻译而成,这篇常见问题解答澄清了在使用 GNU 许可证中遇到许多问题,对于企业和软件开发者在实际应用许可证和解决许可证问题时具有很强的实践指导意义。

  1. 关于 GNU 项目、自由软件基金会(FSF)及其许可证的基本问题
  2. 对于 GNU 许可证的一般了解
  3. 在您的程序中使用 GNU 许可证
  4. 依据 GNU 许可证分发程序
  5. 在编写其他程序时采用依据 GNU 许可证发布的程序
  6. 将作品与依据 GNU 许可证发布的代码相结合
  7. 关于违反 GNU 许可证的问题

2、对于 GNU 许可证的一般了解

2.1 为什么 GPL 允许用户发布其修改版本?

自由软件的一个关键特点是用户可以自由合作。绝对有必要允许希望彼此帮助的用户与其他用户分享他们对错误的修复和改进。

有些人提出了 GPL 的替代方案,需要原作者批准修改版本。只要原作者持续进行维护,这种做法在实践中可能会不错,但是如果作者停止维护(或多或少会)去做别的事情,或并不打算去满足所有用户的需求,这种替代方案就会失败。除了实践上的问题之外,该方案也不允许用户之间互相帮助。

有时候对修改版本的控制,是为了防止用户制作的各种版本之间造成混淆。根据我们的经验,这种混乱不是一个大问题。在 GNU 项目之外出现了许多版本的 Emacs,但用户仍可以将它们区分开。GPL 要求版本创造者将他/她的名字标注其上,以区别于其他版本,并保护其他维护者的声誉。

2.2 GPL 是否要求将修改版本的源代码公开发布?

GPL 不要求您发布修改后的版本或其中的任何一部分。您可以自由地进行修改并私人使用它们,而无需进行发布。这也适用于组织(包括企业);组织可以制作修改版本,在内部使用它,并且绝不将修改版本发布到组织之外。

但是,如果您以某种方式向公众发布修改后的版本,依据 GPL 许可证,GPL 要求您保证程序的用户可以获得修改后源代码。

因此,GPL 给你以某些特定方式发布修改后的程序的授权,而不是以其他方式发布;但是,是否发布修改版本的决定取决于您。

2.3 我可以在同一台电脑上安装一个遵循 GPL 许可证的程序和一个不相关的非自由程序吗?

可以。

2.4 如果我知道某些人有一个遵循 GPL 许可证的程序的副本,我可以要求他们给我一个副本吗?

不可以,GPL 给人们制作和再分发程序副本的授权,倘若有人选择这样做的话。那个人也有权选择不去再分发该程序。

2.5 GPL v2 中的“ 书面文件 written offer 对任何第三方有效”是什么意思? 这是否意味着世界上每个人都可以获得任何遵循 GPL 许可证的程序的源代码?

如果您选择通过书面文件提供源代码,那么任何向您索求源代码的人都有权收到。

如果您对不附带源代码的二进制文件进行商业分发,GPL 要求您必须提供一份书面文件,表明将稍后分发源代码。当用户非商业性地再分发他们从您那里获取的二进制文件时,他们必须传递这份书面文件的副本。这意味着不能直接从您那里获取二进制文件的人,仍然可以收到源代码副本以及该书面文件。

我们要求书面文件对任何第三方有效的原因是,以这种方式间接收到二进制代码的人可以从您那里订购源代码。

2.6 GPL v2 中规定,发布后的修改版本必须“授予…所有第三方许可”。这些第三方是谁?

第 2 节中规定,依据 GPL,您分发的修改版本必须授权给所有第三方。 “所有第三方”当然是指所有人,但这并不要求您为他们任何事情。这仅仅意味着他们依据 GPL 从您那里获得了您的修改版本的许可。

2.7 GPL 允许我出售程序的副本以获利吗?

是的,GPL 允许每个人这样做。销售副本的权利是自由软件定义的一部分。除了一种特殊情况之外,对您可以收取什么样的价格是没有限制的。(这种例外情况是:二进制版本必须附有表明将提供源代码的书面文件。)

2.8 GPL 允许我从我的分发网站收取下载程序的费用吗?

允许。您可以对您分发程序副本收取任何您想收取的费用。如果您通过下载分发二进制文件,则必须提供“等同的访问权限”来让人们下载源代码,因此,下载源代码的费用可能不会超过下载二进制文件的费用。

2.9 GPL 允许我要求任何接收软件的人必须向我支付费用和/或通知我吗?

不允许。实际上,这样的要求会使程序变成非自由软件。如果人们在获得程序副本时必须支付费用,或者他们必须特别通知任何人,那么这个程序就不是自由软件。请参阅自由软件的定义

GPL 是自由软件许可证,因此允许人们使用甚至再分发软件,而不需要向任何人支付费用。

您可以向用户收取费用,以获取您的副本。当他们从别人那里获得副本时,您不能要求人们向您支付费用。

2.10 如果我收费分发遵循 GPL 的软件,我是否还需要向公众免费提供?

不需要。不过,如果有人向您支付费用并获得副本,GPL 给予他们免费或收费向公众发布的自由。例如,有人可以向您支付费用,然后把他的副本放在一个网站上,让公众去获取。

2.11 GPL 允许我根据保密协议分发副本吗?

不允许。GPL 规定,任何从您那里获取副本的人都有权再分发已修改或未修改的副本。您不得在任何更严格的基础上分发作品。

如果有人要求您签署保密协议(NDA),以获取来自 FSF 的遵循 GPL 的软件,请立即通知我们 mailto:[email protected]

如果违规行为涉及其他版权所有者的遵循 GPL 的代码,请通知该版权所有者,就像您对其他任何类型的 GPL 违规行为所做的工作一样。

2.12 GPL 允许我根据保密协议分发程序的修改版或测试版吗?

不可以。GPL 规定,您的修改版本必须具备 GPL 中规定的所有自由。因此,从您那里获取您的版本副本的任何人都有权再分发该版本的副本(已修改或未修改)。您不得在更严格的基础上分发该作品的任何版本。

2.13 GPL 是否允许我根据保密协议开发程序的修改版本?

可以。例如,您可以接受一份合同来开发修改版本,并同意不得发布您的修改版本,直到客户同意才可以发布。这是允许的,因为这种情况下不处于 GPL 协议之下的代码是依据 NDA 分发的。

您还可以依据 GPL 将您的修改版本发布给客户,但须同意不将其发布给其他任何人,除非客户同意。也同样在这种情况下,不处于 GPL 协议之下的代码是以保密协议或任何其他限制条款分发的。

GPL 将给予客户再分发您的版本的权利。在这种情况下,客户可能会选择不行使这项权利,但他确实拥有这项权利。

2.14 为什么 GPL 要求程序的每个副本必须包含 GPL 许可证副本?

作品包含许可证副本至关重要,因此获得程序副本的每个人都可以知道他们的权利是什么。

包括一个指向许可证的 URL,而不是将许可证本身包含在内,这是一种看起来很诱人的做法。但是您不能确定该 URL 在五年或十年后仍然有效。二十年后,我们今天所知道的 URL 们可能已不复存在。

不管网络将发生什么样的变化,确保拥有该程序副本的人员能够继续看到 GPL 许可证的唯一方法是,将许可证的副本包含在该程序中。

2.15 如果作品不是很长,那该怎么办?

如果整个软件包中只有很少的代码——我们使用的基准是不到 300 行,那么您可以使用一个宽松的许可证,而不是像 GNU GPL这样的 Copyleft 许可证(除非代码特别重要)。我们建议这种情况使用 Apache License 2.0

2.16 我是否需要将我对遵循 GPL 的程序所做的修改声明版权?

您不需要对您的修改声明版权。不过,在大多数国家/地区,默认情况下会自动获得版权,因此,如果您不希望修改受到版权限制,您需要将修改明显地放置于公有领域。

无论您是否对您的修改声明版权,依据 GPL,您都必须将修改版本作为整体发布(参见:2.2 GPL 是否要求将修改版本的源代码公开发布?)。

2.17 GPL 对于将某些代码翻译成不同的编程语言是如何规定的?

根据著作权法,翻译工作被认为是一种修改。因此,GPL 对修改版本的规定也适用于翻译版本。

2.18 如果一个程序将公有领域代码与遵循 GPL 的代码相结合,我可以取出公有领域的部分,并作为公有领域代码来使用吗?

您可以这样做,如果您能弄清楚哪个部分是公有领域的部分,并将其与其他部分区分开。如果代码曾经由其开发人员放置在公有领域,那么它就是公有领域代码,无论它现在究竟在哪里。

2.19 我想要因我的作品获得声誉。我想让人们知道我写了什么,如果我使用 GPL,我还能获得声誉吗?

您一定能获得这份作品的声誉。遵循 GPL 发布的程序的一部分是以您自己名义撰写的版权声明(假设您是版权所有者)。GPL 要求所有副本携带恰当的版权声明。

2.20 GPL 允许我添加条款,要求在使用遵循 GPL 的软件或其输出物的研究论文中包含引用或致谢吗?

不可以,根据 GPL 的规定,这是不允许的。虽然我们认识到适当的引用是学术出版物的重要组成部分,但引用不能作为对 GPL 的附加要求。对使用 GPL 软件的研究论文要求包含引用,超出了 GPL v3 第 7(b)条中可接受的附加要求,因此将被视为对 GPL 第 7 节的额外限制。而且版权法也不允许您在软件的输出物中设置这样的要求,无论该软件是依据 GPL 还是其他许可证的条款获得许可。

2.21 为了节省空间,我是否可以省略 GPL 的引言部分,或者省略如何在自己的程序上使用GPL的 指导 instructions 部分吗?

引言和指导是 GNU GPL 的组成部分,不能省略。事实上,GPL 是受版权保护的,其许可证规定只能逐字复制整个 GPL。(您可以使用法律条款制作另一个许可证,但该许可证不再是 GNU GPL。)

引言和指导部分共约 1000 字,不到 GPL 总文字数量的 1/5。除非软件包本身很小,否则引言和指导不会对软件包的大小产生大幅度的改变。在软件包很小的情况下,您可以使用一个简单的 全权 all-permissive 许可证,而不是 GNU GPL。

2.22 两个许可证“兼容”是指什么?

为了将两个程序(或它们的实质部分)组合成一个更大的作品,您需要有以组合方式使用这两个程序的权限。如果两个程序的许可证允许这种使用方式,则它们是兼容的。如果没有办法同时满足这两个许可证,则它们是不兼容的。

对于一些许可证,组合的方式可能会影响它们是否兼容,例如,它们可能允许将两个模块链接在一起,但不允许将其代码合并到一个模块中。

如果您只想在同一个系统中安装两个独立的程序,那么它们的许可证并不是必须兼容的,因为它们没有组合成更大的作品。

2.23 许可证与 GPL 兼容是什么意思?

这意味着其他许可证和 GNU GPL 兼容;在一个更大的程序中,您可以将根据其他许可证发布的代码与根据 GNU GPL 发布的代码进行组合。

所有 GNU GPL 版本都允许进行这种组合;它们还允许分发这些组合,只要该组合在相同的 GNU GPL 版本下发布。其他许可证如果允许这样做,则其与 GPL 兼容。

与 GPL v2 相比,GPL v3 与更多的许可证兼容:它允许您与具有特定类型附加要求(GPL v3 本身不包含)的代码进行组合。GPL v3 第 7 节中有关于此问题的更多信息,包括了允许的附加要求的列表。

2.24 为什么原始的 BSD 许可证与 GPL 不兼容?

因为它规定了 GPL 不包含的具体要求,即对程序广告的要求。GPL v2 第 6 节规定:

您不得对接受者行使本协议授予的权利施加进一步的限制。

GPL v3 在第 10 节中提到类似的内容。广告条款正好提供了这样一个限制,因此与 GPL 不兼容。

修订的 BSD 许可证没有广告条款,从而消除了这个问题。

2.25 “ 聚合 aggregate ”与其他类型的“修改版本”有什么区别?

“聚合”由多个单独的程序组成,分布在同一个 CD-ROM或其他媒介中。GPL 允许您创建和分发聚合,即使其他软件的许可证不是自由许可证或与 GPL 不兼容。唯一的条件是,发布“聚合”所使用的许可证不能禁止用户去行使“聚合”中每个程序对应的许可证所赋予用户的权利。

两个单独的程序还是一个程序有两个部分,区分的界限在哪里?这是一个法律问题,最终由法官决定。我们认为,适当的判断标准取决于通信机制(exec、管道、rpc、共享地址空间内的函数调用等)和通信的语义(哪些信息被互换)。

如果模块们被包含在相同的可执行文件中,则它们肯定是被组合在一个程序中。如果模块们被设计为在共享地址空间中链接在一起运行,那么几乎肯定意味着它们组合成为一个程序。

相比之下,管道、套接字和命令行参数是通常在两个独立程序之间使用的通信机制。所以当它们用于通信时,模块们通常是单独的程序。但是,如果通信的语义足够亲密,交换复杂的内部数据结构,那么也可以视为这两个部分合并成了一个更大的程序。

2.26 为什么 FSF 要求为 FSF拥有版权的程序做出贡献的贡献者将版权 分配 assign 给 FSF?如果我持有 GPL 程序的版权,我也应该这样做吗?如果是,怎么做? (同1.11)

我们的律师告诉我们,为了最大限度地向法院要求违规者强制执行 GPL,我们应该让程序的版权状况尽可能简单。为了做到这一点,我们要求每个贡献者将贡献部分的版权分配给 FSF,或者放弃对贡献部分的版权要求。

我们也要求个人贡献者从雇主那里获得版权放弃声明(如果有的话),以确保雇主不会声称拥有这部分贡献的版权。

当然,如果所有的贡献者把他们的代码放在公共领域,也就没有用之来执行 GPL 许可证的版权了。所以我们鼓励人们为大规模的代码贡献分配版权,只把小规模的修改放在公共领域。

如果您想要在您的程序中执行 GPL,遵循类似的策略可能是一个好主意。如果您需要更多信息,请联系mailto:[email protected]

2.27 如果我使用遵循 GNU GPL 的软件,那么允许我将原始代码修改为新程序,然后在商业上分发和销售新程序吗?

您被允许在商业上出售修改程序的副本,但仅限于在 GNU GPL 的条款之下这么做。因此,例如,您必须依照 GPL 所述,使得程序用户可获取源代码,并且,用户也依照 GPL 所述,被允许再分发和修改程序。

这些要求是将遵循 GPL 的代码包含在您自己的程序中的条件。

2.28 我可以将 GPL 应用于软件以外的其他作品吗? (同1.6)

您可以将 GPL 应用于任何类型的作品,只需明确该作品的“源代码”构成即可。GPL 将“源代码”定义为作品的首选形式,以便在其中进行修改。

不过,对于手册和教科书,或更一般地,任何旨在教授某个主题的作品,我们建议使用 GFDL,而非 GPL。

2.29 我想依据 GPL 授权我的代码,但我也想明确指出,它不能用于军事和/或商业用途。我可以这样做吗?

不可以,因为这两个目标相互矛盾。GNU GPL 被专门设计为防止添加进一步的限制。GPL v3 在第 7 节允许非常有限的一组附加限制,但是用户可以删除任何其他添加的限制。

2.30 我可以依据 GPL 来对硬件进行许可吗?

任何可以受版权保护的 材料 material 都可以依据GPL进行许可。GPL v3 也可以用于受其他类似版权法的法律保护的材料,如半导体掩模。因此,作为一个例子,您可以依据 GPL 发布物理对象的图纸或电路。

在许多情况下,版权不涵盖依照图纸制作的物理硬件。在这种情况下,无论您使用什么许可证,您对图纸的许可都不能对制造或销售物理硬件施加任何控制。当版权不涵盖利用 IC 掩膜等进行硬件制作时,GPL 能以有效的方式处理这种情况。

2.31 将遵循 GPL 的二进制文件 预链接 prelinking 到系统上的各种库,以优化其性能,将被视为修改吗?

不。 预链接 prelinking 是编译过程的一部分;与编译过程所涉及的其他各个方面相比,预链接没有引入更多的许可证要求。如果您被允许将程序链接到各种库,那么也可以预链接到各种库。如果您分发预链接后的目标码,则需要遵循第 6 节的条款。

2.32 LGPL 如何与 Java 配合使用?

详情请参阅这篇文章。LGPL 如同被设计、被预想、被期待的那样去工作。

2.33 为什么你们在 GPL v3 中发明新的术语“ 传播 propagate ”和“ 传递 convey ”?

(译者注:convey 这个词汇在一个 GPL 译本中被翻译为“转发”,此处,我们认为“转发”一词在计算机领域存在一定的歧义,因此,采用“传递”的翻译。)

GPL v2 中使用的“分发”一词来自美国版权法。多年来,我们了解到,一些司法管辖区在自己的版权法中使用了同一个词,但却给出了不同的含义。我们发明了这些新术语,无论在何处对许可证进行解释,都使我们的意图尽可能清楚。这些新术语没有使用在世界上的任何版权法中,我们直接在许可证中提供了它们的定义。

2.34 在GPL v3中的“ 传递 convey ”与GPL v2中的“ 分发 distribute ”意思一样吗?

是的,差不多是一个意思。在执行 GPL v2 的过程中,我们了解到一些司法管辖区在自己的版权法中使用了“分发”这个词,但给出了不同的含义。我们发明了一个新的术语,以使我们的意图清晰,避免这些差异可能引起的任何问题。

2.35 如果我只复制遵循 GPL 的程序并运行它们,而不分发或传递给其他人,许可证对我施加什么要求?

没有要求。GPL 不对此活动附加任何条件。

2.36 GPL v3将“向公众提供”作为 传播 propagate 的一个例子。这是什么意思? 是提供一种可获取的传递形式吗?

“向公众提供”的一个例子是将该软件放在公共网页或FTP服务器上。在您这样做之后,在任何人从您那里真正获取软件之前,可能会需要一段时间,但是由于这种情况可能会立即发生,您也需要能够立即履行 GPL 的义务。因此,我们将“ 传递 convey ”定义为包括这一活动。

2.37 鉴于分发和向公众提供作为传播形式,同样也构成了 GPL v3 中的“ 传递 conveying ”,那么有哪些传播的例子不构成传递吗?

为自己制作软件的副本是不构成“传递”的主要传播形式。您可以依此在多台计算机上安装软件,或进行备份。

2.38 GPL v3 如何让 BitTorrent 分发变得更容易?

因为 GPL v2 是在软件的点对点分发普及之前编写的,所以当您利用这种方式分享代码时,很难满足 GPL v2 的要求。在 BitTorrent 上分发 GPL v2 目标代码时,确保您合规的最佳方法是将所有相应的源代码包含在相同的 种子文件 Torrent 中,但这种方式代价高昂。

GPL v3 以两种方式解决了这个问题。首先,作为该过程的一部分,下载此种子文件并将数据发送给其他人的人不需要做任何事情。因为第 9 节规定:“受保护作品的辅助传播如果仅仅是使用点对点传输来接收副本,不需要接受[本许可证]。”

第二,通过告知接收人在公共网络服务器上哪里可获取,GPL v3 的第 6(e)节旨在给予分发者(最初制作种子文件的人)一种清晰、直观的方式来提供源代码。这样可以确保每个想要获取源代码的人都可以如此获取,而且分发者几乎不用担心。

2.39 什么是 TiVo化 tivoization ? GPL v3 对此如何防止?

一些设备使用可升级的自由软件,但被设计为用户不能修改该软件。有很多不同的方式可以做到这一点;例如,有时硬件校验所安装的软件,如果与预期签名不匹配,则关闭软件。制造商通过提供源代码来遵循GPL v2,但是您仍然无法自由修改您使用的软件。我们称这种做法为 TiVo 化 tivoization

当人们分发包含遵循 GPL v3 软件的“ 用户产品 User Products ”时,第 6 节要求他们为您提供修改该软件所需的信息。“用户产品”是该许可证特别定义的术语;“用户产品”的示例包括便携式音乐播放器、数字录像机和家庭安全系统。

2.40 GPL v3 是否禁止 DRM?

不禁止,您可以使用遵循 GPL v3 发布的代码来开发您喜欢的任何类型的 DRM 技术。不过,如果您这样做,第 3 节规定,系统不会被视为一种有效的技术“保护”措施,这意味着如果有人破坏了 DRM,他也可以自由分发他的软件,不受《美国数字千禧版权法》(DMCA)和类似法律的限制。

像往常一样,GNU GPL 并不限制人们在软件中怎么做,只是阻止他们限制他人。

2.41 GPL v3 是否要求投票人能够修改在投票机中运行的软件?

不要求。企业分发包含遵循 GPL v3 软件的设备,最多只需要为拥有目标代码副本的人提供软件的源代码和安装信息。使用投票机(如同任何其他信息亭一样)的选民不能拥有它,甚至不能暂时拥有,所以选民也不能拥有二进制软件。

不过,请注意,投票是一个非常特殊的情况。仅仅因为计算机中的软件是自由软件,并不意味着您可以信任计算机,并进行投票。我们认为电脑不值得信任,不能被用作投票。投票应在纸上进行。

2.42 GPL v3 是否包含“专利报复条款”?

实际上,是的。第 10 节禁止传递该软件的人向其他被许可人发起专利诉讼。如果有人这样做,第 8 节解释他们将如何丧失许可证权益以及与之伴随的所有专利许可。

2.43 在 GPL v3 和 AGPL v3中,当说到“尽管有本许可证的其他规定”时,是什么意思?

这仅仅意味着以下条款胜过许可证中可能与之冲突的其他任何内容。例如,如果没有该文本,有些人可能声称,您不能将遵循 GPL v3 的代码与遵循 AGPL v3 的代码结合在一起,因为 AGPL 的附加要求将被归类为 GPL v3 第 7 节下的“进一步限制”。该文本明确表示我们的预期解释是正确的,您可以进行组合。

该文本仅解决许可证不同条款之间的冲突。当两个条件之间没有冲突的时候,您必须同时满足它们。这些段落不允许您轻率地忽略许可证的其余部分,它们只是强调了一些非常有限的例外。

2.44 在 AGPL v3 中,怎么才算是“通过计算机网络远程与[软件]进行交互”?

如果程序被明确设计为接受用户请求并通过网络发送响应,则它符合这些标准。属于此类程序的常见示例包括网络和邮件服务器、交互式网络应用程序和在线游戏的服务器。

如果程序没有被明确设计为通过网络与用户进行交互,而是恰好在这样做的环境中运行,那么它不属于此类。例如,仅仅因为用户通过 SSH 或远程 X 会话来运行的应用程序不需要提供源代码。

2.45 GPL v3 中“ you ”的概念如何与 Apache License 2.0 中“ 法律实体 Legal Entity ”的定义相比较?

它们是完全相同的。Apache License 2.0 中“法律实体”的定义在各种法律协议中是非常标准的,因此,如果法院在缺乏明确定义的情况下没有以同样的方式解释该术语,将会令人非常惊讶。我们完全期待他们在看 GPL v3 时也会如此,并考虑到谁有资格作为被许可人。

2.46 在 GPL v3 中,“ 该程序 the Program ”是指什么? 是每个依据 GPL v3 发布的程序?

术语“该程序”是指依据 GPL v3 进行许可的特定作品,由特定被许可人从上游许可人或分发者那里接收。“该程序”是您在 GPL v3 许可的指定情境下接受到的特定软件作品。

“该程序”并不意味着“依据 GPL v3 进行许可的所有作品”;由于一些原因,这种解释没有任何意义。针对那些想要了解更多的人,我们已经发表了对“该程序”一词的分析

2.47 如果某些网络客户端软件依据 AGPL v3 发布,是否必须能够向与之交互的服务器提供源代码?

AGPL v3 需要该程序向“所有通过计算机网络进行远程交互的用户”提供源代码。至于您将程序称为“客户端”还是“服务器”,那无关紧要。您需要询问的问题是,是否存在合理的期望让一个人通过网络远程与该程序交互。

2.48 对于一个运行在代理服务器上的依据 AGPL 进行许可的软件来说,如何向与该软件交互的用户提供源代码书面文件?

对于代理服务器上的软件,您可以通过向此类代理的用户传递消息的常规方法来提供源代码书面文件。例如,Web 代理可以使用登录页。当用户最初开始使用代理时,您可以将他们引导到包含源代码书面文件以及您选择提供的任何其他信息的页面。

AGPL 规定,您必须向“所有用户”提供书面文件。如果您知道某个用户已经被展示过书面文件,对于当前版本的软件,您不必再重复向该用户提供。

通过安装 SLS 1.05 展示了 Linux 内核在这 26 年间走过了多远。

 title=

我第一次安装 Linux 是在 1993 年。那时我跑的是 MS-DOS,但我真的很喜欢学校机房电脑的 Unix 系统,就在那里度过了我大学本科时光。 当我听说了 Linux,一个 Unix 的免费版本,可以在我家的 386 电脑上运行的时候,我立刻就想要试试。我的第一个 Linux 发行版是 Softlanding Linux System (SLS) 1.03,带有 11 级补丁的 0.99 alpha 版本的 Linux 内核。它要求高达 2 MB 的内存,如果你想要编译项目需要 4 MB,运行 X windows 则需要 8 MB。

我认为 Linux 相较于 MS-DOS 世界是一个巨大的进步。 尽管 Linux 缺乏运行在 MS-DOS 上的广泛的应用及游戏,但我发现 Linux 带给我的是巨大的灵活性。不像 MS-DOS ,现在我可以进行真正的多任务,同时运行不止一个程序。并且 Linux 提供了丰富的工具,包括一个 C 语言编译器,让我可以构建自己的项目。

一年后,我升级到了 SLS 1.05,它支持全新的 Linux 内核 1.0。 更重要的,Linux 引入了内核模块。通过内核模块,你不再需要为支持新硬件而编译整个内核;取而代之,只需要从包含 Linux 内核之内的 63 个模块里加载一个就行。在 SLS 1.05 的发行自述文件中包含这些关于模块的注释:

内核的模块化旨在正视减少并最终消除重新编译内核的要求,无论是变更、修改设备驱动或者为了动态访问不常用的驱动。也许更为重要的是,个别工作小组的工作不再影响到内核的正确开发。事实上,这让以二进制发布官方内核现在成为了可能。

在 8 月 25 日,Linux 内核将迎来它的第 26 周年(LCTT 译注:已经过去了 =.= )。为了庆祝,我重新安装了 SLS 1.05 来提醒自己 Linux 1.0 内核是什么样子,去认识 Linux 自二十世纪 90 年代以来走了多远。和我一起踏上 Linux 的怀旧之旅吧!

安装

SLS 是第一个真正的 “发行版”,因为它包含一个安装程序。 尽管安装过程并不像现代发行版一样顺畅。 不能从 CD-ROM 启动安装,我需要从安装软盘启动我的系统,然后从 login 提示中运行安装程序。

 title=

在 SLS 1.05 中引入的一个漂亮的功能是支持彩色的文本模式安装器。当我选择彩色模式时,安装器切换到一个带有黑色文字的亮蓝色背景,不再是我们祖祖辈辈们使用的原始的普通黑白文本。

 title=

SLS 安装器是个简单的东西,文本从屏幕底部滚动而上,显示其做的工作。通过对一些简单的提示的响应,我能够创建一个 Linux 分区,挂载上 ext2 文件系统,并安装 Linux 。 安装包含了 X windows 和开发工具的 SLS 1.05,需要大约 85 MB 的磁盘空间。依照今天的标准这听起来可能不是很多,但在 Linux 1.0 出来的时候,120 MB 的硬件设备才是主流设备。

 title=

 title=

系统级别

当我第一次启动到 Linux 时,让我想起来了一些关于这个早期版本 Linux 系统的事情。首先,Linux 没有占据很多的空间。在启动系统之后运行一些程序来检查的时候,Linux 占用了不到 4 MB 的内存。在一个拥有 16MB 内存的系统中,这就意味着节省了很多内存用来运行程序。

 title=

熟悉的 /proc 元文件系统在 Linux 1.0 就存在了,尽管对比我们今天在现代系统上看到的,它并不能提供许多信息。在 Linux 1.0, /proc 包含一些接口来探测类似 meminfostat 之类的基本系统状态。

 title=

在这个系统上的 /etc 文件目录非常简单。值得一提的是,SLS 1.05 借用了来自 BSD Unixrc 脚本来控制系统启动。 初始化是通过 rc 脚本进行的,由 rc.local 文件来定义本地系统的调整。后来,许多 Linux 发行版采用了来自 Unix System V 的很相似的 init 脚本,后来又是 systemd 初始化系统。

 title=

你能做些什么

随着我的系统的启动运行,接下来就可以使用了了。那么,在这样的早期 Linux 系统上你能做些什么?

让我们从基本的文件管理开始。 每次在你登录的时候,SLS 会让你使用 Softlanding 菜单界面(MESH),这是一个文件管理程序,现代的用户们可能觉得它和 Midnight Commander 很相似。 而二十世纪 90 年代的用户们可能会拿 MESH 与更为接近的 Norton Commander 相比,这个可以说是在 MS-DOS 上最流行的第三方文件管理程序。

 title=")

除了 MESH 之外,在 SLS 1.05 中还少量包含了一些全屏应用程序。你可以找到熟悉的用户工具,包括 Elm 邮件阅读器、GNU Emacs 可编程编辑器,以及古老的 Vim 编辑器。

 title=

 title=

SLS 1.05 甚至包含了一个可以让你在终端玩的俄罗斯方块版本。

 title=

在二十世纪 90 年代,多数住宅的网络接入是通过拨号连接的,所以 SLS 1.05 包含了 Minicom 调制解调器拨号程序。Minicom 提供一个与调制解调器的直接连接,并需要用户通过贺氏调制解调器的 AT 命令来完成一些像是拨号或挂电话这样的基础功能。Minicom 同样支持宏和其他简单功能来使连接你的本地调制解调器池更容易。

 title=

但如果你想要写一篇文档时怎么办? SLS 1.05 的存在要比 LibreOffice 或者 OpenOffice 早很长时间。在二十世纪 90 年代,Linux 还没有这些应用。相反,如果你想要使用一个文字处理器,可能需要引导你的系统进入 MS-DOS,然后运行你喜欢的文字处理器程序,如 WordPerfect 或者共享软件 GalaxyWrite。

但是所有的 Unix 系统都包含一套简单的文本格式化程序,叫做 nroff 和 troff。在 Linux 系统中,他们被合并成 GNU groff 包,而 SLS 1.05 包含了 groff 的一个版本。我在 SLS 1.05 上的一项测试就是用 nroff 生成一个简单的文本文档。

 title=

 title=

运行 X windows

获取安装 X windows 并不特别容易,如 SLS 安装文件承诺的那样:

在你的 PC 上获取安装 X windows 可能会有一些发人深省的体验,主要是因为 PC 的显示卡类型太多。Linux X11 仅支持 VGA 类型的显示卡,但在许多类型的 VGA 中仅有个别的某些类型是完全支持的。SLS 存在两种 X windows 服务器。全彩的 XFree86,支持一些或所有 ET3000、ET400、PVGA1、GVGA、Trident、S3、8514、Accelerated cards、ATI plus 等。

另一个服务器 XF86\_Mono,能够工作在几乎所有的 VGA 卡上,但只提供单色模式。因此,相比于彩色服务器,它会占用更少的内存并拥有更快的速度。当然就是看起来不怎么漂亮。

X windows 的配置信息都堆放在目录 “/usr/X386/lib/X11/”。需要注意的是,“Xconfig” 文件为监视器和显示卡定义了时序。默认情况下,X windows 设置使用彩色服务器,如果彩色服务器出现问题,你可以切换到单色服务器 x386mono,因为它已经支持各种标准的 VGA。本质上,这只是将 /usr/X386/bin/X 链接到它。

只需要编辑 Xconfig 来设置鼠标驱动类型和时序,然后键入 “startx” 即可。

这些听起来令人困惑,但它就是这样。手工配置 X windows 真的可以是一个发人深省的体验。幸好,SLS 1.05 包含了 syssetup 程序来帮你确定系统组件的种类,包括了 X windows 的显示设置。在一些提示过后,经过一些实验和调整,最终我成功启动了 X windows!

 title=

但这是来自于 1994 年的 X windows,它仍然并没有桌面的概念。我可以从 FVWM (一个虚拟窗口管理器)或 TWM (选项卡式的窗口管理器)中选择。TWM 直观地设置提供一个功能简单的图形环境。

 title=

关机

我已经在我的 Linux 寻根之旅沉浸许久,是时候最终回到我的现代桌面上了。最初我跑 Linux 的是一台仅有 8MB 内存和 一个 120MB 硬盘驱动器的 32 位 386 电脑,而我现在的系统已经足够强大了。拥有双核 64 位 Intel Core i5 处理器,4 GB 内存和一个 128 GB 的固态硬盘,我可以在我的运行着 Linux 内核 4.11.11 的系统上做更多事情。那么,在我的 SLS 1.05 的实验结束之后,是时候离开了。

 title=

再见,Linux 1.0。很高兴看到你的茁壮成长。

(题图:图片来源:litlnemo。由 Opnesource.com 修改。CC BY-SA 2.0.


via: https://opensource.com/article/17/8/linux-anniversary

作者:Jim Hall 译者:softpaopao 校对:wxy

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

基于 Linux 击败了专有软件一样的原因,开源应该成为云原生环境的首选。

 title=

让我们回溯到上世纪 90 年代,当时专有软件大行其道,而开源才刚开始进入它自己的时代。是什么导致了这种转变?更重要的是,而今天我们转到云原生环境时,我们能从中学到什么?

基础设施的历史经验

我将以一个高度武断的、开源的视角开始,来看看基础设施过去 30 年的历史。在上世纪 90 年代,Linux 只是大多数组织视野中一个微不足道的小光点而已——如果他们听说过它的话。你早早购入股票的那些公司们很快就发现了 Linux 的好处,它主要是作为专有的 Unix 的廉价替代品,而部署服务器的标准方式是使用专有的 Unix,或者日渐增多的使用 Microsoft Windows NT。

这种模式的专有本性为更专有的软件提供了一个肥沃的生态系统。软件被装在盒子里面放在商店出售。甚至开源软件也参与了这种装盒游戏;你可以在货架上买到 Linux,而不是用你的互联网连接免费下载。去商店和从你的软件供应商那里只是你得到软件的不同方式而已。

 title=

Ubuntu 包装盒出现在百思买的货架上

我认为,随着 LAMP 系列(Linux、Apache、MySQL 和 PHP / Perl / Python)的崛起,情况发生了变化。LAMP 系列非常成功。它是稳定的、可伸缩的和相对用户友好的。与此同时,我开始看到对专有解决方案的不满。一旦客户在 LAMP 系列中尝过了开源的甜头,他们就会改变他们对软件的期望,包括:

  • 不愿被供应商绑架,
  • 关注安全,
  • 希望自己来修复 bug ,以及
  • 孤立开发的软件意味着创新被扼杀。

在技术方面,我们也看到了各种组织在如何使用软件上的巨大变化。忽然有一天,网站的宕机变成不可接受的了。这就对扩展性和自动化有了更多的依赖。特别是在过去的十年里,我们看到了基础设施从传统的“宠物”模式到“群牛”模式的转变,在这种模式中,服务器可以被换下和替换,而不是一直运行和被指定。公司使用大量的数据,更注重数据留存和数据到用户的处理和返回速度。

开源和开源社区,以及来自大公司的日益增多的投入,为我们改变如何使用软件提供了基础。系统管理员的岗位要求开始 要求 Linux 技能和对开源技术和理念的熟悉。通过开源类似 Chef cookbooks 和 Puppet 模块这样东西,管理员可以分享他们的模式配置。我们不再单独配置和调优 MySQL;我们创建了一个掌控基础部分的系统,我们现在可以专注于更有趣的、可以给我们雇主带来更高价值的工程作业。

开源现在无处不在,围绕它的模式也无处不在。曾经仇视这个想法的公司不仅通过协同项目与外界拥抱开源,而且进一步地,还发布了他们自己的开源软件项目并且围绕它们构建了社区。

 title=

转向云端

今天,我们生活在一个 DevOps 和云端的世界里。我们收获了开源运动带来的创新成果。在公司内部采用开源软件开发实践的情况下, Tim O'reilly 所称的 “内部开源” 有了明显增长。我们为云平台共享部署配置。像 Terraform 这样的工具甚至允许我们编写和分享我们如何部署特定的平台。

但这些平台本身呢?

“大多数人想都不想就使用了云……许多用户将钱投入到根本不属于他们的基础设施中,而对放弃他们的数据和信息毫无顾虑。" —Edward Snowden, OpenStack Summit, May 9, 2017

现在是时候要更多地想想本能地转移或扩展到云上的事情了。

就像 Snowden 强调的那样,现在我们正面临着对我们的用户和客户的数据的失控风险。抛开安全不谈,如果我们回顾一下我们转向开源的原因,个中原因还包括被厂商绑架的担忧、创新难以推动、甚至修复 bug 的考虑。

在把你自己和/或你的公司锁定在一个专有平台之前,考虑以下问题:

  • 我使用的服务是遵循开放标准,还是被厂商绑架的?
  • 如果服务供应商破产或被竞争对手收购,什么是我可以依赖的?
  • 关于停机、安全等问题,供应商与其客户沟通中是否有一个明确而真诚的历史过往?
  • 供应商是否响应 bug 和特性请求,即使那是来自小客户?
  • 供应商是否会在我不知情的情况下使用我们的数据(或者更糟,即便我们的客户协议所不同意)?
  • 供应商是否有一个计划来处理长期的,不断上升的增长成本,特别是如果最初的成本很低呢?

您可以通过这个问卷,讨论每个要点,而仍然决定使用专有的解决方案。这很好,很多公司一直都在这么做。然而,如果你像我一样,宁愿找到一个更开放的解决方案而仍然受益于云,你确实有的选择。

基于私有云

当您寻找私有云解决方案时,您的首选是开源,投资一个云提供商,其核心运行在开源软件上。 OpenStack 是行业领袖,在其 7 年的历史中,有 100 多个参与组织和成千上万的贡献者(包括我)。 OpenStack 项目已经证明,结合多个基于 OpenStack 云不仅是可行的,而且相对简单。云公司之间的 API 是相似的,所以您不必局限于特定的 OpenStack 供应商。作为一个开放源码项目,您仍然可以影响该基础设施的特性、bug 请求和发展方向。

第二种选择是继续在基础层面上使用私有云,但在一个开源容器编排系统中。无论您选择 DC/OS(基于Apache Mesos) 、KubernetesDocker Swarm 模式 ,这些平台都允许您将私有云系统提供的虚拟机作为独立的 Linux 机器,并在此之上安装您的平台。您所需要的只是 Linux 而已,不会立即被锁定在特定云的工具或平台上。可以根据具体情况来决定是否使用特定的专属后端,但如果你这样做,就应该着眼于未来。

有了这两种选择,你也可以选择完全离开云服务商。您可以部署自己的 OpenStack 云,或者将容器平台内部架构移动到您自己的数据中心。

做一个登月计划

最后,我想谈一谈开源项目基础设施。今年 3 月,在召开的 南加州 Linux 展会 上,多个开放源码项目的参与者讨论了为他们的项目运行开源基础设施。(更多的,请阅读我的 关于该会议的总结)我认为这些项目正在做的这个工作是基础设施开源的最后一步。除了我们现在正在做的基本分享之外,我相信公司和组织们可以在不放弃与竞争对手相区分的“独门秘方”的情况下,进一步充分利用他们的基础设施开源。

开源了他们的基础设施的开源项目,已经证明了允许多个公司和组织向他们的基础设施提交训练有素的 bug 报告,甚至是补丁和特定论文的价值。突然之间,你可以邀请兼职的贡献者。你的客户可以通过了解你的基础设施,“深入引擎盖子之下”,从而获得信心。

想要更多的证据吗?访问 开源基础设施 的网站了解开源基础设施的项目(以及他们已经发布的大量基础设施)。

可以在 8 月 26 日在费城举办的 FOSSCON 大会上 Elizabeth K. Joseph 的演讲“基础架构开源”上了解更多。

(题图:Jason Baker. CC BY-SA 4.0. Source: Cloud, Globe. Both CC0.)


via: https://opensource.com/article/17/8/open-sourcing-infrastructure

作者:Elizabeth K. Joseph 译者:wenzhiyi 校对:wxy

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

 title=

在 ELC + OpenIoT 峰会上,英特尔安全架构师 Ryan Ware 将会解释如何应对漏洞洪流,并管理你产品的安全性。

在开发开源软件时, 你需要考虑的安全漏洞也许会将你吞没。 常见漏洞及曝光 Common Vulnerabilities and Exposures (CVE)ID、零日漏洞和其他漏洞似乎每天都在公布。随着这些信息洪流,你怎么能保持不掉队?

英特尔安全架构师 Ryan Ware 表示:“如果你发布了基于 Linux 内核 4.4.1 的产品,该内核截止今日已经有 9 个针对该内核的 CVE。这些都会影响你的产品,尽管事实上当你配载它们时还不知道。”

ELC + OpenIoT 峰会上,英特尔安全架构师 Ryan Ware 的演讲将介绍如何实施并成功管理产品的安全性的策略。在他的演讲中,Ware 讨论了最常见的开发者错误,跟上最新的漏洞的策略等等。

Linux.com:让我们从头开始。你能否简要介绍一下常见漏洞和曝光(CVE),零日以及其他漏洞么?它们是什么,为什么重要?

Ryan Ware:好问题。 常见漏洞及曝光 Common Vulnerabilities and Exposures (CVE)是按美国政府的要求由 MITR Corporation(一个非营利组织)维护的数据库。其目前由美国国土安全部资助。它是在 1999 年创建的,以包含有关所有公布的安全漏洞的信息。这些漏洞中的每一个都有自己的标识符(CVE-ID),并且可以被引用。 CVE 这个术语,已经从指整个数据库逐渐演变成代表一个单独的安全漏洞: 一个 CVE 漏洞。

出现于 CVE 数据库中的许多漏洞最初是零日漏洞。这些漏洞出于不管什么原因没有遵循更有序的如“ 责任揭秘 Responsible Disclosure ”这样的披露过程。关键在于,如果没有软件供应商能够通过某种类型的修复(通常是软件补丁)来进行响应,那么它们就成为了公开和可利用的。这些和其他未打补丁的软件漏洞至关重要,因为在修补软件之前,漏洞是可以利用的。在许多方面,发布 CVE 或者零日就像是开枪。在你比赛结束之前,你的客户很容易受到伤害。

Linux.com:有多少漏洞?你如何确定那些与你的产品相关?

Ryan:在探讨有多少之前,以任何形式发布软件的任何人都应该记住。即使你采取一切努力确保你发布的软件没有已知的漏洞,你的软件也会存在漏洞。它们只是不知道而已。例如,如果你发布了一个基于 Linux 内核 4.4.1 的产品,那么截止今日,已经有了 9 个CVE。这些都会影响你的产品,尽管事实上在你使用它们时不知道。

此时,CVE 数据库包含 80,957 个条目(截止至 2017 年 1 月 30 日),包括最早可追溯到 1999 年的所有记录,当时有 894 个已记录问题。迄今为止,一年中出现最大的数字的是 2014 年,当时记录了 7,946 个问题。也就是说,我认为过去两年该数字减少并不是因为安全漏洞的减少。这是我将在我的谈话中说到的东西。

Linux.com:开发人员可以使用哪些策略来跟上这些信息?

Ryan:开发人员可以通过各种方式跟上这些如洪水般涌来的漏洞信息。我最喜欢的工具之一是 CVE Details。它以一种非常容易理解的方式展示了来自 MITRE 的信息。它最好的功能是创建自定义 RSS 源的能力,以便你可以跟踪你关心的组件的漏洞。那些具有更复杂的追踪需求的人可以从下载 MITR CVE 数据库(免费提供)开始,并定期更新。其他优秀工具,如 cvechecker,可以让你检查软件中已知的漏洞。

对于软件栈中的关键部分,我还推荐一个非常有用的工具:参与到上游社区中。这些是最理解你所使用的软件的人。世界上没有比他们更好的专家。与他们一起合作。

Linux.com:你怎么知道你的产品是否解决了所有漏洞?有推荐的工具吗?

Ryan:不幸的是,正如我上面所说,你永远无法从你的产品中移除所有的漏洞。上面提到的一些工具是关键。但是,我还没有提到一个对你发布的任何产品来说都是至关重要的部分:软件更新机制。如果你无法在当场更新产品软件,则当客户受到影响时,你无法解决安全问题。你的软件必须能够更新,更新过程越容易,你的客户将受到更好的保护。

Linux.com:开发人员还需要知道什么才能成功管理安全漏洞?

Ryan:有一个我反复看到的错误。开发人员总是需要牢记将攻击面最小化的想法。这是什么意思?在实践中,这意味着只包括你的产品实际需要的东西!这不仅包括确保你不将无关的软件包加入到你的产品中,而且还可以关闭不需要的功能的配置来编译项目。

这有什么帮助?想象这是 2014 年。你刚刚上班就看到 Heartbleed 的技术新闻。你知道你在产品中包含 OpenSSL,因为你需要执行一些基本的加密功能,但不使用 TLS 心跳,该问题与该漏洞相关。你愿意:

a. 花费时间与客户和合作伙伴合作,通过关键的软件更新来修复这个高度安全问题?

b. 只需要告诉你的客户和合作伙伴,你使用 “-DOPENSSLNOHEARTBEATS” 标志编译 OpenSSL 产品,他们不会受到损害,你就可以专注于新功能和其他生产活动。

最简单解决漏洞的方法是你不包含这个漏洞。

(题图:Creative Commons Zero Pixabay)


via: https://www.linux.com/news/event/elcna/2017/2/how-manage-security-vulnerabilities-your-open-source-product

作者:AMBER ANKERHOLZ 译者:geekpi 校对:wxy

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

开源项目需要认真对待交付成果中所包含的标准

 title=

无论以何种标准来衡量,开源软件作为传统的专有软件的替代品而崛起,取得了不错的效果。 如今,仅 Github 中就有着数以千万计的代码仓库,其中重要项目的数量也在快速增长。在本文撰写的时候,Apache 软件基金会 开展了超过 300 个项目Linux 基金会 支持的项目也超过了 60 个。与此同时,OpenStack 基金会 在 180 多个国家拥有超过 60,000 名成员。

这样说来,这种情景下有什么问题么?

开源软件在面对用户的众多需求时,由于缺少足够的意识,而无法独自去解决全部需求。 更糟糕的是,许多开源软件社区的成员(业务主管以及开发者)对利用最合适的工具解决这一问题并不感兴趣。

让我们开始找出那些有待解决的问题,看看这些问题在过去是如何被处理的。

问题存在于:通常许多项目都在试图解决一个大问题当中重复的一小部分,而客户希望能够在竞争产品之间做出选择,不满意的话还能够轻松选择其他产品。但是现在看来都是不可能的,在这个问题被解决之前它将会阻碍开源软件的使用。

这已经不是一个新的问题或者没有传统解决方案的问题了。在一个半世纪以来,用户期望有更多的选择和自由来变换厂商,而这一直是通过标准的制定来实现的。在现实当中,你可以对螺丝钉、灯泡、轮胎、延长线的厂商做出无数多的选择,甚至于对独特形状的红酒杯也可以专注选择。因为标准为这里的每一件物品都提供了物理规格。而在健康和安全领域,我们的幸福也依赖于成千上万的标准,这些标准是由私营行业制定的,以确保在最大化的竞争中能够有完美的结果。

随着信息与通信技术(ICT)的发展,以同样类似的方式形成了一些重要的组织机构,例如:国际电信联盟(ITU)、国际电工委员会(IEC),以及电气与电子工程师学会标准协会(IEEE-SA)。近千家财团遵循 ICT 标准来进行开发、推广以及测试。

虽然并非是所有的 ICT 标准都形成了无缝对接,但如今在我们生活的科技世界里,成千上万的基本标准履行着这一承诺,这些标准包含了计算机、移动设备、Wi-Fi 路由器以及其他一切依赖电力来运行的东西。

关键的一点,在很长的一段时间里,由于客户对拥有种类丰富的产品、避免受制于供应商,并且享受全球范围内的服务的渴望,逐渐演变出了这一体系。

现在让我们来看看开源软件是如何演进的。

好消息是伟大的软件已经被创造出来了。坏消息是对于像云计算和虚拟化网络这样的关键领域,没有任何单独的基金会在开发整个堆栈。取而代之的是,单个项目开发单独的一层或者多层,依靠需要时才建立的善意的合作,这些项目最终堆叠成栈。当这一过程运行良好时,结果是好的,但也有可能形成与传统的专有产品同样的锁定。相反,当这一过程运行不良时,坏的结果就是它会浪费开发商、社区成员的时间和努力,同时也会辜负客户的期望。

最明确的解决方法的创建标准,允许客户避免被锁定,鼓励多个解决方案通过对附加服务和功能进行有益的竞争。当然也存在着例外,但这不是开源世界正在发生的情况。

这背后的主要原因在于,开源社区的主流观点是:标准意味着限制、落后和多余。对于一个完整的堆栈中的单独一层来说,可能就是这样。但客户想要选择的自由、激烈的竞争,这就导致回到了之前的坏结果上,尽管多个厂商提供相似的集成堆栈,但却被锁定在一个技术上。

在 Yaron Haviv 于 2017 年 6 月 14 日所写的 “除非我们协作,否则我们将被困在专有云上” 一文中,就有对这一问题有着很好的描述。

在今天的开源生态系统当中存在一个问题,跨项目整合并不普遍。开源项目能够进行大型合作,构建出分层的模块化的架构,比如说 Linux — 已经一次又一次的证明了它的成功。但是与 Linux 的意识形成鲜明对比的就是如今许多开源社区的日常状态。

举个例子:大数据生态系统,就是依赖众多共享组件或通用 API 和层的堆叠来实现的。这一过程同样缺少标准的线路协议,同时,每个处理框架(看看 Spark、Presto 和 Flink)都拥有独立的数据源 API。

这种合作的缺乏正在造成担忧。缺少了合作,项目就会变得不通用,结果对客户产生了负面影响。因为每个人都不得不从头开始,重新开发,这基本上就锁定了客户,减缓了项目的发展。

Haviv 提出了两种解决方法:

  • 项目之间更紧密的合作,联合多个项目消除重叠的部分,使堆栈内的整合更加密切;
  • 开发 API ,使切换更加容易。

这两种方法都能达到目的。但除非事情能有所改变,我们将只会看到第一种方法,这就是前边展望中发现的技术锁定。结果会发现工业界,无论是过去 WinTel 的世界,或者纵观苹果的历史,相互竞争的产品都是以牺牲选择来换取紧密整合的。

同样的事情似乎很有可能发生在新的开源界,如果开源项目继续忽视对标准的需求,那么竞争会存在于层内,甚至是堆栈间。如果现在能够做到的话,这样的问题可能就不会发生了。

因为如果口惠无实开发软件优先、标准在后的话,对于标准的制定就没有真正的兴趣。主要原因是,大多数的商人和开发者对标准知之甚少。不幸的是,我们能够理解这些使事情变得糟糕的原因。这些原因有几个:

  • 大学几乎很少对标准进行培训;
  • 过去拥有专业的标准人员的公司遣散了这些部门,现在的部署工程师接受标准组织的培训又远远不够;
  • 在建立雇主标准工作方面的专业知识方面几乎没有职业价值;
  • 参与标准活动的工程师可能需要以他们认为是最佳技术解决方案为代价来延长雇主的战略利益;
  • 在许多公司内部,专业的标准人员与开源开发者之间鲜有交流;
  • 许多软件工程师将标准视为与 FOSS 定义的“四大自由”有着直接冲突。

现在,让我们来看看在开源界正在发生什么:

  • 今天大多数的软件工程师鲜有不知道开源的;
  • 工程师们每天都在享受着开源工具所带来的便利;
  • 许多令人激动的最前沿的工作正是在开源项目中完成的;
  • 在热门的开源领域,有经验的开发者广受欢迎,并获得了大量实质性的奖励;
  • 在备受好评的项目中,开发者在软件开发过程中享受到了空前的自主权;
  • 事实上,几乎所有的大型 ICT 公司都参与了多个开源项目,最高级别的成员当中,通常每个公司每年的合并成本(会费加上投入的雇员)都超过了一百万美元。

如果脱离实际的话,这个比喻似乎暗示着标准是走向 ICT 历史的灰烬。但现实却有很大差别。一个被忽视的事实是,开源开发是比常人所认为的更为娇嫩的花朵。这样比喻的原因是:

  • 项目的主要支持者们可以撤回(已经做过的事情),这将导致一个项目的失败;
  • 社区内的个性和文化冲突会导致社区的瓦解;
  • 重要项目更加紧密的整合能力有待观察;
  • 有时专有权在博弈中被削弱,高资助的开源项目在某些情况下会导致失败。
  • 随着时间的推移,可能个别公司认为其开源策略没能给他们带来预期的回报;
  • 对关键开源项目的失败引起过多关注,会导致厂商放弃一些投资中的新项目,并说服客户谨慎选择开源方案。

奇怪的是,最积极解决这些问题的协作单位是标准组织,部分原因是,他们已经感受到了开源合作的崛起所带来的威胁。他们的回应包括更新知识产权策略以允许在此基础上各种类型的合作,开发开源工具,包含开源代码的标准,以及在其他类型的工作项目中开发开源手册。

结果就是,这些标准组织调整自己成为一个近乎中立的角色,为完整方案的开发提供平台。这些方案能够包含市场上需要的各种类型的合作产品,以及混合工作产品。随着此过程的继续,很有可能使厂商们乐意推行一些包含了标准组织在内的举措,否则他们可能会走向开源基金。

重要的是,由于这些原因,开源项目开始认真对待项目交付所包含的标准,或者与标准开发商合作,共同为完整的方案做准备。这不仅会有更多的产品选择,对客户更少的限制,而且也给客户在开源方案上更大的信心,同时也对开源产品和服务有更多的需求。

倘若这一切不发生的话,将会是一个很大的遗憾,因为这是开源所导致的巨大损失。而这取决于如今的项目所做的决定,是供给市场所需,还是甘心于未来日趋下降的影响力,而不是持续的成功。

本文源自 ConsortiumInfo.org的 Standards Blog,并已获得出版许可

(题图:opensource.com)


作者简介:

Andy Updegrove - Andy helps 的 CEO,管理团队,由他们的投资者建立的成功的组织。他曾作为一名先驱,自1979年起,就为高科技公司提供商业头脑的法律顾问和策略建议。在全球舞台上,他经常作为代表,帮助推动超过 135 部全球标准的制定,宣传开源,主张联盟,其中包括一些世界上最大,最具影响力的标准制定机构。


via: https://opensource.com/article/17/7/software-standards

作者:Andy Updegrove 译者:softpaopao 校对:wxy

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

容器在过去几年内取得很大的进展。现在我们来回顾它发展的时间线。

Linux 容器是如何演变的

在过去几年内,容器不仅成为了开发者们热议的话题,还受到了企业的关注。持续增长的关注使得在它的安全性、可扩展性以及互用性等方面的需求也得以增长。满足这些需求需要很大的工程量,下面我们讲讲在红帽这样的企业级这些工程是如何发展的。

我在 2013 年秋季第一次遇到 Docker 公司(Docker.io)的代表,那时我们在设法使 Red Hat Enterprise Linux (RHEL) 支持 Docker 容器(现在 Docker 项目的一部分已经更名为 Moby)的运行。在移植过程中,我们遇到了一些问题。处理容器镜像分层所需的写时拷贝(COW)文件系统成了我们第一个重大阻碍。Red Hat 最终贡献了一些 COW 文件系统实现,包括 Device Mapperbtrf,以及 OverlayFS 的第一个版本。在 RHEL 上,我们默认使用 Device Mapper, 但是我们在 OverlayFS 上也已经取得了很大进展。

我们在用于启动容器的工具上遇到了第二个主要障碍。那时的上游 docker 使用 LXC 工具来启动容器,然而我们不想在 RHEL 上支持 LXC 工具集。而且在与上游 docker 合作之前,我们已经与 libvrit 团队携手构建了 virt-sandbox 工具,它使用 libvrit-lxc 来启动容器。

在那时,红帽里有员工提到一个好办法,换掉 LXC 工具集而添加桥接器,以便 docker 守护进程通过 libvirt-lxc 与 libvirt 通讯来启动容器。这个方案也有一些顾虑。考虑下面这个例子,使用 Docker 客户端(docker-cli)来启动容器,各层调用会在容器进程(pid1OfContainer)之前依次启动:

docker-cli → docker-daemon → libvirt-lxc → pid1OfContainer

我不是很喜欢这个方案,因为它在启动容器的工具与最终的容器进程之间有两个守护进程。

我的团队与上游 docker 开发者合作实现了一个原生的 Go 编程语言 版本的容器运行时,叫作 libcontainer。这个库作为 [OCI 运行时规范]的最初版实现与 runc 一同发布。

docker-cli → docker-daemon @ pid1OfContainer

大多数人误认为当他们执行一个容器时,容器进程是作为 docker-cli 的子进程运行的。实际上他们执行的是一个客户端/服务端请求操作,容器进程是在一个完全单独的环境作为子进程运行的。这个客户端/服务端请求会导致不稳定性和潜在的安全问题,而且会阻碍一些实用特性的实现。举个例子,systemd 有个叫做套接字唤醒的特性,你可以将一个守护进程设置成仅当相应的套结字被连接时才启动。这意味着你的系统可以节约内存并按需执行服务。套结字唤醒的工作原理是 systemd 代为监听 TCP 套结字,并在数据包到达套结字时启动相应的服务。一旦服务启动完毕,systemd 将套结字交给新启动的守护进程。如果将守护进程运行在基于 docker 的容器中就会出现问题。systemd 的 unit 文件通过 Docker CLI 执行容器,然而这时 systemd 却无法简单地经由 Docker CLI 将套结字转交给 Docker 守护进程。

类似这样的问题让我们意识到我们需要一个运行容器的替代方案。

容器编排问题

上游的 docker 项目简化了容器的使用过程,同时也是一个绝佳的 Linux 容器学习工具。你可以通过一条简单的命令快速地体验如何启动一个容器,例如运行 docker run -ti fedora sh 然后你就立即处于一个容器之中。

当开始把许多容器组织成一个功能更为强大的应用时,你才能体会到容器真正的能力。但是问题在于伴随多容器应用而来的高复杂度使得简单的 Docker 命令无法胜任编排工作。你要如何管理容器应用在有限资源的集群节点间的布局与编排?如何管理它们的生命周期等等?

在第一届 DockerCon,至少有 7 种不同的公司/开源项目展示了其容器的编排方案。红帽演示了 OpenShiftgeard 项目,它基于 OpenShift v2 的容器(叫作 gears)。红帽觉得我们需要重新审视容器编排,而且可能要与开源社区的其他人合作。

Google 则演示了 Kubernetes 容器编排工具,它来源于 Google 对其自内部架构进行编排时所积累的知识经验。OpenShift 决定放弃 Gear 项目,开始和 Google 一同开发 Kubernetes。 现在 Kubernetes 是 GitHub 上最大的社区项目之一。

Kubernetes

Kubernetes 原先被设计成使用 Google 的 lmctfy 容器运行时环境来完成工作。在 2014 年夏天,lmctfy 兼容了 docker。Kubernetes 还会在 kubernetes 集群的每个节点运行一个 kubelet 守护进程,这意味着原先使用 docker 1.8 的 kubernetes 工作流看起来是这样的:

kubelet → dockerdaemon @ PID1

回退到了双守护进程的模式。

然而更糟糕的是,每次 docker 的新版本发布都使得 kubernetes 无法工作。Docker 1.10 切换镜像底层存储方案导致所有镜像重建。而 Docker 1.11 开始使用 runc 来启动镜像:

kubelet → dockerdaemon @ runc @PID1

Docker 1.12 则增加了一个容器守护进程用于启动容器。其主要目的是为了支持 Docker Swarm (Kubernetes 的竞争者之一):

kubelet → dockerdaemon → containerd @runc @ pid1

如上所述,每一次 docker 发布都破坏了 Kubernetes 的功能,这也是为什么 Kubernetes 和 OpenShift 请求我们为他们提供老版本 Docker 的原因。

现在我们有了一个三守护进程的系统,只要任何一个出现问题,整个系统都将崩溃。

走向容器标准化

CoreOS、rkt 和其它替代运行时

因为 docker 运行时带来的问题,几个组织都在寻求一个替代的运行时。CoreOS 就是其中之一。他们提供了一个 docker 容器运行时的替代品,叫 rkt (rocket)。他们同时还引入一个标准容器规范,称作 appc (App Container)。从根本上讲,他们是希望能使得所有人都使用一个标准规范来管理容器镜像中的应用。

这一行为为标准化工作树立了一面旗帜。当我第一次开始和上游 docker 合作时,我最大的担忧就是最终我们会分裂出多个标准。我不希望类似 RPM 和 DEB 之间的战争影响接下来 20 年的 Linux 软件部署。appc 的一个成果是它说服了上游 docker 与开源社区合作创建了一个称作 开放容器计划 Open Container Initiative (OCI) 的标准团体。

OCI 已经着手制定两个规范:

OCI 运行时规范:OCI 运行时规范“旨在规范容器的配置、执行环境以及生命周期”。它定义了容器的磁盘存储,描述容器内运行的应用的 JSON 文件,容器的生成和执行方式。上游 docker 贡献了 libcontainer 并构建了 runc 作为 OCI 运行时规范的默认实现。

OCI 镜像文件格式规范:镜像文件格式规范主要基于上游 docker 所使用的镜像格式,定义了容器仓库中实际存储的容器镜像格式。该规范使得应用开发者能为应用使用单一的标准化格式。一些 appc 中描述的概念被加入到 OCI 镜像格式规范中得以保留。这两份规范 1.0 版本的发布已经临近(LCTT 译注:已经发布)。上游 docker 已经同意在 OCI 镜像规范定案后支持该规范。Rkt 现在既支持运行 OCI 镜像也支持传统的上游 docker 镜像。

OCI 通过为工业界提供容器镜像与运行时标准化的环境,帮助在工具与编排领域解放创新的力量。

抽象运行时接口

得益于标准化工作, Kubernetes 编排领域也有所创新。作为 Kubernetes 的一大支持者,CoreOS 提交了一堆补丁,使 Kubernetes 除了 docker 引擎外还能通过 rkt 运行容器并且与容器通讯。Google 和 Kubernetes 上游预见到增加这些补丁和将来可能添加的容器运行时接口将给 Kubernetes 带来的代码复杂度,他们决定实现一个叫作 容器运行时接口 Container Runtime Interface (CRI) 的 API 协议规范。于是他们将 Kubernetes 由原来的直接调用 docker 引擎改为调用 CRI,这样任何人都可以通过实现服务器端的 CRI 来创建支持 Kubernetes 的容器运行时。Kubernetes 上游还为 CRI 开发者们创建了一个大型测试集以验证他们的运行时对 Kubernetes 的支持情况。开发者们还在努力地移除 Kubernetes 对 docker 引擎的调用并将它们隐藏在一个叫作 docker-shim 的薄抽象层后。

容器工具的创新

伴随 skopeo 而来的容器仓库创新

几年前我们正与 Atomic 项目团队合作构建 atomic CLI。我们希望实现一个功能,在镜像还在镜像仓库时查看它的细节。在那时,查看仓库中的容器镜像相关 JSON 文件的唯一方法是将镜像拉取到本地服务器再通过 docker inspect 来查看 JSON 文件。这些镜像可能会很大,上至几个 GiB。为了允许用户在不拉取镜像的情况下查看镜像细节,我们希望在 docker inspect 接口添加新的 --remote 参数。上游 docker 拒绝了我们的代码拉取请求(PR),告知我们他们不希望将 Docker CLI 复杂化,我们可以构建我们自己的工具去实现相同的功能。

我们的团队在 Antonio Murdaca 的领导下执行这个提议,构建了 skopeo。Antonio 没有止步于拉取镜像相关的 JSON 文件,而是决定实现一个完整的协议,用于在容器仓库与本地主机之间拉取与推送容器镜像。

skopeo 现在被 atomic CLI 大量用于类似检查容器更新的功能以及 atomic 扫描 当中。Atomic 也使用 skopeo 取代上游 docker 守护进程拉取和推送镜像的功能。

Containers/image

我们也曾和 CoreOS 讨论过在 rkt 中使用 skopeo 的可能,然而他们表示不希望运行一个外部的协助程序,但是会考虑使用 skopeo 所使用的代码库。于是我们决定将 skopeo 分离为一个代码库和一个可执行程序,创建了 image 代码库。

containers/images 代码库和 skopeo 被几个其它上游项目和云基础设施工具所使用。Skopeo 和 containers/image 已经支持 docker 和多个存储后端,而且能够在容器仓库之间移动容器镜像,还拥有许多酷炫的特性。skopeo 的一个优点是它不需要任何守护进程的协助来完成任务。Containers/image 代码库的诞生使得类似容器镜像签名等增强功能得以实现。

镜像处理与扫描的创新

我在前文提到 atomic CLI。我们构建这个工具是为了给容器添加不适合 docker CLI 或者我们无法在上游 docker 中实现的特性。我们也希望获得足够灵活性,将其用于开发额外的容器运行时、工具和存储系统。Skopeo 就是一例。

我们想要在 atomic 实现的一个功能是 atomic mount。从根本上讲,我们希望从 Docker 镜像存储(上游 docker 称之为 graph driver)中获取内容,把镜像挂在到某处,以便用工具来查看该镜像。如果你使用上游的 docker,查看镜像内容的唯一方法就是启动该容器。如果其中有不可信的内容,执行容器中的代码来查看它会有潜在危险。通过启动容器查看镜像内容的另一个问题是所需的工具可能没有被包含在容器镜像当中。

大多数容器镜像扫描器遵循以下流程:它们连接到 Docker 的套结字,执行一个 docker save 来创建一个 tar 打包文件,然后在磁盘上分解这个打包文件,最后查看其中的内容。这是一个很慢的过程。

通过 atomic mount,我们希望直接使用 Docker graph driver 挂载镜像。如果 docker 守护进程使用 device mapper,我们将挂载这个设备。如果它使用 overlay,我们会挂载 overlay。这个操作很快而且满足我们的需求。现在你可以执行:

# atomic mount fedora /mnt
# cd /mnt

然后开始探查内容。你完成相应工作后,执行:

# atomic umount /mnt

我们在 atomic scan 中使用了这一特性,实现了一个快速的容器扫描器。

工具协作的问题

其中一个严重的问题是 atomic mount 隐式地执行这些工作。Docker 守护进程不知道有另一个进程在使用这个镜像。这会导致一些问题(例如,如果你先挂载了 Fedora 镜像,然后某个人执行了 docker rmi fedora 命令,docker 守护进程移除镜像时就会产生奇怪的操作失败,同时报告说相应的资源忙碌)。Docker 守护进程可能因此进入一个奇怪的状态。

容器存储系统

为了解决这个问题,我们开始尝试将从上游 docker 守护进程剥离出来的 graph driver 代码拉取到我们的代码库中。Docker 守护进程在内存中为 graph driver 完成所有锁的获取。我们想要将这些锁操作转移到文件系统中,这样我们可以支持多个不同的进程来同时操作容器的存储系统,而不用通过单一的守护进程。

我们创建了 containers/storage 项目,实现了容器运行、构建、存储所需的所有写时拷贝(COW)特性,同时不再需要一个单一进程来控制和监控这个过程(也就是不需要守护进程)。现在 skopeo 以及其它工具和项目可以直接利用镜像的存储系统。其它开源项目也开始使用 containers/storage,在某些时候,我们也会把这些项目合并回上游 docker 项目。

驶向创新

当 Kubernetes 在一个节点上使用 docker 守护进程运行容器时会发生什么?首先,Kubernetes 执行一条类似如下的命令:

kubelet run nginx -image=nginx

这个命令告诉 kubelet 在节点上运行 NGINX 应用程序。kubelet 调用 CRI 请求启动 NGINX 应用程序。在这时,实现了 CRI 规范的容器运行时必须执行以下步骤:

  1. 检查本地是否存在名为 nginx 的容器。如果没有,容器运行时会在容器仓库中搜索标准的容器镜像。
  2. 如果镜像不存在于本地,从容器仓库下载到本地系统。
  3. 使用容器存储系统(通常是写时拷贝存储系统)解析下载的容器镜像并挂载它。
  4. 使用标准的容器运行时执行容器。

让我们看看上述过程使用到的特性:

  1. OCI 镜像格式规范定义了容器仓库存储的标准镜像格式。
  2. Containers/image 代码库实现了从容器仓库拉取镜像到容器主机所需的所有特性。
  3. Containers/storage 提供了在写时拷贝的存储系统上探查并处理 OCI 镜像格式的代码库。
  4. OCI 运行时规范以及 runc 提供了执行容器的工具(同时也是 docker 守护进程用来运行容器的工具)。

这意味着我们可以利用这些工具来使用容器,而无需一个大型的容器守护进程。

在中等到大规模的基于 DevOps 的持续集成/持续交付环境下,效率、速度和安全性至关重要。只要你的工具遵循 OCI 规范,开发者和执行者就能在持续集成、持续交付到生产环境的自动化中自然地使用最佳的工具。大多数的容器工具被隐藏在容器编排或上层容器平台技术之下。我们预想着有朝一日,运行时和镜像工具的选择会变成容器平台的一个安装选项。

系统(独立)容器

在 Atomic 项目中我们引入了 原子主机 atomic host ,一种新的操作系统构建方式:所有的软件可以被“原子地”升级并且大多数应用以容器的形式运行在操作系统中。这个平台的目的是证明将来所有的软件都能部署在 OCI 镜像格式中并且使用标准协议从容器仓库中拉取,然后安装到系统上。用容器镜像的形式发布软件允许你以不同的速度升级应用程序和操作系统。传统的 RPM/yum/DNF 包分发方式把应用更新锁定在操作系统的生命周期中。

在以容器部署基础设施时多数会遇到一个问题——有时一些应用必须在容器运行时执行之前启动。我们看一个使用 docker 的 Kubernetes 的例子:Kubernetes 为了将 pods 或者容器部署在独立的网络中,要求先建立一个网络。现在默认用于创建网络的守护进程是 flanneld,而它必须在 docker 守护进程之前启动,以支持 docker 网络接口来运行 Kubernetes 的 pods。而且,flanneld 使用 etcd 来存储数据,这个守护进程必须在 flanneld 启动之前运行。

如果你想把 etcd 和 flanneld 部署到容器镜像中,那就陷入了鸡与鸡蛋的困境中。我们需要容器运行时来启动容器化的应用,但这些应用又需要在容器运行时之前启动。我见过几个取巧的方法尝试解决这个问题,但这些方法都不太干净利落。而且 docker 守护进程当前没有合适的方法来配置容器启动的优先级顺序。我见过一些提议,但它们看起来和 SysVInit 所使用的启动服务的方式相似(我们知道它带来的复杂度)。

systemd

用 systemd 替代 SysVInit 的原因之一就是为了处理服务启动的优先级和顺序,我们为什么不充分利用这种技术呢?在 Atomic 项目中我们决定在让它在没有容器运行时的情况下也能启动容器,尤其是在系统启动早期。我们增强了 atomic CLI 的功能,让用户可以安装容器镜像。当你执行 atomic install --system etc,它将利用 skopeo 从外部的容器仓库拉取 etcd 的 OCI 镜像,然后把它分解(扩展)为 OSTree 底层存储。因为 etcd 运行在生产环境中,我们把镜像处理为只读。接着 atomic 命令抓取容器镜像中的 systemd 的 unit 文件模板,用它在磁盘上创建 unit 文件来启动镜像。这个 unit 文件实际上使用 runc 来在主机上启动容器(虽然 runc 不是必需的)。

执行 atomic install --system flanneld 时会进行相似的过程,但是这时 flanneld 的 unit 文件中会指明它依赖 etcd。

在系统引导时,systemd 会保证 etcd 先于 flanneld 运行,并且直到 flanneld 启动完毕后再启动容器运行时。这样我们就能把 docker 守护进程和 Kubernetes 部署到系统容器当中。这也意味着你可以启动一台原子主机或者使用传统的基于 rpm 的操作系统,让整个容器编排工具栈运行在容器中。这是一个强大的特性,因为用户往往希望改动容器主机时不受这些组件影响。而且,它保持了主机的操作系统的占用最小化。

大家甚至讨论把传统的应用程序部署到独立/系统容器或者被编排的容器中。设想一下,可以用 atomic install --system httpd 命令安装一个 Apache 容器,这个容器可以和用 RPM 安装的 httpd 服务以相同的方式启动(systemctl start httpd ,区别是这个容器 httpd 运行在一个容器中)。存储系统可以是本地的,换言之,/var/www 是从宿主机挂载到容器当中的,而容器监听着本地网络的 80 端口。这表明了我们可以在不使用容器守护进程的情况下将传统的负载组件部署到一个容器中。

构建容器镜像

在我看来,在过去 4 年来容器发展方面最让人失落的是缺少容器镜像构建机制上的创新。容器镜像不过是将一些 tar 包文件与 JSON 文件一起打包形成的文件。基础镜像则是一个 rootfs 与一个描述该基础镜像的 JSON 文件。然后当你增加镜像层时,层与层之间的差异会被打包,同时 JSON 文件会做出相应修改。这些镜像层与基础文件一起被打包,共同构成一个容器镜像。

现在几乎所有人都使用 docker build 与 Dockerfile 格式来构建镜像。上游 docker 已经在几年前停止了接受修改或改进 Dockerfile 格式的拉取请求(PR)了。Dockerfile 在容器的演进过程中扮演了重要角色,开发者和管理员/运维人员可以通过简单直接的方式来构建镜像;然而我觉得 Dockerfile 就像一个简陋的 bash 脚本,还带来了一些尚未解决的问题,例如:

  • 使用 Dockerfile 创建容器镜像要求运行着 Docker 守护进程。

    • 没有可以独立于 docker 命令的标准工具用于创建 OCI 镜像。
    • 甚至类似 ansible-containers 和 OpenShift S2I (Source2Image) 的工具也在底层使用 docker-engine
  • Dockerfile 中的每一行都会创建一个新的镜像,这有助于创建容器的开发过程,这是因为构建工具能够识别 Dockerfile 中的未改动行,复用已经存在的镜像从而避免了未改动行的重复执行。但这个特性会产生大量的镜像层。

    • 因此,不少人希望构建机制能压制镜像消除这些镜像层。我猜想上游 docker 最后应该接受了一些提交满足了这个需求。
  • 要从受保护的站点拉取内容到容器镜像,你往往需要某种密钥。比如你为了添加 RHEL 的内容到镜像中,就需要访问 RHEL 的证书和订阅。

    • 这些密钥最终会被以层的方式保存在镜像中。开发者要费很大工夫去移除它们。
    • 为了允许在 docker 构建过程中挂载数据卷,我们在我们维护的 projectatomic/docker 中加入了 -v volume 选项,但是这些修改没有被上游 docker 接受。
  • 构建过程的中间产物最终会保留在容器镜像中,所以尽管 Dockerfile 易于学习,当你想要了解你要构建的镜像时甚至可以在笔记本上构建容器,但它在大规模企业环境下还不够高效。然而在自动化容器平台下,你应该不会关心用于构建 OCI 镜像的方式是否高效。

Buildah 起航

在 DevConf.cz 2017,我让我们团队的 Nalin Dahyabhai 考虑构建被我称为 containers-coreutils 的工具,它基本上就是基于 containers/storage 和 containers/image 库构建的一系列可以使用类似 Dockerfile 语法的命令行工具。Nalin 为了取笑我的波士顿口音,决定把它叫做 buildah。我们只需要少量的 buildah 原语就可以构建一个容器镜像:

  • 最小化 OS 镜像、消除不必要的工具是主要的安全原则之一。因为黑客在攻击应用时需要一些工具,如果类似 gccmakednf 这样的工具根本不存在,就能阻碍攻击者的行动。
  • 减小容器的体积总是有益的,因为这些镜像会通过互联网拉取与推送。
  • 使用 Docker 进行构建的基本原理是在容器构建的根目录下利用命令安装或编译软件。
  • 执行 run 命令要求所有的可执行文件都包含在容器镜像内。只是在容器镜像中使用 dnf 就需要完整的 Python 栈,即使在应用中从未使用到 Python。
  • ctr=$(buildah from fedora):

    • 使用 containers/image 从容器仓库拉取 Fedora 镜像。
    • 返回一个容器 ID (ctr)。
  • mnt=$(buildah mount $ctr):

    • 挂载新建的容器镜像($ctr).
    • 返回挂载点路径。
    • 现在你可以使用挂载点来写入内容。
  • dnf install httpd –installroot=$mnt:

    • 你可以使用主机上的命令把内容重定向到容器中,这样你可以把密钥保留在主机而不导入到容器内,同时构建所用的工具也仅仅存在于主机上。
    • 容器内不需要包含 dnf 或者 Python 栈,除非你的应用用到它们。
  • cp foobar $mnt/dir:

    • 你可以使用任何 bash 中可用的命令来构造镜像。
  • buildah commit $ctr:

    • 你可以随时创建一个镜像层,镜像的分层由用户而不是工具来决定。
  • buildah config --env container=oci --entrypoint /usr/bin/httpd $ctr:

    • Buildah 支持所有 Dockerfile 的命令。
  • buildah run $ctr dnf -y install httpd:

    • Buildah 支持 run 命令,但它是在一个锁定的容器内利用 runc 执行命令,而不依赖容器运行时守护进程。
  • buildah build-using-dockerfile -f Dockerfile .

    • 我们希望将移植类似 ansible-containers 和 OpenShift S2I 这样的工具,改用 buildah 以去除对容器运行时守护进程的依赖。
    • 使用与生产环境相同的容器运行时构建容器镜像会遇到另一个大问题。为了保证安全性,我们需要把权限限制到支持容器构建与运行所需的最小权限。构建容器比起运行容器往往需要更多额外的权限。举个例子,我们默认允许 mknod 权限,这会允许进程创建设备节点。有些包的安装会尝试创建设备节点,然而在生产环境中的应用几乎都不会这么做。如果默认移除生产环境中容器的 mknod 特权会让系统更为安全。
    • 另一个例子是,容器镜像默认是可读写的,因为安装过程意味着向 /usr 存入软件包。然而在生产环境中,我强烈建议把所有容器设为只读模式,仅仅允许它们写入 tmpfs 或者是挂载了数据卷的目录。通过分离容器的构建与运行环境,我们可以更改这些默认设置,提供一个更为安全的环境。
    • 当然,buildah 可以使用 Dockerfile 构建容器镜像。

CRI-O :一个 Kubernetes 的运行时抽象

Kubernetes 添加了 容器运行时接口 Container Runtime Interface (CRI)接口,使 pod 可以在任何运行时上工作。虽然我不是很喜欢在我的系统上运行太多的守护进程,然而我们还是加了一个。我的团队在 Mrunal Patel 的领导下于 2016 年后期开始构建 [CRI-O] 守护进程。这是一个用来运行 OCI 应用程序的 OCI 守护进程。理论上,将来我们能够把 CRI-O 的代码直接并入 kubelet 中从而消除这个多余的守护进程。

不像其它容器运行时,CRI-O 的唯一目的就只是为了满足 Kubernetes 的需求。记得前文描述的 Kubernetes 运行容器的条件。

Kubernetes 传递消息给 kubelet 告知其运行 NGINX 服务器:

  1. kubelet 唤醒 CRI-O 并告知它运行 NGINX。
  2. CRI-O 回应 CRI 请求。
  3. CRI-O 在容器仓库查找 OCI 镜像。
  4. CRI-O 使用 containers/image 从仓库拉取镜像到主机。
  5. CRI-O 使用 containers/storage 解压镜像到本地磁盘。
  6. CRI-O 按照 OCI 运行时规范(通常使用 runc)启动容器。如前文所述,Docker 守护进程也同样使用 runc 启动它的容器。
  7. 按照需要,kubelet 也可以使用替代的运行时启动容器,例如 Clear Containers runcv

CRI-O 旨在成为稳定的 Kubernetes 运行平台。只有通过完整的 Kubernetes 测试集后,新版本的 CRI-O 才会被推出。所有提交到 https://github.com/Kubernetes-incubator/cri-o 的拉取请求都会运行完整的 Kubernetes 测试集。没有通过测试集的拉取请求都不会被接受。CRI-O 是完全开放的,我们已经收到了来自 Intel、SUSE、IBM、Google、Hyper.sh 等公司的代码贡献。即使不是红帽想要的特性,只要通过一定数量维护者的同意,提交给 CRI-O 的补丁就会被接受。

小结

我希望这份深入的介绍能够帮助你理解 Linux 容器的演化过程。Linux 容器曾经陷入一种各自为营的困境,Docker 建立起了镜像创建的事实标准,简化了容器的使用工具。OCI 则意味着业界在核心镜像格式与运行时方面的合作,这促进了工具在自动化效率、安全性、高可扩展性、易用性方面的创新。容器使我们能够以一种新奇的方式部署软件——无论是运行于主机上的传统应用还是部署在云端的微服务。而在许多方面,这一切还仅仅是个开始。


作者简介:

Daniel J Walsh - Daniel 有将近 30 年的计算机安全领域工作经验。他在 2001 年 8 月加入 Red Hat。

via: https://opensource.com/article/17/7/how-linux-containers-evolved

作者:Daniel J Walsh 译者:haoqixu 校对:wxy

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