理解多区域配置中的 firewalld

![](/data/attachment/album/201711/21/233944jiz6thts6pk6y6ss.jpg)

现在的新闻里充斥着服务器被攻击和数据失窃事件。对于一个阅读过安全公告博客的人来说，通过访问错误配置的服务器，利用最新暴露的安全漏洞或通过窃取的密码来获得系统控制权，并不是件多困难的事情。在一个典型的 Linux 服务器上的任何互联网服务都可能存在漏洞，允许未经授权的系统访问。

因为在应用程序层面上强化系统以防范任何可能的威胁是不可能做到的事情，而防火墙可以通过限制对系统的访问提供了安全保证。防火墙基于源 IP、目标端口和协议来过滤入站包。因为这种方式中，仅有几个 IP/端口/协议的组合与系统交互，而其它的方式做不到过滤。

Linux 防火墙是通过 netfilter 来处理的，它是内核级别的框架。这十几年来，iptables 被作为 netfilter 的用户态抽象层（LCTT 译注： userland，一个基本的 UNIX 系统是由 kernel 和 userland 两部分构成，除 kernel 以外的称为 userland）。iptables 将包通过一系列的规则进行检查，如果包与特定的 IP/端口/协议的组合匹配，规则就会被应用到这个包上，以决定包是被通过、拒绝或丢弃。

Firewalld 是最新的 netfilter 用户态抽象层。遗憾的是，由于缺乏描述多区域配置的文档，它强大而灵活的功能被低估了。这篇文章提供了一个示例去改变这种情况。

### Firewalld 的设计目标

firewalld 的设计者认识到大多数的 iptables 使用案例仅涉及到几个单播源 IP，仅让每个符合白名单的服务通过，而其它的会被拒绝。这种模式的好处是，firewalld 可以通过定义的源 IP 和/或网络接口将入站流量分类到不同<ruby> 区域 <rt>  zone </rt></ruby>。每个区域基于指定的准则按自己配置去通过或拒绝包。

另外的改进是基于 iptables 进行语法简化。firewalld 通过使用服务名而不是它的端口和协议去指定服务，使它更易于使用，例如，是使用 samba 而不是使用 UDP 端口 137 和 138 和 TCP 端口 139 和 445。它进一步简化语法，消除了 iptables 中对语句顺序的依赖。

最后，firewalld 允许交互式修改 netfilter，允许防火墙独立于存储在 XML 中的永久配置而进行改变。因此，下面的的临时修改将在下次重新加载时被覆盖：

```
# firewall-cmd <some modification>

```

而，以下的改变在重加载后会永久保存：

```
# firewall-cmd --permanent <some modification>
# firewall-cmd --reload

```

### 区域

在 firewalld 中最上层的组织是区域。如果一个包匹配区域相关联的网络接口或源 IP/掩码 ，它就是区域的一部分。可用的几个预定义区域：

```
# firewall-cmd --get-zones
block dmz drop external home internal public trusted work

```

任何配置了一个**网络接口**和/或一个**源**的区域就是一个<ruby> 活动区域 <rt>  active zone </rt></ruby>。列出活动的区域：

```
# firewall-cmd --get-active-zones
public
  interfaces: eno1 eno2

```

**Interfaces** （接口）是系统中的硬件和虚拟的网络适配器的名字，正如你在上面的示例中所看到的那样。所有的活动的接口都将被分配到区域，要么是默认的区域，要么是用户指定的一个区域。但是，一个接口不能被分配给多于一个的区域。

在缺省配置中，firewalld 设置所有接口为 public 区域，并且不对任何区域设置源。其结果是，`public` 区域是唯一的活动区域。

**Sources** （源）是入站 IP 地址的范围，它也可以被分配到区域。一个源（或重叠的源）不能被分配到多个区域。这样做的结果是产生一个未定义的行为，因为不清楚应该将哪些规则应用于该源。

因为指定一个源不是必需的，任何包都可以通过接口匹配而归属于一个区域，而不需要通过源匹配来归属一个区域。这表示通过使用优先级方式，优先到达多个指定的源区域，稍后将详细说明这种情况。首先，我们来检查 `public` 区域的配置：

```
# firewall-cmd --zone=public --list-all
public (default, active)
  interfaces: eno1 eno2
  sources:
  services: dhcpv6-client ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:
# firewall-cmd --permanent --zone=public --get-target
default

```

逐行说明如下：

* `public (default, active)` 表示 `public` 区域是默认区域（当接口启动时会自动默认），并且它是活动的，因为，它至少有一个接口或源分配给它。
* `interfaces: eno1 eno2` 列出了这个区域上关联的接口。
* `sources:` 列出了这个区域的源。现在这里什么都没有，但是，如果这里有内容，它们应该是这样的格式 xxx.xxx.xxx.xxx/xx。
* `services: dhcpv6-client ssh` 列出了允许通过这个防火墙的服务。你可以通过运行 `firewall-cmd --get-services` 得到一个防火墙预定义服务的详细列表。
* `ports:` 列出了一个允许通过这个防火墙的目标端口。它是用于你需要去允许一个没有在 firewalld 中定义的服务的情况下。
* `masquerade: no` 表示这个区域是否允许 IP 伪装。如果允许，它将允许 IP 转发，它可以让你的计算机作为一个路由器。
* `forward-ports:` 列出转发的端口。
* `icmp-blocks:` 阻塞的 icmp 流量的黑名单。
* `rich rules:` 在一个区域中优先处理的高级配置。
* `default` 是目标区域，它决定了与该区域匹配而没有由上面设置中显式处理的包的动作。

### 一个简单的单区域配置示例

如果只是简单地锁定你的防火墙。简单地在删除公共区域上当前允许的服务，并重新加载：

```
# firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client
# firewall-cmd --permanent --zone=public --remove-service=ssh
# firewall-cmd --reload

```

在下面的防火墙上这些命令的结果是：

```
# firewall-cmd --zone=public --list-all
public (default, active)
  interfaces: eno1 eno2
  sources:
  services:
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:
# firewall-cmd --permanent --zone=public --get-target
default

```

本着尽可能严格地保证安全的精神，如果发生需要在你的防火墙上临时开放一个服务的情况（假设是 ssh），你可以增加这个服务到当前会话中（省略 `--permanent`），并且指示防火墙在一个指定的时间之后恢复修改：

```
# firewall-cmd --zone=public --add-service=ssh --timeout=5m

```

这个 `timeout` 选项是一个以秒（`s`）、分（`m`）或小时（`h`）为单位的时间值。

### 目标

当一个区域处理它的源或接口上的一个包时，但是，没有处理该包的显式规则时，这时区域的<ruby> 目标 <rt>  target </rt></ruby>决定了该行为：

* `ACCEPT`：通过这个包。
* `%%REJECT%%`：拒绝这个包，并返回一个拒绝的回复。
* `DROP`：丢弃这个包，不回复任何信息。
* `default`：不做任何事情。该区域不再管它，把它踢到“楼上”。

在 firewalld 0.3.9 中有一个 bug （已经在 0.3.10 中修复），对于一个目标是除了“default”以外的源区域，不管允许的服务是什么，这的目标都会被应用。例如，一个使用目标 `DROP` 的源区域，将丢弃所有的包，甚至是白名单中的包。遗憾的是，这个版本的 firewalld 被打包到 RHEL7 和它的衍生版中，使它成为一个相当常见的 bug。本文中的示例避免了可能出现这种行为的情况。

### 优先权

活动区域中扮演两个不同的角色。关联接口行为的区域作为接口区域，并且，关联源行为的区域作为源区域（一个区域能够扮演两个角色）。firewalld 按下列顺序处理一个包：

1. 相应的源区域。可以存在零个或一个这样的区域。如果这个包满足一个<ruby> 富规则 <rt>  rich rule </rt></ruby>、服务是白名单中的、或者目标没有定义，那么源区域处理这个包，并且在这里结束。否则，向上传递这个包。
2. 相应的接口区域。肯定有一个这样的区域。如果接口处理这个包，那么到这里结束。否则，向上传递这个包。
3. firewalld 默认动作。接受 icmp 包并拒绝其它的一切。

这里的关键信息是，源区域优先于接口区域。因此，对于多区域的 firewalld 配置的一般设计模式是，创建一个优先源区域来允许指定的 IP 对系统服务的提升访问，并在一个限制性接口区域限制其它访问。

### 一个简单的多区域示例

为演示优先权，让我们在 `public` 区域中将 `http` 替换成 `ssh`，并且为我们喜欢的 IP 地址，如 1.1.1.1，设置一个默认的 `internal` 区域。以下的命令完成这个任务：

```
# firewall-cmd --permanent --zone=public --remove-service=ssh
# firewall-cmd --permanent --zone=public --add-service=http
# firewall-cmd --permanent --zone=internal --add-source=1.1.1.1
# firewall-cmd --reload

```

这些命令的结果是生成如下的配置：

```
# firewall-cmd --zone=public --list-all
public (default, active)
  interfaces: eno1 eno2
  sources:
  services: dhcpv6-client http
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:
# firewall-cmd --permanent --zone=public --get-target
default
# firewall-cmd --zone=internal --list-all
internal (active)
  interfaces:
  sources: 1.1.1.1
  services: dhcpv6-client mdns samba-client ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:
# firewall-cmd --permanent --zone=internal --get-target
default

```

在上面的配置中，如果有人尝试从 1.1.1.1 去 `ssh`，这个请求将会成功，因为这个源区域（`internal`）被首先应用，并且它允许 `ssh` 访问。

如果有人尝试从其它的地址，如 2.2.2.2，去访问 `ssh`，它不是这个源区域的，因为和这个源区域不匹配。因此，这个请求被直接转到接口区域（`public`），它没有显式处理 `ssh`，因为，public 的目标是 `default`，这个请求被传递到默认动作，它将被拒绝。

如果 1.1.1.1 尝试进行 `http` 访问会怎样？源区域（`internal`）不允许它，但是，目标是 `default`，因此，请求将传递到接口区域（`public`），它被允许访问。

现在，让我们假设有人从 3.3.3.3 拖你的网站。要限制从那个 IP 的访问，简单地增加它到预定义的 `drop` 区域，正如其名，它将丢弃所有的连接：

```
# firewall-cmd --permanent --zone=drop --add-source=3.3.3.3
# firewall-cmd --reload

```

下一次 3.3.3.3 尝试去访问你的网站，firewalld 将转发请求到源区域（`drop`）。因为目标是 `DROP`，请求将被拒绝，并且它不会被转发到接口区域（`public`）。

### 一个实用的多区域示例

假设你为你的组织的一台服务器配置防火墙。你希望允许全世界使用 `http` 和 `https` 的访问，你的组织（1.1.0.0/16）和工作组（1.1.1.0/8）使用 `ssh` 访问，并且你的工作组可以访问 `samba` 服务。使用 firewalld 中的区域，你可以用一个很直观的方式去实现这个配置。

`public` 这个命名，它的逻辑似乎是把全世界访问指定为公共区域，而 `internal` 区域用于为本地使用。从在 `public` 区域内设置使用 `http` 和 `https` 替换 `dhcpv6-client` 和 `ssh` 服务来开始：

```
# firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client
# firewall-cmd --permanent --zone=public --remove-service=ssh
# firewall-cmd --permanent --zone=public --add-service=http
# firewall-cmd --permanent --zone=public --add-service=https

```

然后，取消 `internal` 区域的 `mdns`、`samba-client` 和 `dhcpv6-client` 服务（仅保留 `ssh`），并增加你的组织为源：

```
# firewall-cmd --permanent --zone=internal --remove-service=mdns
# firewall-cmd --permanent --zone=internal --remove-service=samba-client
# firewall-cmd --permanent --zone=internal --remove-service=dhcpv6-client
# firewall-cmd --permanent --zone=internal --add-source=1.1.0.0/16

```

为容纳你提升的 `samba` 的权限，增加一个富规则：

```
# firewall-cmd --permanent --zone=internal --add-rich-rule='rule family=ipv4 source address="1.1.1.0/8" service name="samba" accept'

```

最后，重新加载，把这些变化拉取到会话中：

```
# firewall-cmd --reload

```

仅剩下少数的细节了。从一个 `internal` 区域以外的 IP 去尝试通过 `ssh` 到你的服务器，结果是回复一个拒绝的消息。它是 firewalld 默认的。更为安全的作法是去显示不活跃的 IP 行为并丢弃该连接。改变 `public` 区域的目标为 `DROP`，而不是 `default` 来实现它：

```
# firewall-cmd --permanent --zone=public --set-target=DROP
# firewall-cmd --reload

```

但是，等等，你不再可以 ping 了，甚至是从内部区域！并且 icmp （ping 使用的协议）并不在 firewalld 可以列入白名单的服务列表中。那是因为，icmp 是第 3 层的 IP 协议，它没有端口的概念，不像那些捆绑了端口的服务。在设置公共区域为 `DROP` 之前，ping 能够通过防火墙是因为你的 `default` 目标通过它到达防火墙的默认动作（default），即允许它通过。但现在它已经被删除了。

为恢复内部网络的 ping，使用一个富规则：

```
# firewall-cmd --permanent --zone=internal --add-rich-rule='rule protocol value="icmp" accept'
# firewall-cmd --reload

```

结果如下，这里是两个活动区域的配置：

```
# firewall-cmd --zone=public --list-all
public (default, active)
  interfaces: eno1 eno2
  sources:
  services: http https
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:
# firewall-cmd --permanent --zone=public --get-target
DROP
# firewall-cmd --zone=internal --list-all
internal (active)
  interfaces:
  sources: 1.1.0.0/16
  services: ssh
  ports:
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:
        rule family=ipv4 source address="1.1.1.0/8" service name="samba" accept
        rule protocol value="icmp" accept
# firewall-cmd --permanent --zone=internal --get-target
default

```

这个设置演示了一个三层嵌套的防火墙。最外层，`public`，是一个接口区域，包含全世界的访问。紧接着的一层，`internal`，是一个源区域，包含你的组织，它是 `public` 的一个子集。最后，一个富规则增加到最内层，包含了你的工作组，它是 `internal` 的一个子集。

这里的关键信息是，当在一个场景中可以突破到嵌套层，最外层将使用接口区域，接下来的将使用一个源区域，并且在源区域中额外使用富规则。

### 调试

firewalld 采用直观范式来设计防火墙，但比它的前任 iptables 更容易产生歧义。如果产生无法预料的行为，或者为了更好地理解 firewalld 是怎么工作的，则可以使用 iptables 描述 netfilter 是如何配置操作的。前一个示例的输出如下，为了简单起见，将输出和日志进行了修剪:

```
# iptables -S
-P INPUT ACCEPT
... (forward and output lines) ...
-N INPUT_ZONES
-N INPUT_ZONES_SOURCE
-N INPUT_direct
-N IN_internal
-N IN_internal_allow
-N IN_internal_deny
-N IN_public
-N IN_public_allow
-N IN_public_deny
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j INPUT_ZONES_SOURCE
-A INPUT -j INPUT_ZONES
-A INPUT -p icmp -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -j REJECT --reject-with icmp-host-prohibited
... (forward and output lines) ...
-A INPUT_ZONES -i eno1 -j IN_public
-A INPUT_ZONES -i eno2 -j IN_public
-A INPUT_ZONES -j IN_public
-A INPUT_ZONES_SOURCE -s 1.1.0.0/16 -g IN_internal
-A IN_internal -j IN_internal_deny
-A IN_internal -j IN_internal_allow
-A IN_internal_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
-A IN_internal_allow -s 1.1.1.0/8 -p udp -m udp --dport 137 -m conntrack --ctstate NEW -j ACCEPT
-A IN_internal_allow -s 1.1.1.0/8 -p udp -m udp --dport 138 -m conntrack --ctstate NEW -j ACCEPT
-A IN_internal_allow -s 1.1.1.0/8 -p tcp -m tcp --dport 139 -m conntrack --ctstate NEW -j ACCEPT
-A IN_internal_allow -s 1.1.1.0/8 -p tcp -m tcp --dport 445 -m conntrack --ctstate NEW -j ACCEPT
-A IN_internal_allow -p icmp -m conntrack --ctstate NEW -j ACCEPT
-A IN_public -j IN_public_deny
-A IN_public -j IN_public_allow
-A IN_public -j DROP
-A IN_public_allow -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
-A IN_public_allow -p tcp -m tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT

```

在上面的 iptables 输出中，新的链（以 `-N` 开始的行）是被首先声明的。剩下的规则是附加到（以 `-A` 开始的行） iptables 中的。已建立的连接和本地流量是允许通过的，并且入站包被转到 `INPUT_ZONES_SOURCE` 链，在那里如果存在相应的区域，IP 将被发送到那个区域。从那之后，流量被转到 `INPUT_ZONES` 链，从那里它被路由到一个接口区域。如果在那里它没有被处理，icmp 是允许通过的，无效的被丢弃，并且其余的都被拒绝。

### 结论

firewalld 是一个文档不足的防火墙配置工具，它的功能远比大多数人认识到的更为强大。以创新的区域范式，firewalld 允许系统管理员去分解流量到每个唯一处理它的分类中，简化了配置过程。因为它直观的设计和语法，它在实践中不但被用于简单的单一区域中也被用于复杂的多区域配置中。

---

via: <https://www.linuxjournal.com/content/understanding-firewalld-multi-zone-configurations>

作者：[Nathan Vance](https://www.linuxjournal.com/users/nathan-vance) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


肯特·贝克：改变人生的代码整理魔法

![](/data/attachment/album/201711/22/152437d7w0kwfb4rw27kc2.jpg)

>
> 本文作者<ruby> 肯特·贝克 <rt>  Kent Beck </rt></ruby>，是最早研究软件开发的模式和重构的人之一，是敏捷开发的开创者之一，更是极限编程和测试驱动开发的创始人，同时还是 Smalltalk 和 JUnit 的作者，对当今世界的软件开发影响深远。现在 Facebook 工作。
>
>
>

本周我一直在整理 Facebook 代码，而且我喜欢这个工作。我的职业生涯中已经整理了数千小时的代码，我有一套使这种整理更加安全、有趣和高效的规则。

整理工作是通过一系列短小而安全的步骤进行的。事实上，规则一就是**如果这很难，那就不要去做**。我以前在晚上做填字游戏。如果我卡住那就去睡觉，第二天晚上那些没有发现的线索往往很容易发现。与其想要一心搞个大的，不如在遇到阻力的时候停下来。

整理会陷入这样一种感觉：你错失的要比你从一个个成功中获得的更多（稍后会细说）。第二条规则是**当你充满活力时开始，当你累了时停下来**。起来走走。如果还没有恢复精神，那这一天的工作就算做完了。

只有在仔细追踪其它变化的时候（我把它和最新的差异搞混了），整理工作才可以与开发同步进行。第三条规则是**立即完成每个环节的工作**。与功能开发所不同的是，功能开发只有在完成一大块工作时才有意义，而整理是基于时间一点点完成的。

整理在任何步骤中都只需要付出不多的努力，所以我会在任何步骤遇到麻烦的时候放弃。所以，规则四是**两次失败后恢复**。如果我整理代码，运行测试，并遇到测试失败，那么我会立即修复它。如果我修复失败，我会立即恢复到上次已知最好的状态。

即便没有闪亮的新设计的愿景，整理也是有用的。不过，有时候我想看看事情会如何发展，所以第五条就是**实践**。执行一系列的整理和还原。第二次将更快，你会更加熟悉避免哪些坑。

只有在附带损害的风险较低，审查整理变化的成本也较低的时候整理才有用。规则六是**隔离整理**。如果你错过了在编写代码中途整理的机会，那么接下来可能很困难。要么完成并接着整理，要么还原、整理并进行修改。

试试这些。将临时申明的变量移动到它第一次使用的位置，简化布尔表达式（`return expression == True`？），提取一个 helper，将逻辑或状态的范围缩小到实际使用的位置。

### 规则

* 规则一、 如果这很难，那就不要去做
* 规则二、 当你充满活力时开始，当你累了时停下来
* 规则三、 立即完成每个环节工作
* 规则四、 两次失败后恢复
* 规则五、 实践
* 规则六、 隔离整理

### 尾声

我通过严格地整理改变了架构、提取了框架。这种方式可以安全地做出重大改变。我认为这是因为，虽然每次整理的成本是不变的，但回报是指数级的，但我需要数据和模型来解释这个假说。

---

via: <https://www.facebook.com/notes/kent-beck/the-life-changing-magic-of-tidying-up-code/1544047022294823/>

作者：[KENT BECK](https://www.facebook.com/kentlbeck) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


很遗憾，我也不知道什么是容器！

Summary: 题图抽象的形容了容器和虚拟机是那么的相似，又是那么的不同！

题图抽象的形容了容器和虚拟机是那么的相似，又是那么的不同！

![But I dont know what a container is!](/data/attachment/album/201711/22/233347d77ay3h3dy73d3ba.png "But I don't know what a container is")

>
> 题图抽象的形容了容器和虚拟机是那么的相似，又是那么的不同！
>
>
>

在近期的一些会议和学术交流会上，我一直在讲述有关 DevOps 的安全问题（亦称为 DevSecOps） 注1 。通常，我首先都会问一个问题：“在座的各位有谁知道什么是容器吗？” 通常并没有很多人举手 注2 ，所以我都会先简单介绍一下什么是容器 注3 ，然后再进行深层次的讨论交流。

更准确的说，在运用 DevOps 或者 DevSecOps 的时候，容器并不是必须的。但容器能很好的融于 DevOps 和 DevSecOps 方案中，结果就是，虽然不用容器便可以运用 DevOps ，但我还是假设大部分人依然会使用容器。

### 什么是容器

几个月前的一个会议上，一个同事正在容器上操作演示，因为大家都不是这个方面的专家，所以该同事就很简单的开始了他的演示。他说了诸如“在 Linux 内核源码中没有一处提及到<ruby> 容器 <rt>  container </rt></ruby>。“之类的话。事实上，在这样的特殊群体中，这种描述表达是很危险的。就在几秒钟内，我和我的老板（坐在我旁边）下载了最新版本的内核源代码并且查找统计了其中 “container” 单词出现的次数。很显然，这位同事的说法并不准确。更准确来说，我在旧版本内核（4.9.2）代码中发现有 15273 行代码包含 “container” 一词 注4 。我和我老板会心一笑，确认同事的说法有误，并在休息时纠正了他这个有误的描述。

后来我们搞清楚同事想表达的意思是 Linux 内核中并没有明确提及容器这个概念。换句话说，容器使用了 Linux 内核中的一些概念、组件、工具以及机制，并没有什么特殊的东西；这些东西也可以用于其他目的 注 5 。所以才有会说“从 Linux 内核角度来看，并没有容器这样的东西。”

然后，什么是容器呢？我有着虚拟化（<ruby> 管理器 <rt>  hypervisor </rt></ruby>和虚拟机）技术的背景，在我看来， 容器既像虚拟机（VM）又不像虚拟机。我知道这种解释好像没什么用，不过请听我细细道来。

### 容器和虚拟机相似之处有哪些？

容器和虚拟机相似的一个主要方面就是它是一个可执行单元。将文件打包生成镜像文件，然后它就可以运行在合适的主机平台上。和虚拟机一样，它运行于主机上，同样，它的运行也受制于该主机。主机平台为容器的运行提供软件环境和硬件资源（诸如 CPU 资源、网络环境、存储资源等等），除此之外，主机还需要负责以下的任务：

1. 为每一个工作单元（这里指虚拟机和容器）提供保护机制，这样可以保证即使某一个工作单元出现恶意的、有害的以及不能写入的情况时不会影响其他的工作单元。
2. 主机保护自己不会受一些恶意运行或出现故障的工作单元影响。

虚拟机和容器实现这种隔离的原理并不一样，虚拟机的隔离是由管理器对硬件资源划分，而容器的隔离则是通过 Linux 内核提供的软件功能实现的 注6 。这种软件控制机制通过不同的“命名空间”保证了每一个容器的文件、用户以及网络连接等互不可见，当然容器和主机之间也互不可见。这种功能也能由 SELinux 之类软件提供，它们提供了进一步隔离容器的功能。

### 容器和虚拟机不同之处又有哪些？

以上描述有个问题，如果你对<ruby> 管理器 <rt>  hypervisor </rt></ruby>机制概念比较模糊，也许你会认为容器就是虚拟机，但它确实不是。

首先，最为重要的一点 注7 ，容器是一种包格式。也许你会惊讶的反问我“什么，你不是说过容器是某种可执行文件么？” 对，容器确实是可执行文件，但容器如此迷人的一个主要原因就是它能很容易的生成比虚拟机小很多的实体化镜像文件。由于这些原因，容器消耗很少的内存，并且能非常快的启动与关闭。你可以在几分钟或者几秒钟（甚至毫秒级别）之内就启动一个容器，而虚拟机则不具备这些特点。

正因为容器是如此轻量级且易于替换，人们使用它们来创建微服务——应用程序拆分而成的最小组件，它们可以和一个或多个其它微服务构成任何你想要的应用。假使你只在一个容器内运行某个特定功能或者任务，你也可以让容器变得很小，这样丢弃旧容器创建新容器将变得很容易。我将在后续的文章中继续跟进这个问题以及它们对安全性的可能影响，当然，也包括 DevSecOps 。

希望这是一次对容器的有用的介绍，并且能带动你有动力去学习 DevSecOps 的知识（如果你不是，假装一下也好）。

---

* 注 1：我觉得 DevSecOps 读起来很奇怪，而 DevOpsSec 往往有多元化的理解，然后所讨论的主题就不一样了。
* 注 2：我应该注意到这不仅仅会被比较保守、不太喜欢被人注意的英国听众所了解，也会被加拿大人和美国人所了解，他们的性格则和英国人不一样。
* 注 3：当然，我只是想讨论 Linux 容器。我知道关于这个问题，是有历史根源的，所以它也值得注意，而不是我故弄玄虚。
* 注 4：如果你感兴趣的话，我使用的是命令 `grep -ir container linux-4.9.2 | wc -l`
* 注 5：公平的说，我们快速浏览一下，一些用途与我们讨论容器的方式无关，我们讨论的是 Linux 容器，它是抽象的，可以用来包含其他元素，因此在逻辑上被称为容器。
* 注 6：也有一些巧妙的方法可以将容器和虚拟机结合起来以发挥它们各自的优势，那个不在我今天的主题范围内。
* 注 7：很明显，除了我们刚才介绍的执行位。

原文来自 [Alice, Eve, and Bob—a security blog](https://aliceevebob.wordpress.com/2017/07/04/but-i-dont-know-what-a-container-is/) ，转载请注明

（题图： opensource.com ）

---

**作者简介**：

原文作者 Mike Bursell 是一名居住在英国、喜欢威士忌的开源爱好者， Red Hat 首席安全架构师。其自从 1997 年接触开源世界以来，生活和工作中一直使用 Linux （尽管不是一直都很容易）。更多信息请参考作者的博客 <https://aliceevebob.com> ，作者会不定期的更新一些有关安全方面的文章。

---

via: <https://opensource.com/article/17/10/what-are-containers>

作者：[Mike Bursell](https://opensource.com/users/mikecamel) 译者：[jrglinux](https://github.com/jrglinux) 校对：[wxy](https://github.com/wxy)

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


使用 LXD 容器运行 Ubuntu Core

![](/data/attachment/album/201711/23/004218pohu77bt0tlrtvz1.jpg)

### Ubuntu Core 是什么？

Ubuntu Core 是完全基于 snap 包构建，并且完全事务化的 Ubuntu 版本。

该系统大部分是只读的，所有已安装的应用全部来自 snap 包，完全使用事务化更新。这意味着不管在系统更新还是安装软件的时候遇到问题，整个系统都可以回退到之前的状态并且记录这个错误。

最新版是在 2016 年 11 月发布的 Ubuntu Core 16。

注意，Ubuntu Core 限制只能够安装 snap 包（而非 “传统” 软件包），并且有相当数量的 snap 包在当前环境下不能正常运行，或者需要人工干预（创建用户和用户组等）才能正常运行。随着新版的 snapd 和 “core” snap 包发布，Ubuntu Core 每周都会得到改进。

### 环境需求

就 LXD 而言，Ubuntu Core 仅仅相当于另一个 Linux 发行版。也就是说，snapd 需要挂载无特权的 FUSE 和 AppArmor 命名空间以及软件栈，像下面这样：

* 一个新版的使用 Ubuntu 官方内核的系统
* 一个新版的 LXD

### 创建一个 Ubuntu Core 容器

当前 Ubuntu Core 镜像发布在社区的镜像服务器。你可以像这样启动一个新的容器：

```
stgraber@dakara:~$ lxc launch images:ubuntu-core/16 ubuntu-core
Creating ubuntu-core
Starting ubuntu-core

```

这个容器启动需要一点点时间，它会先执行第一阶段的加载程序，加载程序会确定使用哪一个镜像（镜像是只读的），并且在系统上设置一个可读层，你不要在这一阶段中断容器执行，这个时候什么都没有，所以执行 `lxc exec` 将会出错。

几秒钟之后，执行 `lxc list` 将会展示容器的 IP 地址，这表明已经启动了 Ubuntu Core：

```
stgraber@dakara:~$ lxc list
+-------------+---------+----------------------+----------------------------------------------+------------+-----------+
|     NAME    |  STATE  |          IPV4        |                      IPV6                    |    TYPE    | SNAPSHOTS |
+-------------+---------+----------------------+----------------------------------------------+------------+-----------+
| ubuntu-core | RUNNING | 10.90.151.104 (eth0) | 2001:470:b368:b2b5:216:3eff:fee1:296f (eth0) | PERSISTENT | 0         |
+-------------+---------+----------------------+----------------------------------------------+------------+-----------+

```

之后你就可以像使用其他的交互一样和这个容器进行交互：

```
stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap list
Name       Version     Rev  Developer  Notes
core       16.04.1     394  canonical  -
pc         16.04-0.8   9    canonical  -
pc-kernel  4.4.0-45-4  37   canonical  -
root@ubuntu-core:~#

```

### 更新容器

如果你一直关注着 Ubuntu Core 的开发，你应该知道上面的版本已经很老了。这是因为被用作 Ubuntu LXD 镜像的代码每隔几个月才会更新。Ubuntu Core 系统在重启时会检查更新并进行自动更新（更新失败会回退）。

如果你想现在强制更新，你可以这样做：

```
stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap refresh
pc-kernel (stable) 4.4.0-53-1 from 'canonical' upgraded
core (stable) 16.04.1 from 'canonical' upgraded
root@ubuntu-core:~# snap version
snap 2.17
snapd 2.17
series 16
root@ubuntu-core:~#

```

然后重启一下 Ubuntu Core 系统，然后看看 snapd 的版本。

```
root@ubuntu-core:~# reboot
root@ubuntu-core:~#

stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap version
snap 2.21
snapd 2.21
series 16
root@ubuntu-core:~#

```

你也可以像下面这样查看所有 snapd 的历史记录：

```
stgraber@dakara:~$ lxc exec ubuntu-core snap changes
ID  Status  Spawn                 Ready                 Summary
1   Done    2017-01-31T05:14:38Z  2017-01-31T05:14:44Z  Initialize system state
2   Done    2017-01-31T05:14:40Z  2017-01-31T05:14:45Z  Initialize device
3   Done    2017-01-31T05:21:30Z  2017-01-31T05:22:45Z  Refresh all snaps in the system

```

### 安装 Snap 软件包

以一个最简单的例子开始，经典的 Hello World：

```
stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap install hello-world
hello-world 6.3 from 'canonical' installed
root@ubuntu-core:~# hello-world
Hello World!

```

接下来让我们看一些更有用的：

```
stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap install nextcloud
nextcloud 11.0.1snap2 from 'nextcloud' installed

```

之后通过 HTTP 访问你的容器就可以看到刚才部署的 Nextcloud 实例。

如果你想直接通过 git 测试最新版 LXD，你可以这样做：

```
stgraber@dakara:~$ lxc config set ubuntu-core security.nesting true
stgraber@dakara:~$ lxc exec ubuntu-core bash
root@ubuntu-core:~# snap install lxd --edge
lxd (edge) git-c6006fb from 'canonical' installed
root@ubuntu-core:~# lxd init
Name of the storage backend to use (dir or zfs) [default=dir]:

We detected that you are running inside an unprivileged container.
This means that unless you manually configured your host otherwise,
you will not have enough uid and gid to allocate to your containers.

LXD can re-use your container's own allocation to avoid the problem.
Doing so makes your nested containers slightly less safe as they could
in theory attack their parent container and gain more privileges than
they otherwise would.

Would you like to have your containers share their parent's allocation (yes/no) [default=yes]?
Would you like LXD to be available over the network (yes/no) [default=no]?
Would you like stale cached images to be updated automatically (yes/no) [default=yes]?
Would you like to create a new network bridge (yes/no) [default=yes]?
What should the new bridge be called [default=lxdbr0]?
What IPv4 address should be used (CIDR subnet notation, “auto” or “none”) [default=auto]?
What IPv6 address should be used (CIDR subnet notation, “auto” or “none”) [default=auto]?
LXD has been successfully configured.

```

已经设置过的容器不能回退版本，但是可以在 Ubuntu Core 16 中运行另一个 Ubuntu Core 16 容器：

```
root@ubuntu-core:~# lxc launch images:ubuntu-core/16 nested-core
Creating nested-core
Starting nested-core
root@ubuntu-core:~# lxc list
+-------------+---------+---------------------+-----------------------------------------------+------------+-----------+
|    NAME     |  STATE  |         IPV4        |                       IPV6                    |    TYPE    | SNAPSHOTS |
+-------------+---------+---------------------+-----------------------------------------------+------------+-----------+
| nested-core | RUNNING | 10.71.135.21 (eth0) | fd42:2861:5aad:3842:216:3eff:feaf:e6bd (eth0) | PERSISTENT | 0         |
+-------------+---------+---------------------+-----------------------------------------------+------------+-----------+

```

### 写在最后

如果你只是想试用一下 Ubuntu Core，这是一个不错的方法。对于 snap 包开发者来说，这也是一个不错的工具来测试你的 snap 包能否在不同的环境下正常运行。

如果你希望你的系统总是最新的，并且整体可复制，Ubuntu Core 是一个很不错的方案，不过这也会带来一些相应的限制，所以可能不太适合你。

最后是一个警告，对于测试来说，这些镜像是足够的，但是当前并没有被正式的支持。在不久的将来，官方的 Ubuntu server 可以完整的支持 Ubuntu Core LXD 镜像。

### 附录

* LXD 主站：<https://linuxcontainers.org/lxd>
* Github：<https://github.com/lxc/lxd>
* 邮件列表：[https://lists.linuxcontainers.org](https://lists.linuxcontainers.org/)
* IRC：#lxcontainers on irc.freenode.net
* 在线试用：<https://linuxcontainers.org/lxd/try-it>

---

来自: <https://insights.ubuntu.com/2017/02/27/ubuntu-core-in-lxd-containers/>

作者：[Stéphane Graber](https://insights.ubuntu.com/author/stgraber/) 译者：[aiwhj](https://github.com/aiwhj) 校对：[wxy](https://github.com/wxy)

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


借助 minikube 上手 OpenFaaS

Summary: 本文将介绍如何借助 minikube 在 Kubernetes 1.8 上搭建 OpenFaaS（让 Serverless Function 变得更简单）。minikube 是一个 Kubernetes 分发版，借助它，你可以在笔记本电脑上运行 Kubernetes 集群，minikube 支持 Mac 和 Linux 操作系统，但是在 MacOS 上使用得更多一些。

![](/data/attachment/album/201711/23/163035naykmjmb00z8ugpo.png)

本文将介绍如何借助 [minikube](https://kubernetes.io/docs/getting-started-guides/minikube/) 在 Kubernetes 1.8 上搭建 OpenFaaS（让 Serverless Function 变得更简单）。minikube 是一个 [Kubernetes](https://kubernetes.io/) 分发版，借助它，你可以在笔记本电脑上运行 Kubernetes 集群，minikube 支持 Mac 和 Linux 操作系统，但是在 MacOS 上使用得更多一些。

>
> 本文基于我们最新的部署手册 [Kubernetes 官方部署指南](https://github.com/openfaas/faas/blob/master/guide/deployment_k8s.md)
>
>
>

![](/data/attachment/album/201711/23/163118ezppccze17o84exx.png)

### 安装部署 Minikube

1、 安装 [xhyve driver](https://git.k8s.io/minikube/docs/drivers.md#xhyve-driver) 或 [VirtualBox](https://www.virtualbox.org/wiki/Downloads) ，然后在上面安装 Linux 虚拟机以部署 minikube 。根据我的经验，VirtualBox 更稳定一些。

2、 [参照官方文档](https://kubernetes.io/docs/tasks/tools/install-minikube/) 安装 minikube 。

3、 使用 `brew` 或 `curl -sL cli.openfaas.com | sudo sh` 安装 `faas-cli`。

4、 通过 `brew install kubernetes-helm` 安装 `helm` 命令行。

5、 运行 minikube ：`minikube start`。

>
> Docker 船长小贴士：Mac 和 Windows 版本的 Docker 已经集成了对 Kubernetes 的支持。现在我们使用 Kubernetes 的时候，已经不需要再安装额外的软件了。
>
>
>

### 在 minikube 上面部署 OpenFaaS

1、 为 Helm 的服务器组件 tiller 新建服务账号：

```
kubectl -n kube-system create sa tiller \
 && kubectl create clusterrolebinding tiller \
 --clusterrole cluster-admin \
 --serviceaccount=kube-system:tiller

```

2、 安装 Helm 的服务端组件 tiller：

```
helm init --skip-refresh --upgrade --service-account tiller

```

3、 克隆 Kubernetes 的 OpenFaaS 驱动程序 faas-netes：

```
git clone https://github.com/openfaas/faas-netes && cd faas-netes

```

4、 Minikube 没有配置 RBAC，这里我们需要把 RBAC 关闭：

```
helm upgrade --install --debug --reset-values --set async=false --set rbac=false openfaas openfaas/

```

（LCTT 译注：RBAC（Role-Based access control）基于角色的访问权限控制，在计算机权限管理中较为常用，详情请参考以下链接：<https://en.wikipedia.org/wiki/Role-based_access_control> ）

现在，你可以看到 OpenFaaS pod 已经在你的 minikube 集群上运行起来了。输入 `kubectl get pods` 以查看 OpenFaaS pod：

```
NAME                            READY     STATUS    RESTARTS   AGE
alertmanager-6dbdcddfc4-fjmrf   1/1       Running   0          1m
faas-netesd-7b5b7d9d4-h9ftx     1/1       Running   0          1m
gateway-965d6676d-7xcv9         1/1       Running   0          1m
prometheus-64f9844488-t2mvn     1/1       Running   0          1m

```

30,000ft：

该 API 网关包含了一个 [用于测试功能的最小化 UI](https://github.com/openfaas/faas/blob/master/TestDrive.md)，同时开放了用于功能管理的 [RESTful API](https://github.com/openfaas/faas/tree/master/api-docs) 。 faas-netesd 守护进程是一种 Kubernetes 控制器，用来连接 Kubernetes API 服务器来管理服务、部署和密码。

Prometheus 和 AlertManager 进程协同工作，实现 OpenFaaS Function 的弹性缩放，以满足业务需求。通过 Prometheus 指标我们可以查看系统的整体运行状态，还可以用来开发功能强悍的仪表盘。

Prometheus 仪表盘示例：

![](/data/attachment/album/201711/23/163120xhgf22bogg8o8vfl.jpg)

### 构建/迁移/运行

和很多其他的 FaaS 项目不同，OpenFaaS 使用 Docker 镜像格式来进行 Function 的创建和版本控制，这意味着可以在生产环境中使用 OpenFaaS 实现以下目标：

* 漏洞扫描（LCTT 译注：此处我觉得应该理解为更快地实现漏洞补丁）
* 持续集成/持续开发
* 滚动更新

你也可以在现有的生产环境集群中利用空闲资源部署 OpenFaaS。其核心服务组件内存占用大概在 10-30MB 。

>
> OpenFaaS 一个关键的优势在于，它可以使用容器编排平台的 API ，这样可以和 Kubernetes 以及 Docker Swarm 进行本地集成。同时，由于使用 Docker <ruby> 存储库 <rt>  registry </rt></ruby>进行 Function 的版本控制，所以可以按需扩展 Function，而没有按需构建 Function 的框架的额外的延时。
>
>
>

### 新建 Function

```
faas-cli new --lang python hello

```

以上命令创建文件 `hello.yml` 以及文件夹 `handler`，文件夹有两个文件 `handler.py`、`requirements.txt` 可用于你可能需要的 pip 模块。你可以随时编辑这些文件和文件夹，不需要担心如何维护 Dockerfile —— 我们为你通过以下方式维护：

* 分级创建
* 非 root 用户
* 以官方的 Docker Alpine Linux 版本为基础进行镜像构建 (可替换)

### 构建你的 Function

先在本地创建 Function，然后推送到 Docker 存储库。 我们这里使用 Docker Hub，打开文件 `hello.yml` 然后输入你的账号名：

```
provider:
  name: faas
  gateway: http://localhost:8080
functions:
  hello:
    lang: python
    handler: ./hello
    image: alexellis2/hello

```

现在，发起构建。你的本地系统上需要安装 Docker 。

```
faas-cli build -f hello.yml

```

把封装好 Function 的 Docker 镜像版本推送到 Docker Hub。如果还没有登录 Docker hub ，继续前需要先输入命令 `docker login` 。

```
faas-cli push -f hello.yml

```

当系统中有多个 Function 的时候，可以使用 `--parallel=N` 来调用多核并行处理构建或推送任务。该命令也支持这些选项： `--no-cache`、`--squash` 。

### 部署及测试 Function

现在，可以部署、列出、调用 Function 了。每次调用 Function 时，可以通过 Prometheus 收集指标值。

```
$ export gw=http://$(minikube ip):31112
$ faas-cli deploy -f hello.yml --gateway $gw
Deploying: hello.
No existing function to remove
Deployed.
URL: http://192.168.99.100:31112/function/hello

```

上面给到的是部署时调用 Function 的标准方法，你也可以使用下面的命令：

```
$ echo test | faas-cli invoke hello --gateway $gw

```

现在可以通过以下命令列出部署好的 Function，你将看到调用计数器数值增加。

```
$ faas-cli list --gateway $gw
Function                       Invocations     Replicas
hello                          1               1

```

*提示：这条命令也可以加上 `--verbose` 选项获得更详细的信息。*

由于我们是在远端集群（Linux 虚拟机）上面运行 OpenFaaS，命令里面加上一条 `--gateway` 用来覆盖环境变量。 这个选项同样适用于云平台上的远程主机。除了加上这条选项以外，还可以通过编辑 .yml 文件里面的 `gateway` 值来达到同样的效果。

### 迁移到 minikube 以外的环境

一旦你在熟悉了在 minikube 上运行 OpenFaaS ，就可以在任意 Linux 主机上搭建 Kubernetes 集群来部署 OpenFaaS 了。

### 继续学习

我们的 Github 上面有很多手册和博文，可以带你轻松“上车”，把我们的页面保存成书签吧：[openfaas/faas](https://github.com/openfaas/faas/tree/master/guide) 。

2017 哥本哈根 Dockercon Moby 峰会上，我做了关于 Serverless 和 OpenFaaS 的概述演讲，这里我把视频放上来，视频不长，大概 15 分钟左右。

最后，别忘了关注 [OpenFaaS on Twitter](https://twitter.com/openfaas) 这里有最潮的新闻、最酷的技术和 Demo 展示。

---

via: <https://medium.com/@alexellisuk/getting-started-with-openfaas-on-minikube-634502c7acdf>

作者：[Alex Ellis](https://medium.com/@alexellisuk?source=post_header_lockup) 译者：[mandeler](https://github.com/mandeler) 校对：[wxy](https://github.com/wxy)

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


Linux 用户的手边工具：Guide to Linux

![Guide to Linux](/data/attachment/album/201711/23/223543k8vaw6i2rfeafwy4.png "Guide to Linux")

>
> “Guide to Linux” 这个应用并不完美，但它是一个非常好的工具，可以帮助你学习 Linux 命令。
>
>
>

还记得你初次使用 Linux 时的情景吗？对于有些人来说，他的学习曲线可能有些挑战性。比如，在 `/usr/bin` 中能找到许多命令。在我目前使用的 Elementary OS 系统中，命令的数量是 1944 个。当然，这并不全是真实的命令（或者，我会使用到的命令数量），但这个数目是很多的。

正因为如此（并且不同平台不一样），现在，新用户（和一些已经熟悉的用户）需要一些帮助。

对于每个管理员来说，这些技能是必须具备的：

* 熟悉平台
* 理解命令
* 编写 Shell 脚本

当你寻求帮助时，有时，你需要去“阅读那些该死的手册”（Read the Fine/Freaking/Funky Manual，LCTT 译注：一个网络用语，简写为 RTFM），但是当你自己都不知道要找什么的时候，它就没办法帮到你了。在那个时候，你就会为你拥有像 [Guide to Linux](https://play.google.com/store/apps/details?id=com.essence.linuxcommands) 这样的手机应用而感到高兴。

不像你在 Linux.com 上看到的那些大多数的内容，这篇文章只是介绍一个 Android 应用的。为什么呢？因为这个特殊的 应用是用来帮助用户学习 Linux 的。

而且，它做的很好。

关于这个应用我清楚地告诉你 —— 它并不完美。Guide to Linux 里面充斥着很烂的英文，糟糕的标点符号，并且（如果你是一个纯粹主义者），它从来没有提到过 GNU。在这之上，它有一个特别的功能（通常它对用户非常有用）功能不是很有用（LCTT 译注：是指终端模拟器，后面会详细解释）。除此之外，我敢说 Guide to Linux 可能是 Linux 平台上最好的一个移动端的 “口袋指南”。

对于这个应用，你可能会喜欢它的如下特性：

* 离线使用
* Linux 教程
* 基础的和高级的 Linux 命令的详细介绍
* 包含了命令示例和语法
* 专用的 Shell 脚本模块

除此以外，Guide to Linux 是免费提供的（尽管里面有一些广告）。如果你想去除广告，它有一个应用内的购买，（$2.99 USD/年）可以去消除广告。

让我们来安装这个应用，来看一看它的构成。

### 安装

像所有的 Android 应用一样，安装 Guide to Linux 是非常简单的。按照以下简单的几步就可以安装它了：

1. 打开你的 Android 设备上的 Google Play 商店
2. 搜索 Guide to Linux
3. 找到 Essence Infotech 的那个，并轻触进入
4. 轻触 Install
5. 允许安装

安装完成后，你可以在你的<ruby> 应用抽屉 <rt>  App Drawer </rt></ruby>或主屏幕上（或者两者都有）上找到它去启动 Guide to Linux 。轻触图标去启动这个应用。

### 使用

让我们看一下 Guide to Linux 的每个功能。我发现某些功能比其它的更有帮助，或许你的体验会不一样。在我们分别讲解之前，我将重点提到其界面。开发者在为这个应用创建一个易于使用的界面方面做的很好。

从主窗口中（图 1），你可以获取四个易于访问的功能。

![Guide to Linux main window](/data/attachment/album/201711/23/223543abnp4ybqzumiim4b.jpg "Guide to Linux main window")

*图 1： The Guide to Linux 主窗口。[已获授权](https://www.linux.com/licenses/category/used-permission)*

轻触四个图标中的任何一个去启动一个功能，然后，准备去学习。

### 教程

让我们从这个应用教程的最 “新手友好” 的功能开始。打开“Tutorial”功能，然后，将看到该教程的欢迎部分，“Linux 操作系统介绍”（图 2）。

![The Tutorial](/data/attachment/album/201711/23/223544klh20ll219g25h69.jpg "The Tutorial")

*图 2：教程开始。[已获授权](https://www.linux.com/licenses/category/used-permission)*

如果你轻触 “汉堡包菜单” （左上角的三个横线），显示了内容列表（图 3），因此，你可以在教程中选择任何一个可用部分。

![Tutorial TOC](/data/attachment/album/201711/23/223544k7ztt49oxx44l94r.jpg "Tutorial TOC")

*图 3：教程的内容列表。[已获授权](https://www.linux.com/licenses/category/used-permission)*

如果你现在还没有注意到，Guide to Linux 教程部分是每个主题的一系列短文的集合。短文包含图片和链接（有时候），链接将带你到指定的 web 网站（根据主题的需要）。这里没有交互，仅仅只能阅读。但是，这是一个很好的起点，由于开发者在描述各个部分方面做的很好（虽然有语法问题）。

尽管你可以在窗口的顶部看到一个搜索选项，但是，我还是没有发现这一功能的任何效果 —— 但是，你可以试一下。

对于 Linux 新手来说，如果希望获得 Linux 管理的技能，你需要去阅读整个教程。完成之后，转到下一个主题。

### 命令

命令功能类似于手机上的 man 页面一样，是大量的频繁使用的 Linux 命令。当你首次打开它，欢迎页面将详细解释使用命令的益处。

读完之后，你可以轻触向右的箭头（在屏幕底部）或轻触 “汉堡包菜单” ，然后从侧边栏中选择你想去学习的其它命令。（图 4）

![Commands](/data/attachment/album/201711/23/223545x51z7ipmwp33fpqm.jpg "Commands")

*图 4：命令侧边栏允许你去查看列出的命令。[已获授权](https://www.linux.com/licenses/category/used-permission)*

轻触任意一个命令，你可以阅读这个命令的解释。每个命令解释页面和它的选项都提供了怎么去使用的示例。

### Shell 脚本

在这个时候，你开始熟悉 Linux 了，并对命令已经有一定程序的掌握。现在，是时候去熟悉 shell 脚本了。这个部分的设置方式与教程部分和命令部分相同。

你可以打开内容列表的侧边栏，然后打开包含 shell 脚本教程的任意部分（图 5）。

![Shell Script](/data/attachment/album/201711/23/223546wsynfson8osga71o.jpg "Shell Script")

*图 5：Shell 脚本节看上去很熟悉。[已获授权](https://www.linux.com/licenses/category/used-permission)*

开发者在解释如何最大限度地利用 shell 脚本方面做的很好。对于任何有兴趣学习 shell 脚本细节的人来说，这是个很好的起点。

### 终端

现在我们到了一个新的地方，开发者在这个应用中包含了一个终端模拟器。遗憾的是，当你在一个没有 “root” 权限的 Android 设备上安装这个应用时，你会发现你被限制在一个只读文件系统中，在那里，大部分命令根本无法工作。但是，我在一台 Pixel 2 （通过 Android 应用商店）安装的 Guide to Linux 中，可以使用更多的这个功能（还只是较少的一部分）。在一台 OnePlus 3 （非 root 过的）上，不管我改变到哪个目录，我都是得到相同的错误信息 “permission denied”，甚至是一个简单的命令也如此。

在 Chromebook 上，不管怎么操作，它都是正常的（图 6）。可以说，它可以一直很好地工作在一个只读操作系统中（因此，你不能用它进行真正的工作或创建新文件）。

![Permission denied](/data/attachment/album/201711/23/223546opizu8xaxpwpv82k.jpg "Permission denied")

*图 6： 可以完美地（可以这么说）用一个终端模拟器去工作。[已获授权](https://www.linux.com/licenses/category/used-permission)*

记住，这并不是真实的成熟终端，但却是一个新用户去熟悉终端是怎么工作的一种方法。遗憾的是，大多数用户只会发现自己对这个工具的终端功能感到沮丧，仅仅是因为，它们不能使用他们在其它部分学到的东西。开发者可能将这个终端功能打造成了一个 Linux 文件系统沙箱，因此，用户可以真实地使用它去学习。每次用户打开那个工具，它将恢复到原始状态。这只是我一个想法。

### 写在最后…

尽管终端功能被一个只读文件系统所限制（几乎到了没法使用的程序），Guide to Linux 仍然是一个新手学习 Linux 的好工具。在 guide to Linux 中，你将学习关于 Linux、命令、和 shell 脚本的很多知识，以便在你安装你的第一个发行版之前，让你学习 Linux 有一个好的起点。

---

via: <https://www.linux.com/learn/intro-to-linux/2017/8/guide-linux-app-handy-tool-every-level-linux-user>

作者：[JACK WALLEN](https://www.linux.com/users/jlwallen) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)

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


放弃你的代码，而不是你的时间

Summary: 我们需要的是一种新的行业规范，即项目领导者将总是能获得（其付出的）时间上的补偿。我们还需要抛弃的想法是， 任何提交问题或合并请求的开发人员都自动会得到维护者的注意。

![](/data/attachment/album/201711/24/070812nzvnszsdnnsp7plq.jpg)

作为软件开发人员，我认为我们可以认同开源代码<sup> 注1</sup> 已经[改变了世界](https://www.wired.com/insights/2013/07/in-a-world-without-open-source/)。它的公共性质去除了壁垒，可以让软件可以变的最好。但问题是，太多有价值的项目由于领导者的精力耗尽而停滞不前：

>
> “我没有时间和精力去投入开源了。我在开源上没有得到任何收入，所以我在那上面花的时间，我可以用在‘生活上的事’，或者写作上……正因为如此，我决定现在结束我所有的开源工作。”
>
>
> —— [Ryan Bigg，几个 Ruby 和 Elixir 项目的前任维护者](http://ryanbigg.com/2015/11/open-source-work)
>
>
>

>
> “这也是一个巨大的机会成本，由于我无法同时学习或者完成很多事情，FubuMVC 占用了我很多的时间，这是它现在必须停下来的主要原因。”
>
>
> —— [前 FubuMVC 项目负责人 Jeremy Miller](https://jeremydmiller.com/2014/04/03/im-throwing-in-the-towel-in-fubumvc/)
>
>
>

>
> “当我们决定要孩子的时候，我可能会放弃开源，我预计最终解决我问题的方案将是：核武器。”
>
>
> —— [Nolan Lawson，PouchDB 的维护者之一](https://nolanlawson.com/2017/03/05/what-it-feels-like-to-be-an-open-source-maintainer/)
>
>
>

我们需要的是一种新的行业规范，即项目领导者将*总是*能获得（其付出的）时间上的补偿。我们还需要抛弃的想法是， 任何提交问题或合并请求的开发人员都自动会得到维护者的注意。

我们先来回顾一下开源代码在市场上的作用。它是一个积木。它是[实用软件](https://martinfowler.com/bliki/UtilityVsStrategicDichotomy.html)，是企业为了在别处获利而必须承担的成本。如果用户能够理解该代码的用途并且发现它比替代方案（闭源专用、定制的内部解决方案等）更有价值，那么围绕该软件的社区就会不断增长。它可以更好，更便宜，或两者兼而有之。

如果一个组织需要改进该代码，他们可以自由地聘请任何他们想要的开发人员。通常情况下[为了他们的利益](https://tessel.io/blog/67472869771/monetizing-open-source)会将改进贡献给社区，因为由于代码合并的复杂性，这是他们能够轻松地从其他用户获得未来改进的唯一方式。这种“引力”倾向于把社区聚集在一起。

但是它也会加重项目维护者的负担，因为他们必须对这些改进做出反应。他们得到了什么回报？最好的情况是，这些社区贡献可能是他们将来可以使用的东西，但现在不是。最坏的情况下，这只不过是一个带着利他主义面具的自私请求罢了。

有一类开源项目避免了这个陷阱。Linux、MySQL、Android、Chromium 和 .NET Core 除了有名，有什么共同点么？他们都对一个或多个大型企业具有*战略性重要意义*，因为它们满足了这些利益。[聪明的公司商品化他们的商品](https://www.joelonsoftware.com/2002/06/12/strategy-letter-v/)，没有什么比开源软件便宜的商品了。红帽需要那些使用 Linux 的公司来销售企业级 Linux，Oracle 使用 MySQL 作为销售 MySQL Enterprise 的引子，谷歌希望世界上每个人都拥有电话和浏览器，而微软则试图将开发者锁定在平台上然后将它们拉入 Azure 云。这些项目全部由各自公司直接资助。

但是那些其他的项目呢，那些不是大玩家核心战略的项目呢？

如果你是其中一个项目的负责人，请向社区成员收取年费。*开放的源码，封闭的社区*。给用户的信息应该是“尽你所愿地使用代码，但如果你想影响项目的未来，请*为我们的时间支付*。”将非付费用户锁定在论坛和问题跟踪之外，并忽略他们的电子邮件。不支付的人应该觉得他们错过了派对。

还要向贡献者收取合并非普通的合并请求的时间花费。如果一个特定的提交不会立即给你带来好处，请为你的时间收取全价。要有原则并[记住 YAGNI](https://martinfowler.com/bliki/Yagni.html)。

这会导致一个极小的社区和更多的分支么？绝对。但是，如果你坚持不懈地构建自己的愿景，并为其他人创造价值，他们会尽快为要做的贡献而支付。*合并贡献的意愿是[稀缺资源](https://hbr.org/2010/11/column-to-win-create-whats-scarce)*。如果没有它，用户必须反复地将它们的变化与你发布的每个新版本进行协调。

如果你想在代码库中保持高水平的[概念完整性](http://wiki.c2.com/?ConceptualIntegrity)，那么限制社区是特别重要的。有[自由贡献政策](https://opensource.com/life/16/5/growing-contributor-base-modern-open-source)的无领导者项目没有必要收费。

为了实现更大的愿景，而不是单独为自己的业务支付成本，而是可能使其他人受益，去[众筹](https://poststatus.com/kickstarter-open-source-project/)吧。有许多成功的故事：

* [Font Awesome 5](https://www.kickstarter.com/projects/232193852/font-awesome-5)
* [Ruby enVironment Management (RVM)](https://www.bountysource.com/teams/rvm/fundraiser)
* [Django REST framework 3](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3)

[众筹有局限性](http://blog.felixbreuer.net/2013/04/24/crowdfunding-for-open-source.html)。它[不适合](https://www.indiegogo.com/projects/geary-a-beautiful-modern-open-source-email-client#/)[大型项目](http://www.itworld.com/article/2708360/open-source-tools/canonical-misses-smartphone-crowdfunding-goal-by--19-million.html)。但是，开源代码也是实用软件，它不需要雄心勃勃、冒险的破局者。它已经一点点地[渗透到每个行业](http://www.infoworld.com/article/2914643/open-source-software/rise-and-rise-of-open-source.html)。

这些观点代表着一条可持续发展的道路，也可以解决[开源的多样性问题](http://readwrite.com/2013/12/11/open-source-diversity/)，这可能源于其历史上无偿的性质。但最重要的是，我们要记住，[我们一生中只留下那么多的按键次数](http://keysleft.com/)，而且我们总有一天会后悔那些我们浪费的东西。

* 注 1 ：当我说“开源”时，我的意思是代码[许可](https://choosealicense.com/)以某种方式来构建专有的东西。这通常意味着一个宽松许可证（MIT 或 Apache 或 BSD），但并非总是如此。Linux 是当今科技行业的核心，但是是以 GPL 授权的。

感谢 Jason Haley、Don McNamara、Bryan Hogan 和 Nadia Eghbal 阅读了这篇文章的草稿。

---

via: <http://wgross.net/essays/give-away-your-code-but-never-your-time>

作者：[William Gross](http://wgross.net/#about-section) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


Let's Encrypt ：2018 年 1 月发布通配证书

![](/data/attachment/album/201711/24/133411nkhvk4abv5631q0a.jpg)

Let’s Encrypt 将于 2018 年 1 月开始发放通配证书。通配证书是一个经常需要的功能，并且我们知道在一些情况下它可以使 HTTPS 部署更简单。我们希望提供通配证书有助于加速网络向 100％ HTTPS 进展。

Let’s Encrypt 目前通过我们的全自动 DV 证书颁发和管理 API 保护了 4700 万个域名。自从 Let's Encrypt 的服务于 2015 年 12 月发布以来，它已经将加密网页的数量从 40% 大大地提高到了 58%。如果你对通配证书的可用性以及我们达成 100% 的加密网页的使命感兴趣，我们请求你为我们的[夏季筹款活动](https://letsencrypt.org/donate/)（LCTT 译注：之前的夏季活动，原文发布于今年夏季）做出贡献。

通配符证书可以保护基本域的任何数量的子域名（例如 \*.example.com）。这使得管理员可以为一个域及其所有子域使用单个证书和密钥对，这可以使 HTTPS 部署更加容易。

通配符证书将通过我们[即将发布的 ACME v2 API 终端](https://letsencrypt.org/2017/06/14/acme-v2-api.html)免费提供。我们最初只支持通过 DNS 进行通配符证书的基础域验证，但是随着时间的推移可能会探索更多的验证方式。我们鼓励人们在我们的[社区论坛](https://community.letsencrypt.org/)上提出任何关于通配证书支持的问题。

我们决定在夏季筹款活动中宣布这一令人兴奋的进展，因为我们是一个非营利组织，这要感谢使用我们服务的社区的慷慨支持。如果你想支持一个更安全和保密的网络，[现在捐赠吧](https://letsencrypt.org/donate/)！

我们要感谢我们的[社区](https://letsencrypt.org/getinvolved/)和我们的[赞助者](https://letsencrypt.org/sponsors/)，使我们所做的一切成为可能。如果你的公司或组织能够赞助 Let's Encrypt，请发送电子邮件至 [sponsor@letsencrypt.org](mailto:sponsor@letsencrypt.org)。

---

via: <https://letsencrypt.org/2017/07/06/wildcard-certificates-coming-jan-2018.html>

作者：[Josh Aas](https://letsencrypt.org/2017/07/06/wildcard-certificates-coming-jan-2018.html) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


如何使用 BorgBackup、Rclone 和 Wasabi 云存储推出自己的家庭备份解决方案

Summary: 使用基于开源软件和廉价云存储的自动备份解决方案来保护你的数据。

使用基于开源软件和廉价云存储的自动备份解决方案来保护你的数据。

>
> 使用基于开源软件和廉价云存储的自动备份解决方案来保护你的数据。
>
>
>

![](/data/attachment/album/201711/25/082459kouk6k6b172mb4bb.jpeg)

几年来，我用 CrashPlan 来备份我家的电脑，包括属于我妻子和兄弟姐妹的电脑。CrashPlan 本质上是“永远在线”，不需要为它操心就可以做的规律性的备份，这真是太棒了。此外，能使用时间点恢复的能力多次派上用场。因为我通常是家庭的 IT 人员，所以我对其用户界面非常容易使用感到高兴，家人可以在没有我帮助的情况下恢复他们的数据。

最近 [CrashPlan 宣布](https://www.crashplan.com/en-us/consumer/nextsteps/)，它正在放弃其消费者订阅，专注于其企业客户。我想，这是有道理的，因为它不能从像我这样的人赚到很多钱，而我们的家庭计划在其系统上使用了大量的存储空间。

我决定，我需要一个合适的替代功能，包括：

* 跨平台支持 Linux 和 Mac
* 自动化（所以没有必要记得点击“备份”）
* 时间点恢复（可以关闭），所以如果你不小心删除了一个文件，但直到后来才注意到，它仍然可以恢复
* 低成本
* 备份有多份存储，这样数据存在于多个地方（即，不仅仅是备份到本地 USB 驱动器上）
* 加密以防备份文件落入坏人手中

我四处搜寻，问我的朋友有关类似于 CrashPlan 的服务。我对其中一个 [Arq](https://www.arqbackup.com/) 非常满意，但没有 Linux 支持意味着对我没用。[Carbonite](https://www.carbonite.com/) 与 CrashPlan 类似，但会很昂贵，因为我有多台机器需要备份。[Backblaze](https://www.backblaze.com/) 以优惠的价格（每月 5 美金）提供无限备份，但其备份客户端不支持 Linux。[BackupPC](http://backuppc.sourceforge.net/BackupPCServerStatus.html) 是一个强有力的竞争者，但在我想起它之前，我已经开始测试我的解决方案了。我看到的其它选项都不符合我要的一切。这意味着我必须找出一种方法来复制 CrashPlan 为我和我的家人提供的服务。

我知道在 Linux 系统上备份文件有很多好的选择。事实上，我一直在使用 [rdiff-backup](http://www.nongnu.org/rdiff-backup/) 至少 10 年了，通常用于本地保存远程文件系统的快照。我希望能够找到可以去除备份数据中重复部分的工具，因为我知道有些（如音乐库和照片）会存储在多台计算机上。

我认为我所做的工作非常接近实现我的目标。

### 我的备份解决方案

![backup solution diagram](/data/attachment/album/201711/25/082609zei0r1v29vchbb07.png "backup solution diagram")

最终，我的目标落在 [BorgBackup](https://www.borgbackup.org/)、[Rclone](https://rclone.org/) 和 [Wasabi 云存储](https://wasabi.com/)的组合上，我的决定让我感到无比快乐。Borg 符合我所有的标准，并有一个非常健康的[用户和贡献者社区](https://github.com/borgbackup/borg/)。它提供重复数据删除和压缩功能，并且在 PC、Mac 和 Linux 上运行良好。我使用 Rclone 将来自 Borg 主机的备份仓库同步到 Wasabi 上的 S3 兼容存储。任何与 S3 兼容的存储都可以工作，但是我选择了 Wasabi，因为它的价格好，而且它的性能超过了亚马逊的 S3。使用此设置，我可以从本地 Borg 主机或从 Wasabi 恢复文件。

在我的机器上安装 Borg 只要 `sudo apt install borgbackup`。我的备份主机是一台连接有 1.5TB USB 驱动器的 Linux 机器。如果你没有可用的机器，那么备份主机可以像 Raspberry Pi 一样轻巧。只要确保所有的客户端机器都可以通过 SSH 访问这个服务器，那么你就能用了。

在备份主机上，使用以下命令初始化新的备份仓库：

```
$ borg init /mnt/backup/repo1

```

根据你要备份的内容，你可能会选择在每台计算机上创建多个仓库，或者为所有计算机创建一个大型仓库。由于 Borg 有重复数据删除功能，如果在多台计算机上有相同的数据，那么从所有这些计算机向同一个仓库发送备份可能是有意义的。

在 Linux 上安装 Borg 非常简单。在 Mac OS X 上，我需要首先安装 XCode 和 Homebrew。我遵循 [how-to](http://osxdaily.com/2014/02/12/install-command-line-tools-mac-os-x/) 来安装命令行工具，然后使用 `pip3 install borgbackup`。

### 备份

每台机器都有一个 `backup.sh` 脚本（见下文），由 cron 任务定期启动。它每天只做一个备份集，但在同一天尝试几次也没有什么不好的。笔记本电脑每隔两个小时就会尝试备份一次，因为不能保证它们在某个特定的时间开启，但很可能在其中一个时间开启。这可以通过编写一个始终运行的守护进程来改进，并在笔记本电脑唤醒时触发备份尝试。但现在，我对它的运作方式感到满意。

我可以跳过 cron 任务，并为每个用户提供一个相对简单的方法来使用 [BorgWeb](https://github.com/borgbackup/borgweb) 来触发备份，但是我真的不希望任何人必须记得备份。我倾向于忘记点击那个备份按钮，直到我急需修复（这时太迟了！）。

我使用的备份脚本来自 Borg 的[快速入门](https://borgbackup.readthedocs.io/en/stable/quickstart.html)文档，另外我在顶部添加了一些检查，看 Borg 是否已经在运行，如果之前的备份运行仍在进行这个脚本就会退出。这个脚本会创建一个新的备份集，并用主机名和当前日期来标记它。然后用简单的保留计划来整理旧的备份集。

这是我的 `backup.sh` 脚本：

```
#!/bin/sh

REPOSITORY=borg@borgserver:/mnt/backup/repo1

#Bail if borg is already running, maybe previous run didn't finish
if pidof -x borg >/dev/null; then
    echo "Backup already running"
    exit
fi

# Setting this, so you won't be asked for your repository passphrase:
export BORG_PASSPHRASE='thisisnotreallymypassphrase'
# or this to ask an external program to supply the passphrase:
export BORG_PASSCOMMAND='pass show backup'

# Backup all of /home and /var/www except a few
# excluded directories
borg create -v --stats                          \
    $REPOSITORY::'{hostname}-{now:%Y-%m-%d}'    \
    /home/doc                                   \
    --exclude '/home/doc/.cache'                \
    --exclude '/home/doc/.minikube'             \
    --exclude '/home/doc/Downloads'             \
    --exclude '/home/doc/Videos'                \
    --exclude '/home/doc/Music'                 \

# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly
# archives of THIS machine. The '{hostname}-' prefix is very important to
# limit prune's operation to this machine's archives and not apply to
# other machine's archives also.
borg prune -v --list $REPOSITORY --prefix '{hostname}-' \
    --keep-daily=7 --keep-weekly=4 --keep-monthly=6

```

备份的输出如下所示：

```
------------------------------------------------------------------------------
Archive name: x250-2017-10-05
Archive fingerprint: xxxxxxxxxxxxxxxxxxx
Time (start): Thu, 2017-10-05 03:09:03
Time (end):   Thu, 2017-10-05 03:12:11
Duration: 3 minutes 8.12 seconds
Number of files: 171150
------------------------------------------------------------------------------
                       Original size      Compressed size Deduplicated size
This archive:               27.75 GB             27.76 GB 323.76 MB
All archives:                3.08 TB              3.08 TB 262.76 GB

                       Unique chunks         Total chunks
Chunk index:                 1682989             24007828
------------------------------------------------------------------------------
[...]
Keeping archive: x250-2017-09-17                      Sun, 2017-09-17 03:09:02
Pruning archive: x250-2017-09-28                      Thu, 2017-09-28 03:09:02

```

我在将所有的机器备份到主机上后，我遵循[安装预编译的 Rclone 二进制文件指导](https://rclone.org/install/)，并将其设置为访问我的 Wasabi 帐户。

此脚本每天晚上运行以将任何更改同步到备份集：

```
#!/bin/bash
set -e

repos=( repo1 repo2 repo3 )

#Bail if rclone is already running, maybe previous run didn't finish
if pidof -x rclone >/dev/null; then
    echo "Process already running"
    exit
fi

for i in "${repos[@]}"
do
    #Lets see how much space is used by directory to back up
    #if directory is gone, or has gotten small, we will exit
    space=`du -s /mnt/backup/$i|awk '{print $1}'`

    if (( $space < 34500000 )); then
       echo "EXITING - not enough space used in $i"
       exit
    fi

    /usr/bin/rclone -v sync /mnt/backup/$i wasabi:$i >> /home/borg/wasabi-sync.log 2>&1
done

```

第一次用 Rclone 同步备份集到 Wasabi 花了好几天，但是我大约有 400GB 的新数据，而且我的出站连接速度不是很快。但是每日的增量是非常小的，能在几分钟内完成。

### 恢复文件

恢复文件并不像 CrashPlan 那样容易，但是相对简单。最快的方法是从存储在 Borg 备份服务器上的备份中恢复。以下是一些用于恢复的示例命令：

```
#List which backup sets are in the repo
$ borg list borg@borgserver:/mnt/backup/repo1
Remote: Authenticated with partial success.
Enter passphrase for key ssh://borg@borgserver/mnt/backup/repo1:
x250-2017-09-17                      Sun, 2017-09-17 03:09:02
#List contents of a backup set
$ borg list borg@borgserver:/mnt/backup/repo1::x250-2017-09-17 | less
#Restore one file from the repo
$ borg extract borg@borgserver:/mnt/backup/repo1::x250-2017-09-17 home/doc/somefile.jpg
#Restore a whole directory
$ borg extract borg@borgserver:/mnt/backup/repo1::x250-2017-09-17 home/doc

```

如果本地的 Borg 服务器或拥有所有备份仓库的 USB 驱动器发生问题，我也可以直接从 Wasabi 直接恢复。如果机器安装了 Rclone，使用 [rclone mount](https://rclone.org/commands/rclone_mount/)，我可以将远程存储仓库挂载到本地文件系统：

```
#Mount the S3 store and run in the background
$ rclone mount wasabi:repo1 /mnt/repo1 &
#List archive contents
$ borg list /mnt/repo1
#Extract a file
$ borg extract /mnt/repo1::x250-2017-09-17 home/doc/somefile.jpg

```

### 它工作得怎样

现在我已经使用了这个备份方法几个星期了，我可以说我真的很高兴。设置所有这些并使其运行当然比安装 CrashPlan 要复杂得多，但这就是使用你自己的解决方案和使用服务之间的区别。我将不得不密切关注以确保备份继续运行，数据与 Wasabi 正确同步。

但是，总的来说，以一个非常合理的价格替换 CrashPlan 以提供相似的备份覆盖率，结果比我预期的要容易一些。如果你看到有待改进的空间，请告诉我。

*这最初发表在 [Local Conspiracy](http://localconspiracy.com/2017/10/backup-everything.html)，并被许可转载。*

---

作者简介：

Christopher Aedo - Christopher Aedo 自从大学时开始就一直在用开源软件工作并为之作出贡献。最近他在领导一支非常棒的 IBM 上游开发团队，他们也是开发支持者。当他不在工作或在会议上发言时，他可能在俄勒冈州波特兰市使用 RaspberryPi 酿造和发酵美味的自制啤酒。

---

via: <https://opensource.com/article/17/10/backing-your-machines-borg>

作者：[Christopher Aedo](https://opensource.com/users/docaedo) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


如何以翻译贡献参与开源社区

Summary: 2017 中国开源年会 - COSCon'17 于 11 月 18 - 19 日在上海交大闵行校区圆满收官。在本次大会上，我发表了题为《如何以翻译贡献参与开源社区——LCTT 这几年》的演讲。

![](/data/attachment/album/201711/25/104856gn5jjjtkjs3mj2jf.jpg)

[2017 中国开源年会 - COSCon'17](http://www.kaiyuanshe.cn/dynamic/217.html) 于 11 月 18 - 19 日在上海交大闵行校区圆满收官。老王应邀代表 “Linux 中国” 参加了本次盛会。

这次大会总共 1,108 人次到场，在线视频观众总计 2,284 人，参加了接近 60 位大牛讲师的 5 场主题演讲，45 场分会场演讲，6 场动手训练营，5 场嘉宾对谈/观众问答，而来自五湖四海的 50 位可爱的志愿者们，热情地为讲师与观众们服务。

在本次大会上，我发表了题为《[如何以翻译贡献参与开源社区——LCTT 这几年](https://img.linux.net.cn/static/pdf/%E5%A6%82%E4%BD%95%E4%BB%A5%E7%BF%BB%E8%AF%91%E8%B4%A1%E7%8C%AE%E5%8F%82%E4%B8%8E%E5%BC%80%E6%BA%90%E7%A4%BE%E5%8C%BA.pdf)》的演讲，就 Linux 中国旗下的志愿者翻译组 LCTT 情况向大家做了介绍，将这几年来的辛酸苦辣、感恩感怀向开源小伙伴们做了倾诉；并就 LCTT 目前的情况和存在的问题，以及下一步的展望做了分析和计划。在本次演讲中，得到诸多关注志愿者翻译活动的社区积极分子的支持，并与其它翻译组织也有了初步合作的沟通。最后，在本次演讲中，我还宣布了重启 LCTT 的 man 翻译计划！

以下内容，摘录自本次演讲，完整的演讲文稿，可[从此下载](https://img.linux.net.cn/static/pdf/%E5%A6%82%E4%BD%95%E4%BB%A5%E7%BF%BB%E8%AF%91%E8%B4%A1%E7%8C%AE%E5%8F%82%E4%B8%8E%E5%BC%80%E6%BA%90%E7%A4%BE%E5%8C%BA.pdf)（PDF，3.1 Mb），版式与实际演讲稿有所不同。

演讲内容分为两大部分，分别面向贡献者个人的和面向社区组织者。

### 面向贡献者谈翻译贡献

首先，谈及为什么要为开源社区做贡献，这是提升自己的一个有益途径：

![](/data/attachment/album/201711/25/105111hwn606fgkwz0b75y.jpg)

而且，翻译活动也适合于初入开源社区的同学了解开源和在开源社区中获得进步：

![](/data/attachment/album/201711/25/105112x88kiyi2799899ky.jpg)

那么，如何参与开源贡献呢？参与的方式有很多，这里从下向上，由易而难依次列出了几个参与的主要方式——而其中所提到的“翻译”就是我本次演讲的主题。

![](/data/attachment/album/201711/25/105308s0eyzvu8qjnsuuuq.jpg)

为什么说“参与翻译”是一个比较适合开源贡献者入门的方式呢？是因为：

![](/data/attachment/album/201711/25/105534uwf3ksvoybyvv2tv.jpg)

而且，参与开源社区的翻译活动，要求并不高：

![](/data/attachment/album/201711/25/105641vd4d3al14y4l81d2.jpg)

当然，这也是需要你做出一点努力和学习的。

![](/data/attachment/album/201711/25/105642v4xtx04bxrtzmcdm.jpg)

在谈完开源志愿者以翻译贡献参与开源活动之后，我介绍了 LCTT 这几年的发展情况。

### LCTT 之路

LCTT 缘起于我对糟糕的 man 文档的中文化翻译的不满：

![](/data/attachment/album/201711/25/105921onfiengtwnleklf3.jpg)

而这四年来，我们已经取得了令人瞩目的成果：

![](/data/attachment/album/201711/25/110009gzv7md313p8zm3m3.jpg)

也涌现出了像 [geekpi](https://linux.cn/lctt/geekpi)、[oska874](https://linux.cn/lctt/oska874) 这样卓越的贡献者：

![](/data/attachment/album/201711/25/110101e3syr3sa77rs7r5s.jpg)

正是这两百多位贡献者，才成就了 LCTT 这几年来成绩。在外出参加社区交流时，我不止一次地听到别人对我表扬 LCTT 翻译的文章不错，这是让我感到最荣耀的事情，是对我们 LCTT 最大的肯定。

![](/data/attachment/album/201711/25/110253wyp43spg3vw2mz4v.jpg)

然后，我立下了本次演讲中的 flag，我将重启 man 翻译计划。

### 中文 man 翻译计划——我的执念

man 翻译计划殇于我们的经验不足和对困难的认识不够：

![](/data/attachment/album/201711/25/110454wlilw4lhw7788sbr.jpg)

对此，我们进行了一些反思总结：

![](/data/attachment/album/201711/25/110536fv7vjnra5axuj5vr.jpg)

历史上，man 中文翻译活动沉沉浮浮，但是一直没有取得像样的成功。

![](/data/attachment/album/201711/25/110635an6u01xgclzx0ggp.jpg)

所以，我觉得，对于这样一件有意义的事情，不应该只是心里的念想，而应该切实做出来。希望大家支持我们，参与我们，让我们将这件利在千秋的事情做好。

![](/data/attachment/album/201711/25/110722n88s8ed8rm74mz2p.jpg)

立下这个目标之后，那么想参与的同学该怎么进入呢？我介绍了加入 LCTT 的方式：

### 如何加入 LCTT

加入 [LCTT](https://linux.cn/lctt/) 并参与到 LCTT 的贡献活动当中，其实很简单，重要的是，你的意愿。你只需要加入我们的专属 QQ 群： **198889102**，验证信息输入“志愿者”，即可加入 LCTT 大家庭。成为了一个 LCTT 人，你不但可以为开源社区做出贡献，而且你还会有自己的专页来展示你的成就。

![](/data/attachment/album/201711/25/111017e535msf9sttpql02.jpg)

我也简单介绍了 LCTT 的贡献流程：

![](/data/attachment/album/201711/25/112703y71vvzo10k16ikn1.gif)

后面还谈及了一些我们总结的翻译技巧，这里就不写了，大家可以看完整演讲稿了解，也可以和 LCTT 成员在群内沟通。

然后，面向开源社区组织者谈了一下我们组织和运营 LCTT 几年来的经验心得，希望可以给其它开源社区一些有益的参考。

### 开源社区如何组织翻译活动

作为志愿者翻译组织，首先要做的就是招募愿意参与的志愿者：

![](/data/attachment/album/201711/25/113241gxt3i8xef66fd6st.jpg)

其实，我们这次演讲，也是具有一定的招募意义的。

有了参与者之外，就要拟定和执行一个翻译流程：

![](/data/attachment/album/201711/25/113357ech2c22hypahmpoa.jpg)

并建立激励机制：

![](/data/attachment/album/201711/25/113445b7ssh0z5le112bn8.jpg)

以及，到了一定规模之后，就应该考虑建立一个翻译工作平台来规范流程和降低参与难度，这也是我们 LCTT 目前亟待进行的工作：

![](/data/attachment/album/201711/25/113614r1rdncndltg1pcgl.jpg)

并且，我们自我反思，在 LCTT 的运营中，也存在一些不足。不怕自曝其丑，这些地方也希望可以给大家一些启示：

![](/data/attachment/album/201711/25/113725qq1ni91mr429t4ik.jpg)

最后，结束演讲之前，我还大致谈了谈我的开源社区观，具体内容不在此处赘述，大家可以参考我以前写的一篇文章：《[如何参与和帮助「Linux 中国」开源社区的发展](/article-8670-1.html)》

### 总结

这次参与[开源社](http://www.kaiyuanshe.cn/)主办的 “[2017 中国开源年会 - COSCon'17](http://www.kaiyuanshe.cn/dynamic/217.html)”，我见到了许多朋友，有之前闻名已久的新朋友，也有已经熟悉的老朋友。而且，大家的很多分享，都是干货满满——这一点并不是我为朋友们吹嘘，确实，作为开源社区活动人士，很多演讲都让我很有共鸣，也很有启发。

感谢开源社做出的贡献！


5 款最酷的 Linux 终端模拟器

![](/data/attachment/album/201711/26/224140mmrcqn8fgmmzkvgv.jpg)

>
> Carla Schroder 正在看着那些她喜欢的终端模拟器， 包括展示在这儿的 Cool Retro Term。
>
>
>

虽然，我们可以继续使用老旧的 GNOME 终端、Konsole，以及好笑而孱弱的旧式 xterm。 不过，让我们带着尝试某种新东西的心境，回过头来看看 5 款酷炫并且实用的 Linux 终端。

### Xiki

首先我要推荐的第一个终端是 [Xiki](http://xiki.org/)。 Xiki 是 Craig Muth 的智慧结晶，他是一个天才程序员，也是一个有趣的人（有趣在此处的意思是幽默，可能还有其它的意思）。 很久以前我在 [遇见 Xiki，Linux 和 Mac OS X 下革命性命令行 Shell](https://www.linux.com/learn/meet-xiki-revolutionary-command-shell-linux-and-mac-os-x) 一文中介绍过 Xiki。 Xiki 不仅仅是又一款终端模拟器；它也是一个扩展命令行用途、加快命令行速度的交互式环境。

Xiki 支持鼠标，并且在绝大多数命令行 Shell 上都支持。 它有大量的屏显帮助，而且可以使用鼠标和键盘快速导航。 它体现在速度上的一个简单例子就是增强了 `ls` 命令。 Xiki 可以快速穿过文件系统上的多层目录，而不用持续的重复输入 `ls` 或者 `cd`， 或者利用那些巧妙的正则表达式。

Xiki 可以与许多文本编辑器相集成， 提供了一个永久的便签， 有一个快速搜索引擎， 同时像他们所说的，还有许许多多的功能。 Xiki 是如此的有特色、如此的不同， 所以学习和了解它的最快的方式可以看 [Craig 的有趣和实用的视频](http://xiki.org/screencasts/)。

### Cool Retro Term

我推荐 [Cool Retro Term](https://github.com/Swordfish90/cool-retro-term) （如题图显示） 主要因为它的外观，以及它的实用性。 它将我们带回了阴极射线管显示器的时代，这不算很久以前，而我也没有怀旧的意思，我死也不会放弃我的 LCD 屏幕。它基于 [Konsole](https://www.linux.com/learn/expert-tips-and-tricks-kate-and-konsole)， 因此有着 Konsole 的优秀功能。可以通过 Cool Retro Term 的配置文件菜单来改变它的外观。配置文件包括 Amber、Green、Pixelated、Apple 和 Transparent Green 等等，而且全都包括一个像真的一样的扫描线。并不是全都是有用的，例如 Vintage 配置文件看起来就像一个闪烁着的老旧的球面屏。

Cool Retro Term 的 GitHub 仓库有着详细的安装指南，且 Ubuntu 用户有 [PPA](https://launchpad.net/%7Ebugs-launchpad-net-falkensweb/+archive/ubuntu/cool-retro-term)。

### Sakura

你要是想要一个优秀的轻量级、易配置的终端，可以尝试下 [Sakura](https://bugs.launchpad.net/sakura)（图 1）。 它依赖少，不像 GNOME 终端 和 Konsole，在 GNOME 和 KDE 中牵扯了很多组件。其大多数选项是可以通过右键菜单配置的，例如选项卡的标签、 颜色、大小、选项卡的默认数量、字体、铃声，以及光标类型。 你可以在你个人的配置文件 `~/.config/sakura/sakura.conf` 里面设置更多的选项，例如绑定快捷键。

![sakura](/data/attachment/album/201711/26/223245lkjw9225u7jucbko.png)

*图 1： Sakura 是一个优秀的、轻量级的、可配置的终端。*

命令行选项详见 `man sakura`。可以使用这些来从命令行启动 sakura，或者在你的图形启动器上使用它们。 例如，打开 4 个选项卡并设置窗口标题为 “MyWindowTitle”：

```
$ sakura -t MyWindowTitle -n 4

```

### Terminology

[Terminology](https://www.enlightenment.org/about-terminology) 来自 Enlightenment 图形环境的郁葱可爱的世界，它能够被美化成任何你所想要的样子 (图 2)。 它有许多有用的功能：独立的拆分窗口、打开文件和 URL、文件图标、选项卡，林林总总。 它甚至能运行在没有图形界面的 Linux 控制台上。

![Terminology](/data/attachment/album/201711/26/223246u2nu9frgtllg29w4.png)

*图 2: Terminology 也能够运行在没有图形界面的 Linux 控制台上。*

当你打开多个拆分窗口时，每个窗口都能设置不同的背景，并且背景文件可以是任意媒体文件：图像文件、视频或者音乐文件。它带有一堆便于清晰可读的暗色主题和透明主题，它甚至一个 Nyan 猫主题。它没有滚动条，因此需要使用组合键 `Shift+PageUp` 和 `Shift+PageDown` 进行上下导航。

它有多个控件：一个右键单击菜单，上下文对话框，以及命令行选项。右键单击菜单里包含世界上最小的字体，且 Miniview 可显示一个微观的文件树，但我没有找到可以使它们易于辨读的选项。当你打开多个标签时，可以点击小标签浏览器来打开一个可以上下滚动的选择器。任何东西都是可配置的；通过 `man terminology` 可以查看一系列的命令和选项，包括一批不错的快捷键快捷方式。奇怪的是，帮助里面没有包括以下命令，这是我偶然发现的：

* tyalpha
* tybg
* tycat
* tyls
* typop
* tyq

使用 `tybg [filename]` 命令来设置背景，不带参数的 `tybg` 命令来移除背景。 运行 `typop [filename]` 来打开文件。 `tyls` 命令以图标视图列出文件。 加上 `-h` 选项运行这些命令可以了解它们是干什么的。 即使有可读性的怪癖，Terminology 依然是快速、漂亮和实用的。

### Tilda

已经有几个优秀的下拉式终端模拟器，包括 Guake 和 Yakuake。 [Tilda](https://github.com/lanoxx/tilda) (图 3) 是其中最简单和轻量级的一个。 打开 Tilda 后它会保持打开状态， 你可以通过快捷键来显示和隐藏它。 Tilda 快捷键是默认设置的， 你可以设置自己喜欢的快捷键。 它一直打开着的，随时准备工作，但是直到你需要它的时候才会出现。

![](/data/attachment/album/201711/26/223247jwwwj7fqzejw7dq0.png)

*图 3: Tilda 是最简单和轻量级的一个终端模拟器。*

Tilda 选项方面有很好的补充，包括默认的大小、位置、外观、绑定键、搜索条、鼠标动作，以及标签条。 这些都被右键单击菜单控制。

*学习更多关于 Linux 的知识可以通过 Linux 基金会 和 edX 的免费课程 ["Linux 介绍"](https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux) 。*

---

via: <https://www.linux.com/learn/intro-to-linux/2017/11/5-coolest-linux-terminal-emulators>

作者：[CARLA SCHRODER](https://www.linux.com/users/cschroder) 译者：[cnobelw](https://github.com/cnobelw) 校对：[wxy](https://github.com/wxy)

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


我们为国内的逆向工程师做了一件事！

如果发现书的翻译有问题，可以到异步社区 http://www.epubit.com.cn/book/details/4696 提交勘误

微信过期了 加作者不回

微信过期了 加作者不回

![](/data/attachment/album/201711/27/175032a8wjwm5wbvmjoddd.jpg)

>
> 拿到这本《Linux 二进制分析》，我不禁心生感慨。
>
>
>

对于软件逆向工程这门手艺来说，最难的便是入门。软件逆向不同于软件的编写。基于汇编语言的软件逆向将绝大多数的人拦在了门外。少部分人打开了这扇门，又为门后的贫瘠所震惊 —— 相关资料少且不系统。

一直以来， Windows 由于其在桌面端的广泛应用而不断受人关注，相关的书籍也不断出新。但随着移动端设备的逐渐崛起，\*nix 系统占据了市场的主流。但是基于 \*nix 的逆向开发一直都处在荒芜的状态，为少数人所掌握。现在，移动端设备成为新的安全隐患增长点，我们也为此忧心忡忡。于是，我们组织译者，翻译了这本<ruby> <a href="https://detail.youzan.com/show/goods?alias=3nffgxtvcasmt&from=wxd&kdtfrom=wxd&type=share_goods&share=wxd_frd&mtd=sh_frd_wxd">  《Linux 二进制分析》 </a> <rp>  （ </rp> <rt>  Learning Linux Binary Analysis </rt> <rp>  ） </rp></ruby> 。

### 1、LCTT 的新台阶

《[Linux 二进制分析](https://detail.youzan.com/show/goods?alias=3nffgxtvcasmt&from=wxd&kdtfrom=wxd&type=share_goods&share=wxd_frd&mtd=sh_frd_wxd)》是棣琦的译作，也是我们 Linux 中国审校的第一本书。在我看来，这是 Linux 中国 [LCTT 翻译组](https://linux.cn/lctt/)的一个新的里程碑。

自 2013 年 9 月 LCTT 创立以来，已有 250 余位志愿者参与到我们的翻译组，累计翻译了近三千篇各种 Linux 相关的文章。但是直到这本《[Linux 二进制分析](https://detail.youzan.com/show/goods?alias=3nffgxtvcasmt&from=wxd&kdtfrom=wxd&type=share_goods&share=wxd_frd&mtd=sh_frd_wxd)》的出版，我们 LCTT 第一次真正意义上完成了一本书的翻译、校对、审核的工作。我们的工作上了一个新的台阶。

### 2、作者简介

Ryan O‘Neill，是一名在逆向工程、软件开发、安全防御和取证分析技术方面深有建树的计算机安全专家，曾就职于 Pikewerks、Leviathan 安全集团，最近在 Backtrace 担任软件工程师。

除了这本书以外，他之前还写了大量相关的论文，比如 “Modern day ELF Runtime infection via GlobalOffsetTable poisoning”、“Extending the ELF core file format for forensics snapshots”。丰富的经历和研究，使他在 ELF 二进制研究上有着超出前人的成就，这些成就，最终促成了这本《[Linux 二进制分析](https://detail.youzan.com/show/goods?alias=3nffgxtvcasmt&from=wxd&kdtfrom=wxd&type=share_goods&share=wxd_frd&mtd=sh_frd_wxd)》的出版。

### 3、译者简介

[棣琦](http://www.epubit.com.cn/space/book/41539)，本名张萌萌，是一个集美貌与智慧并存的程序媛。目前是百度研发工程师， 业余时间爱好翻译。当别人周末约会、逛街时，她选择了开启一段艰辛的翻译之旅，焚膏继晷大半年，一字一句的翻译、一行一行的校对。

《[Linux 二进制分析](https://detail.youzan.com/show/goods?alias=3nffgxtvcasmt&from=wxd&kdtfrom=wxd&type=share_goods&share=wxd_frd&mtd=sh_frd_wxd)》不同于其他 Linux 技术书籍，国内和 Linux 二进制分析相关的图书、资 料十分的少，远不如其他方面的资料那般充盈，对于她来说，除了要对文章进行翻译，还要通读国内外的相关文献，以保证译文的翔实和准确。

![棣琦在翻译……](/data/attachment/album/201711/27/175531n6ek88y6ie6b6kbc.jpg)

此外，由于这本书内包含了大量的实战操作内容，她也需要花费大量的时间进行重复操作、验证，以确保书的内容可以被读者重新实践。

### 4、内容分享

这本书的内容详实，可以帮助读者快速建立起 Linux 二进制分析的整体框架，并且使用了大量的篇幅来介绍 ELF 文件格式，为读者打下良好的基础；并通过取自工作中不同场景下二进制分析的实战来帮助读者明晰二进制分析的重要性和效果，一方面可以让读者不至于只能读到枯燥无味的内容解读，另一方面，也让这本书成为安全工程师的“牛津词典”，在工作中遇到问题，可以翻到对应章节，重温操作、理念。

#### 章节介绍

* 第 1 章，Linux 环境和相关工具，简要介绍了会在本书中用到的 Linux 环境和相关的工具。
* 第 2 章，ELF：二进制格式，帮助读者了解 ELF 文件格式
* 第 3 章，Linux 进程追踪，教会读者使用 ptrace 系统调用读写进程内存并注入代码。
* 第 4 章，ELF 病毒技术 - Linux/UNIX 病毒，介绍了 Linux 病毒的历史、病毒的工程化和围绕病毒进行的相关研究。
* 第 5 章，Linux 二进制保护，解释了 ELF 二进制保护的基本原理。
* 第 6 章，Linux 下的 ELF 二进制取证分析，通过解析 ELF 目标文件来研究病毒、后门和可疑的代码注入。
* 第 7 章，进程内存取证分析，将会介绍如何解析进程的地址空间，以研究内存中的恶意软件、后门和可疑的代码注入。
* 第 8 章，ECFS 一一扩展核心文件快照技术，是对 ECFS 这一用于深入进程内存取证分析的新开源产品的介绍。
* 第 9 章，Linux /proc/kcore 分析，介绍了如何使用 /proc/kcore 进行内存分析来检测 Linux 内核中的恶意软件。

### 5、我对书的评价

在过去，安全工程师们想要学习 Linux 二进制分析，只能通过搜索引擎来搜索有限的资料，不管是中文的还是英文的，都颇为琐碎，工程师们不得不在一个又一个网页间不断跳转，以求得知识的完备性，然而互联网上的资料虽多，但真正有价值的内容却不多，大多是一些颇为浅薄的内容。

这本书的出现，填补了 Linux 二进制分析方面的空白，一方面，体系化的内容设计使得安全工程师能够在读完此书后建立起 Linux 二进制分析的完整知识体系。读者在后续需要继续研究时，只需要在此书的基础上，查询其他相关的资料，丰满自己的知识体系即可。另一方面，对于一些开始在工作中使用 ELF 分析的工程师来说， Ryan 的经验也可以真正的帮助他们更好的工作，这才是这本书最难得的。

如果你已经开始了相关的安全工作又或者希望从事软件逆向研究的相关工作，那么你一定不能错过这本书。

### 6、欢迎交流

译者棣琦已经召集了一个专用的微信群来讨论有关本书的话题，欢迎大家加入（限时）：

![微信群](/data/attachment/album/201711/27/214206qipvvp85thek6e69.jpeg)

如果你加入时二维码已经过期，或者群已经超过百人，你也可以加棣琦的微信，让她拉你进群：

![棣琦的微信](/data/attachment/album/201711/27/214405balbaj56uxdybjfl.jpeg)

### 福利

作为 Linux 中国参与制书流程的第一本书，我们从出版社那里为大家争取到了福利。在异步社区价值 59 的图书，我给你打 7 折，只要 39.99。

扫描下方二维码，即可下单购买这本《[Linux 二进制分析](https://detail.youzan.com/show/goods?alias=3nffgxtvcasmt&from=wxd&kdtfrom=wxd&type=share_goods&share=wxd_frd&mtd=sh_frd_wxd)》，欢迎大家转发此文或转发如下图片：

![图书](/data/attachment/album/201711/27/182311g25u8hqhp5balahd.jpg)


了解用于 Linux 和 Windows 容器的 Docker “容器主机”与“容器操作系统”

![](/data/attachment/album/201711/27/225657t2mt8222b5ma5c24.png)

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

### 一些定义

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

### 如下的一些图

![Linux Containers](/data/attachment/album/201711/27/225709cc3cn4cwwj24acgs.png)

在上面的例子中：

* 主机操作系统是 Ubuntu。
* Docker 客户端和 Docker 守护进程（一起被称为 Docker 引擎）正在主机操作系统上运行。
* 每个容器共享主机操作系统内核。
* CentOS 和 BusyBox 是 Linux 基础操作系统镜像。
* “No OS” 容器表明你不需要基础操作系统以在 Linux 中运行一个容器。你可以创建一个含有 [scratch](https://hub.docker.com/_/scratch/) 基础镜像的 Docker 文件，然后运行直接使用内核的二进制文件。
* 查看[这篇](https://www.brianchristner.io/docker-image-base-os-size-comparison/)文章来比较基础 OS 的大小。

![Windows Containers - Non Hyper-V](/data/attachment/album/201711/27/225710zkx228jja2ux6kbc.png)

在上面的例子中：

* 主机操作系统是 Windows 10 或 Windows Server。
* 每个容器共享主机操作系统内核。
* 所有 Windows 容器都需要 [nanoserver](https://hub.docker.com/r/microsoft/nanoserver/) 或 [windowsservercore](https://hub.docker.com/r/microsoft/windowsservercore/) 的基础操作系统。

![Windows Containers - Hyper-V](/data/attachment/album/201711/27/225710nqztqqb295cqfuqf.png)

在上面的例子中：

* 主机操作系统是 Windows 10 或 Windows Server。
* 每个容器都托管在自己的轻量级 Hyper-V 虚拟机中。
* 每个容器使用 Hyper-V 虚拟机内的内核，它在容器之间提供额外的分离层。
* 所有 Windows 容器都需要 [nanoserver](https://hub.docker.com/r/microsoft/nanoserver/) 或 [windowsservercore](https://hub.docker.com/r/microsoft/windowsservercore/) 的基础操作系统。

### 几个好的链接

* [关于 Windows 容器](https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/)
* [深入实现 Windows 容器，包括多用户模式和“写时复制”来节省资源](http://blog.xebia.com/deep-dive-into-windows-server-containers-and-docker-part-2-underlying-implementation-of-windows-server-containers/)
* [Linux 容器如何通过使用“写时复制”来节省资源](https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/#the-copy-on-write-strategy)

---

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

作者：[Floyd Hilton](http://floydhilton.com/about/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


用 coredumpctl 更好地记录 bug

Summary: 通常开发者要求提供 “回溯（backtrace）” 形式的数据，以显示导致崩溃的指令流。开发人员可以使用它来修复 bug 以改进系统。

![](/data/attachment/album/201711/28/230423v9yp293hhfafy0vf.jpg)

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

### 从使用 coredumpctl 开始

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

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

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

```
coredumpctl list

```

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

```
coredumpctl list --since=today

```

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

```
MYPID=<PID>

```

要查看关于核心转储的信息，请使用此命令（使用 `$MYPID` 变量或替换 PID 编号）：

```
coredumpctl info $MYPID

```

### 安装 debuginfo 包

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

```
coredumpctl gdb $MYPID

```

这可能会在屏幕上显示大量信息。最后一行可能会告诉你使用 `dnf` 安装更多的 debuginfo 软件包。[用 sudo](https://fedoramagazine.org/howto-use-sudo/) 运行该命令以安装：

```
sudo dnf debuginfo-install <packages...>

```

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

### 捕获回溯

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

```
set logging file mybacktrace.txt
set logging on

```

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

```
set pagination off

```

现在运行回溯：

```
thread apply all bt full

```

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

---

作者简介：

Paul W. Frields

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

---

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

作者：[Paul W. Frields](https://fedoramagazine.org/author/pfrields/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


介绍 Moby 项目：推进软件容器化运动的一个新的开源项目

![Moby Project](/data/attachment/album/201711/29/054157oxcaiq4xxu4x4yz1.png)

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

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

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

![Docker Open Source](/data/attachment/album/201711/29/054158phreyriidecrq8dn.png)

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

涌现出来的新独立的 Docker 组件项目帮助促进了合作伙伴生态系统和用户社区的发展。在此期间，我们从 Docker 代码库中提取并快速创新组件，以便系统制造商可以在构建自己的容器系统时独立重用它们：[runc](https://github.com/opencontainers/runc)、[HyperKit](https://github.com/docker/hyperkit)、[VPNKit](https://github.com/docker/vpnkit)、[SwarmKit](https://github.com/docker/swarmkit)、[InfraKit](https://github.com/docker/infrakit)、[containerd](https://github.com/containerd/containerd) 等。

![Docker Open Components](/data/attachment/album/201711/29/054201ctjlutzpypyjfpy2.png)

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

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

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

![Docker production model](/data/attachment/album/201711/29/054202dg5omey011xsowzs.png)

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

![Moby Project](/data/attachment/album/201711/29/054204vjplqig6pzgtqzpk.png)

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

Moby 包括：

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

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

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

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

---

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

作者：[Solomon Hykes](https://blog.docker.com/author/solomon/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

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


Linux 上的科学图像处理

Summary: 在这篇文章中，我将谈到一款叫 ImageJ 的热门图像处理软件。特别的，我会介绍 Fiji，这是一款绑定了一系列用于科学图像处理插件的 ImageJ 软件。

![](/data/attachment/album/201711/29/064214rq07lbllcxquadvl.jpg)

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

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

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

![](/data/attachment/album/201711/29/064226zthxuuy9b8eww9th.png)

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

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

![](/data/attachment/album/201711/29/064226h7biy1cf8z2284cc.jpg)

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

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

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

![](/data/attachment/album/201711/29/064229rz22l3sbtuo5r82w.png)

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

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

![](/data/attachment/album/201711/29/064229pah5d6s6vdyze6v7.jpg)

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

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

![](/data/attachment/album/201711/29/064229e7yzy207nnm4i79m.png)

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

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

![](/data/attachment/album/201711/29/064231lm5yt8cy5y90mcyt.png)

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

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

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

![](/data/attachment/album/201711/29/064232ehejf64eted952b6.png)

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

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

![](/data/attachment/album/201711/29/064232a75n51wmtei1k1kz.png)

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

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

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

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

![](/data/attachment/album/201711/29/064233bj1qrkkhhj9qs9jj.png)

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

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

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

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

---

作者简介：

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

---

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

作者：[Joey Bernard](https://www.linuxjournal.com/users/joey-bernard) 译者：[XYenChi](https://github.com/XYenChi) 校对：[wxy](https://github.com/wxy)

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


如何轻松记住 Linux 命令

Summary: Linux 新手往往对命令行心存畏惧。部分原因是因为需要记忆大量的命令，毕竟掌握命令是高效使用命令行的前提。不幸的是，学习这些命令并无捷径，然而在你开始学习命令之初，有些工具还是可以帮到你的。

![](/data/attachment/album/201711/29/152255euutfdffffdzdfyq.jpg)

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

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

### history

![Linux Bash History 命令](/data/attachment/album/201711/29/152255dev4li442zvsvnd2.jpg)

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

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

### apropos

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

```
apropos "list directory"

```

![Linux Apropos](/data/attachment/album/201711/29/152255hgfcc0qn50qa6fkd.jpg)

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

```
apropos "list directories"

```

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

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

```
apropos "match pattern"

```

![Linux Apropos -a Flag](/data/attachment/album/201711/29/152256pz7wyf550wc6ze6q.jpg)

你会觉得应该会有一些匹配的内容出现，比如 [grep](https://www.maketecheasier.com/what-is-grep-and-uses/) 对吗? 然而，实际上并没有匹配出任何结果。再说一次，apropos 只会根据字面内容进行搜索。

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

```
apropos "match" -a "pattern"

```

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

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

### ZSH

![Linux ZSH Autocomplete](/data/attachment/album/201711/29/152256wxfyxe59h49zxyuu.jpg)

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

### 速记表

最后，也可能是最间的方法就是使用 [速记表](https://www.maketecheasier.com/premium/cheatsheet/linux-command-line/)。

有很多在线的速记表，比如[这个](https://www.cheatography.com/davechild/cheat-sheets/linux-command-line/) 可以帮助你快速查询命令。

![linux-commandline-cheatsheet](/data/attachment/album/201711/29/152256sojudjxm97odfkvh.gif)

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

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

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

---

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

作者：[Nick Congleton](https://www.maketecheasier.com/author/nickcongleton/) 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


操作系统何时运行？

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

![](/data/attachment/album/201711/29/222924esf8201bgwoobtg8.jpg)

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

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

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

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

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

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

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

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

![](/data/attachment/album/201711/29/222933n7l3klcbknbundlb.png)

链接如下：

* [network card](https://github.com/torvalds/linux/blob/v3.17/drivers/net/ethernet/intel/e1000e/netdev.c)
* [USB keyboard](https://github.com/torvalds/linux/blob/v3.16/drivers/hid/usbhid/usbkbd.c)
* [I/O APIC](https://github.com/torvalds/linux/blob/v3.16/arch/x86/kernel/apic/io_apic.c)
* [HPET](https://github.com/torvalds/linux/blob/v3.17/arch/x86/kernel/hpet.c)

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

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

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

![](/data/attachment/album/201711/29/222935aokr7jvzs75ztz9e.png)

此处请留意，中断的到来是如何触发 CPU 到 [Ring 0](http://duartes.org/gustavo/blog/post/cpu-rings-privilege-and-protection) 内核模式的切换而未有改变当前活跃的任务。这看上去就像，Vim 编辑器直接面向操作系统内核产生了一次神奇的函数调用，但 Vim 还在那里，它的[地址空间](http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory)原封未动，等待着执行流返回。

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

---

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

作者：[gustavo](http://duartes.org/gustavo/blog/about/) 译者：[Cwndmiao](https://github.com/Cwndmiao) 校对：[wxy](https://github.com/wxy)

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


tmate：秒级分享你的终端会话

Summary: tmate 的意思是 teammates，它是 tmux 的一个分支，并且使用相同的配置信息（例如快捷键配置，配色方案等）。它是一个终端多路复用器，同时具有即时分享终端的能力。它允许在单个屏幕中创建并操控多个终端，同时这些终端还能与其他同事分享。

![](/data/attachment/album/201711/30/122203xut2ngdhontci2vt.jpg)

不久前，我们写过一篇关于 [teleconsole](https://www.2daygeek.com/teleconsole-share-terminal-session-instantly-to-anyone-in-seconds/) 的介绍，该工具可用于快速分享终端给任何人（任何你信任的人）。今天我们要聊一聊另一款类似的应用，名叫 `tmate`。

`tmate` 有什么用？它可以让你在需要帮助时向你的朋友们求助。

### 什么是 tmate？

[tmate](https://tmate.io/) 的意思是 `teammates`，它是 tmux 的一个分支，并且使用相同的配置信息（例如快捷键配置，配色方案等）。它是一个终端多路复用器，同时具有即时分享终端的能力。它允许在单个屏幕中创建并操控多个终端，同时这些终端还能与其他同事分享。

你可以分离会话，让作业在后台运行，然后在想要查看状态时重新连接会话。`tmate` 提供了一个即时配对的方案，让你可以与一个或多个队友共享一个终端。

在屏幕的地步有一个状态栏，显示了当前会话的一些诸如 ssh 命令之类的共享信息。

### tmate 是怎么工作的？

* 运行 `tmate` 时，会通过 `libssh` 在后台创建一个连接到 tmate.io （由 tmate 开发者维护的后台服务器）的 ssh 连接。
* tmate.io 服务器的 ssh 密钥通过 DH 交换进行校验。
* 客户端通过本地 ssh 密钥进行认证。
* 连接创建后，本地 tmux 服务器会生成一个 150 位(不可猜测的随机字符)会话令牌。
* 队友能通过用户提供的 SSH 会话 ID 连接到 tmate.io。

### 使用 tmate 的必备条件

由于 `tmate.io` 服务器需要通过本地 ssh 密钥来认证客户机，因此其中一个必备条件就是生成 SSH 密钥 key。 记住，每个系统都要有自己的 SSH 密钥。

```
$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/magi/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/magi/.ssh/id_rsa.
Your public key has been saved in /home/magi/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:3ima5FuwKbWyyyNrlR/DeBucoyRfdOtlUmb5D214NC8 magi@magi-VirtualBox
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                 |
|           .     |
|      . . =   o  |
|     *ooS= . + o |
|  . =.@*o.o.+ E .|
|   =o==B++o  = . |
|  o.+*o+..    .  |
| ..o+o=.         |
+----[SHA256]-----+

```

### 如何安装 tmate

`tmate` 已经包含在某些发行版的官方仓库中，可以通过包管理器来安装。

对于 Debian/Ubuntu，可以使用 [APT-GET 命令](https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/)或者 [APT 命令](https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/)to 来安装。

```
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:tmate.io/archive
$ sudo apt-get update
$ sudo apt-get install tmate

```

你也可以从官方仓库中安装 tmate。

```
$ sudo apt-get install tmate

```

对于 Fedora，使用 [DNF 命令](https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/) 来安装。

```
$ sudo dnf install tmate

```

对于基于 Arch Linux 的系统，使用 [Yaourt 命令](https://www.2daygeek.com/install-yaourt-aur-helper-on-arch-linux/)或 [Packer 命令](https://www.2daygeek.com/install-packer-aur-helper-on-arch-linux/) 来从 AUR 仓库中安装。

```
$ yaourt -S tmate

```

或

```
$ packer -S tmate

```

对于 openSUSE，使用 [Zypper 命令](https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/) 来安装。

```
$ sudo zypper in tmate

```

### 如何使用 tmate

成功安装后，打开终端然后输入下面命令，就会打开一个新的会话，在屏幕底部，你能看到 SSH 会话的 ID。

```
$ tmate

```

![](/data/attachment/album/201711/30/122244wto5wd77vk7xkt5k.png)

要注意的是，SSH 会话 ID 会在几秒后消失，不过不要紧，你可以通过下面命令获取到这些详细信息。

```
$ tmate show-messages

```

`tmate` 的 `show-messages` 命令会显示 tmate 的日志信息，其中包含了该 ssh 连接内容。

![](/data/attachment/album/201711/30/122244kypkq9v27pud8yyy.png)

现在，分享你的 SSH 会话 ID 给你的朋友或同事从而允许他们观看终端会话。除了 SSH 会话 ID 以外，你也可以分享 web URL。

另外你还可以选择分享的是只读会话还是可读写会话。

### 如何通过 SSH 连接会话

只需要在终端上运行你从朋友那得到的 SSH 终端 ID 就行了。类似下面这样。

```
$ ssh session: ssh 3KuRj95sEZRHkpPtc2y6jcokP@sg2.tmate.io

```

![](/data/attachment/album/201711/30/122246tyypd8ik4yzuy3s4.png)

### 如何通过 Web URL 连接会话

打开浏览器然后访问朋友给你的 URL 就行了。像下面这样。

![](/data/attachment/album/201711/30/122247v0at3bj3z84gd8t8.png)

只需要输入 `exit` 就能退出会话了。

```
[Source System Output]
[exited]

[Remote System Output]
[server exited]
Connection to sg2.tmate.io closed by remote host。
Connection to sg2.tmate.io closed。

```

---

via: <https://www.2daygeek.com/tmate-instantly-share-your-terminal-session-to-anyone-in-seconds/>

作者：[Magesh Maruthamuthu][a] 译者：[lujun9972](https://github.com/lujun9972) 校对：[wxy](https://github.com/wxy)

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


略谈企业的开源战略

11 月 24 日，Gdevops 全球敏捷运维峰会的 2017 年度收官之站在广州盛大举行。老王受邀参加了本次大会，本做了本次大会的首场演讲《略谈企业的开源战略》。

![](/data/attachment/album/201711/30/130252jr1kdk8k12xxo2d1.jpg)

说起来，Gdevops 已经举办了两年多，我曾经多次参与和主持过大会，开场的视频所滑过的一幕幕，让我不禁心生感慨，逝者如斯夫啊。

虽然参加了两年的 Gdevops，也曾经以主持人的身份主持过多期，但是这次还是老王第一次以演讲者的身份登上 Gdevops 讲台——结果原本感觉 30 分钟还是比较长的，结果讲 high 了，差点没搂着时间。

![](/data/attachment/album/201711/30/130004kmozqxmljoyoqogm.jpeg)

以下是整理自本次演讲的内容，分享给大家，大家也可以下载演讲的稿件（[PDF](https://img.linux.net.cn/static/pdf/%E7%95%A5%E8%B0%88%E4%BC%81%E4%B8%9A%E7%9A%84%E5%BC%80%E6%BA%90%E6%88%98%E7%95%A5%20-%20Gdevops%E5%B3%B0%E4%BC%9A.pdf)，2.3Mb）。

演讲的内容主要分成三个部分：

![](/data/attachment/album/201711/30/130357zfz5h8fnan55d80q.jpg)

首先追本溯源，简单介绍了开源的历史：

![](/data/attachment/album/201711/30/130433pxf6yucb56hkox65.jpg)

从软件的由来、专有软件的兴起谈到了古典黑客文化的回归：

![](/data/attachment/album/201711/30/130641utr999s562wbl25r.jpg)

然后谈到了开源软件的“正确打开方式”：

![](/data/attachment/album/201711/30/130915rvvvc1sxqqp6y4sv.jpg)

什么是开源软件（或者自由软件），很多人都有一些理解，不过<ruby> 开源软件 <rp>  （ </rp> <rt>  Open Source Software </rt> <rp>  ） </rp></ruby>其实是有严格的定义的。开源软件推进联盟（OSI）对其有着[完整严密的定义](https://opensource.org/osd-annotated)，不过主要是以下几点：

![](/data/attachment/album/201711/30/131009foo59o35p5oi95io.jpg)

同样，自由软件也有着严格的定义，这个定义的风格很有 RMS 风格。这就是自由软件的四大自由：

![](/data/attachment/album/201711/30/131253xylsp4y4e4k24nsm.jpg)

开源软件和自由软件有所不同，但是又联系紧密，通常来说，自由软件属于开源软件的[一部分](https://www.gnu.org/philosophy/open-source-misses-the-point.zh-cn.html%20)，其定义更严格一些。当然，有些场景下，我们会使用更中立的说法：FOSS（自由及开源软件），也有时候用 FLOSS 的写法（L 代表 Libre）。

![](/data/attachment/album/201711/30/131509sij2qi5b0ffhs2fi.jpg)

那么，了解是什么是开源软件之后，开源软件可以赋予你什么权利呢？

![](/data/attachment/album/201711/30/154820cnae3wauzewauvaw.jpg)

开源不等于公共领域，所以开源也是有限制的（许可证），正是因为这些限制，才有开源生态的生生不息的发展：

![](/data/attachment/album/201711/30/154915w6depmz6pd0g5d0n.jpg)

开源软件的使用也是有一定的规则的：

![](/data/attachment/album/201711/30/155036lw39ywxln75y3l5i.jpg)

遵循了这些规则，开源软件能给你带来数之不尽的受益：

![](/data/attachment/album/201711/30/155140yw4pgd8cxg4mej7g.jpg)

一般来说，“打开”开源软件有几个阶段，按照深入程度分别是：

![](/data/attachment/album/201711/30/155241pd55qvf9kk5kwtqw.jpg)

而在这个过程中，开源软件也不单纯是只会带来受益的，也存在一些“打开不当”的风险：

![](/data/attachment/album/201711/30/155321txztknnudd9nufxv.jpg)

只有以“正确打开”的方式，才能真正受益于开源软件，而不是在拥抱开源的时候，遇到风险：

![](/data/attachment/album/201711/30/155431b913z1ma3mko9s32.jpg)

最后，以企业的视角，来谈谈企业在开源方面的实践操作。基本上，如果不是浅尝辄止，企业在开源方面的实践，应该考虑如下几个方面：

![](/data/attachment/album/201711/30/155518tauf9f8hqqhihqs8.jpg)

首先是要进行开源计划的规划，而不是随便试试：

![](/data/attachment/album/201711/30/155645pjjyfhniqhhrsnbf.jpg)

并且落实开源方面的组织机构和人员：

![](/data/attachment/album/201711/30/155714zfcfix25xx4z5c59.jpg)

如果公司规模比较大，那么不妨从<ruby> 内部开源 <rp>  （ </rp> <rt>  Inner Source </rt> <rp>  ） </rp></ruby>做起来，这有利于公司内部转换思想、流程，也可以比较早的发现问题：

![](/data/attachment/album/201711/30/155855nfb79hz0p607ukik.jpg)

内部开源有了一定程度之后，可以逐步走向外部社区：

![](/data/attachment/album/201711/30/155941ng3gvv0i2g69xgxv.jpg)

最终形成开放平台和开源生态：

![](/data/attachment/album/201711/30/160144jhwjdogvhkjwq6ke.jpg)

这样，企业的开源才算得上走上了正确的道路。

我的本次演讲就到这里。


ARMv8 上的 kprobes 事件跟踪

![](/data/attachment/album/201712/01/200415tacytrrorw9t2yb9.jpg)

### 介绍

kprobes 是一种内核功能，它允许通过在执行（或模拟）断点指令之前和之后，设置调用开发者提供例程的任意断点来检测内核。可参见 kprobes 文档 注1 获取更多信息。基本的 kprobes 功能可使用 `CONFIG_KPROBEES` 来选择。在 arm64 的 v4.8 内核发行版中， kprobes 支持被添加到主线。

在这篇文章中，我们将介绍 kprobes 在 arm64 上的使用，通过在命令行中使用 debugfs 事件追踪接口来收集动态追踪事件。这个功能在一些架构（包括 arm32）上可用已经有段时间，现在在 arm64 上也能使用了。这个功能可以无需编写任何代码就能使用 kprobes。

### 探针类型

kprobes 子系统提供了三种不同类型的动态探针，如下所述。

#### kprobes

基本探针是 kprobes 插入的一个软件断点，用以替代你正在探测的指令，当探测点被命中时，它为最终的单步执行（或模拟）保存下原始指令。

#### kretprobes

kretprobes 是 kprobes 的一部分，它允许拦截返回函数，而不必在返回点设置一个探针（或者可能有多个探针）。对于支持的架构（包括 ARMv8），只要选择 kprobes，就可以选择此功能。

#### jprobes

jprobes 允许通过提供一个具有相同<ruby> 调用签名 <rt>  call signature </rt></ruby>的中间函数来拦截对一个函数的调用，这里中间函数将被首先调用。jprobes 只是一个编程接口，它不能通过 debugfs 事件追踪子系统来使用。因此，我们将不会在这里进一步讨论 jprobes。如果你想使用 jprobes，请参考 kprobes 文档。

### 调用 kprobes

kprobes 提供一系列能从内核代码中调用的 API 来设置探测点和当探测点被命中时调用的注册函数。在不往内核中添加代码的情况下，kprobes 也是可用的，这是通过写入特定事件追踪的 debugfs 文件来实现的，需要在文件中设置探针地址和信息，以便在探针被命中时记录到追踪日志中。后者是本文将要讨论的重点。最后 kprobes 可以通过 perl 命令来使用。

#### kprobes API

内核开发人员可以在内核中编写函数(通常在专用的调试模块中完成）来设置探测点，并且在探测指令执行前和执行后立即执行任何所需操作。这在 kprobes.txt 中有很好的解释。

#### 事件追踪

事件追踪子系统有自己的自己的文档 注2 ，对于了解一般追踪事件的背景可能值得一读。事件追踪子系统是<ruby> 追踪点 <rt>  tracepoints </rt></ruby>和 kprobes 事件追踪的基础。事件追踪文档重点关注追踪点，所以请在查阅文档时记住这一点。kprobes 与追踪点不同的是没有预定义的追踪点列表，而是采用动态创建的用于触发追踪事件信息收集的任意探测点。事件追踪子系统通过一系列 debugfs 文件来控制和监视。事件追踪（`CONFIG_EVENT_TRACING`）将在被如 kprobe 事件追踪子系统等需要时自动选择。

##### kprobes 事件

使用 kprobes 事件追踪子系统，用户可以在内核任意断点处指定要报告的信息，只需要指定任意现有可探测指令的地址以及格式化信息即可确定。在执行过程中遇到断点时，kprobes 将所请求的信息传递给事件追踪子系统的公共部分，这些部分将数据格式化并追加到追踪日志中，就像追踪点的工作方式一样。kprobes 使用一个类似的但是大部分是独立的 debugfs 文件来控制和显示追踪事件信息。该功能可使用 `CONFIG_KPROBE_EVENT` 来选择。Kprobetrace 文档^ 注3 提供了如何使用 kprobes 事件追踪的基本信息，并且应当被参考用以了解以下介绍示例的详细信息。

#### kprobes 和 perf

perf 工具为 kprobes 提供了另一个命令行接口。特别地，`perf probe` 允许探测点除了由函数名加偏移量和地址指定外，还可由源文件和行号指定。perf 接口实际上是使用 kprobes 的 debugfs 接口的封装器。

### Arm64 kprobes

上述所有 kprobes 的方面现在都在 arm64 上得到实现，然而实际上与其它架构上的有一些不同：

* 注册名称参数当然是依架构而特定的，并且可以在 ARM ARM 中找到。
* 目前不是所有的指令类型都可被探测。当前不可探测的指令包括 mrs/msr（除了 DAIF 读取）、异常生成指令、eret 和 hint（除了 nop 变体）。在这些情况下，只探测一个附近的指令来代替是最简单的。这些指令在探测的黑名单里是因为在 kprobes 单步执行或者指令模拟时它们对处理器状态造成的改变是不安全的，这是由于 kprobes 构造的单步执行上下文和指令所需要的不一致，或者是由于指令不能容忍在 kprobes 中额外的处理时间和异常处理（ldx/stx）。
* 试图识别在 ldx/stx 序列中的指令并且防止探测，但是理论上这种检查可能会失败，导致允许探测到的原子序列永远不会成功。当探测原子代码序列附近时应该小心。
* 注意由于 linux ARM64 调用约定的具体信息，为探测函数可靠地复制栈帧是不可能的，基于此不要试图用 jprobes 这样做，这一点与支持 jprobes 的大多数其它架构不同。这样的原因是被调用者没有足够的信息来确定需要的栈数量。
* 注意当探针被命中时，一个探针记录的栈指针信息将反映出使用中的特定栈指针，它是内核栈指针或者中断栈指针。
* 有一组内核函数是不能被探测的，通常因为它们作为 kprobes 处理的一部分被调用。这组函数的一部分是依架构特定的，并且也包含如异常入口代码等。

### 使用 kprobes 事件追踪

kprobes 的一个常用例子是检测函数入口和/或出口。因为只需要使用函数名来作为探针地址，它安装探针特别简单。kprobes 事件追踪将查看符号名称并且确定地址。ARMv8 调用标准定义了函数参数和返回值的位置，并且这些可以作为 kprobes 事件处理的一部分被打印出来。

#### 例子: 函数入口探测

检测 USB 以太网驱动程序复位功能：

```
$ pwd
/sys/kernel/debug/tracing
$ cat > kprobe_events <<EOF
p ax88772_reset %x0
EOF
$ echo 1 > events/kprobes/enable

```

此时每次该驱动的 `ax8872_reset()` 函数被调用，追踪事件都将会被记录。这个事件将显示指向通过作为此函数的唯一参数的 `X0`（按照 ARMv8 调用标准）传入的 `usbnet` 结构的指针。插入需要以太网驱动程序的 USB 加密狗后，我们看见以下追踪信息：

```
$ cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 1/1   #P:8
#
#                           _—–=> irqs-off
#                          / _—-=> need-resched
#                         | / _—=> hardirq/softirq
#                         || / _–=> preempt-depth
#                         ||| / delay
#        TASK-PID   CPU#  |||| TIMESTAMP  FUNCTION
#           | |    |   ||||    |      |
kworker/0:0-4             [000] d… 10972.102939:   p_ax88772_reset_0:
(ax88772_reset+0x0/0x230)   arg1=0xffff800064824c80

```

这里我们可以看见传入到我们的探测函数的指针参数的值。由于我们没有使用 kprobes 事件追踪的可选标签功能，我们需要的信息自动被标注为 `arg1`。注意这指向我们需要 kprobes 记录这个探针的一组值的第一个，而不是函数参数的实际位置。在这个例子中它也只是碰巧是我们探测函数的第一个参数。

#### 例子: 函数入口和返回探测

kretprobe 功能专门用于探测函数返回。在函数入口 kprobes 子系统将会被调用并且建立钩子以便在函数返回时调用，钩子将记录需求事件信息。对最常见情况，返回信息通常在 `X0` 寄存器中，这是非常有用的。在 `%x0` 中返回值也可以被称为 `$retval`。以下例子也演示了如何提供一个可读的标签来展示有趣的信息。

使用 kprobes 和 kretprobe 检测内核 `do_fork()` 函数来记录参数和结果的例子：

```
$ cd /sys/kernel/debug/tracing
$ cat > kprobe_events <<EOF
p _do_fork %x0 %x1 %x2 %x3 %x4 %x5
r _do_fork pid=%x0
EOF
$ echo 1 > events/kprobes/enable

```

此时每次对 `_do_fork()` 的调用都会产生两个记录到 trace 文件的 kprobe 事件，一个报告调用参数值，另一个报告返回值。返回值在 trace 文件中将被标记为 `pid`。这里是三次 fork 系统调用执行后的 trace 文件的内容：

```
_$ cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 6/6   #P:8
#
#                              _—–=> irqs-off
#                             / _—-=> need-resched
#                            | / _—=> hardirq/softirq
#                            || / _–=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
              bash-1671  [001] d…   204.946007: p__do_fork_0: (_do_fork+0x0/0x3e4) arg1=0x1200011 arg2=0x0 arg3=0x0 arg4=0x0 arg5=0xffff78b690d0 arg6=0x0
              bash-1671  [001] d..1   204.946391: r__do_fork_0: (SyS_clone+0x18/0x20 <- _do_fork) pid=0x724
              bash-1671  [001] d…   208.845749: p__do_fork_0: (_do_fork+0x0/0x3e4) arg1=0x1200011 arg2=0x0 arg3=0x0 arg4=0x0 arg5=0xffff78b690d0 arg6=0x0
              bash-1671  [001] d..1   208.846127: r__do_fork_0: (SyS_clone+0x18/0x20 <- _do_fork) pid=0x725
              bash-1671  [001] d…   214.401604: p__do_fork_0: (_do_fork+0x0/0x3e4) arg1=0x1200011 arg2=0x0 arg3=0x0 arg4=0x0 arg5=0xffff78b690d0 arg6=0x0
              bash-1671  [001] d..1   214.401975: r__do_fork_0: (SyS_clone+0x18/0x20 <- _do_fork) pid=0x726_

```

#### 例子： 解引用指针参数

对于指针值，kprobes 事件处理子系统也允许解引用和打印所需的内存内容，适用于各种基本数据类型。为了展示所需字段，手动计算结构的偏移量是必要的。

检测 `_do_wait()` 函数：

```
$ cat > kprobe_events <<EOF
p:wait_p do_wait wo_type=+0(%x0):u32 wo_flags=+4(%x0):u32
r:wait_r do_wait $retval
EOF
$ echo 1 > events/kprobes/enable

```

注意在第一个探针中使用的参数标签是可选的，并且可用于更清晰地识别记录在追踪日志中的信息。带符号的偏移量和括号表明了寄存器参数是指向记录在追踪日志中的内存内容的指针。`:u32` 表明了内存位置包含一个无符号的 4 字节宽的数据（在这个例子中指局部定义的结构中的一个 emum 和一个 int）。

探针标签（冒号后）是可选的，并且将用来识别日志中的探针。对每个探针来说标签必须是独一无二的。如果没有指定，将从附近的符号名称自动生成一个有用的标签，如前面的例子所示。

也要注意 `$retval` 参数可以只是指定为 `%x0`。

这里是两次 fork 系统调用执行后的 trace 文件的内容：

```
$ cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 4/4   #P:8
#
#                              _—–=> irqs-off
#                             / _—-=> need-resched
#                            | / _—=> hardirq/softirq
#                            || / _–=> preempt-depth
#                            ||| /     delay
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION
#              | |       |   ||||       |         |
             bash-1702  [001] d…   175.342074: wait_p: (do_wait+0x0/0x260) wo_type=0x3 wo_flags=0xe
             bash-1702  [002] d..1   175.347236: wait_r: (SyS_wait4+0x74/0xe4 <- do_wait) arg1=0x757
             bash-1702  [002] d…   175.347337: wait_p: (do_wait+0x0/0x260) wo_type=0x3 wo_flags=0xf
             bash-1702  [002] d..1   175.347349: wait_r: (SyS_wait4+0x74/0xe4 <- do_wait) arg1=0xfffffffffffffff6

```

#### 例子: 探测任意指令地址

在前面的例子中，我们已经为函数的入口和出口插入探针，然而探测一个任意指令（除少数例外）是可能的。如果我们正在 C 函数中放置一个探针，第一步是查看代码的汇编版本以确定我们要放置探针的位置。一种方法是在 vmlinux 文件上使用 gdb,并在要放置探针的函数中展示指令。下面是一个在 `arch/arm64/kernel/modules.c` 中 `module_alloc` 函数执行此操作的示例。在这种情况下，因为 gdb 似乎更喜欢使用弱符号定义，并且它是与这个函数关联的存根代码，所以我们从 System.map 中来获取符号值：

```
$ grep module_alloc System.map
ffff2000080951c4 T module_alloc
ffff200008297770 T kasan_module_alloc

```

在这个例子中我们使用了交叉开发工具，并且在我们的主机系统上调用 gdb 来检查指令包含我们感兴趣函数。

```
$ ${CROSS_COMPILE}gdb vmlinux
(gdb) x/30i 0xffff2000080951c4
        0xffff2000080951c4 <module_alloc>:    sub    sp, sp, #0x30
        0xffff2000080951c8 <module_alloc+4>:    adrp    x3, 0xffff200008d70000
        0xffff2000080951cc <module_alloc+8>:    add    x3, x3, #0x0
        0xffff2000080951d0 <module_alloc+12>:    mov    x5, #0x713             // #1811
        0xffff2000080951d4 <module_alloc+16>:    mov    w4, #0xc0              // #192
        0xffff2000080951d8 <module_alloc+20>:
              mov    x2, #0xfffffffff8000000    // #-134217728
        0xffff2000080951dc <module_alloc+24>:    stp    x29, x30, [sp,#16]         0xffff2000080951e0 <module_alloc+28>:    add    x29, sp, #0x10
        0xffff2000080951e4 <module_alloc+32>:    movk    x5, #0xc8, lsl #48
        0xffff2000080951e8 <module_alloc+36>:    movk    w4, #0x240, lsl #16
        0xffff2000080951ec <module_alloc+40>:    str    x30, [sp]         0xffff2000080951f0 <module_alloc+44>:    mov    w7, #0xffffffff        // #-1
        0xffff2000080951f4 <module_alloc+48>:    mov    x6, #0x0               // #0
        0xffff2000080951f8 <module_alloc+52>:    add    x2, x3, x2
        0xffff2000080951fc <module_alloc+56>:    mov    x1, #0x8000            // #32768
        0xffff200008095200 <module_alloc+60>:    stp    x19, x20, [sp,#32]         0xffff200008095204 <module_alloc+64>:    mov    x20, x0
        0xffff200008095208 <module_alloc+68>:    bl    0xffff2000082737a8 <__vmalloc_node_range>
        0xffff20000809520c <module_alloc+72>:    mov    x19, x0
        0xffff200008095210 <module_alloc+76>:    cbz    x0, 0xffff200008095234 <module_alloc+112>
        0xffff200008095214 <module_alloc+80>:    mov    x1, x20
        0xffff200008095218 <module_alloc+84>:    bl    0xffff200008297770 <kasan_module_alloc>
        0xffff20000809521c <module_alloc+88>:    tbnz    w0, #31, 0xffff20000809524c <module_alloc+136>
        0xffff200008095220 <module_alloc+92>:    mov    sp, x29
        0xffff200008095224 <module_alloc+96>:    mov    x0, x19
        0xffff200008095228 <module_alloc+100>:    ldp    x19, x20, [sp,#16]         0xffff20000809522c <module_alloc+104>:    ldp    x29, x30, [sp],#32
        0xffff200008095230 <module_alloc+108>:    ret
        0xffff200008095234 <module_alloc+112>:    mov    sp, x29
        0xffff200008095238 <module_alloc+116>:    mov    x19, #0x0               // #0

```

在这种情况下，我们将在此函数中显示以下源代码行的结果：

```
p = __vmalloc_node_range(size, MODULE_ALIGN, VMALLOC_START,
VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_EXEC, 0,
NUMA_NO_NODE, __builtin_return_address(0));

```

……以及在此代码行的函数调用的返回值：

```
if (p && (kasan_module_alloc(p, size) < 0)) {

```

我们可以在从调用外部函数的汇编代码中识别这些。为了展示这些值，我们将在目标系统上的 `0xffff20000809520c` 和 `0xffff20000809521c` 处放置探针。

```
$ cat > kprobe_events <<EOF
p 0xffff20000809520c %x0
p 0xffff20000809521c %x0
EOF
$ echo 1 > events/kprobes/enable

```

现在将一个以太网适配器加密狗插入到 USB 端口后，我们看到以下写入追踪日志的内容：

```
$ cat trace
# tracer: nop
#
# entries-in-buffer/entries-written: 12/12   #P:8
#
#                           _—–=> irqs-off
#                          / _—-=> need-resched
#                         | / _—=> hardirq/softirq
#                         || / _–=> preempt-depth
#                         ||| / delay
#        TASK-PID   CPU#  |||| TIMESTAMP  FUNCTION
#           | |    |   ||||    |      |
      systemd-udevd-2082  [000] d… 77.200991: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff200001188000
      systemd-udevd-2082  [000] d… 77.201059: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      systemd-udevd-2082  [000] d… 77.201115: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff200001198000
      systemd-udevd-2082  [000] d… 77.201157: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      systemd-udevd-2082  [000] d… 77.227456: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff2000011a0000
      systemd-udevd-2082  [000] d… 77.227522: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      systemd-udevd-2082  [000] d… 77.227579: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff2000011b0000
      systemd-udevd-2082  [000] d… 77.227635: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      modprobe-2097  [002] d… 78.030643: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff2000011b8000
      modprobe-2097  [002] d… 78.030761: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0
      modprobe-2097  [002] d… 78.031132: p_0xffff20000809520c: (module_alloc+0x48/0x98) arg1=0xffff200001270000
      modprobe-2097  [002] d… 78.031187: p_0xffff20000809521c: (module_alloc+0x58/0x98) arg1=0x0

```

kprobes 事件系统的另一个功能是记录统计信息，这可在 `inkprobe_profile` 中找到。在以上追踪后，该文件的内容为：

```
$ cat kprobe_profile
 p_0xffff20000809520c                                    6            0
p_0xffff20000809521c                                    6            0

```

这表明我们设置的两处断点每个共发生了 8 次命中，这当然与追踪日志数据是一致的。在 kprobetrace 文档中有更多 kprobe\_profile 的功能描述。

也可以进一步过滤 kprobes 事件。用来控制这点的 debugfs 文件在 kprobetrace 文档中被列出，然而它们内容的详细信息大多在 trace events 文档中被描述。

### 总结

现在，Linux ARMv8 对支持 kprobes 功能也和其它架构相当。有人正在做添加 uprobes 和 systemtap 支持的工作。这些功能/工具和其他已经完成的功能（如： perf、 coresight）允许 Linux ARMv8 用户像在其它更老的架构上一样调试和测试性能。

---

参考文献

* 注1： Jim Keniston, Prasanna S. Panchamukhi, Masami Hiramatsu. “Kernel Probes (kprobes).” *GitHub*. GitHub, Inc., 15 Aug. 2016. Web. 13 Dec. 2016.
* 注2： Ts’o, Theodore, Li Zefan, and Tom Zanussi. “Event Tracing.” *GitHub*. GitHub, Inc., 3 Mar. 2016. Web. 13 Dec. 2016.
* 注3： Hiramatsu, Masami. “Kprobe-based Event Tracing.” *GitHub*. GitHub, Inc., 18 Aug. 2016. Web. 13 Dec. 2016.

---

作者简介 ： [David Long](http://www.linaro.org/author/david-long/) 在 Linaro Kernel - Core Development 团队中担任工程师。 在加入 Linaro 之前，他在商业和国防行业工作了数年，既做嵌入式实时工作又为Unix提供软件开发工具。之后，在 Digital（又名 Compaq）公司工作了十几年，负责 Unix 标准，C 编译器和运行时库的工作。之后 David 又去了一系列初创公司做嵌入式 Linux 和安卓系统，嵌入式定制操作系统和 Xen 虚拟化。他拥有 MIPS，Alpha 和 ARM 平台的经验（等等）。他使用过从 1979 年贝尔实验室 V6 开始的大部分Unix操作系统，并且长期以来一直是 Linux 用户和倡导者。他偶尔也因使用烙铁和数字示波器调试设备驱动而知名。

---

via: <http://www.linaro.org/blog/kprobes-event-tracing-armv8/>

作者：[David Long](http://www.linaro.org/author/david-long/) 译者：[kimii](https://github.com/kimii) 校对：[wxy](https://github.com/wxy)

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