一个老奶奶的唠叨：当年我玩 Linux 时……

Summary: 在很久以前，那时还没有 Linux 系统。真的没有！之前也从未存在过。不像现在，Linux 系统随处可见。有各种流派的 Unix 系统、有苹果的操作系统、有微软的 Windows 操作系统。

我一看这人就很脸熟<br />
以前看过Carla Schroder写过的技术博文，写得很好很有水平。

这个图很棒，稀饭@！~

我在Linux.cn翻译的第一篇文章，感谢wxy的校对。

翻译的不错~

話說國內有大媽用Linux嗎？據說幾乎沒有一個國內證券公司的股票軟件能在跑在Linux上...

大妈我不知道，我知道有位老爷子——说起来老爷子好久没冒泡了，不知道老人家怎么样了。

我觉得苹果公司的iOS很无聊

我觉得苹果公司的iOS很无聊

在国内，首先得：

各种炒股软件 for Linux

各种IM for Linux

迅雷 for Linux

......<此处省略一万条>

![](/data/attachment/album/201611/01/115259t6fzdk569886f86m.jpg)

在很久以前，那时还没有 Linux 系统。真的没有！之前也从未存在过。不像现在，Linux 系统随处可见。那时有各种流派的 Unix 系统、有苹果的操作系统、有微软的 Windows 操作系统。

比如说 Windows，它的很多东西都改变了，但是依然保持不变的东西的更多。尽管它已经增加了 20GB 以上的鬼知道是什么的东西，但是 Windows 还是大体保持不变（除了不能在 DOS 的提示下实际做些什么了）。嘿，谁还记得 Gorilla.bas 那个出现在 DOS 系统里的炸香蕉的游戏吗？多么美好的时光啊！不过互联网却不会忘记，你可以在 Kongregate.com 这个网站玩这个游戏的 Flash版本。

苹果系统也改变了，从一个鼓励你 hack 的友善系统变成了一个漂亮而密实的、根本不让你打开的小盒子，而且还限制了你使用的硬件接口。1998 年：软盘没了。2012 年：光驱没了。而 12 英寸的 MacBook 只有一个单一的 USB Type-C 接口，提供了电源、蓝牙、无线网卡、外部存储、视频输出和其它的一些配件的接口。而你要是想一次连接多个外设就不得不背着一堆转接器，这真是太令人抓狂了！然后就轮到耳机插孔了，没错，这唯一一个苹果世界里留着的非专有的标准硬件接口了，也注定要消失了。（LCTT 译注：还好，虽然最新的 IPhone 7 上没有耳机插孔了，但是新发布的 Macbook 上还有）

还有一大堆其它的操作系统，比如：Amiga、BeOS、OS/2 ，如果你愿意的话，你能找到几十个操作系统。我建议你去找找看，太容易找到了。Amiga、 BeOS 和 OS/2 这些系统都值得关注，因为它们有强大的功能，比如 32 位的多任务和高级图形处理能力。但是市场的影响击败了强大的系统性能，因此技术上并不出众的 Apple 和 Windows 操作系统统治了市场的主导地位，而那些曾经的系统也逐渐销声匿迹了。

然后 Linux 系统出现了，世界也因此改变了。

### 第一款电脑

我曾经使用过的第一款电脑是 Apple IIc ，大概在 1994年左右，而那个时候 Linux 系统刚出来 3 年。这是我从一个朋友那里借来的，用起来各方面都还不错，但是很不方便。所以我自己花了将近 500 美元买了一台二手的 Tandy 牌的电脑。这对于卖电脑的人来说是一件很伤心的事，因为新电脑要花费双倍的价钱。那个时候，电脑贬值的速度非常快。这个电脑当时看起来强劲得像是个怪物：一个英特尔 386SX 的 CPU，4MB的内存，一个 107MB 的硬盘，14 英寸的彩色 CRT 显示器，运行 MS-DOS 5 和 Windows 3.1 系统。

我曾无数次的拆开那个可怜的怪物，并且多次重新安装 Windows 和 DOS 系统。因为 Windows 桌面用的比较少，所以我的大部分工作都是在 DOS 下完成的。我喜欢玩血腥暴力的视频游戏，包括 Doom、Duke Nukem、Quake 和 Heretic。啊！那些美好的，让人心动的 8 位图像！

那个时候硬件的发展一直落后于软件，因此我经常升级硬件。现在我们能买到满足我们需求的任何配置的电脑。我已经好多年都没有再更新我的任何电脑硬件了。

### 《<ruby> 比特杂志 <rp>  （ </rp> <rt>  Computer bits </rt> <rp>  ） </rp></ruby>》

回到那些曾经辉煌的年代，电脑商店布满大街小巷，找到本地的一家网络服务提供商（ISP）也不用走遍整个街区。ISP 那个时候真的非比寻常，它们不是那种冷冰冰的令人讨论的超级大公司，而是像美国电信运营商和有线电视公司这样的好朋友。他们都非常友好，并且提供各种各样的像 BBS、文件下载、MUD （多玩家在线游戏）等的额外服务。

我花了很多的时间在电脑商店购买配件，但是很多时候我一个女人家去那里会让店里的员工感到吃惊，我真的很无语了，这怎么就会让一些人看不惯了。我现成已经是一位 58 岁的老家伙了，但是他们还是一样的看不惯我。我希望我这个女电脑迷在我死之前能被他们所接受。

![](/data/attachment/album/201611/01/113437rzohdj9d0adm6t3e.jpg)

那些商店的书架上摆满了《<ruby> 比特杂志 <rp>  （ </rp> <rt>  Computer bits </rt> <rp>  ） </rp></ruby>》。有关《比特杂志》的[历史刊物](https://web.archive.org/web/20020122193349/http://computerbits.com/)可以在<ruby> 互联网档案库 <rp>  （ </rp> <rt>  Internet Archive </rt> <rp>  ） </rp></ruby>中查到。《比特杂志》是当地一家免费报纸，有很多关于计算机方面的优秀的文章和大量的广告。可惜当时的广告没有网络版，因此大家不能再看到那些很有价值的关于计算机方面的详细信息了。你知道现在的广告商们有多么的抓狂吗？他们埋怨那些安装广告过滤器的人，致使科技新闻变成了伪装的广告。他们应该学习一下过去的广告模式，那时候的广告里有很多有价值的信息，大家都喜欢阅读。我从《比特杂志》和其它的电脑杂志的广告中学到了所有关于计算机硬件的知识。《<ruby> 电脑购买者杂志 <rp>  （ </rp> <rt>  Computer Shopper </rt> <rp>  ） </rp></ruby>》更是非常好的学习资料，其中有上百页的广告和很多高质量的文章。

![](/data/attachment/album/201611/01/115446nijbr331izja3y9d.jpg)

《比特杂志》的出版人 Paul Harwood 开启了我的写作生涯。我的第一篇计算机专业性质的文章就是在《比特杂志》发表的。 Paul，仿佛你一直都在我的身旁，谢谢你。

在互联网档案库中，关于《比特杂志》的分类广告信息已经几乎查询不到了。分类广告模式曾经给出版商带来巨大的收入。免费的分类广告网站 Craigslist 在这个领域独占鳌头，同时也扼杀了像《比特杂志》这种以传统的报纸和出版为主的杂志行业。

其中有一些让我最难以忘怀的记忆就是一个 12 岁左右的吊儿郎当的小屁孩，他脸上挂满了对我这种光鲜亮丽的女人所做工作的不屑和不理解的表情，他在我钟爱的电脑店里走动，递给我一本《比特杂志》，当成给初学者的一本好书。我翻开杂志，指着其中一篇我写的关于 Linux 系统的文章给他看，他说“哦，我明白了”。他尴尬的脸变成了那种正常生理上都不可能呈现的颜色，然后很仓促地夹着尾巴溜走了。(不是的，我亲爱的、诚实的读者们，他不是真的只有 12 岁，而应该是 20 来岁。他现在应该比以前更成熟懂事一些了吧！）

### 发现 Linux

我第一次了解到 Linux 系统是在《比特杂志》上，大概在 1997 年左右。我一开始用的一些 Linux操作系统版本是 Red Hat 5 和 Mandrake Linux（曼德拉草）。 Mandrake 真是太棒了，它是第一款易安装型的 Linux 系统，并且还附带图形界面和声卡驱动，因此我马上就可以玩 Tux Racer 游戏了。不像那时候大多数的 Linux 迷们，因为我之前没接触过 Unix系统，所以我学习起来比较难。但是一切都还顺利吧，因为我学到的东西都很有用。相对于我在 Windows 中的体验，我在 Windows 中学习的大部分东西都是徒劳，最终只能放弃返回到 DOS 下。

玩转电脑真是充满了太多的乐趣，后来我转行成为计算机自由顾问，去帮助一些小型公司的 IT 部门把数据迁移到 Linux 服务器上，这让 Windows 系统或多或少的失去一些用武之地。通常情况下我们都是在背地里偷偷地做这些工作的，因为那段时期微软把 Linux 称为毒瘤，诬蔑 Linux 系统是一种共产主义，用来削弱和吞噬我们身体里的珍贵血液的阴谋。

### Linux 赢了

我持续做了很多年的顾问工作，也做其它一些相关的工作，比如：电脑硬件修理和升级、布线、系统和网络管理，还有运行包括 Apple、Windows、Linux 系统在内的混合网络。Apple 和 Windows 系统故意不兼容对方，因此这两个系统真的是最头疼，也最难整合到同一网络中。但是在 Linux 系统和其它开源软件中最有趣的一件事是总有一些人能够处理这些厂商之间的兼容性问题。

现在已经大不同了。在系统间的互操作方面一直存在一些兼容性问题，而且也没有桌面 Linux 系统的 1 级 OEM 厂商。我觉得这是因为微软和苹果公司在零售行业在大力垄断造成的。也许他们这样做反而帮了我们帮大忙，因为我们可以从 ZaReason 和 System76 这样独立的 Linux 系统开发商得到更好的服务和更高性能的系统。他们对 Linux 系统都很专业，也特别欢迎我们这样的用户。

Linux 除了在零售行业的桌面版系统占有一席之地以外，从嵌入式系统到超级计算机以及分布式计算系统等各个方面都占据着主要地位。开源技术掌握着软件行业的发展方向，所有的软件行业的前沿技术，比如容器、集群以及人工智能的发展都离不开开源技术的支持。从我的第一台老式的 386SX 电脑到现在，Linux 和开源技术都取得了巨大的进步。

如果没有 Linux 系统和开源，这一切都不可能发生。

（题图来自：[wallpapersafari](http://cdn.wallpapersafari.com/32/70/uLMive.jpg) ，高清）

---

via: <https://opensource.com/life/16/7/my-linux-story-carla-schroder>

作者：[Carla Schroder](https://opensource.com/users/carlaschroder) 译者：[rusking](https://github.com/rusking) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


谷歌也不信任沃通的证书了，StartCom CA 一并受到同等处罚

Summary: 从 Chrome 56 开始，不再信任沃通及被其收购的 StartCom 于 2016 年 10 月 21 日之后所颁发的证书，直到最终完全移除对这两个 CA 的信任！

出来混迟早是要还的

站长只发个新闻，也不对新闻评论下（评论下此新闻对国内的吃瓜群众有何影响，或者有何可能的影响。。）<br />
呵呵

这篇新闻是我写的。我下面评论了啊。其实一句话，尽快更换保平安。

愈演愈烈。

最后半句是错别字吧？  抑或=>亦或

为什么不稍微科普点？

可以趁1折买一个证书玩玩。

貌似国内好沃通的免费证书0.0

听西贝的喷友说是沃通很流氓，其背后是360

没错，本站有整个事件的相关线索，你可以跟着文章内的链接看看。

囧

整个事件其实我们连续报道了多篇了。不过这个事情还真没法再明白说了——明白的人自然明白其危害，不明白的人其实也根本不会意识到其危害。

吓得我赶紧用搜索引擎来验证我几十年来的用法。

这下彻底完了。360这钱白瞎了，只能说，以他们的一向行事风格，致此后果并不意外。

呵呵，

所以贵站的办站宗旨是什么呢？

是为了传播linux相关内容给精通系统、安全、网络各方面知识点的小伙伴？

是为了传播linux相关内容给linux感兴趣的初级小伙伴？

360倒闭了都活该拍手称快弹冠相庆，只是可惜了咱中国为数不多的CA机构

沒怎麼關注，幾個月前早就幹掉這個證書了，加上Chrome跟Firefox老早就封殺了，至少對一般用戶來說沒什麼影響。這貨走CNZZ老路罷了，忽悠不了誰。

哪里还有免费的证书可以申请么, 或者相当便宜的也可以

let's encrypt

这文章跟此站宗旨有毛线冲突。。。

不是很懂你们吃瓜群众。

像我，在此站和freebuf抛出沃通证书问题的时候就把自己个人博客上的startcom证书给换成了let's encrypt了

关于证书问题，从CNZZ到现在的沃通，懂的自然会懂，不懂也没关系，正常上网并没有什么影响。

你想了解证书的危害可以翻翻freebuf等网站的历史文章，很详细也很方便，善用搜索引擎，自己动手丰衣足食。

别整天等着别人喂食，那和咸鱼有何区别？#滑稽

继 Mozilla 做出对<ruby> 沃通 <rp>  （ </rp> <rt>  WoSign </rt> <rp>  ） </rp></ruby>的[处罚决定](/article-7898-1.html)之后，谷歌也跟随了这一做法，从 Chrome 56 开始，不再信任沃通及被其收购的 StartCom 于 2016 年 10 月 21 日之后所颁发的证书。

此前， 苹果已经率先于 [9 月 30 日](https://support.apple.com/en-us/HT204132)将沃通的根证书[从证书存储库中移除](/article-7846-1.html)了。虽然沃通及其被其秘密收购的 StartCom 均存在不同程度的 CA 违规问题，但是苹果和 Mozilla 在最近的操作中都只对沃通采取了处罚，而谷歌的处置则更进一步，也同时对 StartCom 进行了同等处罚。

![](/data/attachment/album/201611/01/232735zu1qnbnnffbvf8mn.jpg)

谷歌在其[通告](https://security.googleblog.com/2016/10/distrusting-wosign-and-startcom.html)中说：

>
> 谷歌已经查明了沃通和 StartCom 这两个 CA 没有维持对其作为 CA 的高标准预期，因此根据我们的[根证书策略](https://www.chromium.org/Home/chromium-security/root-ca-policy#TOC-Removal-of-Trust)，谷歌 Chrome 将不再信任它们。这个观点类似于苹果和 Mozilla 的根证书计划发出的最近公告。
>
>
>

在 2016 年 8 月 17 日，谷歌接到了 GitHub 安全团队的通告，称沃通在没有得到他们授权的情况下签发了一个 GitHub 的证书。这促使 GitHub 安全团队和 Mozilla 合作对沃通进行了调查，发现了[沃通的若干违规签发证书的问题](https://wiki.mozilla.org/CA:WoSign_Issues)。该调查表明沃通有意地规避了浏览器限制（即对 SHA-1 签名证书的失效计划）和对 CA 的要求。更进一步的，还发现了另外一家 CA 公司 StartCom 也被沃通秘密收购，这违反了对 CA 公司被收购需要披露信息的要求。而且，沃通公司还替换了原 StartCom 的基础设施、人员、政策和签发系统。面对这种情况，沃通和 StartCom 管理层还尝试误导社区这两个公司之间的收购事实和关系。

谷歌于 10 月 31 日发布了 Chrome 56 的 Dev 渠道版本。谷歌决定从该版本的 Chrome 开始，不再信任沃通和 StartCom 于 2016 年 10 月 21 日之后签发的证书。在这个日期之前签发的证书依旧信任，但是之后，除非他们遵循 [Chrome 的证书透明策略](https://www.chromium.org/Home/chromium-security/root-ca-policy/CTPolicyMay2016edition.pdf?attredirects=0)，将只能对其已有客户的域名签发。按照计划，Chrome 56 将于 2017 年 1 月正式发布稳定版，因此在此之前，**使用这两个 CA 所签发证书的网站应该尽快迁移到其它被 Chrome 信任的 CA 所签发的证书下**。

沃通和 StartCom 的客户会发现他们的证书在 Chrome 56 中不再有效。并且，更严厉的是，谷歌还说：

>
> 在接下来的 Chrome 版本中，还会进一步减少对这两个 CA 签发的证书的支持，直到最终完全移除对这两个 CA 的信任！
>
>
>

并且称：

>
> 沃通和 StartCom 的任何试图规避处罚的做法都将导致这两个 CA 被马上全部移除！
>
>
>

沃通的证书在国内使用比较多，而 StartCom 的 StartSSL 证书则在全球范围内有广泛的使用，尤其是它的免费证书有很多个人网站在使用。鉴于 Chrome 在浏览器市场上已经占据了[一半左右的份额](/article-7534-1.html)，因此其带来的影响将是毁灭性的。

目前，主流浏览器里面，Mozilla 的 Firefox 、苹果的 Safari 和谷歌的 Chrome 都已经做出了相应的反应，但是我们目前还没见到微软对此的跟进和表态。似乎微软在 CA 策略方面一向比较散漫，因此，IE 和 Edge 浏览器的反应或许还需要一段时间，抑或不会采取措施。


如何在 Ubuntu 命令行下管理浏览器书签

Summary: 如果你已经厌倦了这些内置在浏览器中的主流工具，你或许想要寻找一个替代品。这里介绍 Buku：一个命令行下的书签管理器。它不仅可以管理你的书签，还可以给它们加密，将它们保存在一个数据库中等等。

![](/data/attachment/album/201611/02/094421s6deeg2r9rdzog9r.jpg)

浏览器书签虽然不常被提及，但是作为互联网浏览的一部分。没有好的书签功能，网站链接可能会丢失，下次再不能访问。这就是为什么一个好的书签管理器很重要。

所有的现代浏览器都提供了一些形式的管理工具，虽然它们严格上来讲功能较少。如果你已经厌倦了这些内置在浏览器中的主流工具，你或许想要寻找一个替代品。这里介绍 **Buku**：一个命令行下的书签管理器。它不仅可以管理你的书签，还可以给它们加密，将它们保存在一个数据库中等等。下面是如何安装它。

### 安装

![](/data/attachment/album/201611/02/094438tpm80mq0w7sebaep.jpg)

Buku 不是非常流行。因此，用户需要自己编译它。然而，在 Ubuntu 上安装实际上很简单。打开终端并且使用 apt 安装`git` 和 `python3`，这两个工具在构建中很关键。

```
sudo apt python3-cryptography python3-bs4

```

装完所需的工具后，就可以拉取源码了。

```
git clone https://github.com/jarun/Buku/.
cd Buku

```

最后要安装它，只需要运行 `make` 命令。在这之后就可以在终端中输入 `buku`来运行 Buku 了。

```
sudo make install

```

**注意**：虽然这份指导针对的是 Ubuntu，但是 Buku 可以在任何 Linux 发行版中用相似的方法安装。

### 导入书签

![](/data/attachment/album/201611/02/094458nkwe67555255bxg4.jpg)

要将书签直接导入 Buku 中，首先从浏览器中将书签导出成一个 html 文件。接着，输入下面的命令：

```
buku -i bookmarks.html

```

最后，导入的书签会添加到 Buku 的数据库中。

### 导出书签

![](/data/attachment/album/201611/02/094517jo5u0o850ju585ob.jpg)

导出书签和导入一样简单。要导出所有的书签，使用下面的命令：

```
buku -e bookmarks.html

```

它会和其他书签管理器一样，将数据库中所有的书签导出成一个 html 文件。之后就可以用它做你任何要做的事情了！

### 打开书签

![](/data/attachment/album/201611/02/094544kart6a43ap0qapta.jpg)

要打开一个书签，首先要搜索。这需要用 `-s` 选项。运行下面的命令来搜索：

```
buku -s searchterm

```

接着一旦找到匹配的结果，输入旁边的数字，书签将会在默认的浏览器中打开了。

### 加密

不像其他的书签管理器，Buku 可以加密你的数据。这对拥有“敏感”书签的用户而言很有用的功能。要加密数据库，使用 `-l` 标志来创建一个密码。

```
buku -l

```

![](/data/attachment/album/201611/02/094609kn68aftb68yqwbby.jpg)

数据库加锁后，没有输入密码将不能打开书签。要解密它，使用 `-k` 选项。

```
buku -k

```

![](/data/attachment/album/201611/02/094631r4cqs3f7s755i3sz.jpg)

### 其他功能

这个书签管理器有许多不同的功能。要了解其他的功能，使用 `--help` 选项。当使用这个选项后，所有的选项以及每个功能详细内容都会列出来。这个非常有用，由于用户经常忘记东西，并且有时可以打开一个备忘单也不错。

```
buku --help

```

![](/data/attachment/album/201611/02/094657swxw5l5uw345zjwa.jpg)

### 总结

即使这个工具不是浏览器的一部分，它的功能比任何现在管理器提供的功能多。尽管事实是它在命令行中运行，但是也有很好的竞争力。书签对大部分人来言并不重要，但是哪些不喜欢现有选择以及喜欢 Linux 命令行的应该看一下 Buku。

---

via: <https://www.maketecheasier.com/manage-browser-bookmarks-ubuntu-command-line/>

作者：[Derrik Diener](https://www.maketecheasier.com/author/derrikdiener/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


苹果新的文件系统 APFS 比 HFS+ 强在哪里？

额，和btrfs比起来谁好一些？

这个要测评一下才知道啊。兄弟要不你买两台测试机来造福人类

鉴于hfs+是史上最垃圾fs，我对这个东西不作任何期待

不用比較，蘋果的東西都是辣雞

等你换了windows 10再去评价好了，还在用windows 7还有脸评价Mac。

你还是安心用的Linux好了，喷子

![](/data/attachment/album/201611/02/101332qc1pcord5coyzuao.jpg)

如果你一直关注苹果最新版的 macOS 的消息，你可能已经注意到苹果文件系统 APFS。这是不太让人感冒的话题之一。然而，它是支撑了操作系统用户体验的核心结构。APFS 将在 2017 年之前完成，不过你现在可以在 Sierra（最新版的 macOS） 上面体验一番开发者预览版。

### 特色与改进

先快速科普一下，**文件系统**是操作系统用于存储和检索数据的基本结构，不同的文件系统采用不同的方式来实现这个任务。随着计算机变得越来越快，新生代的文件系统已经从计算机速度的提升中获益，以提供新功能和适应现代存储需求。

HFS+，作为今天新一代 Mac 的附带文件系统，已经 18 岁了。它的祖先 HFS 比 Tom Cruise 的兄弟情影片“壮志凌云”还要老。它有点像一辆老丰田。它仍然可以工作（也许惊人的好），但是它不再得到人们的嘉奖。

APFS 不完全是 HFS+ 的升级版，因为相对现在而言，它是一个大幅度的飞跃。虽然这对苹果用户来说是一个重大的升级，但似乎这看起来更像是苹果赶上了其它系统，而不是超越了它们。然而，更新还进展得非常慢。

### 克隆和数据完整性

![](/data/attachment/album/201611/02/101349jyyco4kkyzch40yp.png)

APFS 使用称为写时复制（copy-on-write）的方案来生成重复文件的即时克隆。在 HFS+ 下，当用户复制文件的时候，每一个比特（二进制中的“位”）都会被复制。而 APFS 则通过操作元数据并分配磁盘空间来创建克隆。但是，在修改复制的文件之前都不会复制任何比特。当克隆体与原始副本分离的时候，那些改动（并且只有那些改动）才会被保存。

写时复制还提高了数据的完整性。在其它系统下，如果你卸载卷导致覆写操作挂起的话，你可能会发现你的文件系统有一部分与其它部分不同步。写时复制则通过将改动写入到可用的磁盘空间而不是覆盖旧文件来避免这个问题。直到写入操作成功完成前，旧文件都是正式版本。只有当新文件被成功复制时，旧文件才会被清除。

### 系统快照

![](/data/attachment/album/201611/02/101414sq2o42f2cffo2tro.png)

快照是写时复制架构给你带来的一个主要的升级。快照是文件系统在某个时间点的一个只读的可装载映像。随着文件系统发生改动，只有改动的比特会被更改。这可以让备份更简单，更可靠。考虑到时间机器（一个苹果出品的备份工具）已经成为硬链接的痛点，这可能是一个重大的升级。

### 输入/输出的服务质量（QoS）

你可能已经在你的路由器说明书看到了服务质量（QoS）这个名词。QoS 优先分配带宽使用以避免降低优先任务的速度。在你的路由器上，它采用用户定义的规则来为指定任务提供最大的带宽。据报道，苹果的 QoS 会优先考虑用户操作，例如活跃窗口。而诸如时间机器备份这些后台任务将会被降级。所以，这意味着更少的闲暇时光了？

### 本地加密

![](/data/attachment/album/201611/02/101433wic3tztnd7o3oq0i.jpg)

在后斯诺登时代，加密成为众所关注的了。越来越多的苹果产品正在强调其系统安全性。内置强大的加密机制并不让人感到意外。包括 APFS 在内，苹果正在采用更加细致入微的加密方案，要么不加密，要么就将加密进行到底。用户可以使用单个密钥来为所有数据加密，或者使用多个加密密钥分别锁定单个文件和文件夹。当然，你也可以不加密，只要你对坏蛋无所忌惮。

### 固态硬盘和闪存优化

![](/data/attachment/album/201611/02/101451kdd7r0u4t5z1ur7a.jpg)

闪存优化已经被列为 APFS 的一个亮点功能，不过它的实现并没有那么振奋人心。苹果选择将一些典型的固态硬盘芯片的处理功能迁移到操作系统，而没有深度系统集成的优势。这更像是让文件系统感知固态硬盘，而不是为它们做优化。

### 动态分区调整

![](/data/attachment/album/201611/02/101506abizvkdckpjbrkg4.jpg)

APFS 驱动器的逻辑分区可以动态调整自身大小。用户只需指定所需分区的数量，然后文件系统会在运行时进行磁盘分配。每个分区只占用其用于存储文件的磁盘空间。剩余的磁盘空间会由任何分区获取。这种设计很整洁，不过比起其它文件系统，这更像是元文件夹。

### 结论

这是否重要？对于开发者和高级用户来说真是棒极了。对于一般的 Mac 用户应该没有太多的外部差异。虽然升级是重大的举措，但仍然存在一些缺失的部分。本地压缩显然还没有，对用户数据进行的校验也没有。当然，2017 年还没到，一切皆有可能，让我们拭目以待。

---

编译自: <https://www.maketecheasier.com/apple-file-system-better-than-hfs/>

作者：[Alexander Fox](https://www.maketecheasier.com/author/alexfox-2-2-2/) 译者：[OneNewLife](https://github.com/OneNewLife) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


捐赠 Let's Encrypt，共建安全的互联网

Summary: 随着 Mozilla、苹果和谷歌对沃通和 StartCom 这两家 CA 公司处罚落定，很多使用这两家 CA 所签发证书的网站纷纷寻求新的证书签发商。有一个非盈利组织可以为大家提供了免费、可靠和安全的 SSL 证书服务，这就是 Let's Encrypt 项目。现在，它需要您的帮助

支持！ let's encrypt.

最近关于[沃通和 StartCom 这两家 CA 公司的消息](/article-7898-1.html)让人们再次关注到了网络隐私和安全的问题。随着 [Mozilla](/article-7814-1.html)、[苹果](/article-7846-1.html)和[谷歌](/article-7922-1.html)对这两家 CA 公司处罚落定，很多使用这两家 CA 所签发证书的网站纷纷寻求新的证书签发商。这里面固然有不少可信赖的 CA 公司可以提供服务，不过，有另外一个非盈利组织却为大家提供了免费、可靠和安全的 SSL 证书服务，这就是 [Let's Encrypt](/article-6565-1.html) 项目。

[Let's Encrypt](https://letsencrypt.org/) 项目是由<ruby> 互联网安全研究小组 <rt>  ISRG，Internet Security Research Group </rt></ruby>主导并开发的一个新型<ruby> 数字证书认证机构 <rt>  CA，Certificate Authority </rt></ruby>。该项目旨在开发一个自由且开放的自动化 CA 套件，并向公众提供相关的证书免费签发服务以降低安全通讯的财务、技术和教育成本。

![](/data/attachment/album/201611/02/221527wx3u6wq6md9kqxum.jpg)

**网站的完全加密是非常有必要的，这样每个人都可以随意在网上畅游而不用担心他们的活动被监视、拦截和修改。**

Let’s Encrypt 的做法与一般的 CA 服务商不同。他们为那些需要加密的网站提供了免费、易用的获取和管理证书的服务，而且在全球的每一个国家都可以使用。这些服务可以帮助人们或组织战胜来自经济、技术和培训方面的障碍，在互联网上安全地通讯。

![](/data/attachment/album/201611/02/222104lzdhzaf0zzd49bha.png)

仅仅在 Let’s Encrypt 运营了 10 个月之后，加密的页面数量就有了快速提升！这里面，Let’s Encrypt 项目居功甚伟，采用加密 Let’s Encrypt 的页面 90% 都是之前从未进行过加密的。

然而，互联网上还有超过一半的页面仍然没有加密。所以 Let’s Encrypt 还任重而道远，为了达成让互联网全都变成加密的这一目标，他们需要你的帮助！因此 Let’s Encrypt 在众筹网站 [generosity.com](https://www.generosity.com/community-fundraising/make-a-more-secure-web-with-let-s-encrypt) 上发起了众筹，募集更多的运营资金，以期做的更好！

如果您能捐助他们，您就为建立一个更安全的互联网埋下了一块基石。您所捐赠的每一块钱，都可以帮助 Let’s Encrypt 为所有用户创建一个尊重隐私的互联网体验。

他们划定了几个从 $25 到 $42000 不等的捐赠级别，并且为了感谢您的支持，会提供给您一些有趣的礼品以示谢意：

第一个级别 $25，您将收到一声感谢！

第二个级别 $50，您将收到一些精美的贴纸，可以贴在你的保险杠、水杯或者其它的什么地方。

![](/data/attachment/album/201611/02/222104wjdjd3jrdrhy323d.png)

第三个级别是 $100，他们叫这个“To Encryption and Beyond!”，礼品是这些漂亮的、合身的 T恤。

![](/data/attachment/album/201611/02/222105l44k42lcffc8p8ru.png)

如果您捐赠了 $250，您将同时收到 T 恤和贴纸。

更高额度的捐赠就不在这里一一列出了，富有爱心的土豪可以移步[这个众筹网站](https://www.generosity.com/community-fundraising/make-a-more-secure-web-with-let-s-encrypt)去看看。

如果您暂时手头比较紧张，你还有其它的几种方式支持：

* 分享这篇文章或其中的视频到你常用的社交媒体中。
* 转发这个的捐赠计划。
* 参与他们的社区论坛。
* 帮助他们找到 bug 以便可以修复它。

关于 Let's Encrypt 的更多信息，您可以访问其官网： <https://letsencrypt.org/> ；如何使用他们的服务，你可以参考[这篇文章](/article-6565-1.html)。


俄罗斯总统普京要把微软赶出俄国

Summary: 一个资深的美国情报来源告诉 NBC News，普京总统将停止使用微软产品当做优先要处理的工作，他认为这个软件巨头会直接参与到美国政府发起的间谍活动当中。

其实自主研发的感觉只要你用的不是自己的内核，而是linux，我感觉其实也不安全。说不定有后门没有被发现而已，其实什么都不安全

来自江苏南京的 Internet Explorer 11.0|Windows 7 用户

它不会和美国政府或其它的政府合作在其软件中注入后门，这点我相信是真的，因为它根本就全身后门，哪还需要专门注入？

这个是偏激了。

当一个软件上升到一定规模时，无论开源还是闭源，漏洞都是不可避免的。

即便是对于显示一句的 “Hello, world!"，也需要在底层硬件没有问题的情况下才能按预期执行。这还不说运行的平台，像当年任天堂的 GBA 上，要想在屏幕上显示这句话，并不是只写几句就能搞定。

软件可以有漏洞，但明知有漏洞却不及时打补丁就是耍流氓！！！

普京牛X啊

不要因为个人情感因素，说一些信口雌黄的话。要知道在俄罗斯，除了微软，苹果，谷歌这些都是目标。另外就安卓这块来说，虽然谷歌市场份额大，但是安全方面，还是很糟糕。再多说一句，即便俄罗斯要强推 Linux，尚未看到其推荐哪些著名的 Linux 发行版。

因为根本不可能推荐啊，主流发行版哪个是俄罗斯的？倒时候他们自己改一个出来给政府用呀

政府统一用libreoffice就好了

你太理想主义了

厉害了，普京。

当一个开源公司强大后，也会变质，如ubuntu有商业公司的影子，作为使用，我们只能不断的将目前使用的系统、软件更改为使用人数少的系统和软件

更改一下：作为使用者

windows只是个玩具吧

好样的，中国政府为什么还在推广臃肿的windows？学生或者政府招聘考试仍然考windows，中国真的造不出芯片吗？联发科不是中国的吗？

用linux内核又怎样，linux内核是开源的，如果这样都看不出内核中有没有后门，那程序员不如s了算了

MTK是台湾的2333我们一厢情愿

WangYueScream [Baidu Spark 8.6|Windows 7]

scd

俄罗斯已经计划通过支持本国的公司和软件来停止使用国外软件，但是最近有消息称普京总统计划加速这一进程，尽可能的快的停止使用微软的产品。

![](/data/attachment/album/201611/02/235432okw0nwzsskwtnwkj.jpg)

在普京看来，有很好的理由这样做：微软的软件可以被用来对它国做网络攻击，美国可以利用这些产品，比如 Windows 和 Office 来潜入到俄罗斯的系统当中。

[NBC News](http://www.nbcnews.com/nightly-news/video/exclusive-putin-targeting-microsoft-in-effort-to-nationalize-internet-798636099746?) 宣称他们从美国国土安全局得到的一份文件显示，去年俄罗斯黑客采用注入到微软 Office 文档中的木马软件中断了乌克兰电网的运行，所以普京总统担心美国利用类似的攻击来对俄罗斯发起攻击。

普京总统现在正在推行在政府和国企中停止使用外国软件，而采用可控的本国解决方案来免除间谍事件的困扰。

### 普京总统“专门”针对了微软

一个资深的美国情报来源告诉 [NBC News](http://www.nbcnews.com/nightly-news/video/exclusive-putin-targeting-microsoft-in-effort-to-nationalize-internet-798636099746?)，普京总统将停止使用微软产品当做优先要处理的工作，他认为这个软件巨头会直接参与到美国政府发起的间谍活动当中。

该内线人员说：“不仅仅是因为他们是 IT 领域最重要的美国公司，而且他们也是俄罗斯人普遍认为的美国情报机构的合作伙伴。”

微软已经解释了它不会参与任何间谍活动，并且明确说明了它不会和美国政府或其它的政府合作在其软件中注入后门。

微软的公共事务总经理 Dominic Carr 说：“我们不会秘密监视任何人，我们不会和任何政府合作监视其它政府，绝不会。”

不过，要摆脱微软的软件并不能一夜之间完成，特别是俄罗斯有着数以百万计的系统运行着 Windows 和 Office，但是该国的法律会强制政府机构和企业采用本地开发的软件来替代那些由外国公司所开发的软件。


如何在 Ubuntu 上使用 Grafana 监控 Docker

Grafana 是一个有着丰富指标的开源控制面板。在可视化大规模测量数据的时候是非常有用的。根据不同的指标数据，它提供了一个强大、优雅的来创建、分享和浏览数据的方式。

它提供了丰富多样、灵活的图形选项。此外，针对<ruby> 数据源 <rp>  （ </rp> <rt>  Data Source </rt> <rp>  ） </rp></ruby>，它支持许多不同的存储后端。每个数据源都有针对特定数据源的特性和功能所定制的查询编辑器。Grafana 提供了对下述数据源的正式支持：Graphite、InfluxDB、OpenTSDB、 Prometheus、Elasticsearch 和 Cloudwatch。

每个数据源的查询语言和能力显然是不同的，你可以将来自多个数据源的数据混合到一个单一的仪表盘上，但每个<ruby> 面板 <rp>  （ </rp> <rt>  Panel </rt> <rp>  ） </rp></ruby>被绑定到属于一个特定<ruby> 组织 <rp>  （ </rp> <rt>  Organization </rt> <rp>  ） </rp></ruby>的特定数据源上。它支持验证登录和基于角色的访问控制方案。它是作为一个独立软件部署，使用 Go 和 JavaScript 编写的。

![](/data/attachment/album/201611/03/095645ok0uehrwdehr4eeu.jpg)

在这篇文章，我将讲解如何在 Ubuntu 16.04 上安装 Grafana 并使用这个软件配置 Docker 监控。

### 先决条件

* 安装好 Docker 的服务器

### 安装 Grafana

我们可以在 Docker 中构建我们的 Grafana。 有一个官方提供的 Grafana Docker 镜像。请运行下述命令来构建Grafana 容器。

```
root@ubuntu:~# docker run -i -p 3000:3000 grafana/grafana

Unable to find image 'grafana/grafana:latest' locally
latest: Pulling from grafana/grafana
5c90d4a2d1a8: Pull complete
b1a9a0b6158e: Pull complete
acb23b0d58de: Pull complete
Digest: sha256:34ca2f9c7986cb2d115eea373083f7150a2b9b753210546d14477e2276074ae1
Status: Downloaded newer image for grafana/grafana:latest
t=2016-07-27T15:20:19+0000 lvl=info msg="Starting Grafana" logger=main version=3.1.0 commit=v3.1.0 compiled=2016-07-12T06:42:28+0000
t=2016-07-27T15:20:19+0000 lvl=info msg="Config loaded from" logger=settings file=/usr/share/grafana/conf/defaults.ini
t=2016-07-27T15:20:19+0000 lvl=info msg="Config loaded from" logger=settings file=/etc/grafana/grafana.ini
t=2016-07-27T15:20:19+0000 lvl=info msg="Config overriden from command line" logger=settings arg="default.paths.data=/var/lib/grafana"
t=2016-07-27T15:20:19+0000 lvl=info msg="Config overriden from command line" logger=settings arg="default.paths.logs=/var/log/grafana"
t=2016-07-27T15:20:19+0000 lvl=info msg="Config overriden from command line" logger=settings arg="default.paths.plugins=/var/lib/grafana/plugins"
t=2016-07-27T15:20:19+0000 lvl=info msg="Path Home" logger=settings path=/usr/share/grafana
t=2016-07-27T15:20:19+0000 lvl=info msg="Path Data" logger=settings path=/var/lib/grafana
t=2016-07-27T15:20:19+0000 lvl=info msg="Path Logs" logger=settings path=/var/log/grafana
t=2016-07-27T15:20:19+0000 lvl=info msg="Path Plugins" logger=settings path=/var/lib/grafana/plugins
t=2016-07-27T15:20:19+0000 lvl=info msg="Initializing DB" logger=sqlstore dbtype=sqlite3

t=2016-07-27T15:20:20+0000 lvl=info msg="Executing migration" logger=migrator id="create playlist table v2"
t=2016-07-27T15:20:20+0000 lvl=info msg="Executing migration" logger=migrator id="create playlist item table v2"
t=2016-07-27T15:20:20+0000 lvl=info msg="Executing migration" logger=migrator id="drop preferences table v2"
t=2016-07-27T15:20:20+0000 lvl=info msg="Executing migration" logger=migrator id="drop preferences table v3"
t=2016-07-27T15:20:20+0000 lvl=info msg="Executing migration" logger=migrator id="create preferences table v3"
t=2016-07-27T15:20:20+0000 lvl=info msg="Created default admin user: [admin]"
t=2016-07-27T15:20:20+0000 lvl=info msg="Starting plugin search" logger=plugins
t=2016-07-27T15:20:20+0000 lvl=info msg="Server Listening" logger=server address=0.0.0.0:3000 protocol=http subUrl=

```

我们可以通过运行此命令确认 Grafana 容器的工作状态 `docker ps -a` 或通过这个URL访问 `http://Docker IP:3000`。

所有的 Grafana 配置设置都使用环境变量定义，在使用容器技术时这个是非常有用的。Grafana 配置文件路径为 `/etc/grafana/grafana.ini`。

### 理解配置项

Grafana 可以在它的 ini 配置文件中指定几个配置选项，或可以使用前面提到的环境变量来指定。

#### 配置文件位置

通常配置文件路径：

* 默认配置文件路径 : `$WORKING_DIR/conf/defaults.ini`
* 自定义配置文件路径 : `$WORKING_DIR/conf/custom.ini`

PS：当你使用 deb、rpm 或 docker 镜像安装 Grafana 时，你的配置文件在 `/etc/grafana/grafana.ini`。

#### 理解配置变量

现在我们看一些配置文件中的变量：

* `instance_name`：这是 Grafana 服务器实例的名字。默认值从 `${HOSTNAME}` 获取，其值是环境变量`HOSTNAME`，如果该变量为空或不存在，Grafana 将会尝试使用系统调用来获取机器名。
* `[paths]`：这些路径通常都是在 init.d 脚本或 systemd service 文件中通过命令行指定。
	+ `data`：这个是 Grafana 存储 sqlite3 数据库（如果使用）、基于文件的会话（如果使用），和其他数据的路径。
	+ `logs`：这个是 Grafana 存储日志的路径。
* `[server]`
	+ `http_addr`：应用监听的 IP 地址，如果为空，则监听所有的接口。
	+ `http_port`：应用监听的端口，默认是 3000，你可以使用下面的命令将你的 80 端口重定向到 3000 端口：`$iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3000`
	+ `root_url` : 这个 URL 用于从浏览器访问 Grafana 。
	+ `cert_file` : 证书文件的路径（如果协议是 HTTPS）。
	+ `cert_key` : 证书密钥文件的路径（如果协议是 HTTPS）。
* `[database]`：Grafana 使用数据库来存储用户和仪表盘以及其他信息，默认配置为使用内嵌在 Grafana 主二进制文件中的 SQLite3。
	+ `type`：你可以根据你的需求选择 MySQL、Postgres、SQLite3。
	+ `path`：仅用于选择 SQLite3 数据库时，这个是数据库所存储的路径。
	+ `host`：仅适用 MySQL 或者 Postgres。它包括 IP 地址或主机名以及端口。例如，Grafana 和 MySQL 运行在同一台主机上设置如： `host = 127.0.0.1:3306`。
	+ `name`：Grafana 数据库的名称，把它设置为 Grafana 或其它名称。
	+ `user`：数据库用户（不适用于 SQLite3）。
	+ `password`：数据库用户密码（不适用于 SQLite3）。
	+ `ssl_mode`：对于 Postgres，使用 `disable`，`require`，或 `verify-full` 等值。对于 MySQL，使用 `true`，`false`，或 `skip-verify`。
	+ `ca_cert_path`：（只适用于 MySQL）CA 证书文件路径，在多数 Linux 系统中，证书可以在 `/etc/ssl/certs` 找到。
	+ `client_key_path`：（只适用于 MySQL）客户端密钥的路径，只在服务端需要用户端验证时使用。
	+ `client_cert_path`：（只适用于 MySQL）客户端证书的路径，只在服务端需要用户端验证时使用。
	+ `server_cert_name`：（只适用于 MySQL）MySQL 服务端使用的证书的通用名称字段。如果 `ssl_mode` 设置为 `skip-verify` 时可以不设置。
* `[security]`
	+ `admin_user`：这个是 Grafana 默认的管理员用户的用户名，默认设置为 admin。
	+ `admin_password`：这个是 Grafana 默认的管理员用户的密码，在第一次运行时设置，默认为 admin。
	+ `login_remember_days`：保持登录/记住我的持续天数。
	+ `secret_key`：用于保持登录/记住我的 cookies 的签名。

### 设置监控的重要组件

我们可以使用下面的组件来创建我们的 Docker 监控系统。

* `cAdvisor`：它被称为 Container Advisor。它给用户提供了一个资源利用和性能特征的解读。它会收集、聚合、处理、导出运行中的容器的信息。你可以通过[这个文档](https://github.com/google/cadvisor)了解更多。
* `InfluxDB`：这是一个包含了时间序列、度量和分析数据库。我们使用这个数据源来设置我们的监控。cAdvisor 只展示实时信息，并不保存这些度量信息。Influx Db 帮助保存 cAdvisor 提供的监控数据，以展示非某一时段的数据。
* `Grafana Dashboard`：它可以帮助我们在视觉上整合所有的信息。这个强大的仪表盘使我们能够针对 InfluxDB 数据存储进行查询并将他们放在一个布局合理好看的图表中。

### Docker 监控的安装

我们需要一步一步的在我们的 Docker 系统中安装以下每一个组件：

#### 安装 InfluxDB

我们可以使用这个命令来拉取 InfluxDB 镜像，并部署了 influxDB 容器。

```
root@ubuntu:~# docker run -d -p 8083:8083 -p 8086:8086 --expose 8090 --expose 8099 -e PRE_CREATE_DB=cadvisor --name influxsrv tutum/influxdb:0.8.8
Unable to find image 'tutum/influxdb:0.8.8' locally
0.8.8: Pulling from tutum/influxdb
a3ed95caeb02: Already exists
23efb549476f: Already exists
aa2f8df21433: Already exists
ef072d3c9b41: Already exists
c9f371853f28: Already exists
a248b0871c3c: Already exists
749db6d368d0: Already exists
7d7c7d923e63: Pull complete
e47cc7808961: Pull complete
1743b6eeb23f: Pull complete
Digest: sha256:8494b31289b4dbc1d5b444e344ab1dda3e18b07f80517c3f9aae7d18133c0c42
Status: Downloaded newer image for tutum/influxdb:0.8.8
d3b6f7789e0d1d01fa4e0aacdb636c221421107d1df96808ecbe8e241ceb1823

    -p 8083:8083 : user interface, log in with username-admin, pass-admin
    -p 8086:8086 : interaction with other application
    --name influxsrv : container have name influxsrv, use to cAdvisor link it.

```

你可以测试 InfluxDB 是否安装好，通过访问这个 URL `http://你的 IP 地址:8083`，用户名和密码都是 ”root“。

![InfluxDB Administration 2016-08-01 14-10-08](/data/attachment/album/201611/03/095728jjvtvuvvrluckvjb.png)

我们可以在这个界面上创建我们所需的数据库。

![createDB influx](/data/attachment/album/201611/03/095729gcgzg7jboivgjo7b.png)

#### 安装 cAdvisor

我们的下一个步骤是安装 cAdvisor 容器，并将其链接到 InfluxDB 容器。你可以使用此命令来创建它。

```
root@ubuntu:~# docker run --volume=/:/rootfs:ro --volume=/var/run:/var/run:rw --volume=/sys:/sys:ro --volume=/var/lib/docker/:/var/lib/docker:ro --publish=8080:8080 --detach=true --link influxsrv:influxsrv --name=cadvisor google/cadvisor:latest -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
Unable to find image 'google/cadvisor:latest' locally
latest: Pulling from google/cadvisor
09d0220f4043: Pull complete
151807d34af9: Pull complete
14cd28dce332: Pull complete
Digest: sha256:8364c7ab7f56a087b757a304f9376c3527c8c60c848f82b66dd728980222bd2f
Status: Downloaded newer image for google/cadvisor:latest
3bfdf7fdc83872485acb06666a686719983a1172ac49895cd2a260deb1cdde29
root@ubuntu:~#

    --publish=8080:8080 : user interface
    --link=influxsrv:influxsrv: link to container influxsrv
    -storage_driver=influxdb: set the storage driver as InfluxDB
    Specify what InfluxDB instance to push data to:
    -storage_driver_host=influxsrv:8086: The ip:port of the database. Default is ‘localhost:8086’
    -storage_driver_db=cadvisor: database name. Uses db ‘cadvisor’ by default

```

你可以通过访问这个地址来测试安装 cAdvisor 是否正常 `http://你的 IP 地址:8080`。 这将为你的 Docker 主机和容器提供统计信息。

![cAdvisor - Docker Containers 2016-08-01 14-24-18](/data/attachment/album/201611/03/095730mc4y0lb3qjiv6y4v.png)

#### 安装 Grafana 控制面板

最后，我们需要安装 Grafana 仪表板并连接到 InfluxDB，你可以执行下面的命令来设置它。

```
root@ubuntu:~# docker run -d -p 3000:3000 -e INFLUXDB_HOST=localhost -e INFLUXDB_PORT=8086 -e INFLUXDB_NAME=cadvisor -e INFLUXDB_USER=root -e INFLUXDB_PASS=root --link influxsrv:influxsrv --name grafana grafana/grafana
f3b7598529202b110e4e6b998dca6b6e60e8608d75dcfe0d2b09ae408f43684a

```

现在我们可以登录 Grafana 来配置数据源. 访问 `http://你的 IP 地址:3000` 或 `http://你的 IP 地址`（如果你在前面做了端口映射的话）:

* 用户名 - admin
* 密码 - admin

一旦我们安装好了 Grafana，我们可以连接 InfluxDB。登录到仪表盘并且点击面板左上方角落的 Grafana 图标（那个火球）。点击<ruby> 数据源 <rp>  （ </rp> <rt>  Data Sources </rt> <rp>  ） </rp></ruby>来配置。

![addingdatabsource](/data/attachment/album/201611/03/095731jo3nll2p1ssk5lnb.png)

现在你可以添加新的<ruby> 图形 <rp>  （ </rp> <rt>  Graph </rt> <rp>  ） </rp></ruby>到我们默认的数据源 InfluxDB。

![panelgraph](/data/attachment/album/201611/03/095732i9ht99q6ey8j19ri.png)

我们可以通过在<ruby> 测量 <rp>  （ </rp> <rt>  Metric </rt> <rp>  ） </rp></ruby>页面编辑和调整我们的查询以调整我们的图形。

![Grafana - Grafana Dashboard 2016-08-01 14-53-40](/data/attachment/album/201611/03/095732mx2zoifp1ptop2oo.png)

![Grafana - Grafana Dashboard](/data/attachment/album/201611/03/095733qitcr9bzi77up599.png)

关于 Docker 监控，你可用[从此了解](https://github.com/vegasbrianc/docker-monitoring)更多信息。 感谢你的阅读。我希望你可以留下有价值的建议和评论。希望你有个美好的一天。

---

via: <http://linoxide.com/linux-how-to/monitor-docker-containers-grafana-ubuntu/>

作者：[Saheetha Shameer](http://linoxide.com/author/saheethas/) 译者：[Bestony](https://github.com/bestony) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


两款免费的 Linux 桌面录制工具：SimpleScreenRecorder 和 Kazam

Summary: 桌面录制工具可以帮做我们快速高效的制作教学视频和在线示范。

linuxmint！！！编辑用的系统还蛮多啊！

感觉simplescreenrecorder还不错

再推荐一个gome shell的录频扩展 easy screen cast  (arch用户可在aur中搜索安装)

simplescreenrecorder是不错

桌面录制工具可以帮做我们快速高效的制作教学视频和在线示范。

>
> 桌面录制工具可以帮做我们快速高效的制作教学视频和在线示范。
>
>
>

一图胜千言，但一段视频演示则可以让你不用大费口舌。我是一个“视觉学习者”，亲眼目睹一件事情的发生对我的学习大有裨益。我也曾观察发现，如果学生实际看到应用程序的设置流程或者代码的编写过程，他们就能从中受益良多。所以，录屏工具是制作教学视频的绝佳工具。在本文中我将介绍一下两款开源桌面录制工具： [SimpleScreenRecorder](http://www.maartenbaert.be/simplescreenrecorder/) 和 [Kazam](https://launchpad.net/kazam)。

![](/data/attachment/album/201611/03/212608b9y7m77l7q7fxws9.png)

### SimpleScreenRecorder

使用 SimpleScreenRecorder 能够轻松录制桌面动作，它拥有直观的用户界面以及多样的编码方式，如 MP4、OGG、[Matroska](https://www.matroska.org/technical/whatis/index.html) 或 [WebM](https://www.webmproject.org/) 格式。 SimpleScreenRecorder 遵从 GPL 协议发行，运行在 Linux 上。

在安装运行 SimpleScreenRecorder 后，你可以轻松选择录制整个桌面、指定窗口或者一个自定义的区域。我比较偏爱最后这种方式，因为这样我可以使我的学生把注意力集中在我想让他们注意的地方。你还可以在设置中选择是否隐藏光标、调整录制帧率（默认帧率为 30fps）、视频压缩比例或者调整音频后端（如 ALSA、JACK 或 PusleAudio）。

由于 SimpleScreenRecorder 使用了 libav/ffmpeg 库进行编码，故而支持多种文件格式和视频编码方式。可以使用不同的配置文件（编码更快的配置文件意味着更大的体积），包括 YouTube 和 1000kbps – 3000kbps 的 LiveStream。

![simplescreencast screenshot](/data/attachment/album/201611/03/213725q55q593xq3qrjr33.png)

![simplescreencast screenshot](/data/attachment/album/201611/03/213726hykatz1akzukguab.png)

配置完毕后，单击“开始录制”按钮或者使用自定义的快捷键就可以轻松开始录制屏幕啦~

![simplescreencast screenshot](/data/attachment/album/201611/03/213727wgog8yfctd0e384g.png)

你还能在设置中开启提示音功能，它会开始录制和录制结束时给你声音的提示。屏幕录制完成后，你可以对视频文件进行编辑或者直接上传到 YouTube、Vimeo 等视频网站上。

SimpleScreenRecorder 的[官方网站](http://www.maartenbaert.be/simplescreenrecorder/)上还有大量说明文档，其中包括设置、录制、上传等方面的帮助手册和针对多种Linux发行版的安装说明。

### Kazam

Kazam 桌面录制工具同样是遵循 GPL 协议的软件。同时和 SimpleScreenRecorder 一样，Kazam 易于上手，界面直观。安装运行 Kazam 之后，你可以设置选择录制整个桌面、指定窗口或是一个自定义的区域。(LCTT 译注：关于自定义区域录制一部分的内容与 SimpleScreenRecorder 介绍中的内容基本相似，略过) ，你还可以选择记录鼠标的移动轨迹。我最中意 Kazam 的一点是延时录制的功能，这在制作视频教程的时候必不可少。

在“文件|设置”菜单下可以轻松对 Kazam 进行个性化设置，比如可以选择扬声器或是麦克风中的音源、关闭倒计时提示等等。

![kazam screenshot](/data/attachment/album/201611/03/213728jeqrgxieffhfi1ce.png)

在设置页的第二个选项卡中可以进行视频录制设置。Kazam 默认录制帧率为 15fps，编码格式为 H264（MP4）。其它可供选择的格式有 VP8(WEBM)、HUFFYUV、Lossless JPEG 以及 RAW AVI。录制好的文件会以附加一个预设的前缀来命名，并自动保存在默认目录下，你可以随时修改这些设置。

![kazam screenshot](/data/attachment/album/201611/03/213730yof10izh1qqkxxnf.png)

设置屏幕截图同样很简单。你可以选择 Nikon D80 或 Canon 7D 的快门音效，也可以干脆关掉他们。截图文件是自动存放的。除非你关闭这一功能。

![](/data/attachment/album/201611/03/213732n1ppk2xola49fxh3.png)

录制好的视频将会存储在你选定的目录下，随时可以上传到你喜欢的视频分享网站或是教程网站上。

是时候利用 Linux 和录屏工具让你的课堂焕然一新了！如果你还有其他的屏幕录制工具或是使用技巧，记得在评论里与我交流哦~

### 赠品：Kap

前面提到两款软件都是 Linux 下的屏幕录制软件，这里还有一款是 Mac 下的开源录屏软件推荐给大家： [Kap](https://getkap.co/)。它是使用 Web 技术（Node.js）构建的，以 MIT 协议开源在 [GitHub](https://github.com/wulkano/kap) 上。

![](/data/attachment/album/201611/03/213133r4r5feax3roaefu3.jpg)

你可以[直接下载 dmg 镜像](https://getkap.co/download)安装（300M），也可以使用 `brew` 从 Homebrew Cask 安装：

```
$ brew update
$ brew cask install kap
```

如果你使用 Mac，不妨一试，也欢迎你对这个项目提交贡献。

---

via: <https://opensource.com/education/16/10/simplescreenrecorder-and-kazam>

作者：[Don Watkins](https://opensource.com/users/don-watkins) 译者：[HaohongWANG](https://github.com/HaohongWANG) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


C++ 程序员 Protocol Buffers 基础指南

Summary: 如何序列化和获取结构化的数据？Protocol buffers 是针对这个问题的一种灵活、高效、自动化的解决方案。

好久没见 C++ 的美文了

好文！费心了！

这篇教程提供了一个面向 C++ 程序员关于 protocol buffers 的基础介绍。通过创建一个简单的示例应用程序，它将向我们展示：

* 在 `.proto` 文件中定义消息格式
* 使用 protocol buffer 编译器
* 使用 C++ protocol buffer API 读写消息

这不是一个关于在 C++ 中使用 protocol buffers 的全面指南。要获取更详细的信息，请参考 [Protocol Buffer Language Guide](https://developers.google.com/protocol-buffers/docs/proto) 和 [Encoding Reference](https://developers.google.com/protocol-buffers/docs/encoding)。

### 为什么使用 Protocol Buffers

我们接下来要使用的例子是一个非常简单的"地址簿"应用程序，它能从文件中读取联系人详细信息。地址簿中的每一个人都有一个名字、ID、邮件地址和联系电话。

如何序列化和获取结构化的数据？这里有几种解决方案：

* 以二进制形式发送/接收原生的内存数据结构。通常，这是一种脆弱的方法，因为接收/读取代码必须基于完全相同的内存布局、大小端等环境进行编译。同时，当文件增加时，原始格式数据会随着与该格式相关的软件而迅速扩散，这将导致很难扩展文件格式。
* 你可以创造一种 ad-hoc 方法，将数据项编码为一个字符串——比如将 4 个整数编码为 `12:3:-23:67`。虽然它需要编写一次性的编码和解码代码且解码需要耗费一点运行时成本，但这是一种简单灵活的方法。这最适合编码非常简单的数据。
* 序列化数据为 XML。这种方法是非常吸引人的，因为 XML 是一种适合人阅读的格式，并且有为许多语言开发的库。如果你想与其他程序和项目共享数据，这可能是一种不错的选择。然而，众所周知，XML 是空间密集型的，且在编码和解码时，它对程序会造成巨大的性能损失。同时，使用 XML DOM 树被认为比操作一个类的简单字段更加复杂。

Protocol buffers 是针对这个问题的一种灵活、高效、自动化的解决方案。使用 Protocol buffers，你需要写一个 `.proto` 说明，用于描述你所希望存储的数据结构。利用 `.proto` 文件，protocol buffer 编译器可以创建一个类，用于实现对高效的二进制格式的 protocol buffer 数据的自动化编码和解码。产生的类提供了构造 protocol buffer 的字段的 getters 和 setters，并且作为一个单元来处理读写 protocol buffer 的细节。重要的是，protocol buffer 格式支持格式的扩展，代码仍然可以读取以旧格式编码的数据。

![](/data/attachment/album/201611/03/235451klrr358u5pz8trxu.png)

### 在哪可以找到示例代码

示例代码被包含于源代码包，位于“examples”文件夹。可在[这里](https://developers.google.com/protocol-buffers/docs/downloads.html)下载代码。

### 定义你的协议格式

为了创建自己的地址簿应用程序，你需要从 `.proto` 开始。`.proto` 文件中的定义很简单：为你所需要序列化的每个数据结构添加一个<ruby> 消息 <rp>  （ </rp> <rt>  message </rt> <rp>  ） </rp></ruby>，然后为消息中的每一个字段指定一个名字和类型。这里是定义你消息的 `.proto` 文件 `addressbook.proto`。

```
package tutorial;

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

message AddressBook {
  repeated Person person = 1;
}

```

如你所见，其语法类似于 C++ 或 Java。我们开始看看文件的每一部分内容做了什么。

`.proto` 文件以一个 `package` 声明开始，这可以避免不同项目的命名冲突。在 C++，你生成的类会被置于与 `package` 名字一样的命名空间。

下一步，你需要定义<ruby> 消息 <rp>  （ </rp> <rt>  message </rt> <rp>  ） </rp></ruby>。消息只是一个包含一系列类型字段的集合。大多标准的简单数据类型是可以作为字段类型的，包括 `bool`、`int32`、`float`、`double` 和 `string`。你也可以通过使用其他消息类型作为字段类型，将更多的数据结构添加到你的消息中——在以上的示例，`Person` 消息包含了 `PhoneNumber` 消息，同时 `AddressBook` 消息包含 `Person` 消息。你甚至可以定义嵌套在其他消息内的消息类型——如你所见，`PhoneNumber` 类型定义于 `Person` 内部。如果你想要其中某一个字段的值是预定义值列表中的某个值，你也可以定义 `enum` 类型——这儿你可以指定一个电话号码是 `MOBILE`、`HOME` 或 `WORK` 中的某一个。

每一个元素上的 `= 1`、`= 2` 标记确定了用于二进制编码的唯一<ruby> “标签” <rp>  （ </rp> <rt>  tag </rt> <rp>  ） </rp></ruby>。标签数字 1-15 的编码比更大的数字少需要一个字节，因此作为一种优化，你可以将这些标签用于经常使用的元素或 `repeated` 元素，剩下 16 以及更高的标签用于非经常使用的元素或 `optional` 元素。每一个 `repeated` 字段的元素需要重新编码标签数字，因此 `repeated` 字段适合于使用这种优化手段。

每一个字段必须使用下面的修饰符加以标注：

* `required`：必须提供该字段的值，否则消息会被认为是<ruby> “未初始化的” <rp>  （ </rp> <rt>  uninitialized </rt> <rp>  ） </rp></ruby>。如果 `libprotobuf` 以调试模式编译，序列化未初始化的消息将引起一个断言失败。以优化形式构建，将会跳过检查，并且无论如何都会写入该消息。然而，解析未初始化的消息总是会失败（通过 `parse` 方法返回 `false`）。除此之外，一个 `required` 字段的表现与 `optional` 字段完全一样。
* `optional`：字段可能会被设置，也可能不会。如果一个 `optional` 字段没被设置，它将使用默认值。对于简单类型，你可以指定你自己的默认值，正如例子中我们对电话号码的 `type` 一样，否则使用系统默认值：数字类型为 0、字符串为空字符串、布尔值为 false。对于嵌套消息，默认值总为消息的“默认实例”或“原型”，它的所有字段都没被设置。调用 accessor 来获取一个没有显式设置的 `optional`（或 `required`） 字段的值总是返回字段的默认值。
* `repeated`：字段可以重复任意次数（包括 0 次）。`repeated` 值的顺序会被保存于 protocol buffer。可以将 `repeated` 字段想象为动态大小的数组。

你可以查找关于编写 `.proto` 文件的完整指导——包括所有可能的字段类型——在 [Protocol Buffer Language Guide](https://developers.google.com/protocol-buffers/docs/proto) 里面。不要在这里面查找与类继承相似的特性，因为 protocol buffers 不会做这些。

>
> **`required` 是永久性的**
>
>
> 在把一个字段标识为 `required` 的时候，你应该特别小心。如果在某些情况下你不想写入或者发送一个 `required` 的字段，那么将该字段更改为 `optional` 可能会遇到问题——旧版本的读者（LCTT 译注：即读取、解析旧版本 Protocol Buffer 消息的一方）会认为不含该字段的消息是不完整的，从而有可能会拒绝解析。在这种情况下，你应该考虑编写特别针对于应用程序的、自定义的消息校验函数。Google 的一些工程师得出了一个结论：使用 `required` 弊多于利；他们更愿意使用 `optional` 和 `repeated` 而不是 `required`。当然，这个观点并不具有普遍性。
>
>
>

### 编译你的 Protocol Buffers

既然你有了一个 `.proto`，那你需要做的下一件事就是生成一个将用于读写 `AddressBook` 消息的类（从而包括 `Person` 和 `PhoneNumber`）。为了做到这样，你需要在你的 `.proto` 上运行 protocol buffer 编译器 `protoc`：

1. 如果你没有安装编译器，请[下载这个包](https://developers.google.com/protocol-buffers/docs/downloads.html)，并按照 README 中的指令进行安装。
2. 现在运行编译器，指定源目录（你的应用程序源代码位于哪里——如果你没有提供任何值，将使用当前目录）、目标目录（你想要生成的代码放在哪里；常与 `$SRC_DIR` 相同），以及你的 `.proto` 路径。在此示例中：

```
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

```

因为你想要 C++ 的类，所以你使用了 `--cpp_out` 选项——也为其他支持的语言提供了类似选项。

在你指定的目标文件夹，将生成以下的文件：

* `addressbook.pb.h`，声明你生成类的头文件。
* `addressbook.pb.cc`，包含你的类的实现。

### Protocol Buffer API

让我们看看生成的一些代码，了解一下编译器为你创建了什么类和函数。如果你查看 `addressbook.pb.h`，你可以看到有一个在 `addressbook.proto` 中指定所有消息的类。关注 `Person` 类，可以看到编译器为每个字段生成了<ruby> 读写函数 <rp>  （ </rp> <rt>  accessors </rt> <rp>  ） </rp></ruby>。例如，对于 `name`、`id`、`email` 和 `phone` 字段，有下面这些方法：（LCTT 译注：此处原文所指文件名有误，径该之。）

```
// name
inline bool has_name() const;
inline void clear_name();
inline const ::std::string& name() const;
inline void set_name(const ::std::string& value);
inline void set_name(const char* value);
inline ::std::string* mutable_name();

// id
inline bool has_id() const;
inline void clear_id();
inline int32_t id() const;
inline void set_id(int32_t value);

// email
inline bool has_email() const;
inline void clear_email();
inline const ::std::string& email() const;
inline void set_email(const ::std::string& value);
inline void set_email(const char* value);
inline ::std::string* mutable_email();

// phone
inline int phone_size() const;
inline void clear_phone();
inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phone() const;
inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phone();
inline const ::tutorial::Person_PhoneNumber& phone(int index) const;
inline ::tutorial::Person_PhoneNumber* mutable_phone(int index);
inline ::tutorial::Person_PhoneNumber* add_phone();

```

正如你所见到，getters 的名字与字段的小写名字完全一样，并且 setter 方法以 `set_` 开头。同时每个<ruby> 单一 <rp>  （ </rp> <rt>  singular </rt> <rp>  ） </rp></ruby>（`required` 或 `optional`）字段都有 `has_` 方法，该方法在字段被设置了值的情况下返回 true。最后，所有字段都有一个 `clear_` 方法，用以清除字段到<ruby> 空 <rp>  （ </rp> <rt>  empty </rt> <rp>  ） </rp></ruby>状态。

数字型的 `id` 字段仅有上述的基本<ruby> 读写函数 <rp>  （ </rp> <rt>  accessors </rt> <rp>  ） </rp></ruby>集合，而 `name` 和 `email` 字段有两个额外的方法，因为它们是字符串——一个是可以获得字符串直接指针的`mutable_` 的 getter ，另一个为额外的 setter。注意，尽管 `email` 还没被<ruby> 设置 <rp>  （ </rp> <rt>  set </rt> <rp>  ） </rp></ruby>，你也可以调用 `mutable_email`；因为 `email` 会被自动地初始化为空字符串。在本例中，如果你有一个单一的（`required` 或 `optional`）消息字段，它会有一个 `mutable_` 方法，而没有 `set_` 方法。

`repeated` 字段也有一些特殊的方法——如果你看看 `repeated` 的 `phone` 字段的方法，你可以看到：

* 检查 `repeated` 字段的 `_size`（也就是说，与 `Person` 相关的电话号码的个数）
* 使用下标取得特定的电话号码
* 更新特定下标的电话号码
* 添加新的电话号码到消息中，之后你便可以编辑。（`repeated` 标量类型有一个 `add_` 方法，用于传入新的值）

为了获取 protocol 编译器为所有字段定义生成的方法的信息，可以查看 [C++ generated code reference](https://developers.google.com/protocol-buffers/docs/reference/cpp-generated)。

#### 枚举和嵌套类

与 `.proto` 的枚举相对应，生成的代码包含了一个 `PhoneType` 枚举。你可以通过 `Person::PhoneType` 引用这个类型，通过 `Person::MOBILE`、`Person::HOME` 和 `Person::WORK` 引用它的值。（实现细节有点复杂，但是你无须了解它们而可以直接使用）

编译器也生成了一个 `Person::PhoneNumber` 的嵌套类。如果你查看代码，你可以发现真正的类型为 `Person_PhoneNumber`，但它通过在 `Person` 内部使用 `typedef` 定义，使你可以把 `Person_PhoneNumber` 当成嵌套类。唯一产生影响的一个例子是，如果你想要在其他文件前置声明该类——在 C++ 中你不能前置声明嵌套类，但是你可以前置声明 `Person_PhoneNumber`。

#### 标准的消息方法

所有的消息方法都包含了许多别的方法，用于检查和操作整个消息，包括：

* `bool IsInitialized() const;` ：检查是否所有 `required` 字段已经被设置。
* `string DebugString() const;` ：返回人类可读的消息表示，对调试特别有用。
* `void CopyFrom(const Person& from);`：使用给定的值重写消息。
* `void Clear();`：清除所有元素为空的状态。

上面这些方法以及下一节要讲的 I/O 方法实现了被所有 C++ protocol buffer 类共享的<ruby> 消息 <rp>  （ </rp> <rt>  Message </rt> <rp>  ） </rp></ruby>接口。为了获取更多信息，请查看 [complete API documentation for Message](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message.html#Message)。

#### 解析和序列化

最后，所有 protocol buffer 类都有读写你选定类型消息的方法，这些方法使用了特定的 protocol buffer [二进制格式](https://developers.google.com/protocol-buffers/docs/encoding)。这些方法包括：

* `bool SerializeToString(string* output) const;`：序列化消息并将消息字节数据存储在给定的字符串中。注意，字节数据是二进制格式的，而不是文本格式；我们只使用 `string` 类作为合适的容器。
* `bool ParseFromString(const string& data);`：从给定的字符创解析消息。
* `bool SerializeToOstream(ostream* output) const;`：将消息写到给定的 C++ `ostream`。
* `bool ParseFromIstream(istream* input);`：从给定的 C++ `istream` 解析消息。

这些只是两个用于解析和序列化的选择。再次说明，可以查看 `Message API reference` 完整的列表。

>
> **Protocol Buffers 和面向对象设计**
>
>
> Protocol buffer 类通常只是纯粹的数据存储器（像 C++ 中的结构体）；它们在对象模型中并不是一等公民。如果你想向生成的 protocol buffer 类中添加更丰富的行为，最好的方法就是在应用程序中对它进行封装。如果你无权控制 `.proto` 文件的设计的话，封装 protocol buffers 也是一个好主意（例如，你从另一个项目中重用一个 `.proto` 文件）。在那种情况下，你可以用封装类来设计接口，以更好地适应你的应用程序的特定环境：隐藏一些数据和方法，暴露一些便于使用的函数，等等。**但是你绝对不要通过继承生成的类来添加行为。**这样做的话，会破坏其内部机制，并且不是一个好的面向对象的实践。
>
>
>

### 写消息

现在我们尝试使用 protocol buffer 类。你的地址簿程序想要做的第一件事是将个人详细信息写入到地址簿文件。为了做到这一点，你需要创建、填充 protocol buffer 类实例，并且将它们写入到一个<ruby> 输出流 <rp>  （ </rp> <rt>  output stream </rt> <rp>  ） </rp></ruby>。

这里的程序可以从文件读取 `AddressBook`，根据用户输入，将新 `Person` 添加到 `AddressBook`，并且再次将新的 `AddressBook` 写回文件。这部分直接调用或引用 protocol buffer 类的代码会以“`// pb`”标出。

```
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h" // pb
using namespace std;

// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
  cout << "Enter person ID number: ";
  int id;
  cin >> id;
  person->set_id(id);   // pb
  cin.ignore(256, '\n');

  cout << "Enter name: ";
  getline(cin, *person->mutable_name());    // pb

  cout << "Enter email address (blank for none): ";
  string email;
  getline(cin, email);
  if (!email.empty()) { // pb
    person->set_email(email);   // pb
  }

  while (true) {
    cout << "Enter a phone number (or leave blank to finish): ";
    string number;
    getline(cin, number);
    if (number.empty()) {
      break;
    }

    tutorial::Person::PhoneNumber* phone_number = person->add_phone();  //pb
    phone_number->set_number(number);   // pb

    cout << "Is this a mobile, home, or work phone? ";
    string type;
    getline(cin, type);
    if (type == "mobile") {
      phone_number->set_type(tutorial::Person::MOBILE); // pb
    } else if (type == "home") {
      phone_number->set_type(tutorial::Person::HOME);   // pb
    } else if (type == "work") {
      phone_number->set_type(tutorial::Person::WORK);   // pb
    } else {
      cout << "Unknown phone type.  Using default." << endl;
    }
  }
}

// Main function:  Reads the entire address book from a file,
//   adds one person based on user input, then writes it back out to the same
//   file.
int main(int argc, char* argv[]) {
  // Verify that the version of the library that we linked against is
  // compatible with the version of the headers we compiled against.
  GOOGLE_PROTOBUF_VERIFY_VERSION;   // pb

  if (argc != 2) {
    cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
    return -1;
  }

  tutorial::AddressBook address_book;   // pb

  {
    // Read the existing address book.
    fstream input(argv[1], ios::in | ios::binary);
    if (!input) {
      cout << argv[1] << ": File not found.  Creating a new file." << endl;
    } else if (!address_book.ParseFromIstream(&input)) {    // pb
      cerr << "Failed to parse address book." << endl;
      return -1;
    }
  }

  // Add an address.
  PromptForAddress(address_book.add_person());  // pb

  {
    // Write the new address book back to disk.
    fstream output(argv[1], ios::out | ios::trunc | ios::binary);
    if (!address_book.SerializeToOstream(&output)) {    // pb
      cerr << "Failed to write address book." << endl;
      return -1;
    }
  }

  // Optional:  Delete all global objects allocated by libprotobuf.
  google::protobuf::ShutdownProtobufLibrary();  // pb

  return 0;
}

```

注意 `GOOGLE_PROTOBUF_VERIFY_VERSION` 宏。它是一种好的实践——虽然不是严格必须的——在使用 C++ Protocol Buffer 库之前执行该宏。它可以保证避免不小心链接到一个与编译的头文件版本不兼容的库版本。如果被检查出来版本不匹配，程序将会终止。注意，每个 `.pb.cc` 文件在初始化时会自动调用这个宏。

同时注意在程序最后调用 `ShutdownProtobufLibrary()`。它用于释放 Protocol Buffer 库申请的所有全局对象。对大部分程序，这不是必须的，因为虽然程序只是简单退出，但是 OS 会处理释放程序的所有内存。然而，如果你使用了内存泄漏检测工具，工具要求全部对象都要释放，或者你正在写一个 Protocol Buffer 库，该库可能会被一个进程多次加载和卸载，那么你可能需要强制 Protocol Buffer 清除所有东西。

### 读取消息

当然，如果你无法从它获取任何信息，那么这个地址簿没多大用处！这个示例读取上面例子创建的文件，并打印文件里的所有内容。

```
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h" // pb
using namespace std;

// Iterates though all people in the AddressBook and prints info about them.
void ListPeople(const tutorial::AddressBook& address_book) {    // pb
  for (int i = 0; i < address_book.person_size(); i++) {        // pb
    const tutorial::Person& person = address_book.person(i);    // pb

    cout << "Person ID: " << person.id() << endl;   // pb
    cout << "  Name: " << person.name() << endl;    // pb
    if (person.has_email()) {   // pb
      cout << "  E-mail address: " << person.email() << endl;   // pb
    }

    for (int j = 0; j < person.phone_size(); j++) { // pb
      const tutorial::Person::PhoneNumber& phone_number = person.phone(j);  // pb

      switch (phone_number.type()) {    // pb
        case tutorial::Person::MOBILE:  // pb
          cout << "  Mobile phone #: ";
          break;
        case tutorial::Person::HOME:    // pb
          cout << "  Home phone #: ";
          break;
        case tutorial::Person::WORK:    // pb
          cout << "  Work phone #: ";
          break;
      }
      cout << phone_number.number() << endl;    // ob
    }
  }
}

// Main function:  Reads the entire address book from a file and prints all
//   the information inside.
int main(int argc, char* argv[]) {
  // Verify that the version of the library that we linked against is
  // compatible with the version of the headers we compiled against.
  GOOGLE_PROTOBUF_VERIFY_VERSION;   // pb

  if (argc != 2) {
    cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
    return -1;
  }

  tutorial::AddressBook address_book;   // pb

  {
    // Read the existing address book.
    fstream input(argv[1], ios::in | ios::binary);
    if (!address_book.ParseFromIstream(&input)) {   // pb
      cerr << "Failed to parse address book." << endl;
      return -1;
    }
  }

  ListPeople(address_book);

  // Optional:  Delete all global objects allocated by libprotobuf.
  google::protobuf::ShutdownProtobufLibrary();  // pb

  return 0;
}

```

### 扩展 Protocol Buffer

或早或晚在你发布了使用 protocol buffer 的代码之后，毫无疑问，你会想要 "改善" protocol buffer 的定义。如果你想要新的 buffers 向后兼容，并且老的 buffers 向前兼容——几乎可以肯定你很渴望这个——这里有一些规则，你需要遵守。在新的 protocol buffer 版本：

* 你绝不可以修改任何已存在字段的标签数字
* 你绝不可以添加或删除任何 `required` 字段
* 你可以删除 `optional` 或 `repeated` 字段
* 你可以添加新的 `optional` 或 `repeated` 字段，但是你必须使用新的标签数字（也就是说，标签数字在 protocol buffer 中从未使用过，甚至不能是已删除字段的标签数字）。

（对于上面规则有一些[例外情况](https://developers.google.com/protocol-buffers/docs/proto#updating)，但它们很少用到。）

如果你能遵守这些规则，旧代码则可以欢快地读取新的消息，并且简单地忽略所有新的字段。对于旧代码来说，被删除的 `optional` 字段将会简单地赋予默认值，被删除的 `repeated` 字段会为空。新代码显然可以读取旧消息。然而，请记住新的 `optional` 字段不会呈现在旧消息中，因此你需要显式地使用 `has_` 检查它们是否被设置或者在 `.proto` 文件在标签数字后使用 `[default = value]` 提供一个合理的默认值。如果一个 `optional` 元素没有指定默认值，它将会使用类型特定的默认值：对于字符串，默认值为空字符串；对于布尔值，默认值为 false；对于数字类型，默认类型为 0。注意，如果你添加一个新的 `repeated` 字段，新代码将无法辨别它被留空（被新代码）或者从没被设置（被旧代码），因为 `repeated` 字段没有 `has_` 标志。

### 优化技巧

C++ Protocol Buffer 库已极度优化过了。但是，恰当的用法能够更多地提高性能。这里是一些技巧，可以帮你从库中挤压出最后一点速度：

* 尽可能复用消息对象。即使它们被清除掉，消息也会尽量保存所有被分配来重用的内存。因此，如果我们正在处理许多相同类型或一系列相似结构的消息，一个好的办法是重用相同的消息对象，从而减少内存分配的负担。但是，随着时间的流逝，对象可能会膨胀变大，尤其是当你的消息尺寸（LCTT 译注：各消息内容不同，有些消息内容多一些，有些消息内容少一些）不同的时候，或者你偶尔创建了一个比平常大很多的消息的时候。你应该自己通过调用 [SpaceUsed](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message.html#Message.SpaceUsed.details) 方法监测消息对象的大小，并在它太大的时候删除它。
* 对于在多线程中分配大量小对象的情况，你的操作系统内存分配器可能优化得不够好。你可以尝试使用 google 的 [tcmalloc](http://code.google.com/p/google-perftools/)。

### 高级用法

Protocol Buffers 绝不仅用于简单的数据存取以及序列化。请阅读 [C++ API reference](https://developers.google.com/protocol-buffers/docs/reference/cpp/index.html) 来看看你还能用它来做什么。

protocol 消息类所提供的一个关键特性就是<ruby> 反射 <rp>  （ </rp> <rt>  reflection </rt> <rp>  ） </rp></ruby>。你不需要针对一个特殊的消息类型编写代码，就可以遍历一个消息的字段并操作它们的值。一个使用反射的有用方法是 protocol 消息与其他编码互相转换，比如 XML 或 JSON。反射的一个更高级的用法可能就是可以找出两个相同类型的消息之间的区别，或者开发某种“协议消息的正则表达式”，利用正则表达式，你可以对某种消息内容进行匹配。只要你发挥你的想像力，就有可能将 Protocol Buffers 应用到一个更广泛的、你可能一开始就期望解决的问题范围上。

反射是由 [Message::Reflection interface](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message.html#Message.Reflection) 提供的。

---

via: <https://developers.google.com/protocol-buffers/docs/cpptutorial>

作者：[Google](https://developers.google.com/protocol-buffers/docs/cpptutorial) 译者：[cposture](https://github.com/cposture) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


新手指南：通过 Docker 在 Linux 上托管 .NET Core

想学习linux系统，能不能推荐一下书籍，或其他的学习方式，谢谢！

来自黑龙江哈尔滨的 Chrome Mobile 46.0|Android 6.0 用户

这篇文章基于我之前的文章 [.NET Core 入门](http://blog.scottlogic.com/2016/01/20/restful-api-with-aspnet50.html)。首先，我把 RESTful API 从 .NET Core RC1 升级到了 .NET Core 1.0，然后，我增加了对 Docker 的支持并描述了如何在 Linux 生产环境里托管它。

我是首次接触 Docker 并且距离成为一名 Linux 高手还有很远的一段路程。因此，这里的很多想法是来自一个新手。

![](/data/attachment/album/201611/04/213354q8bd9jb8e88teo5g.jpg)

### 安装

按照 <https://www.microsoft.com/net/core> 上的介绍在你的电脑上安装 .NET Core 。这将会同时在 Windows 上安装 dotnet 命令行工具以及最新的 Visual Studio 工具。

### 源代码

你可以直接到 [GitHub](https://github.com/niksoper/aspnet5-books/tree/blog-docker) 上找最到最新完整的源代码。

### 转换到 .NET CORE 1.0

自然地，当我考虑如何把 API 从 .NET Core RC1 升级到 .NET Core 1.0 时想到的第一个求助的地方就是谷歌搜索。我是按照下面这两条非常全面的指导来进行升级的：

* [从 DNX 迁移到 .NET Core CLI](https://docs.microsoft.com/en-us/dotnet/articles/core/migrating-from-dnx)
* [从 ASP.NET 5 RC1 迁移到 ASP.NET Core 1.0](https://docs.asp.net/en/latest/migration/rc1-to-rtm.html)

当你迁移代码的时候，我建议仔细阅读这两篇指导，因为我在没有阅读第一篇指导的情况下又尝试浏览第二篇，结果感到非常迷惑和沮丧。

我不想描述细节上的改变因为你可以看 GitHub 上的[提交](https://github.com/niksoper/aspnet5-books/commit/b41ad38794c69a70a572be3ffad051fd2d7c53c0)。这儿是我所作改变的总结：

* 更新 `global.json` 和 `project.json` 上的版本号
* 删除 `project.json` 上的废弃章节
* 使用轻型 `ControllerBase` 而不是 `Controller`， 因为我不需要与 MVC 视图相关的方法（这是一个可选的改变）。
* 从辅助方法中去掉 `Http` 前缀，比如：`HttpNotFound` -> `NotFound`
* `LogVerbose` -> `LogTrace`
* 名字空间改变： `Microsoft.AspNetCore.*`
* 在 `Startup` 中使用 `SetBasePath`（没有它 `appsettings.json` 将不会被发现）
* 通过 `WebHostBuilder` 来运行而不是通过 `WebApplication.Run` 来运行
* 删除 Serilog（在写文章的时候，它不支持 .NET Core 1.0）

唯一令我真正头疼的事是需要移动 Serilog。我本可以实现自己的文件记录器，但是我删除了文件记录功能，因为我不想为了这次操作在这件事情上花费精力。

不幸的是，将有大量的第三方开发者扮演追赶 .NET Core 1.0 的角色，我非常同情他们，因为他们通常在休息时间还坚持工作但却依旧根本无法接近靠拢微软的可用资源。我建议阅读 Travis Illig 的文章 [.NET Core 1.0 发布了，但 Autofac 在哪儿](http://www.paraesthesia.com/archive/2016/06/29/netcore-rtm-where-is-autofac/)？这是一篇关于第三方开发者观点的文章。

做了这些改变以后，我可以从 `project.json` 目录恢复、构建并运行 dotnet，可以看到 API 又像以前一样工作了。

### 通过 Docker 运行

在我写这篇文章的时候， Docker 只能够在 Linux 系统上工作。在 [Windows](https://docs.docker.com/engine/installation/windows/#/docker-for-windows) 系统和 [OS X](https://docs.docker.com/engine/installation/mac/) 上有 beta 支持 Docker，但是它们都必须依赖于虚拟化技术，因此，我选择把 Ubuntu 14.04 当作虚拟机来运行。如果你还没有安装过 Docker，请按照[指导](https://docs.docker.com/engine/installation/linux/ubuntulinux/)来安装。

我最近阅读了一些关于 Docker 的东西，但我直到现在还没有真正用它来干任何事。我假设读者还没有关于 Docker 的知识，因此我会解释我所使用的所有命令。

#### HELLO DOCKER

在 Ubuntu 上安装好 Docker 之后，我所进行的下一步就是按照 <https://www.microsoft.com/net/core#docker> 上的介绍来开始运行 .NET Core 和 Docker。

首先启动一个已安装有 .NET Core 的容器。

```
docker run -it microsoft/dotnet:latest

```

`-it` 选项表示交互，所以你执行这条命令之后，你就处于容器之内了，可以如你所希望的那样执行任何 bash 命令。

然后我们可以执行下面这五条命令来在 Docker 内部运行起来微软 .NET Core 控制台应用程序示例。

```
mkdir hwapp
cd hwapp
dotnet new
dotnet restore
dotnet run

```

你可以通过运行 `exit` 来离开容器，然后运行 `Docker ps -a` 命令，这会显示你创建的那个已经退出的容器。你可以通过上运行命令 `Docker rm <container_name>` 来清除容器。

#### 挂载源代码

我的下一步骤是使用和上面相同的 `microsoft/dotnet` 镜像，但是将为我们的应用程序以[数据卷](https://docs.docker.com/engine/tutorials/dockervolumes/1)的方式挂载上源代码。

首先签出有相关提交的仓库：

```
git clone https://github.com/niksoper/aspnet5-books.git
cd aspnet5-books/src/MvcLibrary
git checkout dotnet-core-1.0

```

现在启动一个容器来运行 .NET Core 1.0，并将源代码放在 `/book` 下。注意更改 `/path/to/repo` 这部分文件来匹配你的电脑：

```
docker run -it \
-v /path/to/repo/aspnet5-books/src/MvcLibrary:/books \
microsoft/dotnet:latest

```

现在你可以在容器中运行应用程序了！

```
cd /books
dotnet restore
dotnet run

```

作为一个概念性展示这的确很棒，但是我们可不想每次运行一个程序都要考虑如何把源代码安装到容器里。

#### 增加一个 DOCKERFILE

我的下一步骤是引入一个 Dockerfile，这可以让应用程序很容易在自己的容器内启动。

我的 Dockerfile 和 `project.json` 一样位于 `src/MvcLibrary` 目录下，看起来像下面这样：

```
FROM microsoft/dotnet:latest

# 为应用程序源代码创建目录
RUN mkdir -p /usr/src/books
WORKDIR /usr/src/books

# 复制源代码并恢复依赖关系
COPY . /usr/src/books
RUN dotnet restore

# 暴露端口并运行应用程序
EXPOSE 5000
CMD [ "dotnet", "run" ]

```

严格来说，`RUN mkdir -p /usr/src/books` 命令是不需要的，因为 `COPY` 会自动创建丢失的目录。

Docker 镜像是按层建立的，我们从包含 .NET Core 的镜像开始，添加另一个从源代码生成应用程序，然后运行这个应用程序的层。

添加了 Dockerfile 以后，我通过运行下面的命令来生成一个镜像，并使用生成的镜像启动一个容器（确保在和 Dockerfile 相同的目录下进行操作，并且你应该使用自己的用户名）。

```
docker build -t niksoper/netcore-books .
docker run -it niksoper/netcore-books

```

你应该看到程序能够和之前一样的运行，不过这一次我们不需要像之前那样安装源代码，因为源代码已经包含在 docker 镜像里面了。

#### 暴露并发布端口

这个 API 并不是特别有用，除非我们需要从容器外面和它进行通信。 Docker 已经有了暴露和发布端口的概念，但这是两件完全不同的事。

据 Docker [官方文档](https://docs.docker.com/engine/reference/builder/#/expose)：

>
> `EXPOSE` 指令通知 Docker 容器在运行时监听特定的网络端口。`EXPOSE` 指令不能够让容器的端口可被主机访问。要使可被访问，你必须通过 `-p` 标志来发布一个端口范围或者使用 `-P` 标志来发布所有暴露的端口
>
>
>

`EXPOSE` 指令只是将元数据添加到镜像上，所以你可以如文档中说的认为它是镜像消费者。从技术上讲，我本应该忽略 `EXPOSE 5000` 这行指令，因为我知道 API 正在监听的端口，但把它们留下很有用的，并且值得推荐。

在这个阶段，我想直接从主机访问这个 API ，因此我需要通过 `-p` 指令来发布这个端口，这将允许请求从主机上的端口 5000 转发到容器上的端口 5000，无论这个端口是不是之前通过 Dockerfile 暴露的。

```
docker run -d -p 5000:5000 niksoper/netcore-books

```

通过 `-d` 指令告诉 docker 在分离模式下运行容器，因此我们不能看到它的输出，但是它依旧会运行并监听端口 5000。你可以通过 `docker ps` 来证实这件事。

因此，接下来我准备从主机向容器发起一个请求来庆祝一下：

```
curl http://localhost:5000/api/books

```

它不工作。

重复进行相同 `curl` 请求，我看到了两个错误：要么是 `curl: (56) Recv failure: Connection reset by peer`，要么是 `curl: (52) Empty reply from server`。

我返回去看 docker run 的[文档](https://docs.docker.com/engine/reference/run/#/expose-incoming-ports)，然后再次检查我所使用的 `-p` 选项以及 Dockerfile 中的 `EXPOSE` 指令是否正确。我没有发现任何问题，这让我开始有些沮丧。

重新振作起来以后，我决定去咨询当地的一个 Scott Logic DevOps 大师 - Dave Wybourn（也在[这篇 Docker Swarm 的文章](http://blog.scottlogic.com/2016/08/30/docker-1-12-swarm-mode-round-robin.html)里提到过），他的团队也曾遇到这个实际问题。这个问题是我没有配置过 [Kestral](https://docs.asp.net/en/latest/fundamentals/servers.html#kestrel)，这是一个全新的轻量级、跨平台 web 服务器，用于 .NET Core 。

默认情况下， Kestrel 会监听 `http://localhost:5000`。但问题是，这儿的 `localhost` 是一个回路接口。

据[维基百科](https://en.wikipedia.org/wiki/Localhost)：

>
> 在计算机网络中，localhost 是一个代表本机的主机名。本地主机可以通过网络回路接口访问在主机上运行的网络服务。通过使用回路接口可以绕过任何硬件网络接口。
>
>
>

当运行在容器内时这是一个问题，因为 `localhost` 只能够在容器内访问。解决方法是更新 `Startup.cs` 里的 `Main` 方法来配置 Kestral 监听的 URL：

```
public static void Main(string[] args)
{
  var host = new WebHostBuilder()
    .UseKestrel()
    .UseContentRoot(Directory.GetCurrentDirectory())
    .UseUrls("http://*:5000") // 在所有网络接口上监听端口 5000
    .UseIISIntegration()
    .UseStartup<Startup>()
    .Build();

  host.Run();
}

```

通过这些额外的配置，我可以重建镜像，并在容器中运行应用程序，它将能够接收来自主机的请求：

```
docker build -t niksoper/netcore-books .
docker run -d -p 5000:5000 niksoper/netcore-books
curl -i http://localhost:5000/api/books

```

我现在得到下面这些相应：

```
HTTP/1.1 200 OK
Date: Tue, 30 Aug 2016 15:25:43 GMT
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Kestrel

[{"id":"1","title":"RESTful API with ASP.NET Core MVC 1.0","author":"Nick Soper"}]

```

### 在产品环境中运行 KESTREL

[微软的介绍](https://docs.asp.net/en/latest/publishing/linuxproduction.html#why-use-a-reverse-proxy-server)：

>
> Kestrel 可以很好的处理来自 ASP.NET 的动态内容，然而，网络服务部分的特性没有如 IIS，Apache 或者 Nginx 那样的全特性服务器那么好。反向代理服务器可以让你不用去做像处理静态内容、缓存请求、压缩请求、SSL 端点这样的来自 HTTP 服务器的工作。
>
>
>

因此我需要在我的 Linux 机器上把 Nginx 设置成一个反向代理服务器。微软介绍了如何[发布到 Linux 生产环境下](https://docs.asp.net/en/latest/publishing/linuxproduction.html)的指导教程。我把说明总结在这儿：

1. 通过 `dotnet publish` 来给应用程序产生一个自包含包。
2. 把已发布的应用程序复制到服务器上
3. 安装并配置 Nginx（作为反向代理服务器）
4. 安装并配置 [supervisor](http://supervisord.org/)（用于确保 Nginx 服务器处于运行状态中）
5. 安装并配置 [AppArmor](https://wiki.ubuntu.com/AppArmor)（用于限制应用的资源使用）
6. 配置服务器防火墙
7. 安全加固 Nginx（从源代码构建和配置 SSL）

这些内容已经超出了本文的范围，因此我将侧重于如何把 Nginx 配置成一个反向代理服务器。自然地，我通过 Docker 来完成这件事。

### 在另一个容器中运行 NGINX

我的目标是在第二个 Docker 容器中运行 Nginx 并把它配置成我们的应用程序容器的反向代理服务器。

我使用的是[来自 Docker Hub 的官方 Nginx 镜像](https://hub.docker.com/_/nginx/)。首先我尝试这样做：

```
docker run -d -p 8080:80 --name web nginx

```

这启动了一个运行 Nginx 的容器并把主机上的 8080 端口映射到了容器的 80 端口上。现在在浏览器中打开网址 `http://localhost:8080` 会显示出 Nginx 的默认登录页面。

现在我们证实了运行 Nginx 是多么的简单，我们可以关闭这个容器。

```
docker rm -f web

```

### 把 NGINX 配置成一个反向代理服务器

可以通过像下面这样编辑位于 `/etc/nginx/conf.d/default.conf` 的配置文件，把 Nginx 配置成一个反向代理服务器：

```
server {
  listen 80;

  location / {
    proxy_pass http://localhost:6666;
  }
}

```

通过上面的配置可以让 Nginx 将所有对根目录的访问请求代理到 `http://localhost:6666`。记住这里的 `localhost` 指的是运行 Nginx 的容器。我们可以在 Nginx容器内部利用卷来使用我们自己的配置文件：

```
docker run -d -p 8080:80 \
-v /path/to/my.conf:/etc/nginx/conf.d/default.conf \
nginx

```

注意：这把一个单一文件从主机映射到容器中，而不是一个完整目录。

### 在容器间进行通信

Docker 允许内部容器通过共享虚拟网络进行通信。默认情况下，所有通过 Docker 守护进程启动的容器都可以访问一种叫做“桥”的虚拟网络。这使得一个容器可以被另一个容器在相同的网络上通过 IP 地址和端口来引用。

你可以通过<ruby> 监测 <rp>  （ </rp> <rt>  inspect </rt> <rp>  ） </rp></ruby>容器来找到它的 IP 地址。我将从之前创建的 `niksoper/netcore-books` 镜像中启动一个容器并<ruby> 监测 <rp>  （ </rp> <rt>  inspect </rt> <rp>  ） </rp></ruby>它：

```
docker run -d -p 5000:5000 --name books niksoper/netcore-books
docker inspect books

```

![](/data/attachment/album/201611/04/214147ff5if5556rqmi5h8.png)

我们可以看到这个容器的 IP 地址是 `"IPAddress": "172.17.0.3"`。

所以现在如果我创建下面的 Nginx 配置文件，并使用这个文件启动一个 Nginx 容器， 它将代理请求到我的 API ：

```
server {
  listen 80;

  location / {
    proxy_pass http://172.17.0.3:5000;
  }
}

```

现在我可以使用这个配置文件启动一个 Nginx 容器（注意我把主机上的 8080 端口映射到了 Nginx 容器上的 80 端口）：

```
docker run -d -p 8080:80 \
-v ~/dev/nginx/my.nginx.conf:/etc/nginx/conf.d/default.conf \
nginx

```

一个到 `http://localhost:8080` 的请求将被代理到应用上。注意下面 `curl` 响应的 `Server` 响应头：

![](/data/attachment/album/201611/04/214211az6777pz7pcc9ici.png)

### DOCKER COMPOSE

在这个地方，我为自己的进步而感到高兴，但我认为一定还有更好的方法来配置 Nginx，可以不需要知道应用程序容器的确切 IP 地址。另一个当地的 Scott Logic DevOps 大师 Jason Ebbin 在这个地方进行了改进，并建议使用 [Docker Compose](https://docs.docker.com/compose/)。

概况描述一下，Docker Compose 使得一组通过声明式语法互相连接的容器很容易启动。我不想再细说 Docker Compose 是如何工作的，因为你可以在[之前的文章](http://blog.scottlogic.com/2016/01/25/playing-with-docker-compose-and-erlang.html)中找到。

我将通过一个我所使用的 `docker-compose.yml` 文件来启动：

```
version: '2'
services:
    books-service:
        container_name: books-api
        build: .

    reverse-proxy:
        container_name: reverse-proxy
        image: nginx
        ports:
         - "9090:8080"
        volumes:
         - ./proxy.conf:/etc/nginx/conf.d/default.conf

```

*这是版本 2 语法，所以为了能够正常工作，你至少需要 1.6 版本的 Docker Compose。*

这个文件告诉 Docker 创建两个服务：一个是给应用的，另一个是给 Nginx 反向代理服务器的。

### BOOKS-SERVICE

这个与 `docker-compose.yml` 相同目录下的 Dockerfile 构建的容器叫做 `books-api`。注意这个容器不需要发布任何端口，因为只要能够从反向代理服务器访问它就可以，而不需要从主机操作系统访问它。

### REVERSE-PROXY

这将基于 nginx 镜像启动一个叫做 `reverse-proxy` 的容器，并将位于当前目录下的 `proxy.conf` 文件挂载为配置。它把主机上的 9090 端口映射到容器中的 8080 端口，这将允许我们在 `http://localhost:9090` 上通过主机访问容器。

`proxy.conf` 文件看起来像下面这样：

```
server {
    listen 8080;

    location / {
      proxy_pass http://books-service:5000;
    }
}

```

这儿的关键点是我们现在可以通过名字引用 `books-service`，因此我们不需要知道 `books-api` 这个容器的 IP 地址！

现在我们可以通过一个运行着的反向代理启动两个容器（`-d` 意味着这是独立的，因此我们不能看到来自容器的输出）：

```
docker compose up -d

```

验证我们所创建的容器：

```
docker ps

```

最后来验证我们可以通过反向代理来控制该 API ：

```
curl -i http://localhost:9090/api/books

```

### 怎么做到的？

Docker Compose 通过创建一个新的叫做 `mvclibrary_default` 的虚拟网络来实现这件事，这个虚拟网络同时用于 `books-api` 和 `reverse-proxy` 容器（名字是基于 `docker-compose.yml` 文件的父目录）。

通过 `docker network ls` 来验证网络已经存在：

![](/data/attachment/album/201611/04/214239m1h9dndn6z71ckk1.png)

你可以使用 `docker network inspect mvclibrary_default` 来看到新的网络的细节：

![](/data/attachment/album/201611/04/214309g0ac0uzvkchvuoov.png)

注意 Docker 已经给网络分配了子网：`"Subnet": "172.18.0.0/16"`。`/16` 部分是无类域内路由选择（CIDR），完整的解释已经超出了本文的范围，但 CIDR 只是表示 IP 地址范围。运行 `docker network inspect bridge` 显示子网：`"Subnet": "172.17.0.0/16"`，因此这两个网络是不重叠的。

现在用 `docker inspect books-api` 来确认应用程序的容器正在使用该网络：

![](/data/attachment/album/201611/04/214338m0d52xft4z6wds5g.png)

注意容器的两个别名（`"Aliases"`）是容器标识符（`3c42db680459`）和由 `docker-compose.yml` 给出的服务名（`books-service`）。我们通过 `books-service` 别名在自定义 Nginx 配置文件中来引用应用程序的容器。这本可以通过 `docker network create` 手动创建，但是我喜欢用 Docker Compose，因为它可以干净简洁地将容器创建和依存捆绑在一起。

### 结论

所以现在我可以通过几个简单的步骤在 Linux 系统上用 Nginx 运行应用程序，不需要对主机操作系统做任何长期的改变：

```
git clone https://github.com/niksoper/aspnet5-books.git
cd aspnet5-books/src/MvcLibrary
git checkout blog-docker
docker-compose up -d
curl -i http://localhost:9090/api/books

```

我知道我在这篇文章中所写的内容不是一个真正的生产环境就绪的设备，因为我没有写任何有关下面这些的内容，绝大多数下面的这些主题都需要用单独一篇完整的文章来叙述。

* 安全考虑比如防火墙和 SSL 配置
* 如何确保应用程序保持运行状态
* 如何选择需要包含的 Docker 镜像（我把所有的都放入了 Dockerfile 中）
* 数据库 - 如何在容器中管理它们

对我来说这是一个非常有趣的学习经历，因为有一段时间我对探索 ASP.NET Core 的跨平台支持非常好奇，使用 “Configuratin as Code” 的 Docker Compose 方法来探索一下 DevOps 的世界也是非常愉快并且很有教育意义的。

如果你对 Docker 很好奇，那么我鼓励你来尝试学习它 或许这会让你离开舒适区，不过，有可能你会喜欢它？

---

via: <http://blog.scottlogic.com/2016/09/05/hosting-netcore-on-linux-with-docker.html>

作者：[Nick Soper](http://blog.scottlogic.com/nsoper) 译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


为什么 Chrome 又不支持我的 HTTP/2 网站了？

"插件好像好久没亮了"，那个插件叫什么名字？<br />
从头到翻到尾就没看到那个插件是什么…… (´・ω・`)

Debian jessie backports 已经提供 openssl 1.0.2 了。

第一句。。。

额……看到了，原来是，哈哈……

请教一下，想学linux，能不能推荐本书籍，或其他学习方式，谢谢

我也装上那个扩展试试。

鸟哥的linux私房菜基础篇,

昨晚偶尔清理 Chrome 插件时发现我的 “[HTTP/2 and SPDY indicator](https://chrome.google.com/webstore/detail/http2-and-spdy-indicator/mpbpobfflnpcgagjijhmgnchggcjblin)”插件好像好久没亮了。这个插件在你访问到一个支持 HTTP/2 （或之前的 SPDY 协议）的网站时会点亮，而我明明记得之前专门让 <https://linux.cn/> 支持了 HTTP/2 。

我的第一反应是不是这个插件有问题了？于是打开 Chrome 调试工具，然后发现，真的是请求和响应都是 HTTP/1.1 哎！

经过一番研究，原来是从 Chrome 51 开始，在 2016 年 5 月 31 日之前，对支持 NPN 协商协议的 HTTP/2 网站还会采用 HTTP/2 访问；而之后就只支持 ALPN 协商协议的 HTTP/2 网站了——而目前 ALPN 协议仅被鲜少有发行版支持 openssl-1.0.2 支持。

![](/data/attachment/album/201611/06/130031xmoaa0lutlcrualu.jpg)

### 发生了什么？

#### 服务器端

我们知道，最初的 Web 访问协议是 HTTP/1，包括以前的 HTTP/1.0 和现在大部分网站采用的 HTTP/1.1（HTTP/0.9 是试验性协议，已经废弃）。但是随着 Web 应用越来越复杂，之前的 HTTP/1.x 协议就看起来不能满足日益庞杂的 Web 服务需求了。比如说，明文请求、请求复用等问题。因此，谷歌就开发了一个新的传输层协议，名为 SPDY。由于这个新的协议用了的人都说好，因此谷歌就把这个协议提交到了 IETF，然后大家觉得，SPDY 这名字不好听（SPDY 是谷歌的注册商标），就干脆叫 [HTTP/2](https://tools.ietf.org/html/rfc7540) 吧！

SPDY 协议是基于 SSL/TLS 的，谷歌开发了一个名为<ruby>   下一代协议协商  <rp>  （ </rp> <rt>  Next Protocol Negotiation </rt> <rp>  ） </rp></ruby>（NPN）的 SSL/TLS 扩展，用于在客户端连接服务器时协商是否采用 HTTP/2 协议。SPDY 协议是由 Web 服务器所实现支持的，而 NPN 则是由 OpenSSL 等 SSL 实现支持的。

但是，随着 SPDY 被提交到 IETF，然后变成了 HTTP/2 协议，谷歌也放弃了 SPDY 的开发，全力投入到了 HTTP/2 的开发中，之前所采用 NPN 也被一种新的协商协议 ALPN ——<ruby>   应用层协议协商  <rp>  （ </rp> <rt>  Application-Layer Protocol Negotiation </rt> <rp>  ） </rp></ruby>所替代。NPN 和 ALPN 是不兼容的，它们的主要不同是：

* NPN 是服务器发送所支持的协议列表，由客户端进行选择。而 ALPN 则是客户端发送该列表，由服务端选择。
* 在 NPN 中，最终的选择结果是在 Change Cipher Spec 之后发送给服务端的，也就是说是被加密了的。而在 ALPN 中，所有的协商都是明文的。

这样做的好处主要是安全性方面的考虑，但是这造成了一个问题就是，NPN 已经广泛地被 OpenSSL 支持，而 ALPN 则目前只有最新的 openssl-1.0.2 才支持。当前的几个主流 Linux 发行版的 OpenSSL 版本以及支持的协商协议如下：

| Linux 发行版 | OpenSSL 版本 | 所支持的协商协议 |
| --- | --- | --- |
| CentOS/Oracle Linux/RHEL 5.10+ | 0.9.8e | 不支持 |
| CentOS/Oracle Linux/RHEL 6.5+, 7.0+ | 1.0.1e | NPN |
| Ubuntu 12.04 LTS | 1.0.1 | NPN |
| Ubuntu 14.04 LTS | 1.0.1f | NPN |
| *Ubuntu 16.04 LTS* | *1.0.2g* | *ALPN 和 NPN* |
| Debian 7.0 | 1.0.1e | NPN |
| Debian 8.0 | 1.0.1k | NPN |

从上面我们可以看到，基本上所有的服务器级的 Linux 发行版都不支持 OpenSSL 及 ALPN，唯一支持的 Ubuntu 16.04 LTS 显然用的不会很多。不要小看这 0.0.1 的版本差异，对于别的软件来说这 0.0.1 的差异基本上可以忽略，但是对于 OpenSSL 来说，那就是两个版本代际。OpenSSL 是个相当底层的库，很多重要的软件都依赖于它，因此各个发行版在升级 OpenSSL 时采用的态度是相当保守，比如我们可以看看 CentOS 系统中有哪些软件使用了 OpenSSL：

```
$ lsof | grep libssl | awk '{print $1}' | sort | uniq
anvil
fail2ban
gdbus
gmain
httpd
postfix
mysqld
NetworkManager
nginx
php-fpm
puppet
sshd
sudo
tuned
zabbix_agent
```

没有经过足够的测试，Linux 发行版是不会在产品级（服务器级）的环境中随便升级的。为了解决旧版本（1.0.1）中的安全问题，他们宁可将新的版本（1.0.2）中安全修复移植回旧版本，也不会升级到有新功能的新版本（1.0.2），这就是你见到了各种 1.0.1e、1.0.1k 这样的版本号的原因。

当然，你可以自己编译一个最新 OpenSSL 替代你系统中的 openssl-1.0.1，但是我想你不会这样做的，是吧？

顺便提一句，NPN 和 ALPN 可以并存，但是会客户端会优先选择 ALPN。

#### 浏览器端（Chrome）

从 Chrome 51 开始，谷歌就去掉了对 SPDY 的支持，不过这不是个事，因为不但使用 SPDY 的 Web 服务器比较少，而且从 SPDY 升级到 HTTP/2 也很简单，这方面 Nginx、Apache 等服务器的配置都很简单。

但不幸的是，在 Chrome 51 中，谷歌也去掉了对 NPN 的支持！如果你的 Web 服务器使用的是 openssl-1.0.2 以下的版本，不支持 ALPN 协商，那么 Chrome 51 及以后版本就会以 HTTP/1 协议访问你的网站。

谷歌对放弃 NPN 支持做了一个[简短的解释](https://bugs.chromium.org/p/chromium/issues/detail?id=527066)，但是不管怎么说，NPN 协议在 Chrome 51 之后的版本不会再次回来了。而另一方面，OpenSSL 在 2016 年 12 月 31 日之后也不会继续发布 openssl-1.0.1 系列的新版本了，安全修复到此为止。

而在这种情况下，你原本支持 HTTP/2 的网站通过连接复用等 HTTP/2 所提供的新特性，在 Chrome 下访问取得了不错的体验，而现在又跌回了之前的残旧状态。

### 怎么办呢？

有几种办法：

#### 换浏览器

山不来就我，我去就山。Chrome 51+ 不支持带 NPN 的 HTTP/2 网站，作为浏览者，你可以使用其它的浏览器，比如 Safari、Edge 之类的。这样，你就可以用新的协议来访问世界上那 [10% 支持 HTTP/2 的 Web 服务器](https://w3techs.com/technologies/details/ce-http2/all/all)了。

但是，作为服务器运营者，你却不能忽视[高达 50% 以上的 Chrome 用户](https://www.netmarketshare.com/browser-market-share.aspx?qprid=0&qpcustomd=0)。

#### 换服务器

如上面所示，Ubuntu 16.04 LTS 是目前唯一官方支持 openssl-1.0.2 的 Linux 发行版，如果你一直采用 Ubuntu 做服务器，考虑一下升级吧。LTS 版本的支持期长达五年。

当然，在产品环境中，即便你是 Ubuntu 服务器，更新版本也是一件重大事宜，宜慎思之。

#### 重新编译

既然换服务器不是一个好的选择，那你还有一个方案，就是使用新的 openssl-1.0.2 源代码重新编译你的 Web 服务器，比如 nginx。

下面我简单介绍一下如何用 openssl-1.0.2 来编译 nginx。（1.0.2 系列的最新版本是 1.0.2j，当然你要非用 1.1.0，我也无话可说……）

首先下载并解压 openssl-1.0.2j：

```
# wget https://www.openssl.org/source/openssl-1.0.2j.tar.gz
# tar -zxvf openssl-1.0.2j.tar.gz
```

然后在编译 nginx 的时候使用 `--with-openssl=../openssl-1.0.2j` 选项以及你的其它选项：

```
./configure --with-openssl=../openssl-1.0.2j --with-http_v2_module --with-http_ssl_module
```

配置并编译之后，你可以用 `nginx -V`来看一下你的 nginx 中的 OpenSSL 版本。

这种自行编译的好处是灵活性高，但是你需要随时注意各个组件是否有严重的安全漏洞，并在出了修复版本之后重新编译。

#### 容器

除了自己编译之外，如果你的系统环境中已经有了容器支持，你还可以在容器中运行一个 Ubuntu 16.04 LTS，并将 Web 服务器运行在其中。

### 总结

以上就是 HTTP/2 和 Chrome 之间的故事，你准备去升级 HTTP/2 支持了吗？要知道相比 HTTP/2 的访问体验，你肯定不会想再回到 HTTP/1 了。


怎样在 RHEL、CentOS 和 Fedora 上安装 Git 及设置 Git 账号

对于新手来说，Git 是一个自由、开源、高效的分布式版本控制系统（VCS），它是基于速度、高性能以及数据一致性而设计的，以支持从小规模到大体量的软件开发项目。

Git 是一个可以让你追踪软件改动、版本回滚以及创建另外一个版本的目录和文件的软件仓库。

![](/data/attachment/album/201611/06/175311hj2ft92r2rvz98fs.jpg)

Git 主要是用 C 语言来写的，混杂了少量的 Perl 脚本和各种 shell 脚本。它主要在 Linux 内核上运行，并且有以下列举的卓越的性能：

* 易于上手
* 运行速度飞快，且大部分操作在本地进行，因此，它极大的提升了那些需要与远程服务器通信的集中式系统的速度。
* 高效
* 提供数据一致性检查
* 支持低开销的本地分支
* 提供非常便利的暂存区
* 可以集成其它工具来支持多种工作流

在这篇操作指南中，我们将介绍在 CentOS/RHEL 7/6 和 Fedora 20-24 Linux 发行版上安装 Git 的必要步骤以及怎么配置 Git，以便于你可以快速开始工作。

### 使用 Yum 安装 Git

我们将从系统默认的仓库安装 Git，并通过运行以下 [YUM 包管理器](/article-2272-1.html) 的更新命令来确保你系统的软件包都是最新的：

```
# yum update

```

接着，通过以下命令来安装 Git：

```
# yum install git

```

在 Git 成功安装之后，你可以通过以下命令来显示 Git 安装的版本：

```
# git --version

```

![检查 Git 的安装版本](/data/attachment/album/201611/06/175402iyfluoadkogwttue.png)

*检查 Git 安装的版本*

注意：从系统默认仓库安装的 Git 会是比较旧的版本。如果你想拥有最新版的 Git，请考虑使用以下说明来编译源代码进行安装。

### 从源代码安装 Git

开始之前，你首先需要从系统默认仓库安装所需的软件依赖包，以及从源代码构建二进制文件所需的实用工具：

```
# yum groupinstall "Development Tools"
# yum install gettext-devel openssl-devel perl-CPAN perl-devel zlib-devel
```

安装所需的软件依赖包之后，转到官方的 [Git 发布页面](https://github.com/git/git/releases)，抓取最新版的 Git 并使用下列命令编译它的源代码：

```
# wget https://github.com/git/git/archive/v2.10.1.tar.gz -O git.tar.gz
# tar -zxf git.tar.gz
# cd git-2.10.1/
# make configure
# ./configure --prefix=/usr/local
# make install
# git --version
```

![检查 Git 的安装版本](/data/attachment/album/201611/06/175405tmn1kw2huwlue0gw.png)

*检查 Git 的安装版本*

**推荐阅读:** [Linux 下 11 个最好用的 Git 客户端和 Git 仓库查看器](http://www.tecmint.com/best-gui-git-clients-git-repository-viewers-for-linux/)。

### 在 Linux 设置 Git 账户

在这个环节中，我们将介绍如何使用正确的用户信息（如：姓名、邮件地址）和 `git config` 命令来设置 Git 账户，以避免出现提交错误。

注意：确保将下面的 `username` 替换为在你的系统上创建和使用的 Git 用户的真实名称。

你可以使用下面的 [useradd 命令](http://www.tecmint.com/add-users-in-linux/) 创建一个 Git 用户，其中 `-m` 选项用于在 `/home` 目录下创建用户主目录，`-s` 选项用于指定用户默认的 shell。

```
# useradd -m -s /bin/bash username
# passwd username

```

现在，将新用户添加到 `wheel` 用户组以启用其使用 `sudo` 命令的权限：

```
# usermod username -aG wheel

```

![创建 Git 用户账号](/data/attachment/album/201611/06/175406mxyrupe111lzeyss.png)

*创建 Git 用户账号*

然后通过以下命令使用新用户配置 Git：

```
# su username
$ sudo git config --global user.name "Your Name"
$ sudo git config --global user.email "you@example.com"
```

现在通过下面的命令校验 Git 的配置。

```
$ sudo git config --list
```

如果配置没有错误的话，你应该能够看到类似以下详细信息的输出：

```
user.name=username
user.email= username@some-domian.com
```

![在 Linux 设置 Git 用户](/data/attachment/album/201611/06/175406ngcqvrkc7gfr1wwr.png)

*在 Linux 设置 Git 用户*

### 总结

在这个简单的教程中，我们已经了解怎么在你的 Linux 系统上安装 Git 以及配置它。我相信你应该可以驾轻就熟。

---

via: <http://www.tecmint.com/install-git-centos-fedora-redhat/>

作者：[Aaron Kili](http://www.tecmint.com/author/aaronkili/) 译者：[OneNewLife](https://github.com/OneNewLife) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


使用命令行生成高强度密码

问题是我记不住哇！

所以有一种东西叫password manager，如：开源的KeePassX

这个 user-agent 是自己改得吧？Chromium 的版本号有那么高？

简单，抄下来，贴显示器旁。只要你的用户名不被别人知道就行。

可以很实用

openssl rand -base64 14<br />
这个不错，可以推荐使用vivaldi笔记功能，这样常用的密码可以记在旁边，如果你怕别人看到，可以使用密码管理器保存起来

一直在用第一个

![](/data/attachment/album/201611/07/121112icf4y744jucyvdvp.jpg)

设置一个高强度的密码是非常重要的，这样才能够很好的保护自己的账号或者服务器以及确保自己的数据的安全。通常来说，一个高强度密码至少有 14 个字符，包括大小写字母、数字和特殊字符，并且要牢记永远不用那些字典中的单词。使用长密码比短密码要来的安全，因为密码越长越难猜测。在本文中，我将给你介绍几个不同方法，让你可以在 Linux 命令行下生成一个高强度密码。

### 使用 openssl 生成高强度密码

这里使用 openssl 的 rand 方法，它会生成一个 14 位字符的随机字符：

```
openssl rand -base64 14

```

### 使用 urandom 生成高强度密码

这里我们将使用 `tr` 条件来过滤 `/dev/urandom` 的输出，从而删掉那些不想要的字符，并打印出第一个出现的 14 位字符。

```
< /dev/urandom tr -dc A-Za-z0-9 | head -c14; echo

```

### 使用 pwgen 生成高强度密码

`pwgen` 是一个生成随机、无特殊含义但可以正常拼读的密码。

安装 `pwgen`，运行：

```
sudo apt-get install pwgen

```

安装好之后，使用以下命令来生成一个 14 位随机字符：

```
pwgen 14 1

```

你也可以使用以下标记：

* -c 或 --capitalize 生成的密码中至少包含一个大写字母
* -A 或 --no-capitalize 生成的密码中不含大写字母
* -n 或 --numerals 生成的密码中至少包含一个数字
* -0 或 --no-numerals 生成的密码中不含数字
* -y 或 --symbols 生成的密码中至少包含一个特殊字符
* -s 或 --secure 生成一个完全随机的密码
* -B 或 --ambiguous 生成的密码中不含<ruby> 易混淆字符 <rp>  （ </rp> <rt>  ambiguous characters </rt> <rp>  ） </rp></ruby>
* -h 或 --help 输出帮助信息
* -H 或 --sha1=path/to/file[#seed] 使用指定文件的 sha1 哈希值作为随机生成器
* -C 按列输出生成的密码
* -1 不按列输出生成的密码
* -v 或 --no-vowels 不使用任何元音，以免意外生成让人讨厌的单词

### 使用 gpg 生成高强度密码

我们也可以使用 `gpg` 工具来生成一个 14 位字符的密码：

```
gpg --gen-random --armor 1 14

```

### 其它方法

当然，可能还有很多方法可以生成一个高强度密码。比方说，你可以添加以下 bash shell 方法到 `~/.bashrc` 文件：

```
genpasswd() {
    strings /dev/urandom | grep -o '[[:alnum:]]' | head -n 14 | tr -d '\n'; echo
}

```

当你想要生成一个高强度的随机密码时，运行 `genpasswd` 就好了。

---

via: <https://www.rosehosting.com/blog/generate-password-linux-command-line/>

作者：[RoseHosting](www.rosehosting.com) 译者：[GHLandy](https://github.com/GHLandy) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


怎样在 CentOS 里下载 RPM 包及其所有依赖包

很不错的技巧

本地化最靠谱。所以自从开始使用Debian Gnu/Linux之后就没改过了。这个就是比其他版本好一点点！！！

本地化是什么意思？

Debian不是有光盤鏡像下載嗎？可以做成本地源～

很奇怪suse与redhat商业化源下载后给别人建立本地源怎么办？

厉害了！

最简单的方法是yum install PACKAGE, 系统给出提示的时候选择d，只下载不安装即可。

来自上海的 Internet Explorer 11.0|Windows 7 用户

这个只是下载了依赖的rpm，但是rpm所以来的lib包，如glibc等等，就下载不下来了……比较无语

![](/data/attachment/album/201611/07/173052bje21e908eajj2ek.jpg)

前几天我尝试去创建一个仅包含我们经常在 CentOS 7 下使用的软件的本地仓库。当然，我们可以使用 curl 或者 wget 下载任何软件包，然而这些命令并不能下载要求的依赖软件包。你必须去花一些时间而且手动的去寻找和下载被安装的软件所依赖的软件包。然而，我们并不是必须这样。在这个简短的教程中，我将会带领你以两种方式下载软件包及其所有依赖包。我已经在 CentOS 7 下进行了测试，不过这些相同的步骤或许在其他基于 RPM 管理系统的发行版上也可以工作，例如 RHEL，Fedora 和 Scientific Linux。

### 方法 1 利用 “Downloadonly” 插件下载 RPM 软件包及其所有依赖包

我们可以通过 yum 命令的 “Downloadonly” 插件下载 RPM 软件包及其所有依赖包。

为了安装 Downloadonly 插件，以 root 身份运行以下命令。

```
yum install yum-plugin-downloadonly

```

现在，运行以下命令去下载一个 RPM 软件包。

```
yum install --downloadonly <package-name>

```

默认情况下，这个命令将会下载并把软件包保存到 `/var/cache/yum/` 的 `rhel-{arch}-channel/packageslocation` 目录，不过，你也可以下载和保存软件包到任何位置，你可以通过 `–downloaddir` 选项来指定。

```
yum install --downloadonly --downloaddir=<directory> <package-name>

```

例子:

```
yum install --downloadonly --downloaddir=/root/mypackages/ httpd

```

终端输出:

```
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: centos.excellmedia.net
 * epel: epel.mirror.angkasa.id
 * extras: centos.excellmedia.net
 * updates: centos.excellmedia.net
Resolving Dependencies
--> Running transaction check
---> Package httpd.x86_64 0:2.4.6-40.el7.centos.4 will be installed
--> Processing Dependency: httpd-tools = 2.4.6-40.el7.centos.4 for package: httpd-2.4.6-40.el7.centos.4.x86_64
--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-40.el7.centos.4.x86_64
--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-40.el7.centos.4.x86_64
--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-40.el7.centos.4.x86_64
--> Running transaction check
---> Package apr.x86_64 0:1.4.8-3.el7 will be installed
---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed
---> Package httpd-tools.x86_64 0:2.4.6-40.el7.centos.4 will be installed
---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=======================================================================================================================================
 Package Arch Version Repository Size
=======================================================================================================================================
Installing:
 httpd x86_64 2.4.6-40.el7.centos.4 updates 2.7 M
Installing for dependencies:
 apr x86_64 1.4.8-3.el7 base 103 k
 apr-util x86_64 1.5.2-6.el7 base 92 k
 httpd-tools x86_64 2.4.6-40.el7.centos.4 updates 83 k
 mailcap noarch 2.1.41-2.el7 base 31 k

Transaction Summary
=======================================================================================================================================
Install 1 Package (+4 Dependent packages)

Total download size: 3.0 M
Installed size: 10 M
Background downloading packages, then exiting:
(1/5): apr-1.4.8-3.el7.x86_64.rpm | 103 kB 00:00:01
(2/5): apr-util-1.5.2-6.el7.x86_64.rpm | 92 kB 00:00:01
(3/5): mailcap-2.1.41-2.el7.noarch.rpm | 31 kB 00:00:01
(4/5): httpd-tools-2.4.6-40.el7.centos.4.x86_64.rpm | 83 kB 00:00:01
(5/5): httpd-2.4.6-40.el7.centos.4.x86_64.rpm | 2.7 MB 00:00:09
---------------------------------------------------------------------------------------------------------------------------------------
Total 331 kB/s | 3.0 MB 00:00:09
exiting because "Download Only" specified

```

![](/data/attachment/album/201611/07/172733jqrrvca6qb6roqx8.png)

现在去你指定的目录位置下，你将会看到那里有下载好的软件包和依赖的软件。在我这种情况下，我已经把软件包下载到 `/root/mypackages/` 目录下。

让我们来查看一下内容。

```
ls /root/mypackages/

```

样本输出：

```
apr-1.4.8-3.el7.x86_64.rpm
apr-util-1.5.2-6.el7.x86_64.rpm
httpd-2.4.6-40.el7.centos.4.x86_64.rpm
httpd-tools-2.4.6-40.el7.centos.4.x86_64.rpm
mailcap-2.1.41-2.el7.noarch.rpm

```

![](/data/attachment/album/201611/07/172800chxg00wlpd0ylx0v.png)

正如你在上面输出所看到的, httpd软件包已经被依据所有依赖性下载完成了 。

请注意，这个插件适用于 `yum install/yum update`， 但是并不适用于 `yum groupinstall`。默认情况下，这个插件将会下载仓库中最新可用的软件包。然而你可以通过指定版本号来下载某个特定的软件版本。

例子:

```
yum install --downloadonly --downloaddir=/root/mypackages/ httpd-2.2.6-40.el7

```

此外，你也可以如下一次性下载多个包：

```
yum install --downloadonly --downloaddir=/root/mypackages/ httpd vsftpd

```

### 方法 2 使用 “Yumdownloader” 工具来下载 RPM 软件包及其所有依赖包

“Yumdownloader” 是一款简单，但是却十分有用的命令行工具，它可以一次性下载任何 RPM 软件包及其所有依赖包。

以 root 身份运行如下命令安装 “Yumdownloader” 工具。

```
yum install yum-utils

```

一旦安装完成，运行如下命令去下载一个软件包，例如 httpd。

```
yumdownloader httpd

```

为了根据所有依赖性下载软件包，我们使用 `--resolve` 参数：

```
yumdownloader --resolve httpd

```

默认情况下，Yumdownloader 将会下载软件包到当前工作目录下。

为了将软件下载到一个特定的目录下，我们使用 `--destdir` 参数：

```
yumdownloader --resolve --destdir=/root/mypackages/ httpd

```

或者，

```
yumdownloader --resolve --destdir /root/mypackages/ httpd

```

终端输出：

```
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: centos.excellmedia.net
 * epel: epel.mirror.angkasa.id
 * extras: centos.excellmedia.net
 * updates: centos.excellmedia.net
--> Running transaction check
---> Package httpd.x86_64 0:2.4.6-40.el7.centos.4 will be installed
--> Processing Dependency: httpd-tools = 2.4.6-40.el7.centos.4 for package: httpd-2.4.6-40.el7.centos.4.x86_64
--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-40.el7.centos.4.x86_64
--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-40.el7.centos.4.x86_64
--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-40.el7.centos.4.x86_64
--> Running transaction check
---> Package apr.x86_64 0:1.4.8-3.el7 will be installed
---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed
---> Package httpd-tools.x86_64 0:2.4.6-40.el7.centos.4 will be installed
---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed
--> Finished Dependency Resolution
(1/5): apr-util-1.5.2-6.el7.x86_64.rpm | 92 kB 00:00:01
(2/5): mailcap-2.1.41-2.el7.noarch.rpm | 31 kB 00:00:02
(3/5): apr-1.4.8-3.el7.x86_64.rpm | 103 kB 00:00:02
(4/5): httpd-tools-2.4.6-40.el7.centos.4.x86_64.rpm | 83 kB 00:00:03
(5/5): httpd-2.4.6-40.el7.centos.4.x86_64.rpm | 2.7 MB 00:00:19

```

![](/data/attachment/album/201611/07/172825ez4nhrn96b39lbr8.png)

让我们确认一下软件包是否被下载到我们指定的目录下。

```
ls /root/mypackages/

```

终端输出：

```
apr-1.4.8-3.el7.x86_64.rpm
apr-util-1.5.2-6.el7.x86_64.rpm
httpd-2.4.6-40.el7.centos.4.x86_64.rpm
httpd-tools-2.4.6-40.el7.centos.4.x86_64.rpm
mailcap-2.1.41-2.el7.noarch.rpm

```

![](/data/attachment/album/201611/07/172848ua6rsyccao0zxan6.png)

不像 Downloadonly 插件，Yumdownload 可以下载一组相关的软件包。

```
yumdownloader "@Development Tools" --resolve --destdir /root/mypackages/

```

在我看来，我喜欢 Yumdownloader 更胜于 Yum 的 Downloadonly 插件。但是，两者都是十分简单易懂而且可以完成相同的工作。

这就是今天所有的内容，如果你觉得这份引导教程有用，清在你的社交媒体上面分享一下去让更多的人知道。

干杯！

---

via: <https://www.ostechnix.com/download-rpm-package-dependencies-centos/>

作者：[SK](http://ostechnix.tradepub.com/free/w_make272/prgm.cgi?a=1) 译者：[LinuxBars](https://github.com/LinuxBars) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Wire：一个极酷、专注于个人隐私的开源聊天应用程序已经来到了 Linux 上

Summary: 使 Wire 对于我们这些 FOSS（自由/开源软件）爱好者来说更加重要的是，几个月前 Wire 开源了。几个月下来我们见到了一个用于 Linux 的 beta 版本 Wire 桌面应用程序。

不错哟，telegram被墙很不爽，试试这个。

有伟大的墙，这东西只能看起耍

来自陕西西安的 Chrome Mobile 54.0|Android 6.0 用户

再好的IM, 没有使用者也没用, 天朝人民都被 深圳的企鹅绑架着. 我已不想挣扎了.

注重安全的东东不被qiang才怪～～～

悲伤的故事

这界面好像一般啊<br />
Electron的性能如何？

来自广东广州广东工贸职业技术学院的 Firefox 49.0|GNU/Linux 用户

试了一下，还没中文和表情包，要下载net4.5之类的东西

来自香港的 Internet Explorer 10.0|Windows 8 用户

支持开源软件

优秀的聊天软件的最悲剧就是，抵不过企鹅的用户基数，常联系的人，需要联系的人都不用，那是一点办法都没有

telegram被墙，其客户端开源，保障隐私，关键是服务端不清楚，也不安全，这个也如此

聊天软件没联系人其他方面做的再好有个卵用

支持。不喜欢qq的商业氛围。

有意思

![](/data/attachment/album/201611/08/101545s8plpwfmy8hd8wvh.jpeg)

回到大约两年前，一些曾开发 [Skype](https://www.skype.com/en/) 的开发人员发行了一个漂亮的新聊天应用个程序：[Wire](https://wire.com/)。当我说它漂亮的时候，只是谈论它的“外貌”。Wire 具有一个许多其他聊天应用程序所没有的整洁优美的“外貌”，但这并不是它最大的卖点。

从一开始，Wire 就推销自己是[世界上最注重隐私的聊天应用程序](http://www.ibtimes.co.uk/wire-worlds-most-private-messaging-app-offers-total-encryption-calls-texts-1548964)。无论是文本、语音电话，还是图表、图像等基本的内容，它都提供端到端的加密。

WhatsApp 也提供‘端到端加密’，但是考虑一下它的所有者 [Facebook 为了吸引用户而把 WhatsApp 的数据分享出去](https://techcrunch.com/2016/08/25/whatsapp-to-share-user-data-with-facebook-for-ad-targeting-heres-how-to-opt-out/)。我不太相信 WhatsApp 以及它的加密手段。

使 Wire 对于我们这些 FOSS（自由/开源软件）爱好者来说更加重要的是，几个月前 [Wire 开源了](http://www.infoworld.com/article/3099194/security/wire-open-sources-messaging-client-woos-developers.html)。几个月下来我们见到了一个用于 Linux 的 beta 版本 Wire 桌面应用程序。

除了一个包装器以外，桌面版的 Wire 并没有比 web 版多任何东西。感谢 [Electron 开源项目](http://electron.atom.io/)提供了一种开发跨平台桌面应用程序的简单方式。许多其他应用程序也通过使用 Electron 为 Linux 带去了一个本地桌面应用程序，包括 [Skype](https://itsfoss.com/skpe-alpha-linux/)。

### WIRE 的特性：

在我们了解有关 Linux 版 Wire 应用程序的更多信息之前，让我们先快速看一下它的一些主要特性。

* 开源应用程序
* 针对所有类型内容的全加密
* 无广告，无数据收集，无数据分享
* 支持文本，语音以及视频聊天
* 支持群聊和群电话
* [音频过滤器](https://medium.com/colorful-conversations/the-tune-for-this-summer-audio-filters-eca8cb0b4c57#.c8gvs143k)（不需要吸入氦元素，只需要使用过滤器就可以用有趣的声音说话）
* 不需要电话号码，可以使用邮箱登录
* 优美、现代化的界面
* 跨平台聊天应用程序，iOS，Android，Web，Mac，Windows 和 Linux 客户机均有相应版本
* 欧洲法保护（欧洲法比美国法更注重隐私）

Wire 有一些更棒的特性，尤其是和[Snapchat](https://www.snapchat.com/)类似的音频过滤器。

### 在 Linux 上安装 WIRE

在安装 Wire 到 Linux 上之前，让我先警告你它目前还处于 beta 阶段。所以，如果你遇到一些故障，请不要生气。

Wire 有一个 64 位系统可使用的 .deb 客户端。如果你有一台 [32 位或者 64 位系统](https://itsfoss.com/32-bit-64-bit-ubuntu/)的电脑，你可以使用这些技巧来找到它。你可以从下面的链接下载 .deb 文件。

* [下载 Linux 版 Wire [Beta]](https://wire.com/download/)

如果感兴趣的话，你也可以看一看它的源代码：

* [桌面版 Wire 源代码](https://github.com/wireapp/wire-desktop)

这是 Wire 的默认界面，看起来像 [elementary OS Loki](https://itsfoss.com/tag/elementary-os-loki/):

![](/data/attachment/album/201611/08/101614uo2woz4qzymfg2w5.jpeg)

你看，他们甚至还弄了一个机器人：）

你已经开始使用 Wire 了吗？如果是，你的体验是什么样的？如果没有，你将尝试一下吗？因为它现在是[开源的](https://itsfoss.com/tag/open-source)并且可以在 Linux 上使用。

---

via: <https://itsfoss.com/wire-messaging-linux/>

作者：[Abhishek Prakash](https://itsfoss.com/author/abhishek/)  译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


通过 docker-compose 进行快速原型设计

一个`docker-compose up -d`被错打成`docker compose up -d`

谢谢！

在这篇文章中，我们将考察一个 Node.js 开发原型，该原型用于从英国三个主要折扣网店查找“Raspberry PI Zero”的库存。

我写好了代码，然后经过一晚的鼓捣把它部署在 Aure 上的 Ubuntu 虚拟机上。Docker 和 docker-compose 工具使得部署和更新过程非常快。

![](/data/attachment/album/201611/08/111444sa8fbkk442xx0k09.jpg)

### 还记得链接指令（link）吗？

如果你已经阅读过 [Hands-on Docker tutorial](http://blog.alexellis.io/handsondocker)，那么你应该已经可以使用命令行链接 Docker 容器。通过命令行将 Node.js 的计数器链接到 Redis 服务器，其命令可能如下所示：

```
$ docker run -d -P --name redis1
$ docker run -d hit_counter -p 3000:3000 --link redis1:redis

```

现在假设你的应用程序分为三层：

* Web 前端
* 处理长时间运行任务的批处理层
* Redis 或者 mongo 数据库

通过`--link`的显式链接只是管理几个容器是可以的，但是可能会因为我们向应用程序添加更多层或容器而失控。

### 加入 docker-compose

![](/data/attachment/album/201611/08/111459z96ycryjjyqlq7c2.png)

*Docker Compose logo*

docker-compose 工具是标准 Docker 工具箱的一部分，也可以单独下载。 它提供了一组丰富的功能，通过纯文本 YAML 文件配置所有应用程序的部件。

上面的例子看起来像这样：

```
version: "2.0"
services:
  redis1:
    image: redis
  hit_counter:
    build: ./hit_counter
    ports:
     - 3000:3000

```

从 Docker 1.10 开始，我们可以利用网络覆盖（network overlays）来帮助我们在多个主机上进行扩展。 在此之前，链接仅能工作在单个主机上。 `docker-compose scale` 命令可以用来在需要时带来更多的计算能力。

>
> 查看 docker.com 上的 [docker-compose](https://docs.docker.com/compose/compose-file/) 参考
>
>
>

### 　真实工作示例：Raspberry PI 库存警示

![](/data/attachment/album/201611/08/111459mn5l72lckj7nm8cz.jpg)

*新的 Raspberry PI Zero v1.3 图片，由 Pimoroni 提供*

Raspberry PI Zero 嗡嗡作响 - 它是一个极小的微型计算机，具有 1GHz CPU 和 512MB RAM，可以运行完整的Linux、Docker、Node.js、Ruby 和其他许多流行的开源工具。 PI Zero 最好的优点之一就是它成本只有 5 美元。 这也意味着它销售的速度非常之快。

*如果你想在 PI 上尝试 Docker 和 Swarm，请查看下面的教程：[Docker Swarm on the PI Zero](http://blog.alexellis.io/dockerswarm-pizero/)*

### 原始网站：whereismypizero.com

我发现一个网页，它使用屏幕抓取以找出 4-5 个最受欢迎的折扣网店是否有库存。

* 网站包含静态 HTML 网页
* 向每个折扣网店发出一个 XMLHttpRequest 访问 /public/api/
* 服务器向每个网店发出 HTTP 请求并执行抓屏

每一次对 /public/api/ 的调用，其执行花 3 秒钟，而使用 Apache Bench（ab），我每秒只能完成 0.25 个请求。

### 重新发明轮子

零售商似乎并不介意 whereismypizero.com 抓取他们的网站的商品库存信息，所以我开始从头写一个类似的工具。 我尝试通过缓存和解耦 web 层来处理更多的抓取请求。 Redis 是执行这项工作的完美工具。 它允许我设置一个自动过期的键/值对（即一个简单的缓存），还可以通过 pub/sub 在 Node.js 进程之间传输消息。

>
> 复刻或者追踪放在 github 上的代码: [alexellis/pi*zero*stock](https://github.com/alexellis/pi_zero_stock)
>
>
>

如果之前使用过 Node.js，你肯定知道它是单线程的，并且任何 CPU 密集型任务，如解析 HTML 或 JSON 都可能导致速度放缓。一种缓解这种情况的方法是使用一个工作进程和 Redis 消息通道作为它和 web 层之间的连接组织。

* Web 层
	+ 使用 200 代表缓冲命中（该商店的 Redis 键存在）
	+ 使用 202 代表高速缓存未命中（该商店的 Redis 键不存在，因此发出消息）
	+ 因为我们只是读一个 Redis 键，响应时间非常快。
* 库存抓取器
	+ 执行 HTTP 请求
	+ 用于在不同类型的网店上抓屏
	+ 更新 Redis 键的缓存失效时间为 60 秒
	+ 另外，锁定一个 Redis 键，以防止对网店过多的 HTTP 请求。

```
version: "2.0"
services:
  web:
    build: ./web/
    ports:
     - "3000:3000"
  stock_fetch:
    build: ./stock_fetch/
  redis:
    image: redis

```

*来自示例的 docker-compose.yml 文件*

一旦本地正常工作，再向 Azure 的 Ubuntu 16.04 镜像云部署就轻车熟路，只花了不到 5 分钟。 我登录、克隆仓库并键入`docker-compose up -d`， 这就是所有的工作 - 快速实现整个系统的原型不会比这几个步骤更多。 任何人（包括 whereismypizero.com 的所有者）只需两行命令就可以部署新解决方案：

```
$ git clone https://github.com/alexellis/pi_zero_stock
$ docker-compose up -d

```

更新网站很容易，只需要一个`git pull`命令，然后执行`docker-compose up -d`命令，该命令需要带上`--build`参数。

如果你仍然手动链接你的 Docker 容器，请自己或使用如下我的代码尝试 Docker Compose：

>
> 复刻或者追踪在 github 上的代码： [alexellis/pi*zero*stock](https://github.com/alexellis/pi_zero_stock)
>
>
>

### 一睹测试网站芳容

目前测试网站使用 docker-compose 部署：[stockalert.alexellis.io](http://stockalert.alexellis.io/)

![](/data/attachment/album/201611/08/111500zsbew23e32no2e88.png)

*预览于 2016 年 5 月 16 日*

---

via: <http://blog.alexellis.io/rapid-prototype-docker-compose/>

作者：[Alex Ellis](http://blog.alexellis.io/author/alex/) 译者：[firstadream](https://github.com/firstadream) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译，[Linux中国](https://linux.cn/) 荣誉推出


标志性文本编辑器 Vim 迎来其 25 周年纪念日

Live long & prosper!

8.0 版本怎么样？稳定么？

zan

让我们把时钟往回拨一点。不，别停…再来一点……好了！在 25 年前，当你的某些专家同事还在蹒跚学步时，Bram Moolenaar 已经开始为他的 Amiga 计算机开发一款文本编辑器。他曾经是 Unix 上的 vi 用户，但 Amiga 上却没有与其类似的编辑器。在三年的开发之后，1991 年 11 月 2 日，他发布了“<ruby> 仿 vi 编辑器 <rp>  （ </rp> <rt>  Vi IMitation </rt> <rp>  ） </rp></ruby>”（也就是 [Vim](http://www.vim.org/)）的第一个版本。

两年之后，随着 2.0 版本的发布，Vim 的功能集已经超过了 vi，所以这款编辑器的全称也被改为了“<ruby> vi 增强版 <rp>  （ </rp> <rt>  Vi IMproved </rt> <rp>  ） </rp></ruby>”。现在，刚刚度过 25 岁生日的 Vim，已经可以在绝大部分平台上运行——Windows、OS/2、OpenVMS、BSD、Android、iOS——并且已在 OS X 及很多 Linux 发行版上成为标配软件。它受到了许多赞誉，也受到了许多批评，不同组织或开发者也会围绕它来发起争论，甚至有些面试官会问：“你用 Emacs 还是 Vim？”Vim 已拥有自由许可证，它基于<ruby> <a href="http://vimdoc.sourceforge.net/htmldoc/uganda.html#license">  慈善软件证书 </a> <rp>  （ </rp> <rt>  charityware license </rt> <rp>  ） </rp></ruby>（“帮助乌干达的可怜儿童”）发布，该证书与 GPL 兼容。

![](/data/attachment/album/201611/08/150300nhw863h63h84x2xz.jpg)

Vim 是一个灵活的、可扩展的编辑器，带有一个强大的插件系统，被深入集成到许多开发工具，并且可以编辑上百种编程语言或文件类型的文件。 在 Vim 诞生二十五年后，Bram Moolenaar 仍然在主导开发并维护它——这真是一个壮举！Vim 曾经在超过 20 年的时间里数次间歇中断开发，但在 2016 年 9 月，它发布了 [8.0 版本](/article-7766-1.html)，添加了许多新功能，为现代程序员用户提供了更多方便。很多年来，Vim 在官网上售卖 T 恤及 logo 贴纸，所得的销售款为支持 [ICCF](http://iccf-holland.org/)——一个帮助乌干达儿童的德国慈善机构做出了巨大贡献。Vim 所支持的慈善项目深受 Moolenaar 喜爱，Mooleaar 本人也去过乌干达，在基巴莱的一个儿童中心做志愿者。

Vim 在开源历史上记下了有趣的一笔：一个工程，在 25 年中，坚持由一个稳定的核心贡献者维护，拥有超多的用户，但很多人从未了解过它的历史。如果你想简单的了解 Vim，[请访问它的网站](http://www.vim.org/)，或者你可以读一读 [Vim 入门的一些小技巧](https://opensource.com/life/16/7/tips-getting-started-vim)，或者在 Opensource.com 阅读一位 [Vim 新用户的故事](https://opensource.com/business/16/8/7-reasons-love-vim)。

---

via: <https://opensource.com/life/16/11/happy-birthday-vim-25>

作者：[D Ruth Bavousett](https://opensource.com/users/druthb) 译者：[StdioA](https://github.com/StdioA) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


如何在 Arch Linux 的终端里设定 WiFi 网络

很实用的技巧性操作文章，希望大家收藏。

wifi-menu so easy

谢谢楼主，看完配置好了。一开始不能自动连接，每次报错，只能开机后再运行WiFi-menu，或者netctl。后来我认为是以前启动的netctl不对引起的，于是删除了所有的热点设置，重新配置一个wlp9s0-111，然后netctl  reenable   wlp9s0-111,netctl  restart  wlp9s0-111。就可以自动启动了。

来自黑龙江黑河的 MIUI Browser 10.7|Android 8.0 用户

![How To Setup A WiFi In Arch Linux Using Terminal](/data/attachment/album/201611/09/070520vow2jp725rr7zvvq.jpg)

如果你使用的是其他 Linux 发行版 而不是 Arch CLI，那么可能会不习惯在终端里设置 WiFi。尽管整个过程有点简单，不过我还是要讲一下。在这篇文章里，我将带领新手们通过一步步的设置向导，把你们的 Arch Linux 接入到你的 WiFi 网络里。

在 Linux 里有很多程序来设置无线连接，我们可以用 `ip` 和 `iw` 来配置因特网连接，但是对于新手来说有点复杂。所以我们会使用 `netctl` 命令，这是一个基于命令行的工具，用来通过配置文件来设置和管理网络连接。

注意：所有的设定都需要 root 权限，或者你也可以使用 `sudo` 命令来完成。

### 搜索网络

运行下面的命令来查看你的网络接口：

```
iwconfig

```

运行如下命令启用你的网络接口，如果没有启用的话：

```
ip link set  interface up

```

运行下面的命令搜索可用的 WiFi 网络。可以向下翻页来查看。

```
iwlist interface scan | less

```

**注意：** 命令里的 interface 是之前用 `iwconfig` 获取到的实际网络接口。

扫描完，如果不使用该接口可以运行如下命令关闭：

```
ip link set interface down

```

### 使用 netctl 配置 Wi-Fi：

在使用 `netctl` 设置连接之前，你必须先检查一下你的网卡在 Linux 下的兼容性。

运行命令：

```
lspci -k

```

这条命令是用来检查内核是否加载了你的无线网卡驱动。输出必须是像这样的：

![](/data/attachment/album/201611/09/070520rhzzzv7ozn52yhgx.png)

如果内核没有加载驱动，你就必须使用有线连接来安装一下。这里是 Linux 无线网络的官方维基页面：<https://wireless.wiki.kernel.org/>。

如果你的无线网卡和 Linux 兼容，你可以使用 `netctl configuration`。

`netctl` 使用配置文件，这是一个包含连接信息的文件。创建这个文件有简单和困难两种方式。

#### 简单方式 – Wifi-menu

如果你想用 `wifi-menu`，必须安装 `dialog`。

1. 运行命令: `wifi-menu`
2. 选择你的网络

![wifi-menu to setup wifi in arch](/data/attachment/album/201611/09/070521jzlfn8u38nbh9bnn.png)
3. 输入正确的密码并等待

![wifi-menu setup wifi password in arch](/data/attachment/album/201611/09/070521nt1l3k4zf7l34uj3.png)

如果没有连接失败的信息，你可以用下面的命令确认下：

```
ping -c 3 www.google.com

```

哇！如果你看到正在 ping，意味着网络设置成功。你现在已经在 Arch Linux 下连上 WiFi 了。如果有任何问题，可以倒回去重来。也许漏了什么。

#### 困难方式

比起上面的 `wifi-menu` 命令，这种方式会难一点点，所以我叫做困难方式。在上面的命令里，网络配置会自动生成。而在困难方式里，我们将手动修改配置文件。不过不要担心，也没那么难。那我们开始吧！

1. 首先第一件事，你必须要知道网络接口的名字，通常会是 `wlan0` 或 `wlp2s0`，但是也有很多例外。要确认你自己的网络接口，输入 `iwconfig` 命令并记下来。

[![scan wifi networks in arch linux cli](/data/attachment/album/201611/09/070521cyz0gm1mie4m3zml.png)](http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/scan-wifi-networks-in-arch-linux-cli_orig.png)
2. 运行命令:

```
cd /etc/netctl/examples

```

在这个目录里，有很多不同的配置文件例子。
3. 拷贝将用到的配置文件例子到 `/etc/netctl/your_profile`

```
cp /etc/netctl/examples/wireless-wpa /etc/netctl/your_profile

```
4. 你可以用这个命令来查看配置文件内容: `cat /etc/netctl/your_profile`

![view network profile in arch linux](/data/attachment/album/201611/09/070521ddjflkxgsgjrkgd4.png)
5. 用 `vi` 或者 `nano` 编辑你的配置文件的下面几个部分：

```
nano /etc/netctl/your_profile

```

```
- `Interface`：比如说 `wlan0`
- `ESSID`：你的无线网络名字
- `key`：你的无线网络密码

```

**注意:**

如果你不知道怎么用 `nano`，打开文件后，编辑要修改的地方，完了按 `ctrl+o`，然后回车，然后按 `ctrl+x`。

![edit network profile in arch](/data/attachment/album/201611/09/070522t70dz75ptdp3x22l.png)

### 运行 netctl

1. 运行命令：

```
cd /etc/netctl
ls

```

你一定会看到 `wifi-menu` 生成的配置文件，比如 `wlan0-SSID`；或者你选择了困难方式，你一定会看到你自己创建的配置文件。
2. 运行命令启动连接配置：`netctl start your_profile`。
3. 用下面的命令测试连接：

```
ping -c 3 www.google.com

```

输出看上去像这样： ![check internet connection in arch linux](/data/attachment/album/201611/09/070522nytojdxwaxxxauyt.png)
4. 最后，你必须运行下面的命令：`netctl enable your_profile`。

```
netctl enable your_profile

```

这样将创建并激活一个 systemd 服务，然后开机时自动启动。然后欢呼吧！你在你的 Arch Linux 里配置好 wifi 网络啦。

### 其他工具

你还可以使用其他程序来设置无线连接：

iw：

1. `iw dev wlan0 link` – 状态
2. `iw dev wlan0 scan` – 搜索网络
3. `iw dev wlan0 connect your_essid` – 连接到开放网络
4. `iw dev wlan0 connect your_essid key your_key` - 使用 16 进制密钥连接到 WEP 加密的网络

wpa\_supplicant

* <https://wiki.archlinux.org/index.php/WPA_supplicant>

Wicd

* <https://wiki.archlinux.org/index.php/wicd>

NetworkManager

* <https://wiki.archlinux.org/index.php/NetworkManager>

### 总结

会了吧！我提供了在 **Arch Linux** 里接入 WiFI 网络的三种方式。这里有一件事我再强调一下，当你执行第一条命令的时候，请记住你的网络接口名字。在接下来搜索网络的命令里，请使用你的网络接口名字比如 `wlan0` 或 `wlp2s0`（上一个命令里得到的），而不是用 interface 这个词。如果你碰到任何问题，可以在下面的评论区里直接留言给我。然后别忘了在你的朋友圈里和大家分享这篇文章哦。谢谢！

---

via: <http://www.linuxandubuntu.com/home/how-to-setup-a-wifi-in-arch-linux-using-terminal>

作者：[Mohd Sohail](http://www.linuxandubuntu.com/contact-us.html) 译者：[zpl1025](https://github.com/zpl1025) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出