Merge pull request #7 from LCTT/master

更新2018年9月30日
This commit is contained in:
shipsw 2018-09-30 10:22:12 +08:00 committed by GitHub
commit 2b0936b955
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
546 changed files with 69656 additions and 15561 deletions

2
.gitignore vendored
View File

@ -3,3 +3,5 @@ members.md
*.html
*.bak
.DS_Store
sources/*/.*
translated/*/.*

75
lctt2018.md Normal file
View File

@ -0,0 +1,75 @@
LCTT 2018五周年纪念日
======
我是老王,可能大家有不少人知道我,由于历史原因,我有好几个生日(;o但是这些年来我又多了一个生日或者说纪念日——每过两年我就要严肃认真地写一篇 [LCTT](https://linux.cn/lctt) 生日纪念文章。
这一篇就是今年的了LCTT 如今已经五岁了!
或许如同小孩子过生日总是比较快乐,而随着年岁渐长,过生日往往有不少负担——比如说,每次写这篇纪念文章时,我就需要回忆、反思这两年的做了些什么,往往颇为汗颜。
不过不管怎么说,总要总结一下这两年我们做了什么,有什么不足,也发一些展望吧。
### 江山代有英豪出
LCTT如同一般的开源贡献组织总是有不断的新老传承。我们的翻译组也有不少成员由于工作学习的原因慢慢淡出但同时也不断有新的成员加入并接过前辈手中的旗帜就是没人接我的
> **加入方式**
> 请首先加入翻译组的 QQ 群,群号是:**198889102**,加群时请说明是“**志愿者**”。加入后记得修改您的群名片为您的 GitHub 的 ID。
> 加入的成员,请先阅读 [WIKI 如何开始](https://github.com/LCTT/TranslateProject/wiki/01-%E5%A6%82%E4%BD%95%E5%BC%80%E5%A7%8B)。
比如说我们这两年来oska874 承担了主要的选题工作,然后 lujun9972 适时的出现接过了不少选题工作再比如说qhwdw 出现后承担了大量繁难文章的翻译pityonline 则专注于校对,甚至其校对的严谨程度让我都甘拜下风。还有 MjSeven 也同 qhwdw 一样,以极高的翻译频率从一星译者迅速登顶五星译者。当然,还有 Bestony、Locez、VizV 等人为 LCTT 提供了不少技术支持和开发工作。
### 硕果累累
我们并没有特别的招新渠道,但是总是时不时会有新的成员慕名而来,到目前为止,我们已经有 [331](https://linux.cn/lctt-list) 位做过贡献的成员,已经翻译发布了 3885 篇译文,合计字节达 33MB 之多!
这两年,我们不但翻译了很多技术、新闻和评论类文章,也新增了新的翻译类型:[漫画](https://linux.cn/talk/comic/),其中一些漫画得到了很多好评。
我们发布的文章有一些达到了 100000+ 的访问量,这对于我们这种技术垂直内容可不容易。
而同时,[Linux 中国](https://linux.cn/)也发布了近万篇文章,而这一篇,应该就是第 [9999](https://linux.cn/article-9999-1.html) 篇文章,我们将在明天,进入新的篇章。
### 贡献者主页和贡献者证书
为了彰显诸位贡献者的贡献,我们为每位贡献者创立的自己的专页,并据此建立了[排行榜](https://linux.cn/lctt-list)。
同时,我们还特意请 Bestony 和“一一”设计开发和”贡献者证书”,大家可以在 [LCTT 贡献平台](https://lctt.linux.cn/)中领取。
### 规则进化
LCTT 最初创立时,甚至都没有采用 PR 模式。但是随着贡献者的增多,我们也逐渐在改善我们的流程、方法。
之前采用了很粗糙的 PR 模式,对 PR 中的文件、提交乃至于信息都没有进行硬性约束。后来在 VizV 的帮助下,建立了对 PR 的合规性检查;又在 pityonline 的督促下,采用了更为严格的 PR 审查机制。
LCTT 创立几年来,我们的一些流程和规范,已经成为其它一些翻译组的参考范本,我们也希望我们的这些经验,可以进一步帮助到其它的开源社区。
### 仓库重建和版权问题
今年还发生一次严重的事故,由于对选题来源把控不严和对版权问题没有引起足够的重视,我们引用的一篇文章违背了原文的版权规定,结果被原文作者投诉到 GitHub。而我并没有及时看到 GitHub 给我发的 DMCA 处理邮件,因此错过了处理窗口期,从而被 GitHub 将整个库予以删除。
出现这样的重大失误之后,经过大家的帮助,我们历经周折才将仓库基本恢复。这要特别感谢 VizV 的辛苦工作。
在此之后,我们对译文选文的规则进行了梳理,并全面清查了文章版权。这个教训对我们来说弥足沉重。
### 通证时代
在 Linux 中国及 LCTT 发展过程中,我一直小心翼翼注意商业化的问题。严格来说,没有经济支持的开源组织如同无根之木,无源之水,是长久不了的。而商业化的技术社区又难免为了三斗米而折腰。所以往往很多技术社区要么渐渐凋零,要么就变成了商业机构。
从中国电信辞职后,我专职运营 Linux 中国这个开源社区已经近三年了,其间也有一些商业性收入,但是仅能勉强承担基本的运营费用。
这种尴尬的局面,使我,以及其它的开源社区同仁们纷纷寻求更好的发展之路。
去年参加中国开源年会时,在闭门会上,大家的讨论启发了我和诸位同仁,我们认为,开源社区结合通证经济,似乎是一条可行的开源社区发展之路。
今年 8 月 1 日,我们经过了半年的论证和实验,[发布了社区通证 LCCN](https://linux.cn/article-9886-1.html),并已经初步发放到了各位译者手中。我们还在继续建设通证生态各种工具,如合约、交易商城等。
我们希望能够通过通证为开源社区转入新的活力,也愿意将在探索道路上遇到的问题和解决的思路、工具链分享给更多的社区。
### 总结
从上一次总结以来,这又是七百多天,时光荏苒,而 LCTT 的创立也近两千天了。我希望,我们的翻译组以及更多的贡献者可以在通证经济的推动下,找到自洽、自治的发展道路;也希望能有更多的贡献者涌现出来接过我们的大旗,将开源发扬光大。
wxy
2018/9/9 夜

View File

@ -0,0 +1,77 @@
如何在 Ubuntu 上安装 Cinnamon 桌面环境
======
> 这篇教程将会为你展示如何在 Ubuntu 上安装 Cinnamon 桌面环境。
[Cinnamon][1] 是 [Linux Mint][2] 的默认桌面环境。不同于 Ubuntu 的 Unity 桌面环境Cinnamon 是一个更加传统而优雅的桌面环境,其带有底部面板和应用菜单。由于 Cinnamon 桌面以及它类 Windows 的用户界面,许多桌面用户[相较于 Ubuntu 更喜欢 Linux Mint][3]。
现在你无需[安装 Linux Mint][4] 就能够体验到 Cinnamon了。在这篇教程我将会展示给你如何在 Ubuntu 18.0416.04 和 14.04 上安装 Cinnamon。
在 Ubuntu 上安装 Cinnamon 之前,有一些事情需要你注意。有时候,安装的额外桌面环境可能会与你当前的桌面环境有冲突。可能导致会话、应用程序或功能等的崩溃。这就是为什么你需要在做这个决定时谨慎一点的原因。
### 如何在 Ubuntu 上安装 Cinnamon 桌面环境
![如何在 Ubuntu 上安装 Cinnamon 桌面环境][5]
过去有 Cinnamon 团队为 Ubuntu 提供的一系列的官方 PPA但现在都已经失效了。不过不用担心还有一个非官方的 PPA而且它运行的很完美。这个 PPA 里包含了最新的 Cinnamon 版本。
```
sudo add-apt-repository
ppa:embrosyn/cinnamon
sudo apt update && sudo apt install cinnamon
```
下载的大小大概是 150 MB如果我没记错的话。这其中提供的 NemoCinnamon 的文件管理器,基于 Nautilus和 Cinnamon 控制中心。这些东西提供了一个更加接近于 Linux Mint 的感觉。
### 在 Ubuntu 上使用 Cinnamon 桌面环境
Cinnamon 安装完成后,退出当前会话,在登录界面,点击用户名旁边的 Ubuntu 符号:
![](https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2014/08/Change_Desktop_Environment_Ubuntu.jpeg)
之后,它将会显示所有系统可用的桌面环境。选择 Cinnamon。
![](https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2014/08/Install_Cinnamon_Ubuntu.jpeg)
现在你应该已经登录到有着 Cinnamon 桌面环境的 Ubuntu 中了。你还可以通过同样的方式再回到 Unity 桌面。这里有一张以 Cinnamon 做为桌面环境的 Ubuntu 桌面截图。
![](https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2014/08/Cinnamon_Ubuntu_1404.jpeg)
看起来是不是像极了 Linux Mint。此外我并没有发现任何有关 Cinnamon 和 Unity 的兼容性问题。在 Unity 和 Cinnamon 来回切换,它们也依旧工作的很完美。
#### 从 Ubuntu 卸载 Cinnamon
如果你想卸载 Cinnamon可以使用 PPA Purge 来完成。首先安装 PPA Purge
```
sudo apt-get install ppa-purge
```
安装完成之后,使用下面的命令去移除该 PPA
```
sudo ppa-purge ppa:embrosyn/cinnamon
```
更多的信息,我建议你去阅读 [如何从 Linux 移除 PPA][6] 这篇文章。
我希望这篇文章能够帮助你在 Ubuntu 上安装 Cinnamon。也可以分享一下你使用 Cinnamon 的经验。
------
via: https://itsfoss.com/install-cinnamon-on-ubuntu/
作者:[Abhishek Prakash][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[dianbanjiu](https://github.com/dianbanjiu)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/abhishek/
[1]: http://cinnamon.linuxmint.com/
[2]: http://www.linuxmint.com/
[3]: https://itsfoss.com/linux-mint-vs-ubuntu/
[4]: https://itsfoss.com/guide-install-linux-mint-16-dual-boot-windows/
[5]: https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/09/install-cinnamon-ubuntu.png
[6]: https://itsfoss.com/how-to-remove-or-delete-ppas-quick-tip/

View File

@ -0,0 +1,143 @@
Cloud Commander一个有控制台和编辑器的 Web 文件管理器
======
![](https://www.ostechnix.com/wp-content/uploads/2016/05/Cloud-Commander-A-Web-File-Manager-With-Console-And-Editor-720x340.png)
**Cloud Commander** 是一个基于 web 的文件管理程序,它允许你通过任何计算机、移动端或平板电脑的浏览器查看、访问或管理系统文件或文件夹。它有两个简单而又经典的面板,并且会像你设备的显示尺寸一样自动转换大小。它也拥有两款内置的叫做 **Dword****Edward** 的文本编辑器它们支持语法高亮并带有一个支持系统命令行的控制台。因此您可以随时随地编辑文件。Cloud Commander 服务器是一款在 Linux、Windows、Mac OS X 运行的跨平台应用,而且该应用客户端可以在任何一款浏览器上运行。它是用 **JavaScript/Node.Js** 写的,并使用 **MIT** 许可证。
在这个简易教程中,让我们看一看如何在 Ubuntu 18.04 LTS 服务器上安装 Cloud Commander。
### 前提条件
像我之前提到的,是用 Node.js 写的。所以为了安装 Cloud Commander我们需要首先安装 Node.js。要执行安装参考下面的指南。
- [如何在 Linux 上安装 Node.js](https://www.ostechnix.com/install-node-js-linux/)
### 安装 Cloud Commander
在安装 Node.js 之后,运行下列命令安装 Cloud Commander:
```
$ npm i cloudcmd -g
```
祝贺Cloud Commander 已经安装好了。让我们往下继续看看 Cloud Commander 的基本使用。
### 开始使用 Cloud Commander
运行以下命令启动 Cloud Commander
```
$ cloudcmd
```
**输出示例:**
```
url: http://localhost:8000
```
现在,打开你的浏览器并转到链接:`http://localhost:8000` 或 `http://IP-address:8000`
从现在开始您可以直接在本地系统或远程系统或移动设备平板电脑等Web浏览器中创建删除查看管理文件或文件夹。
![][2]
如你所见上面的截图Clouder Commander 有两个面板,十个热键 `F1` 到 `F10`),还有控制台。
每个热键执行的都是一个任务。
* `F1` 帮助
* `F2` 重命名文件/文件夹
* `F3` 查看文件/文件夹
* `F4` 编辑文件
* `F5` 复制文件/文件夹
* `F6` 移动文件/文件夹
* `F7` 创建新目录
* `F8` 删除文件/文件夹
* `F9` 打开菜单
* `F10` 打开设置
#### Cloud Commmander 控制台
点击控制台图标。这即将打开系统默认的命令行界面。
![][3]
在此控制台中,您可以执行各种管理任务,例如安装软件包、删除软件包、更新系统等。您甚至可以关闭或重新引导系统。 因此Cloud Commander 不仅仅是一个文件管理器,还具有远程管理工具的功能。
#### 创建文件/文件夹
要创建新的文件或文件夹就右键单击任意空位置并找到 “New - >File or Directory”。
![][4]
#### 查看文件
你可以查看图片,查看音视频文件。
![][5]
#### 上传文件
另一个很酷的特性是我们可以从任何系统或设备简单地上传一个文件到 Cloud Commander 系统。
要上传文件,右键单击 Cloud Commander 面板的任意空白处并且单击“Upload”选项。
![][6]
选择你想要上传的文件。
另外,你也可以上传来自像 Google 云盘、Dropbox、Amazon 云盘、Facebook、Twitter、Gmail、GitHub、Picasa、Instagram 还有很多的云服务上的文件。
要从云端上传文件, 右键单击面板的任意空白处并且右键单击面板任意空白处并选择“Upload from Cloud”。
![][7]
选择任意一个你选择的网络服务例如谷歌云盘。点击“Connect to Google drive”按钮。
![][8]
下一步,用 Cloud Commander 验证你的谷歌云端硬盘从谷歌云端硬盘选择文件并点击“Upload”。
![][9]
#### 更新 Cloud Commander
要更新到最新的可用版本,执行下面的命令:
```
$ npm update cloudcmd -g
```
#### 总结
据我测试,它运行很好。在我的 Ubuntu 服务器测试期间我没有遇到任何问题。此外Cloud Commander 不仅是基于 Web 的文件管理器,还可以充当执行大多数 Linux 管理任务的远程管理工具。 您可以创建文件/文件夹、重命名、删除、编辑和查看它们。此外,您可以像在终端中在本地系统中那样安装、更新、升级和删除任何软件包。当然,您甚至可以从 Cloud Commander 控制台本身关闭或重启系统。 还有什么需要的吗? 尝试一下,你会发现它很有用。
目前为止就这样吧。 我将很快在这里发表另一篇有趣的文章。 在此之前,请继续关注我们。
祝贺!
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/cloud-commander-a-web-file-manager-with-console-and-editor/
作者:[SK][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[fuzheng1998](https://github.com/fuzheng1998)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.ostechnix.com/author/sk/
[1]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
[2]:http://www.ostechnix.com/wp-content/uploads/2016/05/Cloud-Commander-Google-Chrome_006-4.jpg
[3]:http://www.ostechnix.com/wp-content/uploads/2016/05/Cloud-Commander-Google-Chrome_007-2.jpg
[4]:http://www.ostechnix.com/wp-content/uploads/2016/05/Cloud-commander-file-folder-1.png
[5]:http://www.ostechnix.com/wp-content/uploads/2016/05/Cloud-Commander-home-sk-Google-Chrome_008-1.jpg
[6]:http://www.ostechnix.com/wp-content/uploads/2016/05/cloud-commander-upload-2.png
[7]:http://www.ostechnix.com/wp-content/uploads/2016/05/upload-from-cloud-1.png
[8]:http://www.ostechnix.com/wp-content/uploads/2016/05/Cloud-Commander-home-sk-Google-Chrome_009-2.jpg
[9]:http://www.ostechnix.com/wp-content/uploads/2016/05/Cloud-Commander-home-sk-Google-Chrome_010-1.jpg

View File

@ -104,10 +104,10 @@ Arch Linux 也因其丰富的 Wiki 帮助文档而大受推崇。该系统基于
][23]
输入下面的命令来检查网络连接。
```
ping google.com
```
```
这个单词 ping 表示网路封包搜寻。你将会看到下面的返回信息,表明 Arch Linux 已经连接到外网了。这是执行安装过程中的很关键的一点。LCTT 译注:或许你 ping 不到那个不存在的网站,你选个存在的吧。)
@ -117,8 +117,8 @@ ping google.com
输入如下命令清屏:
```
clear
```
clear
```
在开始安装之前,你得先为硬盘分区。输入 `fdisk -l` ,你将会看到当前系统的磁盘分区情况。注意一开始你给 Arch Linux 系统分配的 20 GB 存储空间。
@ -137,8 +137,8 @@ clear
输入下面的命令:
```
cfdisk
```
cfdisk
```
你将看到 `gpt`、`dos`、`sgi` 和 `sun` 类型,选择 `dos` 选项,然后按回车。
@ -185,8 +185,8 @@ cfdisk
以同样的方式创建逻辑分区。在“退出quit”选项按回车键然后输入下面的命令来清屏
```
clear
```
clear
```
[
@ -195,21 +195,21 @@ clear
输入下面的命令来格式化新建的分区:
```
```
mkfs.ext4 /dev/sda1
```
```
这里的 `sda1` 是分区名。使用同样的命令来格式化第二个分区 `sda3` :
```
```
mkfs.ext4 /dev/sda3
```
```
格式化 swap 分区:
```
```
mkswap /dev/sda2
```
```
[
![Format the swap partition with mkswap](https://www.howtoforge.com/images/install_arch_linux_on_virtual_box/121224.png)
@ -217,14 +217,14 @@ mkswap /dev/sda2
使用下面的命令来激活 swap 分区:
```
swapon /dev/sda2
```
swapon /dev/sda2
```
输入 clear 命令清屏:
```
clear
```
clear
```
[
@ -233,9 +233,9 @@ clear
输入下面的命令来挂载主分区以开始系统安装:
```
mount /dev/sda1 / mnt
```
```
mount /dev/sda1 /mnt
```
[
![Mount the partitions](https://www.howtoforge.com/images/install_arch_linux_on_virtual_box/121226.png)
@ -245,9 +245,9 @@ mount /dev/sda1 / mnt
输入下面的命令来引导系统启动:
```
```
pacstrap /mnt base base-devel
```
```
可以看到系统正在同步数据包。
@ -263,9 +263,9 @@ pacstrap /mnt base base-devel
系统基本软件安装完成后,输入下面的命令来创建 fstab 文件:
```
```
genfstab /mnt>> /mnt/etc/fstab
```
```
[
![Generating /etc/fstab](https://www.howtoforge.com/images/install_arch_linux_on_virtual_box/121229.png)
@ -275,14 +275,14 @@ genfstab /mnt>> /mnt/etc/fstab
输入下面的命令来更改系统的根目录为 Arch Linux 的安装目录:
```
```
arch-chroot /mnt /bin/bash
```
```
 现在来更改语言配置:
```
nano /etc/local.gen
```
nano /etc/locale.gen
```
[
@ -297,9 +297,9 @@ nano /etc/local.gen
输入下面的命令来激活它:
```
```
locale-gen
```
```
按回车。
@ -309,8 +309,8 @@ locale-gen
使用下面的命令来创建 `/etc/locale.conf` 配置文件:
```
nano /etc/locale.conf
```
nano /etc/locale.conf
```
然后按回车。现在你就可以在配置文件中输入下面一行内容来为系统添加语言:
@ -326,9 +326,9 @@ LANG=en_US.UTF-8
][44]
输入下面的命令来同步时区:
```
ls user/share/zoneinfo
ls /usr/share/zoneinfo
```
下面你将看到整个世界的时区列表。
@ -339,9 +339,9 @@ ls user/share/zoneinfo
输入下面的命令来选择你所在的时区:
```
```
ln s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
```
```
或者你可以从下面的列表中选择其它名称。
@ -351,8 +351,8 @@ ln s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
使用下面的命令来设置标准时间:
```
hwclock --systohc utc
```
hwclock --systohc --utc
```
硬件时钟已同步。
@ -363,8 +363,8 @@ hwclock --systohc utc
设置 root 帐号密码:
```
passwd
```
passwd
```
按回车。 然而输入你想设置的密码,按回车确认。
@ -377,9 +377,9 @@ passwd
使用下面的命令来设置主机名:
```
```
nano /etc/hostname
```
```
然后按回车。输入你想设置的主机名称,按 `control + x` ,按 `y` ,再按回车 。
@ -389,9 +389,9 @@ nano /etc/hostname
启用 dhcpcd
```
```
systemctl enable dhcpcd
```
```
这样在下一次系统启动时, dhcpcd 将会自动启动,并自动获取一个 IP 地址:
@ -403,9 +403,9 @@ systemctl enable dhcpcd
最后一步,输入以下命令来初始化 grub 安装。输入以下命令:
```
```
pacman S grub os-rober
```
```
然后按 `y` ,将会下载相关程序。
@ -415,14 +415,14 @@ pacman S grub os-rober
使用下面的命令来将启动加载程序安装到硬盘上:
```
```
grub-install /dev/sda
```
```
然后进行配置:
```
grub-mkconfig -o /boot/grub/grub.cfg
```
grub-mkconfig -o /boot/grub/grub.cfg
```
[
@ -431,9 +431,9 @@ grub-mkconfig -o /boot/grub/grub.cfg
最后重启系统:
```
```
reboot
```
```
然后按回车 。
@ -459,7 +459,7 @@ reboot
via: https://www.howtoforge.com/tutorial/install-arch-linux-on-virtualbox/
译者简介:
译者简介:
rusking春城初春/春水初生/春林初盛/春風十裏不如妳

View File

@ -0,0 +1,420 @@
如何 Docker 化 Python Django 应用程序
======
Docker 是一个开源项目为开发人员和系统管理员提供了一个开放平台可以将应用程序构建、打包为一个轻量级容器并在任何地方运行。Docker 会在软件容器中自动部署应用程序。
Django 是一个用 Python 编写的 Web 应用程序框架,遵循 MVC模型-视图-控制器)架构。它是免费的,并在开源许可下发布。它速度很快,旨在帮助开发人员尽快将他们的应用程序上线。
在本教程中,我将逐步向你展示在 Ubuntu 16.04 中如何为现有的 Django 应用程序创建 docker 镜像。我们将学习如何 docker 化一个 Python Django 应用程序,然后使用一个 `docker-compose` 脚本将应用程序作为容器部署到 docker 环境。
为了部署我们的 Python Django 应用程序,我们需要其它 docker 镜像:一个用于 Web 服务器的 nginx docker 镜像和用于数据库的 PostgreSQL 镜像。
### 我们要做什么?
1. 安装 Docker-ce
2. 安装 Docker-compose
3. 配置项目环境
4. 构建并运行
5. 测试
### 步骤 1 - 安装 Docker-ce
在本教程中,我们将从 docker 仓库安装 docker-ce 社区版。我们将安装 docker-ce 社区版和 `docker-compose`(其支持 compose 文件版本 3
在安装 docker-ce 之前,先使用 `apt` 命令安装所需的 docker 依赖项。
```
sudo apt install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common
```
现在通过运行以下命令添加 docker 密钥和仓库。
```
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
```
[![安装 Docker-ce](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/1.png)][14]
更新仓库并安装 docker-ce。
```
sudo apt update
sudo apt install -y docker-ce
```
安装完成后,启动 docker 服务并使其能够在每次系统引导时启动。
```
systemctl start docker
systemctl enable docker
```
接着,我们将添加一个名为 `omar` 的新用户并将其添加到 `docker` 组。
```
useradd -m -s /bin/bash omar
usermod -a -G docker omar
```
[![启动 Docker](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/2.png)][15]
`omar` 用户身份登录并运行 `docker` 命令,如下所示。
```
su - omar
docker run hello-world
```
确保你能从 Docker 获得 hello-world 消息。
[![检查 Docker 安装](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/3.png)][16]
Docker-ce 安装已经完成。
### 步骤 2 - 安装 Docker-compose
在本教程中,我们将使用支持 compose 文件版本 3 的最新 `docker-compose`。我们将手动安装 `docker-compose`
使用 `curl` 命令将最新版本的 `docker-compose` 下载到 `/usr/local/bin` 目录,并使用 `chmod` 命令使其有执行权限。
运行以下命令:
```
sudo curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
```
现在检查 `docker-compose` 版本。
```
docker-compose version
```
确保你安装的是最新版本的 docker-compose 1.21。
[![安装 Docker-compose](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/4.png)][17]
已安装支持 compose 文件版本 3 的 `docker-compose` 最新版本。
### 步骤 3 - 配置项目环境
在这一步中,我们将配置 Python Django 项目环境。我们将创建新目录 `guide01`,并使其成为我们项目文件的主目录,例如包括 Dockerfile、Django 项目、nginx 配置文件等。
登录到 `omar` 用户。
```
su - omar
```
创建一个新目录 `guide01`,并进入目录。
```
mkdir -p guide01
cd guide01/
```
现在在 `guide01` 目录下,创建两个新目录 `project``config`
```
mkdir project/ config/
```
注意:
* `project` 目录:我们所有的 python Django 项目文件都将放在该目录中。
* `config` 目录:项目配置文件的目录,包括 nginx 配置文件、python pip 的`requirements.txt` 文件等。
#### 创建一个新的 requirements.txt 文件
接下来,使用 `vim` 命令在 `config` 目录中创建一个新的 `requirements.txt` 文件。
```
vim config/requirements.txt
```
粘贴下面的配置:
```
Django==2.0.4 
gunicorn==19.7.0 
psycopg2==2.7.4
```
保存并退出。
#### 创建 Nginx 虚拟主机文件 django.conf
`config` 目录下创建 nginx 配置目录并添加虚拟主机配置文件 `django.conf`
```
mkdir -p config/nginx/
vim config/nginx/django.conf
```
粘贴下面的配置:
```
upstream web {
ip_hash;
server web:8000;
}
# portal
server {
location / {
proxy_pass http://web/;
}
listen 8000;
server_name localhost;
location /static {
autoindex on;
alias /src/static/;
}
}
```
保存并退出。
#### 创建 Dockerfile
`guide01` 目录下创建新文件 `Dockerfile`
运行以下命令:
```
vim Dockerfile
```
现在粘贴下面的 Dockerfile 脚本:
```
FROM python:3.5-alpine
ENV PYTHONUNBUFFERED 1 
RUN apk update && \
   apk add --virtual build-deps gcc python-dev musl-dev && \
   apk add postgresql-dev bash
RUN mkdir /config 
ADD /config/requirements.txt /config/ 
RUN pip install -r /config/requirements.txt
RUN mkdir /src
WORKDIR /src
```
保存并退出。
注意:
我们想要为我们的 Django 项目构建基于 Alpine Linux 的 Docker 镜像Alpine 是最小的 Linux 版本。我们的 Django 项目将运行在带有 Python 3.5 的 Alpine Linux 上,并添加 postgresql-dev 包以支持 PostgreSQL 数据库。然后,我们将使用 python `pip` 命令安装在 `requirements.txt` 上列出的所有 Python 包,并为我们的项目创建新目录 `/src`
#### 创建 Docker-compose 脚本
使用 [vim][18] 命令在 `guide01` 目录下创建 `docker-compose.yml` 文件。
```
vim docker-compose.yml
```
粘贴以下配置内容:
```
version: '3'
services:
  db:
     image: postgres:10.3-alpine
    container_name: postgres01
  nginx:
    image: nginx:1.13-alpine
    container_name: nginx01
    ports:
      - "8000:8000"
    volumes:
      - ./project:/src
      - ./config/nginx:/etc/nginx/conf.d
    depends_on:
      - web
  web:
    build: .
    container_name: django01
    command: bash -c "python manage.py makemigrations && python manage.py migrate && python manage.py collectstatic --noinput && gunicorn hello_django.wsgi -b 0.0.0.0:8000"
    depends_on:
      - db
    volumes:
      - ./project:/src
    expose:
      - "8000"
    restart: always
```
保存并退出。
注意:
使用这个 `docker-compose` 文件脚本,我们将创建三个服务。使用 alpine Linux 版的 PostgreSQL 创建名为 `db` 的数据库服务,再次使用 alpine Linux 版的 Nginx 创建 `nginx` 服务,并使用从 Dockerfile 生成的自定义 docker 镜像创建我们的 python Django 容器。
[![配置项目环境](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/5.png)][19]
#### 配置 Django 项目
将 Django 项目文件复制到 `project` 目录。
```
cd ~/django
cp -r * ~/guide01/project/
```
进入 `project` 目录并编辑应用程序设置 `settings.py`
```
cd ~/guide01/project/
vim hello_django/settings.py
```
注意:
我们将部署名为 “hello_django” 的简单 Django 应用程序。
`ALLOW_HOSTS` 行中,添加服务名称 `web`
```
ALLOW_HOSTS = ['web']
```
现在更改数据库设置,我们将使用 PostgreSQL 数据库来运行名为 `db` 的服务,使用默认用户和密码。
```
DATABASES = { 
   'default': {
       'ENGINE': 'django.db.backends.postgresql_psycopg2',
       'NAME': 'postgres',
       'USER': 'postgres',
       'HOST': 'db',
       'PORT': 5432,
   }
}
```
至于 `STATIC_ROOT` 配置目录,将此行添加到文件行的末尾。
```
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
```
保存并退出。
[![配置 Django 项目](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/6.png)][20]
现在我们准备在 docker 容器下构建和运行 Django 项目。
### 步骤 4 - 构建并运行 Docker 镜像
在这一步中,我们想要使用 `guide01` 目录中的配置为我们的 Django 项目构建一个 Docker 镜像。
进入 `guide01` 目录。
```
cd ~/guide01/
```
现在使用 `docker-compose` 命令构建 docker 镜像。
```
docker-compose build
```
[![运行 docker 镜像](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/7.png)][21]
启动 `docker-compose` 脚本中的所有服务。
```
docker-compose up -d
```
等待几分钟让 Docker 构建我们的 Python 镜像并下载 nginx 和 postgresql docker 镜像。
[![使用 docker-compose 构建镜像](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/8.png)][22]
完成后,使用以下命令检查运行容器并在系统上列出 docker 镜像。
```
docker-compose ps
docker-compose images
```
现在,你将在系统上运行三个容器,列出 Docker 镜像,如下所示。
[![docke-compose ps 命令](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/9.png)][23]
我们的 Python Django 应用程序现在在 docker 容器内运行,并且已经创建了为我们服务的 docker 镜像。
### 步骤 5 - 测试
打开 Web 浏览器并使用端口 8000 键入服务器地址,我的是:`http://ovh01:8000/`。
现在你将看到默认的 Django 主页。
[![默认 Django 项目主页](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/10.png)][24]
接下来,通过在 URL 上添加 `/admin` 路径来测试管理页面。
```
http://ovh01:8000/admin/
```
然后你将会看到 Django 管理登录页面。
[![Django administration](https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/11.png)][25]
Docker 化 Python Django 应用程序已成功完成。
### 参考
* [https://docs.docker.com/][13]
--------------------------------------------------------------------------------
via: https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/
作者:[Muhammad Arul][a]
译者:[MjSeven](https://github.com/MjSeven)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/
[1]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#create-a-new-requirementstxt-file
[2]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#create-the-nginx-virtual-host-file-djangoconf
[3]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#create-the-dockerfile
[4]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#create-dockercompose-script
[5]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#configure-django-project
[6]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#what-we-will-do
[7]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#step-install-dockerce
[8]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#step-install-dockercompose
[9]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#step-configure-project-environment
[10]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#step-build-and-run-the-docker-image
[11]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#step-testing
[12]:https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-application/#reference
[13]:https://docs.docker.com/
[14]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/1.png
[15]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/2.png
[16]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/3.png
[17]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/4.png
[18]:https://www.howtoforge.com/vim-basics
[19]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/5.png
[20]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/6.png
[21]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/7.png
[22]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/8.png
[23]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/9.png
[24]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/10.png
[25]:https://www.howtoforge.com/images/docker_guide_dockerizing_python_django_application/big/11.png

View File

@ -0,0 +1,889 @@
全面教程:在 RxJS 中创建流
================================
![](https://cdn-images-1.medium.com/max/900/1*hj8mGnl5tM_lAlx5_vqS-Q.jpeg)
对大多数开发者来说,与 RxJS 的初次接触是通过库的形式,就像 Angular。一些函数会返回<ruby><rt>stream</rt></ruby>,要使用它们就得把注意力放在操作符上。
有些时候,混用响应式和非响应式代码似乎很有用。然后大家就开始热衷流的创造。不论是在编写异步代码或者是数据处理时,流都是一个不错的方案。
RxJS 提供很多方式来创建流。不管你遇到的是什么情况,都会有一个完美的创建流的方式。你可能根本用不上它们,但了解它们可以节省你的时间,让你少码一些代码。
我把所有可能的方法,按它们的主要目的,放在四个分类当中:
* 流式化现有数据
* 生成数据
* 使用现有 API 进行交互
* 选择现有的流,并结合起来
注意:示例用的是 RxJS 6可能会以前的版本有所不同。已知的区别是你导入函数的方式不同了。
RxJS 6
```
import {of, from} from 'rxjs';
of(...);
from(...);
```
RxJS < 6
```
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/from';
Observable.of(...);
Observable.from(...);
//或
import { of } from 'rxjs/observable/of';
import { from } from 'rxjs/observable/from';
of(...);
from(...);
```
流的图示中的标记:
* `|` 表示流结束了
* `X` 表示流出现错误并被终结
* `...` 表示流的走向不定
### 流式化已有数据
你有一些数据,想把它们放到流中。有三种方式,并且都允许你把调度器当作最后一个参数传入(你如果想深入了解调度器,可以看看我的 [上一篇文章][5])。这些生成的流都是静态的。
#### of
如果只有一个或者一些不同的元素,使用 `of`
```
of(1,2,3)
.subscribe();
```
```
// 结果
// 1 2 3 |
```
#### from
如果有一个数组或者 _可迭代的对象_ ,而且你想要其中的所有元素发送到流中,使用 `from`。你也可以用它来把一个 promise 对象变成可观测的。
```
const foo = [1,2,3];
from(foo)
.subscribe();
```
```
// 结果
// 1 2 3 |
```
#### pairs
流式化一个对象的键/值对。用这个对象表示字典时特别有用。
```
const foo = { a: 1, b: 2};
pairs(foo)
.subscribe();
```
```
// 结果
// [a,1] [b,2] |
```
#### 那么其他的数据结构呢?
也许你的数据存储在自定义的结构中,而它又没有实现 _可迭代的对象_ 接口,又或者说你的结构是递归的、树状的。也许下面某种选择适合这些情况:
1. 先将数据提取到数组里
2. 使用下一节将会讲到的 `generate` 函数,遍历所有数据
3. 创建一个自定义流(见下一节)
4. 创建一个迭代器
稍后会讲到选项 2 和 3 ,因此这里的重点是创建一个迭代器。我们可以对一个 _可迭代的对象_ 调用 `from` 创建一个流。 _可迭代的对象_ 是一个对象,可以产生一个迭代器(如果你对细节感兴趣,参考 [这篇 mdn 文章][6])。
创建一个迭代器的简单方式是 <ruby>[生成函数][7]<rt>generator function</rt></ruby>。当你调用一个生成函数时,它返回一个对象,该对象同时遵循 _可迭代的对象_ 接口和 _迭代器_ 接口。
```
// 自定义的数据结构
class List {
add(element) ...
get(index) ...
get size() ...
...
}
function* listIterator(list) {
for (let i = 0; i<list.size; i++) {
yield list.get(i);
}
}
const myList = new List();
myList.add(1);
myList.add(3);
from(listIterator(myList))
.subscribe(console.log);
```
```
// 结果
// 1 3 |
```
调用 `listIterator` 函数时,返回值是一个 _可迭代的对象_ / _迭代器_ 。函数里面的代码在调用 `subscribe` 前不会执行。
### 生成数据
你知道要发送哪些数据,但想(或者必须)动态生成它。所有函数的最后一个参数都可以用来接收一个调度器。他们产生静态的流。
#### 范围(`range`
从初始值开始,发送一系列数字,直到完成了指定次数的迭代。
```
range(10, 2) // 从 10 开始,发送两个值
.subscribe();
```
```
// 结果
// 10 11 |
```
#### 间隔(`interval` / 定时器(`timer`
有点像范围,但定时器是周期性的发送累加的数字(就是说,不是立即发送)。两者的区别在于在于定时器允许你为第一个元素设定一个延迟。也可以只产生一个值,只要不指定周期。
```
interval(1000) // 每 1000ms = 1 秒 发送数据
.subscribe()
```
```
// 结果
// 0 1 2 3 4 ...
```
```
delay(5000, 1000) // 和上面相同,在开始前先等待 5000ms
delay(5000)
.subscribe(i => console.log("foo");
// 5 秒后打印 foo
```
大多数定时器将会用来周期性的处理数据:
```
interval(10000).pipe(
flatMap(i => fetch("https://server/stockTicker")
).subscribe(updateChart)
```
这段代码每 10 秒获取一次数据,更新屏幕。
#### 生成(`generate `
这是个更加复杂的函数,允许你发送一系列任意类型的对象。它有一些重载,这里你看到的是最有意思的部分:
```
generate(
0, // 从这个值开始
x => x < 10, // 条件只要值小于 10就一直发送
x => x*2 // 迭代:前一个值加倍
).subscribe();
```
```
// 结果
// 1 2 4 8 |
```
你也可以用它来迭代值,如果一个结构没有实现 _可迭代的对象_ 接口。我们用前面的列表例子来进行演示:
```
const myList = new List();
myList.add(1);
myList.add(3);
generate(
0, // 从这个值开始
i => i < list.size, // 条件发送数据直到遍历完整个列表
i => ++i, // 迭代:获取下一个索引
i => list.get(i) // 选择器:从列表中取值
).subscribe();
```
```
// 结果
// 1 3 |
```
如你所见,我添加了另一个参数:选择器。它和 `map` 操作符作用类似,将生成的值转换为更有用的东西。
### 空的流
有时候你要传递或返回一个不用发送任何数据的流。有三个函数分别用于不同的情况。你可以给这三个函数传递调度器。`empty` 和 `throwError` 接收一个调度器参数。
#### `empty`
创建一个空的流,一个值也不发送。
```
empty()
.subscribe();
```
```
// 结果
// |
```
#### `never`
创建一个永远不会结束的流,仍然不发送值。
```
never()
.subscribe();
```
```
// 结果
// ...
```
#### `throwError`
创建一个流,流出现错误,不发送数据。
```
throwError('error')
.subscribe();
```
```
// 结果
// X
```
### 挂钩已有的 API
不是所有的库和所有你之前写的代码使用或者支持流。幸运的是 RxJS 提供函数用来桥接非响应式和响应式代码。这一节仅仅讨论 RxJS 为桥接代码提供的模版。
你可能还对这篇出自 [Ben Lesh][9] 的 [全面的文章][8] 感兴趣,这篇文章讲了几乎所有能与 promises 交互操作的方式。
#### `from`
我们已经用过它,把它列在这里是因为,它可以封装一个含有 observable 对象的 promise 对象。
```
from(new Promise(resolve => resolve(1)))
.subscribe();
```
```
// 结果
// 1 |
```
#### fromEvent
fromEvent 为 DOM 元素添加一个事件监听器,我确定你知道这个。但你可能不知道的是,也可以通过其它类型来添加事件监听器,例如,一个 jQuery 对象。
```
const element = $('#fooButton'); // 从 DOM 元素中创建一个 jQuery 对象
from(element, 'click')
.subscribe();
```
```
// 结果
// clickEvent ...
```
#### fromEventPattern
要理解为什么有 fromEvent 了还需要 fromEventPattern我们得先理解 fromEvent 是如何工作的。看这段代码:
```
from(document, 'click')
.subscribe();
```
这告诉 RxJS 我们想要监听 document 中的点击事件。在提交过程中RxJS 发现 document 是一个 _EventTarget_ 类型,因此它可以调用它的 `addEventListener` 方法。如果我们传入的是一个 jQuery 对象而非 document那么 RxJs 知道它得调用 _on_ 方法。
这个例子用的是 _fromEventPattern_ ,和 _fromEvent_ 的工作基本上一样:
```
function addClickHandler(handler) {
document.addEventListener('click', handler);
}
function removeClickHandler(handler) {
document.removeEventListener('click', handler);
}
fromEventPattern(
addClickHandler,
removeClickHandler,
)
.subscribe(console.log);
// 等效于
fromEvent(document, 'click')
```
RxJS 自动创建实际的监听器( _handler_ 你的工作是添加或者移除监听器。_fromEventPattern_ 的目的基本上是告诉 RxJS 如何注册和移除事件监听器。
现在想象一下你使用了一个库,你可以调用一个叫做 _registerListener_ 的方法。我们不能再用 _fromEvent_,因为它并不知道该怎么处理这个对象。
```
const listeners = [];
class Foo {
registerListener(listener) {
listeners.push(listener);
}
emit(value) {
listeners.forEach(listener => listener(value));
}
}
const foo = new Foo();
fromEventPattern(listener => foo.registerListener(listener))
.subscribe();
foo.emit(1);
```
```
// 结果
// 1 ...
```
当我们调用 `foo.emit(1)`RxJS 中的监听器将被调用,然后它就能把值发送到流中。
你也可以用它来监听多个事件类型,或者结合所有可以通过回调进行通讯的 API例如WebWorker API:
```
const myWorker = new Worker('worker.js');
fromEventPattern(
handler => { myWorker.onmessage = handler },
handler => { myWorker.onmessage = undefined }
)
.subscribe();
```
```
// 结果
// workerMessage ...
```
#### bindCallback
它和 fromEventPattern 相似,但它能用于单个值。就在回调函数被调用时,流就结束了。用法当然也不一样 —— 你可以用 bindCallBack 封装函数,然后它就会在调用时魔术般的返回一个流:
```
function foo(value, callback) {
callback(value);
}
// 没有流
foo(1, console.log); //prints 1 in the console
// 有流
const reactiveFoo = bindCallback(foo);
// 当我们调用 reactiveFoo 时,它返回一个 observable 对象
reactiveFoo(1)
.subscribe(console.log); // 在控制台打印 1
```
```
// 结果
// 1 |
```
#### websocket
是的,你完全可以创建一个 websocket 连接然后把它暴露给流:
```
import { webSocket } from 'rxjs/webSocket';
let socket$ = webSocket('ws://localhost:8081');
// 接收消息
socket$.subscribe(
(msg) => console.log('message received: ' + msg),
(err) => console.log(err),
() => console.log('complete') * );
// 发送消息
socket$.next(JSON.stringify({ op: 'hello' }));
```
把 websocket 功能添加到你的应用中真的很简单。_websocket_ 创建一个 subject。这意味着你可以订阅它通过调用 `next` 来获得消息和发送消息。
#### ajax
如你所知:类似于 websocket提供 AJAX 查询的功能。你可能用了一个带有 AJAX 功能的库或者框架。或者你没有用,那么我建议使用 fetch或者必要的话用 polyfill把返回的 promise 封装到一个 observable 对象中(参考稍后会讲到的 `defer` 函数)。
### 定制流
有时候已有的函数用起来并不是足够灵活。或者你需要对订阅有更强的控制。
#### 主题(`Subject`
`Subject` 是一个特殊的对象,它使得你的能够把数据发送到流中,并且能够控制数据。`Subject` 本身就是一个可观察对象,但如果你想要把流暴露给其它代码,建议你使用 `asObservable` 方法。这样你就不能意外调用原始方法。
```
const subject = new Subject();
const observable = subject.asObservable();
observable.subscribe();
subject.next(1);
subject.next(2);
subject.complete();
```
```
// 结果
// 1 2 |
```
注意在订阅前发送的值将会“丢失”:
```
const subject = new Subject();
const observable = subject.asObservable();
subject.next(1);
observable.subscribe(console.log);
subject.next(2);
subject.complete();
```
```
// 结果
// 2
```
除了常规的 `Subject`RxJS 还提供了三种特殊的版本。
`AsyncSubject` 在结束后只发送最后的一个值。
```
const subject = new AsyncSubject();
const observable = subject.asObservable();
observable.subscribe(console.log);
subject.next(1);
subject.next(2);
subject.complete();
```
```
// 输出
// 2
```
`BehaviorSubject` 使得你能够提供一个(默认的)值,如果当前没有其它值发送的话,这个值会被发送给每个订阅者。否则订阅者收到最后一个发送的值。
```
const subject = new BehaviorSubject(1);
const observable = subject.asObservable();
const subscription1 = observable.subscribe(console.log);
subject.next(2);
subscription1.unsubscribe();
```
```
// 输出
// 1
// 2
```
```
const subscription2 = observable.subscribe(console.log);
// 输出
// 2
```
`ReplaySubject` 存储一定数量、或一定时间或所有的发送过的值。所有新的订阅者将会获得所有存储了的值。
```
const subject = new ReplaySubject();
const observable = subject.asObservable();
subject.next(1);
observable.subscribe(console.log);
subject.next(2);
subject.complete();
```
```
// 输出
// 1
// 2
```
你可以在 [ReactiveX 文档][10](它提供了一些其它的连接) 里面找到更多关于 `Subject` 的信息。[Ben Lesh][11] 在 [On The Subject Of Subjects][12] 上面提供了一些关于 `Subject` 的理解,[Nicholas Jamieson][13] 在 [in RxJS: Understanding Subjects][14] 上也提供了一些理解。
#### 可观察对象
你可以简单地用 new 操作符创建一个可观察对象。通过你传入的函数,你可以控制流,只要有人订阅了或者它接收到一个可以当成 `Subject` 使用的观察者,这个函数就会被调用,比如,调用 `next`、`complet` 和 `error`
让我们回顾一下列表示例:
```
const myList = new List();
myList.add(1);
myList.add(3);
new Observable(observer => {
for (let i = 0; i<list.size; i++) {
observer.next(list.get(i));
}
observer.complete();
})
.subscribe();
```
```
// 结果
// 1 3 |
```
这个函数可以返回一个 `unsubcribe` 函数,当有订阅者取消订阅时这个函数就会被调用。你可以用它来清楚或者执行一些收尾操作。
```
new Observable(observer => {
// 流式化
return () => {
//clean up
};
})
.subscribe();
```
#### 继承可观察对象
在有可用的操作符前这是一种实现自定义操作符的方式。RxJS 在内部扩展了 _可观察对象_ 。`Subject` 就是一个例子,另一个是 `publisher` 操作符。它返回一个 `ConnectableObservable` 对象,该对象提供额外的方法 `connect`
#### 实现 `Subscribable` 接口
有时候你已经用一个对象来保存状态,并且能够发送值。如果你实现了 `Subscribable` 接口,你可以把它转换成一个可观察对象。`Subscribable` 接口中只有一个 `subscribe` 方法。
```
interface Subscribable<T> { subscribe(observerOrNext?: PartialObserver<T> | ((value: T) => void), error?: (error: any) => void, complete?: () => void): Unsubscribable}
```
### 结合和选择现有的流
知道怎么创建一个独立的流还不够。有时候你有好几个流但其实只需要一个。有些函数也可作为操作符,所以我不打算在这里深入展开。推荐看看 [Max NgWizard K][16] 所写的一篇 [文章][15],它还包含一些有趣的动画。
还有一个建议:你可以通过拖拽元素的方式交互式的使用结合操作,参考 [RxMarbles][17]。
#### ObservableInput 类型
期望接收流的操作符和函数通常不单独和可观察对象一起工作。相反,它们实际上期望的参数类型是 ObservableInput定义如下
```
type ObservableInput<T> = SubscribableOrPromise<T> | ArrayLike<T> | Iterable<T>;
```
这意味着你可以传递一个 promises 或者数组却不需要事先把他们转换成可观察对象。
#### defer
主要的目的是把一个 observable 对象的创建延迟(`defer`)到有人想要订阅的时间。在以下情况,这很有用:
* 创建可观察对象的开销较大
* 你想要给每个订阅者新的可观察对象
* 你想要在订阅时候选择不同的可观察对象
* 有些代码必须在订阅之后执行
最后一点包含了一个并不起眼的用例Promises`defer` 也可以返回一个 promise 对象)。看看这个用到了 fetch API 的例子:
```
function getUser(id) {
console.log("fetching data");
return fetch(`https://server/user/${id}`);
}
const userPromise = getUser(1);
console.log("I don't want that request now");
// 其它地方
userPromise.then(response => console.log("done");
```
```
// 输出
// fetching data
// I don't want that request now
// done
```
只要流在你订阅的时候执行了promise 就会立即执行。我们调用 `getUser` 的瞬间,就发送了一个请求,哪怕我们这个时候不想发送请求。当然,我们可以使用 `from` 来把一个 promise 对象转换成可观察对象,但我们传递的 promise 对象已经创建或执行了。`defer` 让我们能够等到订阅才发送这个请求:
```
const user$ = defer(() => getUser(1));
console.log("I don't want that request now");
// 其它地方
user$.subscribe(response => console.log("done");
```
```
// 输出
// I don't want that request now
// fetching data
// done
```
#### iif
`iif` 包含了一个关于 `defer` 的特殊用例:在订阅时选择两个流中的一个:
```
iif(
() => new Date().getHours() < 12,
of("AM"),
of("PM")
)
.subscribe();
```
```
// 结果
// AM before noon, PM afterwards
```
引用该文档:
> 实际上 [iif][3] 能够轻松地用 [defer][4] 实现,它仅仅是出于方便和可读性的目的。
#### onErrorResumeNext
开启第一个流并且在失败的时候继续进行下一个流。错误被忽略掉。
```
const stream1$ = of(1, 2).pipe(
tap(i => { if(i>1) throw 'error'}) //fail after first element
);
const stream2$ = of(3,4);
onErrorResumeNext(stream1$, stream2$)
.subscribe(console.log);
```
```
// 结果
// 1 3 4 |
```
如果你有多个 web 服务,这就很有用了。万一主服务器开启失败,那么备份的服务就能自动调用。
#### forkJoin
它让流并行运行,当流结束时发送存在数组中的最后的值。由于每个流只有最后一个值被发送,它一般用在只发送一个元素的流的情况,就像 HTTP 请求。你让请求并行运行,在所有流收到响应时执行某些任务。
```
function handleResponses([user, account]) {
// 执行某些任务
}
forkJoin(
fetch("https://server/user/1"),
fetch("https://server/account/1")
)
.subscribe(handleResponses);
```
#### merge / concat
发送每一个从可观察对象源中发出的值。
`merge` 接收一个参数,让你定义有多少流能被同时订阅。默认是无限制的。设为 1 就意味着监听一个源流在它结束的时候订阅下一个。由于这是一个常见的场景RxJS 为你提供了一个显示的函数:`concat`。
```
merge(
interval(1000).pipe(mapTo("Stream 1"), take(2)),
interval(1200).pipe(mapTo("Stream 2"), take(2)),
timer(0, 1000).pipe(mapTo("Stream 3"), take(2)),
2 //two concurrent streams
)
.subscribe();
// 只订阅流 1 和流 2
// 输出
// Stream 1 -> after 1000ms
// Stream 2 -> after 1200ms
// Stream 1 -> after 2000ms
// 流 1 结束后,开始订阅流 3
// 输出
// Stream 3 -> after 0 ms
// Stream 2 -> after 400 ms (2400ms from beginning)
// Stream 3 -> after 1000ms
merge(
interval(1000).pipe(mapTo("Stream 1"), take(2)),
interval(1200).pipe(mapTo("Stream 2"), take(2))
1
)
// 等效于
concat(
interval(1000).pipe(mapTo("Stream 1"), take(2)),
interval(1200).pipe(mapTo("Stream 2"), take(2))
)
// 输出
// Stream 1 -> after 1000ms
// Stream 1 -> after 2000ms
// Stream 2 -> after 3200ms
// Stream 2 -> after 4400ms
```
#### zip / combineLatest
`merge``concat` 一个接一个的发送所有从源流中读到的值,而 `zip``combineLatest` 是把每个流中的一个值结合起来一起发送。`zip` 结合所有源流中发送的第一个值。如果流的内容相关联,那么这就很有用。
```
zip(
interval(1000),
interval(1200),
)
.subscribe();
```
```
// 结果
// [0, 0] [1, 1] [2, 2] ...
```
`combineLatest` 与之类似,但结合的是源流中发送的最后一个值。直到所有源流至少发送一个值之后才会触发事件。这之后每次源流发送一个值,它都会把这个值与其他流发送的最后一个值结合起来。
```
combineLatest(
interval(1000),
interval(1200),
)
.subscribe();
```
```
// 结果
// [0, 0] [1, 0] [1, 1] [2, 1] ...
```
两个函数都让允许传递一个选择器函数,把元素结合成其它对象而不是数组:
```
zip(
interval(1000),
interval(1200),
(e1, e2) -> e1 + e2
)
.subscribe();
```
```
// 结果
// 0 2 4 6 ...
```
#### race
选择第一个发送数据的流。产生的流基本是最快的。
```
race(
interval(1000),
of("foo")
)
.subscribe();
```
```
// 结果
// foo |
```
由于 `of` 立即产生一个值,因此它是最快的流,然而这个流就被选中了。
### 总结
已经有很多创建可观察对象的方式了。如果你想要创造响应式的 API 或者想用响应式的 API 结合传统 API那么了解这些方法很重要。
我已经向你展示了所有可用的方法,但它们其实还有很多内容可以讲。如果你想更加深入地了解,我极力推荐你查阅 [文档][20] 或者阅读相关文章。
[RxViz][21] 是另一种值得了解的有意思的方式。你编写 RxJS 代码,产生的流可以用图形或动画进行显示。
--------------------------------------------------------------------------------
via: https://blog.angularindepth.com/the-extensive-guide-to-creating-streams-in-rxjs-aaa02baaff9a
作者:[Oliver Flaggl][a]
译者:[BriFuture](https://github.com/BriFuture)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://blog.angularindepth.com/@abetteroliver
[1]:https://rxjs-dev.firebaseapp.com/api/index/Subscribable
[2]:https://rxjs-dev.firebaseapp.com/api/index/Subscribable#subscribe
[3]:https://rxjs-dev.firebaseapp.com/api/index/iif
[4]:https://rxjs-dev.firebaseapp.com/api/index/defer
[5]:https://itnext.io/concurrency-and-asynchronous-behavior-with-rxjs-11b0c4b22597
[6]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
[7]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*
[8]:https://medium.com/@benlesh/rxjs-observable-interop-with-promises-and-async-await-bebb05306875
[9]:https://medium.com/@benlesh
[10]:http://reactivex.io/documentation/subject.html
[11]:https://medium.com/@benlesh
[12]:https://medium.com/@benlesh/on-the-subject-of-subjects-in-rxjs-2b08b7198b93
[13]:https://medium.com/@cartant
[14]:https://blog.angularindepth.com/rxjs-understanding-subjects-5c585188c3e1
[15]:https://blog.angularindepth.com/learn-to-combine-rxjs-sequences-with-super-intuitive-interactive-diagrams-20fce8e6511
[16]:https://medium.com/@maximus.koretskyi
[17]:http://rxmarbles.com/#merge
[18]:https://rxjs-dev.firebaseapp.com/api/index/ObservableInput
[19]:https://rxjs-dev.firebaseapp.com/api/index/SubscribableOrPromise
[20]:http://reactivex.io/documentation/operators.html#creating
[21]:https://rxviz.com/

View File

@ -1,85 +1,86 @@
How To Set Up PF Firewall on FreeBSD to Protect a Web Server
如何在 FreeBSD 上设置 PF 防火墙来保护 Web 服务器
======
I am a new FreeBSD server user and moved from netfilter on Linux. How do I setup a firewall with PF on FreeBSD server to protect a web server with single public IP address and interface?
[![How To Set Up a Firewall with PF on FreeBSD to Protect a Web Server][1]][1]
我是从 Linux 迁移过来的 FreeBSD 新用户Linux 中使用的是 netfilter 防火墙框架LCTT 译注netfilter 是由 Rusty Russell 提出的 Linux 2.4 内核防火墙框架)。那么在 FreeBSD 上,我该如何设置 PF 防火墙,来保护只有一个公共 IP 地址和端口的 web 服务器呢?
PF is an acronym for packet filter. It was created for OpenBSD but has been ported to FreeBSD and other operating systems. It is a stateful packet filtering engine. This tutorial will show you how to set up a firewall with PF on FreeBSD 10.x and 11.x server to protect your web server.
PF <ruby>包过滤器<rt>packet filter</rt></ruby>的简称。它是为 OpenBSD 开发的,但是已经被移植到了 FreeBSD 以及其它操作系统上。PF 是一个包状态过滤引擎。在这篇教程中,我将向你展示如何在 FreeBSD 10.x 以及 11.x 中设置 PF 防火墙,从而来保护 web 服务器。
### 第一步:开启 PF 防火墙
## Step 1 - Turn on PF firewall
你需要把下面这几行内容添加到文件 `/etc/rc.conf` 文件中:
You need to add the following three lines to /etc/rc.conf file:
```
# echo 'pf_enable="YES"' >> /etc/rc.conf
# echo 'pf_rules="/usr/local/etc/pf.conf"' >> /etc/rc.conf
# echo 'pflog_enable="YES"' >> /etc/rc.conf
# echo 'pflog_logfile="/var/log/pflog"' >> /etc/rc.conf
```
Where,
1. **pf_enable="YES"** - Turn on PF service.
2. **pf_rules="/usr/local/etc/pf.conf"** - Read PF rules from this file.
3. **pflog_enable="YES"** - Turn on logging support for PF.
4. **pflog_logfile="/var/log/pflog"** - File where pflogd should store the logfile i.e. store logs in /var/log/pflog file.
在这里:
1. `pf_enable="YES"` - 开启 PF 服务
2. `pf_rules="/usr/local/etc/pf.conf"` - 从文件 `/usr/local/etc/pf.conf` 中读取 PF 规则
3. `pflog_enable="YES"` - 为 PF 服务打开日志支持
4. `pflog_logfile="/var/log/pflog"` - 存储日志的文件,即日志存于文件 `/var/log/pflog`
### 第二步:在 `/usr/local/etc/pf.conf` 文件中创建防火墙规则
[![How To Set Up a Firewall with PF on FreeBSD to Protect a Web Server][1]][1]
输入下面这个命令打开文件(超级用户模式下):
## Step 2 - Creating firewall rules in /usr/local/etc/pf.conf
Type the following command:
```
# vi /usr/local/etc/pf.conf
```
Append the following PF rulesets :
在文件中添加下面这些 PF 规则集:
```
# vim: set ft=pf
# /usr/local/etc/pf.conf
## Set your public interface ##
## 设置公共端口 ##
ext_if="vtnet0"
## Set your server public IP address ##
## 设置服务器公共 IP 地址 ##
ext_if_ip="172.xxx.yyy.zzz"
## Set and drop these IP ranges on public interface ##
## 设置并删除下面这些公共端口上的 IP 范围 ##
martians = "{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, \
10.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24, \
0.0.0.0/8, 240.0.0.0/4 }"
## Set http(80)/https (443) port here ##
## 设置 http(80)/https (443) 端口 ##
webports = "{http, https}"
## enable these services ##
## 启用下面这些服务 ##
int_tcp_services = "{domain, ntp, smtp, www, https, ftp, ssh}"
int_udp_services = "{domain, ntp}"
## Skip loop back interface - Skip all PF processing on interface ##
## 跳过回环端口 - 跳过端口上的所有 PF 处理 ##
set skip on lo
## Sets the interface for which PF should gather statistics such as bytes in/out and packets passed/blocked ##
## 设置 PF 应该统计的端口信息,如发送/接收字节数,通过/禁止的包的数目 ##
set loginterface $ext_if
## Set default policy ##
## 设置默认策略 ##
block return in log all
block out all
# Deal with attacks based on incorrect handling of packet fragments
# 基于 IP 分片的错误处理来防御攻击
scrub in all
# Drop all Non-Routable Addresses
# 删除所有不可达路由地址
block drop in quick on $ext_if from $martians to any
block drop out quick on $ext_if from any to $martians
## Blocking spoofed packets
## 禁止欺骗包
antispoof quick for $ext_if
# Open SSH port which is listening on port 22 from VPN 139.xx.yy.zz Ip only
# I do not allow or accept ssh traffic from ALL for security reasons
# 打开 SSH 端口SSH 服务仅从 VPN IP 139.xx.yy.zz 监听 22 号端口
# 出于安全原因,我不允许/接收 SSH 流量
pass in quick on $ext_if inet proto tcp from 139.xxx.yyy.zzz to $ext_if_ip port = ssh flags S/SA keep state label "USER_RULE: Allow SSH from 139.xxx.yyy.zzz"
## Use the following rule to enable ssh for ALL users from any IP address #
## 使用下面这些规则来为所有来自任何 IP 地址的用户开启 SSH 服务 #
## pass in inet proto tcp to $ext_if port ssh
### [ OR ] ###
## pass in inet proto tcp to $ext_if port 22
@ -90,44 +91,67 @@ pass inet proto icmp icmp-type echoreq
# All access to our Nginx/Apache/Lighttpd Webserver ports
pass proto tcp from any to $ext_if port $webports
# Allow essential outgoing traffic
# 允许重要的发送流量
pass out quick on $ext_if proto tcp to any port $int_tcp_services
pass out quick on $ext_if proto udp to any port $int_udp_services
# Add custom rules below
# 在下面添加自定义规则
```
Save and close the file. PR [welcome here to improve rulesets][2]. To check for syntax error, run:
`# service pf check`
OR
`/etc/rc.d/pf check`
OR
`# pfctl -n -f /usr/local/etc/pf.conf `
保存并关闭文件。欢迎来参考我的[规则集][2]。如果要检查语法错误,可以运行:
## Step 3 - Start PF firewall
```
# service pf check
```
The commands are as follows. Be careful you might be disconnected from your server over ssh based session:
### Start PF
```
/etc/rc.d/pf check
```
`# service pf start`
### Stop PF
```
# pfctl -n -f /usr/local/etc/pf.conf
```
`# service pf stop`
### 第三步:开始运行 PF 防火墙
### Check PF for syntax error
命令如下。请小心,如果是基于 SSH 的会话,你可能会和服务器断开连接。
`# service pf check`
#### 开启 PF 防火墙:
### Restart PF
```
# service pf start
```
`# service pf restart`
#### 停用 PF 防火墙:
### See PF status
```
# service pf stop
```
#### 检查语法错误:
```
# service pf check
```
#### 重启服务:
```
# service pf restart
```
#### 查看 PF 状态:
```
# service pf status
```
示例输出:
`# service pf status`
Sample outputs:
```
Status: Enabled for 0 days 00:02:18 Debug: Urgent
@ -165,24 +189,28 @@ Counters
map-failed 0 0.0/s
```
#### 开启/关闭/重启 pflog 服务的命令
### Command to start/stop/restart pflog service
输入下面这些命令
Type the following commands:
```
# service pflog start
# service pflog stop
# service pflog restart
```
## Step 4 - A quick introduction to pfctl command
### 第四步:`pfctl` 命令的简单介绍
You need to use the pfctl command to see PF ruleset and parameter configuration including status information from the packet filter. Let us see all common commands:
你需要使用 `pfctl` 命令来查看 PF 规则集和参数配置,包括来自<ruby>包过滤器<rt>packet filter</rt></ruby>的状态信息。让我们来看一下所有常见命令:
### Show PF rules information
#### 显示 PF 规则信息
```
# pfctl -s rules
```
示例输出:
`# pfctl -s rules`
Sample outputs:
```
block return in log all
block drop out all
@ -201,15 +229,19 @@ pass out quick on vtnet0 proto udp from any to any port = domain keep state
pass out quick on vtnet0 proto udp from any to any port = ntp keep state
```
#### Show verbose output for each rule
#### 显示每条规则的详细内容
`# pfctl -v -s rules`
```
# pfctl -v -s rules
```
#### Add rule numbers with verbose output for each rule
在每条规则的详细输出中添加规则编号:
`# pfctl -vvsr show`
```
# pfctl -vvsr show
```
#### Show state
#### 显示状态信息
```
# pfctl -s state
@ -217,18 +249,26 @@ pass out quick on vtnet0 proto udp from any to any port = ntp keep state
# pfctl -s state | grep 'something'
```
### How to disable PF from the CLI
#### 如何在命令行中禁止 PF 服务
`# pfctl -d `
```
# pfctl -d
```
### How to enable PF from the CLI
#### 如何在命令行中启用 PF 服务
`# pfctl -e `
```
# pfctl -e
```
### How to flush ALL PF rules/nat/tables from the CLI
#### 如何在命令行中刷新 PF 规则/NAT/路由表
```
# pfctl -F all
```
示例输出:
`# pfctl -F all`
Sample outputs:
```
rules cleared
nat cleared
@ -239,27 +279,40 @@ pf: statistics cleared
pf: interface flags reset
```
#### How to flush only the PF RULES from the CLI
#### 如何在命令行中仅刷新 PF 规则
`# pfctl -F rules `
```
# pfctl -F rules
```
#### How to flush only queue's from the CLI
#### 如何在命令行中仅刷新队列
`# pfctl -F queue `
```
# pfctl -F queue
```
#### How to flush all stats that are not part of any rule from the CLI
#### 如何在命令行中刷新统计信息(它不是任何规则的一部分)
`# pfctl -F info`
```
# pfctl -F info
```
#### How to clear all counters from the CLI
#### 如何在命令行中清除所有计数器
`# pfctl -z clear `
```
# pfctl -z clear
```
## Step 5 - See PF log
### 第五步:查看 PF 日志
PF 日志是二进制格式的。使用下面这一命令来查看:
```
# tcpdump -n -e -ttt -r /var/log/pflog
```
示例输出:
PF logs are in binary format. To see them type:
`# tcpdump -n -e -ttt -r /var/log/pflog`
Sample outputs:
```
Aug 29 15:41:11.757829 rule 0/(match) block in on vio0: 86.47.225.151.55806 > 45.FOO.BAR.IP.23: S 757158343:757158343(0) win 52206 [tos 0x28]
Aug 29 15:41:44.193309 rule 0/(match) block in on vio0: 5.196.83.88.25461 > 45.FOO.BAR.IP.26941: S 2224505792:2224505792(0) ack 4252565505 win 17520 (DF) [tos 0x24]
@ -295,31 +348,36 @@ Aug 29 15:55:07.001743 rule 0/(match) block in on vio0: 190.83.174.214.58863 > 4
Aug 29 15:55:51.269549 rule 0/(match) block in on vio0: 142.217.201.69.26112 > 45.FOO.BAR.IP.22: S 757158343:757158343(0) win 22840 <mss 1460>
Aug 29 15:58:41.346028 rule 0/(match) block in on vio0: 169.1.29.111.29765 > 45.FOO.BAR.IP.23: S 757158343:757158343(0) win 28509
Aug 29 15:59:11.575927 rule 0/(match) block in on vio0: 187.160.235.162.32427 > 45.FOO.BAR.IP.5358: S 22445:22445(0) win 14600 [tos 0x28]
Aug 29 15:59:37.826598 rule 0/(match) block in on vio0: 94.74.81.97.54656 > 45.FOO.BAR.IP.3128: S 2720157526:2720157526(0) win 1024 [tos 0x28]
Aug 29 15:59:37.826598 rule 0/(match) block in on vio0: 94.74.81.97.54656 > 45.FOO.BAR.IP.3128: S 2720157526:2720157526(0) win 1024 [tos 0x28]stateful
Aug 29 15:59:37.991171 rule 0/(match) block in on vio0: 94.74.81.97.54656 > 45.FOO.BAR.IP.3128: R 2720157527:2720157527(0) win 1200 [tos 0x28]
Aug 29 16:01:36.990050 rule 0/(match) block in on vio0: 182.18.8.28.23299 > 45.FOO.BAR.IP.445: S 1510146048:1510146048(0) win 16384
```
To see live log run:
`# tcpdump -n -e -ttt -i pflog0`
For more info the [PF FAQ][3], [FreeBSD HANDBOOK][4] and the following man pages:
如果要查看实时日志,可以运行:
```
# tcpdump -n -e -ttt -i pflog0
```
如果你想了解更多信息,可以访问 [PF FAQ][3] 和 [FreeBSD HANDBOOK][4] 以及下面这些 man 页面:
```
# man tcpdump
# man pfctl
# man pf
```
## about the author:
### 关于作者
The author is the creator of nixCraft and a seasoned sysadmin and a trainer for the Linux operating system/Unix shell scripting. He has worked with global clients and in various industries, including IT, education, defense and space research, and the nonprofit sector. Follow him on [Twitter][5], [Facebook][6], [Google+][7].
我是 nixCraft 的创立者,一个经验丰富的系统管理员,同时也是一位 Linux 操作系统/Unix shell 脚本培训师。我在不同的行业与全球客户工作过,包括 IT、教育、国防和空间研究、以及非营利组织。你可以在 [Twitter][5]、[Facebook][6] 或 [Google+][7] 上面关注我。
--------------------------------------------------------------------------------
via: https://www.cyberciti.biz/faq/how-to-set-up-a-firewall-with-pf-on-freebsd-to-protect-a-web-server/
作者:[Vivek Gite][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
译者:[ucasFL](https://github.com/ucasFL)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,144 @@
Trash-CliLinux 上的命令行回收站工具
======
相信每个人都对<ruby>回收站<rt>trashcan</rt></ruby>很熟悉,因为无论是对 Linux 用户,还是 Windows 用户,或者 Mac 用户来说,它都很常见。当你删除一个文件或目录的时候,该文件或目录会被移动到回收站中。
需要注意的是,当把文件移动到回收站以后,文件系统空间并没有被释放,除非把回收站清空。
如果不想永久删除文件的话(清空回收站),可以利用回收站临时存储被删除了的文件,从而在必要的时候能够帮助我们恢复删除了的文件。
但是,如果在命令行使用 `rm` 命令进行删除操作,那么你是不可能在回收站中找到任何被删除了的文件或目录的。所以,在执行 `rm` 命令前请一定要三思。如果你犯了错误(执行了 `rm` 命令),那么文件就被永久删除了,无法再恢复回来,因为存储在磁盘上的元数据已经不在了。
根据 [freedesktop.org 规范][1]<ruby>垃圾<rt>trash</rt></ruby>是由桌面管理器比如 GNOME、KDE 和 XFCE 等提供的一个特性。当通过文件管理器删除一个文件或目录的时候,该文件或目录将会成为<ruby>垃圾<rt>trash</rt></ruby>,然后被移动到回收站中,回收站对应的目录是 `$HOME/.local/share/Trash`
回收站目录包含两个子目录:`files` 和 `info` 。`files` 目录存储实际被删除了的文件和目录,`info` 目录包含被删除了的文件和目录的信息,比如文件路径、删除日期和时间,每个文件单独存储。
你可能会问,既然已经有了<ruby>图形用户界面<rt>GUI</rt></ruby>的回收站,为什么还需要命令行工具呢?因为对于大多数使用 *NIX 系统的家伙(包括我)来说,即使使用的是基于图形用户界面的系统,也更喜欢使用命令行而不是图形用户界面。所以,如果有人在寻找一个命令行回收站工具,那么这儿有一个不错的选择。
### Trash-Cli 是什么
[trash-cli][2] 是一个命令行回收站工具,并且符合 FreeDesktop.org 的<ruby>垃圾<rt>trash</rt></ruby>规范。它能够存储每一个垃圾文件的名字、原始路径、删除日期和权限。
### 如何在 Linux 上安装 Trash-Cli
绝大多数的 Linux 发行版官方仓库都提供了 Trash-Cli 的安装包,所以你可以运行下面这些命令来安装。
对于 Debian/Ubuntu 用户,使用 [apt-get][3] 或 [apt][4] 命令来安装 Trash-Cli
```
$ sudo apt install trash-cli
```
对于 RHEL/CentOS 用户,使用 [yum][5] 命令来安装 Trash-Cli
```
$ sudo yum install trash-cli
```
对于 Fedora 用户,使用 [dnf][6] 命令来安装 Trash-Cli
```
$ sudo dnf install trash-cli
```
对于 Arch Linux 用户,使用 [pacman][7] 命令来安装 Trash-Cli
```
$ sudo pacman -S trash-cli
```
对于 openSUSE 用户,使用 [zypper][8] 命令来安装 Trash-Cli
```
$ sudo zypper in trash-cli
```
如果你的发行版中没有提供 Trash-Cli 的安装包,那么你也可以使用 `pip` 来安装。为了能够安装 python 包,你的系统中应该会有 `pip` 包管理器。
```
$ sudo pip install trash-cli
Collecting trash-cli
Downloading trash-cli-0.17.1.14.tar.gz
Installing collected packages: trash-cli
Running setup.py bdist_wheel for trash-cli ... done
Successfully installed trash-cli-0.17.1.14
```
### 如何使用 Trash-Cli
Trash-Cli 的使用不难因为它提供了一个很简单的语法。Trash-Cli 提供了下面这些命令:
* `trash-put` 删除文件和目录(仅放入回收站中)
* `trash-list` :列出被删除了的文件和目录
* `trash-restore`:从回收站中恢复文件或目录 trash.
* `trash-rm`:删除回收站中的文件
* `trash-empty`:清空回收站
下面,让我们通过一些例子来试验一下。
1) 删除文件和目录:在这个例子中,我们通过运行下面这个命令,将 `2g.txt` 这一文件和 `magi` 这一文件夹移动到回收站中。
```
$ trash-put 2g.txt magi
```
和你在文件管理器中看到的一样。
2) 列出被删除了的文件和目录:为了查看被删除了的文件和目录,你需要运行下面这个命令。之后,你可以在输出中看到被删除文件和目录的详细信息,比如名字、删除日期和时间,以及文件路径。
```
$ trash-list
2017-10-01 01:40:50 /home/magi/magi/2g.txt
2017-10-01 01:40:50 /home/magi/magi/magi
```
3) 从回收站中恢复文件或目录:任何时候,你都可以通过运行下面这个命令来恢复文件和目录。它将会询问你来选择你想要恢复的文件或目录。在这个例子中,我打算恢复 `2g.txt` 文件,所以我的选择是 `0`
```
$ trash-restore
0 2017-10-01 01:40:50 /home/magi/magi/2g.txt
1 2017-10-01 01:40:50 /home/magi/magi/magi
What file to restore [0..1]: 0
```
4) 从回收站中删除文件:如果你想删除回收站中的特定文件,那么可以运行下面这个命令。在这个例子中,我将删除 `magi` 目录。
```
$ trash-rm magi
```
5)清空回收站:如果你想删除回收站中的所有文件和目录,可以运行下面这个命令。
```
$ trash-empty
```
6)删除超过 X 天的垃圾文件:或者,你可以通过运行下面这个命令来删除回收站中超过 X 天的文件。在这个例子中,我将删除回收站中超过 `10` 天的项目。
```
$ trash-empty 10
```
Trash-Cli 可以工作的很好,但是如果你想尝试它的一些替代品,那么你也可以试一试 [gvfs-trash][9] 和 [autotrash][10] 。
--------------------------------------------------------------------------------
via: https://www.2daygeek.com/trash-cli-command-line-trashcan-linux-system/
作者:[2daygeek][a]
译者:[ucasFL](https://github.com/ucasFL)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.2daygeek.com/author/2daygeek/
[1]:https://freedesktop.org/wiki/Specifications/trash-spec/
[2]:https://github.com/andreafrancia/trash-cli
[3]:https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
[4]:https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
[5]:https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/
[6]:https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/
[7]:https://www.2daygeek.com/pacman-command-examples-manage-packages-arch-linux-system/
[8]:https://www.2daygeek.com/zypper-command-examples-manage-packages-opensuse-system/
[9]:http://manpages.ubuntu.com/manpages/trusty/man1/gvfs-trash.1.html
[10]:https://github.com/bneijt/autotrash

View File

@ -1,36 +1,30 @@
运营一个 Kubernetes 网络
============================================================
Kubernetes 网络运维
======
最近我一直在研究 Kubernetes 网络。我注意到一件事情就是,虽然关于如何设置 Kubernetes 网络的文章很多,也写得很不错,但是却没有看到关于如何去运 Kubernetes 网络的文章、以及如何完全确保它不会给你造成生产事故。
最近我一直在研究 Kubernetes 网络。我注意到一件事情就是,虽然关于如何设置 Kubernetes 网络的文章很多,也写得很不错,但是却没有看到关于如何去运 Kubernetes 网络的文章、以及如何完全确保它不会给你造成生产事故。
在本文中,我将尽力让你相信三件事情(我觉得这些都很合理 :)
* 避免生产系统网络中断非常重要
* 运营联网软件是很难的
* 运维联网软件是很难的
* 有关你的网络基础设施的重要变化值得深思熟虑以及这种变化对可靠性的影响。虽然非常“牛x”的谷歌人常说“这是我们在谷歌正在用的”谷歌工程师在 Kubernetes 上正做着很重大的工作!但是我认为重要的仍然是研究架构,并确保它对你的组织有意义)。
我肯定不是 Kubernetes 网络方面的专家,但是我在配置 Kubernetes 网络时遇到了一些问题,并且比以前更加了解 Kubernetes 网络了。
### 运联网软件是很难的
### 运联网软件是很难的
在这里,我并不讨论有关运物理网络的话题(对于它我不懂),而是讨论关于如何让像 DNS 服务、负载均衡以及代理这样的软件正常工作方面的内容。
在这里,我并不讨论有关运物理网络的话题(对于它我不懂),而是讨论关于如何让像 DNS 服务、负载均衡以及代理这样的软件正常工作方面的内容。
我在一个负责很多网络基础设施的团队工作过一年时间,并且因此学到了一些运营网络基础设施的知识!(显然我还有很多的知识需要继续学习)在我们开始之前有三个整体看法:
* 联网软件经常重度依赖 Linux 内核。因此除了正确配置软件之外你还需要确保许多不同的系统控制sysctl配置正确而一个错误配置的系统控制就很容易让你处于“一切都很好”和“到处都出问题”的差别中。
我在一个负责很多网络基础设施的团队工作过一年时间,并且因此学到了一些运维网络基础设施的知识!(显然我还有很多的知识需要继续学习)在我们开始之前有三个整体看法:
* 联网软件经常重度依赖 Linux 内核。因此除了正确配置软件之外,你还需要确保许多不同的系统控制(`sysctl`)配置正确,而一个错误配置的系统控制就很容易让你处于“一切都很好”和“到处都出问题”的差别中。
* 联网需求会随时间而发生变化(比如,你的 DNS 查询或许比上一年多了五倍!或者你的 DNS 服务器突然开始返回 TCP 协议的 DNS 响应而不是 UDP 的,它们是完全不同的内核负载!)。这意味着之前正常工作的软件突然开始出现问题。
* 修复一个生产网络的问题,你必须有足够的经验。(例如,看这篇 [由 Sophie Haskins 写的关于 kube-dns 问题调试的文章][1])我在网络调试方面比以前进步多了,但那也是我花费了大量时间研究 Linux 网络知识之后的事了。
我距离成为一名网络运专家还差得很远,但是我认为以下几点很重要:
我距离成为一名网络运专家还差得很远,但是我认为以下几点很重要:
1. 对生产网络的基础设施做重要的更改是很难得的(因为它会产生巨大的混乱)
2. 当你对网络基础设施做重大更改时,真的应该仔细考虑如果新网络基础设施失败该如何处理
3. 是否有很多人都能理解你的网络配置
切换到 Kubernetes 显然是个非常大的更改!因此,我们来讨论一下可能会导致错误的地方!
@ -39,86 +33,72 @@
在本文中我们将要讨论的 Kubernetes 网络组件有:
* 网络覆盖后端(像 flannel/calico/weave 网络/romana
* <ruby>覆盖网络<rt>overlay network</rt></ruby>的后端(像 flannel/calico/weave 网络/romana
* `kube-dns`
* `kube-proxy`
* 入站控制器 / 负载均衡器
* `kubelet`
如果你打算配置 HTTP 服务,或许这些你都会用到。这些组件中的大部分我都不会用到,但是我尽可能去理解它们,因此,本文将涉及它们有关的内容。
### 最简化的方式:为所有容器使用宿主机网络
我们从你能做到的最简单的东西开始。这并不能让你在 Kubernetes 中运行 HTTP 服务。我认为它是非常安全的,因为在这里面可以让你动的东西很少。
我们从你能做到的最简单的东西开始。这并不能让你在 Kubernetes 中运行 HTTP 服务。我认为它是非常安全的,因为在这里面可以让你动的东西很少。
如果你为所有容器使用宿主机网络,我认为需要你去做的全部事情仅有:
1. 配置 kubelet以便于容器内部正确配置 DNS
2. 没了,就这些!
如果你为每个 Pod 直接使用宿主机网络,那就不需要 kube-dns 或者 kube-proxy 了。你都不需要一个作为基础的覆盖网络。
如果你为每个 pod 直接使用宿主机网络,那就不需要 kube-dns 或者 kube-proxy 了。你都不需要一个作为基础的覆盖网络。
这种配置方式中,你的 pod 们都可以连接到外部网络(同样的方式,你的宿主机上的任何进程都可以与外部网络对话),但外部网络不能连接到你的 pod 们。
这并不是最重要的(我认为大多数人想在 Kubernetes 中运行 HTTP 服务并与这些服务进行真实的通讯),但我认为有趣的是,从某种程度上来说,网络的复杂性并不是绝对需要的,并且有时候你不用这么复杂的网络就可以实现你的需要。如果可以的话,尽可能地避免让网络过于复杂。
### 运一个覆盖网络
### 运一个覆盖网络
我们将要讨论的第一个网络组件是有关覆盖网络的。Kubernetes 假设每个 pod 都有一个 IP 地址,这样你就可以与那个 pod 中的服务进行通讯了。我在说到“覆盖网络”这个词时,指的就是这个意思(“让你通过它的 IP 地址指向到 pod 的系统)。
所有其它的 Kubernetes 网络的东西都依赖正确工作的覆盖网络。更多关于它的内容,你可以读 [这里的 kubernetes 网络模型][10]。
Kelsey Hightower 在 [kubernetes the hard way][11] 中描述的方式看起来似乎很好,但是,事实上它的作法在超过 50 个节点的 AWS 上是行不通的,因此,我不打算讨论它了。
Kelsey Hightower 在 [kubernetes 艰难之路][11] 中描述的方式看起来似乎很好,但是,事实上它的作法在超过 50 个节点的 AWS 上是行不通的,因此,我不打算讨论它了。
有许多覆盖网络后端calico、flannel、weaveworks、romana并且规划非常混乱。就我的观点来看我认为一个覆盖网络有 2 个职责:
1. 确保你的 pod 能够发送网络请求到外部的集群
2. 保持一个到子网络的稳定的节点映射,并且保持集群中每个节点都可以使用那个映射得以更新。当添加和删除节点时,能够做出正确的反应。
Okay! 因此!你的覆盖网络可能会出现的问题是什么呢?
* 覆盖网络负责设置 iptables 规则(最基本的是 `iptables -A -t nat POSTROUTING -s $SUBNET -j MASQUERADE`),以确保那个容器能够向 Kubernetes 之外发出网络请求。如果在这个规则上有错误,你的容器就不能连接到外部网络。这并不很难(它只是几条 iptables 规则而已),但是它非常重要。我发起了一个 [pull request][2],因为我想确保它有很好的弹性。
* 添加或者删除节点时可能会有错误。我们使用 `flannel hostgw` 后端,我们开始使用它的时候,节点删除 [尚未开始工作][3]。
* 覆盖网络负责设置 iptables 规则(最基本的是 `iptables -A -t nat POSTROUTING -s $SUBNET -j MASQUERADE`),以确保那个容器能够向 Kubernetes 之外发出网络请求。如果在这个规则上有错误,你的容器就不能连接到外部网络。这并不很难(它只是几条 iptables 规则而已),但是它非常重要。我发起了一个 [拉取请求][2],因为我想确保它有很好的弹性。
* 添加或者删除节点时可能会有错误。我们使用 `flannel hostgw` 后端,我们开始使用它的时候,节点删除功能 [尚未开始工作][3]。
* 你的覆盖网络或许依赖一个分布式数据库etcd。如果那个数据库发生什么问题这将导致覆盖网络发生问题。例如[https://github.com/coreos/flannel/issues/610][4] 上说,如果在你的 `flannel etcd` 集群上丢失了数据,最后的结果将是在容器中网络连接会丢失。(现在这个问题已经被修复了)
* 你升级 Docker 以及其它东西导致的崩溃
* 还有更多的其它的可能性!
我在这里主要讨论的是过去发生在 Flannel 中的问题,但是我并不是要承诺不去使用 Flannel —— 事实上我很喜欢 Flannel因为我觉得它很简单比如类似 [vxlan 在后端这一块的部分][12] 只有 500 行代码),并且我觉得对我来说,通过代码来找出问题的根源成为了可能。并且很显然,它在不断地改进。他们在审查 `pull requests` 方面做的很好。
我在这里主要讨论的是过去发生在 Flannel 中的问题,但是我并不是要承诺不去使用 Flannel —— 事实上我很喜欢 Flannel因为我觉得它很简单比如类似 [vxlan 在后端这一块的部分][12] 只有 500 行代码),对我来说,通过代码来找出问题的根源成为了可能。并且很显然,它在不断地改进。他们在审查拉取请求方面做的很好。
到目前为止,我运覆盖网络的方法是:
到目前为止,我运覆盖网络的方法是:
* 学习它的工作原理的详细内容以及如何去调试它比如Flannel 用于创建路由的 hostgw 网络后端,因此,你只需要使用 `sudo ip route list` 命令去查看它是否正确即可)
* 如果需要的话,维护一个内部构建版本,这样打补丁比较容易
* 有问题时,向上游贡献补丁
我认为去遍历所有已合并的 PR 以及过去已修复的 bug 清单真的是非常有帮助的 —— 这需要花费一些时间,但这是得到一个其它人遇到的各种问题的清单的好方法。
我认为去遍历所有已合并的拉取请求以及过去已修复的 bug 清单真的是非常有帮助的 —— 这需要花费一些时间,但这是得到一个其它人遇到的各种问题的清单的好方法。
对其他人来说他们的覆盖网络可能工作的很好但是我并不能从中得到任何经验并且我也曾听说过其他人报告类似的问题。如果你有一个类似配置的覆盖网络a) 在 AWS 上并且 b) 在多于 50-100 节点上运行,我想知道你运这样的一个网络有多大的把握。
对其他人来说他们的覆盖网络可能工作的很好但是我并不能从中得到任何经验并且我也曾听说过其他人报告类似的问题。如果你有一个类似配置的覆盖网络a) 在 AWS 上并且 b) 在多于 50-100 节点上运行,我想知道你运这样的一个网络有多大的把握。
### 运 kube-proxy 和 kube-dns
### 运 kube-proxy 和 kube-dns
现在,我有一些关于运覆盖网络的想法,我们来讨论一下。
现在,我有一些关于运覆盖网络的想法,我们来讨论一下。
这个标题的最后面有一个问号,那是因为我并没有真的去运过。在这里我还有更多的问题要问答。
这个标题的最后面有一个问号,那是因为我并没有真的去运过。在这里我还有更多的问题要问答。
这里的 Kubernetes 服务是如何工作的!一个服务是一群 pod 们,它们中的每个都有自己的 IP 地址(像 10.1.0.3、10.2.3.5、10.3.5.6 这样)
1. 每个 Kubernetes 服务有一个 IP 地址(像 10.23.1.2 这样)
2. `kube-dns` 去解析 Kubernetes 服务 DNS 名字为 IP 地址因此my-svc.my-namespace.svc.cluster.local 可能映射到 10.23.1.2 上)
3. `kube-proxy` 配置 `iptables` 规则是为了在它们之间随机进行均衡负载。Kube-proxy 也有一个用户空间的轮询负载均衡器,但是在我的印象中,他们并不推荐使用它。
因此,当你发出一个请求到 `my-svc.my-namespace.svc.cluster.local` 时,它将解析为 10.23.1.2,然后,在你本地主机上的 `iptables` 规则(由 kube-proxy 生成)将随机重定向到 10.1.0.3 或者 10.2.3.5 或者 10.3.5.6 中的一个上。
@ -126,9 +106,7 @@ Okay! 因此!你的覆盖网络可能会出现的问题是什么呢?
在这个过程中我能想像出的可能出问题的地方:
* `kube-dns` 配置错误
* `kube-proxy` 挂了,以致于你的 `iptables` 规则没有得以更新
* 维护大量的 `iptables` 规则相关的一些问题
我们来讨论一下 `iptables` 规则,因为创建大量的 `iptables` 规则是我以前从没有听过的事情!
@ -141,7 +119,6 @@ kube-proxy 像如下这样为每个目标主机创建一个 `iptables` 规则:
-A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-RKIFTWKKG3OHTTMI
-A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CGDKBCNM24SZWCMS
-A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -j KUBE-SEP-RI4SRNQQXWSTGE2Y
```
因此kube-proxy 创建了许多 `iptables` 规则。它们都是什么意思?它对我的网络有什么样的影响?这里有一个来自华为的非常好的演讲,它叫做 [支持 50,000 个服务的可伸缩 Kubernetes][14],它说如果在你的 Kubernetes 集群中有 5,000 服务,增加一个新规则,将需要 **11 分钟**。如果这种事情发生在真实的集群中,我认为这将是一件非常糟糕的事情。
@ -152,19 +129,16 @@ kube-proxy 像如下这样为每个目标主机创建一个 `iptables` 规则:
但是,我觉得使用 HAProxy 更舒服!它能够用于去替换 kube-proxy我用谷歌搜索了一下然后发现了这个 [thread on kubernetes-sig-network][15],它说:
> kube-proxy 是很难用的,我们在生产系统中使用它近一年了,它在大部分的时间都表现的很好,但是,随着我们集群中的服务越来越多,我们发现它的排错和维护工作越来越难。在我们的团队中没有 iptables 方面的专家,我们只有 HAProxy&LVS 方面的专家,由于我们已经使用它们好几年了,因此我们决定使用一个中心化的 HAProxy 去替换分布式的代理。我觉得这可能会对在 Kubernetes 中使用 HAProxy 的其他人有用,因此,我们更新了这个项目,并将它开源:[https://github.com/AdoHe/kube2haproxy][5]。如果你发现它有用,你可以去看一看、试一试。
> kube-proxy 是很难用的,我们在生产系统中使用它近一年了,它在大部分的时间都表现的很好,但是,随着我们集群中的服务越来越多,我们发现它的排错和维护工作越来越难。在我们的团队中没有 iptables 方面的专家,我们只有 HAProxy & LVS 方面的专家,由于我们已经使用它们好几年了,因此我们决定使用一个中心化的 HAProxy 去替换分布式的代理。我觉得这可能会对在 Kubernetes 中使用 HAProxy 的其他人有用,因此,我们更新了这个项目,并将它开源:[https://github.com/AdoHe/kube2haproxy][5]。如果你发现它有用,你可以去看一看、试一试。
因此,那是一个有趣的选择!我在这里确实没有答案,但是,有一些想法:
* 负载均衡器是很复杂的
* DNS 也很复杂
* 如果你有运维某种类型的负载均衡器(比如 HAProxy的经验与其使用一个全新的负载均衡器比如 kube-proxy还不如做一些额外的工作去使用你熟悉的那个来替换或许更有意义。
* 我一直在考虑,我们希望在什么地方能够完全使用 kube-proxy 或者 kube-dns —— 我认为,最好是只在 Envoy 上投入,并且在负载均衡&服务发现上完全依赖 Envoy 来做。因此,你只需要将 Envoy 运维好就可以了。
* 如果你有运营某种类型的负载均衡器(比如 HAProxy的经验与其使用一个全新的负载均衡器比如 kube-proxy还不如做一些额外的工作去使用你熟悉的那个来替换或许更有意义。
* 我一直在考虑,我们希望在什么地方能够完全使用 kube-proxy 或者 kube-dns —— 我认为,最好是只在 Envoy 上投入,并且在负载均衡&服务发现上完全依赖 Envoy 来做。因此,你只需要将 Envoy 运营好就可以了。
正如你所看到的,我在关于如何运营 Kubernetes 中的内部代理方面的思路还是很混乱的并且我也没有使用它们的太多经验。总体上来说kube-proxy 和 kube-dns 还是很好的,也能够很好地工作,但是我仍然认为应该去考虑使用它们可能产生的一些问题(例如,”你不能有超出 5000 的 Kubernetes 服务“)。
正如你所看到的,我在关于如何运维 Kubernetes 中的内部代理方面的思路还是很混乱的并且我也没有使用它们的太多经验。总体上来说kube-proxy 和 kube-dns 还是很好的,也能够很好地工作,但是我仍然认为应该去考虑使用它们可能产生的一些问题(例如,”你不能有超出 5000 的 Kubernetes 服务“)。
### 入口
@ -175,14 +149,12 @@ kube-proxy 像如下这样为每个目标主机创建一个 `iptables` 规则:
几个有用的链接,总结如下:
* [Kubernetes 网络模型][6]
* GKE 网络是如何工作的:[https://www.youtube.com/watch?v=y2bhV81MfKQ][7]
* 上述的有关 `kube-proxy` 上性能的讨论:[https://www.youtube.com/watch?v=4-pawkiazEg][8]
### 我认为网络运很重要
### 我认为网络运很重要
我对 Kubernetes 的所有这些联网软件的感觉是,它们都仍然是非常新的,并且我并不能确定我们(作为一个社区)真的知道如何去把它们运好。这让我作为一个操作者感到很焦虑,因为我真的想让我的网络运行的很好!:) 而且我觉得作为一个组织,运行你自己的 Kubernetes 集群需要相当大的投入,以确保你理解所有的代码片段,这样当它们出现问题时你可以去修复它们。这不是一件坏事,它只是一个事而已。
我对 Kubernetes 的所有这些联网软件的感觉是,它们都仍然是非常新的,并且我并不能确定我们(作为一个社区)真的知道如何去把它们运好。这让我作为一个操作者感到很焦虑,因为我真的想让我的网络运行的很好!:) 而且我觉得作为一个组织,运行你自己的 Kubernetes 集群需要相当大的投入,以确保你理解所有的代码片段,这样当它们出现问题时你可以去修复它们。这不是一件坏事,它只是一个事而已。
我现在的计划是,继续不断地学习关于它们都是如何工作的,以尽可能多地减少对我动过的那些部分的担忧。
@ -192,9 +164,9 @@ kube-proxy 像如下这样为每个目标主机创建一个 `iptables` 规则:
via: https://jvns.ca/blog/2017/10/10/operating-a-kubernetes-network/
作者:[Julia Evans ][a]
作者:[Julia Evans][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,132 @@
“用户组”在 Linux 上到底是怎么工作的?
========
嗨!就在上周,我还自认为对 Linux 上的用户和组的工作机制了如指掌。我认为它们的关系是这样的:
1. 每个进程都属于一个用户(比如用户 `julia`
2. 当这个进程试图读取一个被某个组所拥有的文件时, Linux 会
a. 先检查用户`julia` 是否有权限访问文件。LCTT 译注:此处应该是指检查文件的所有者是否就是 `julia`
b. 检查 `julia` 属于哪些组,并进一步检查在这些组里是否有某个组拥有这个文件或者有权限访问这个文件。
3. 如果上述 a、b 任一为真(或者“其它”位设为有权限访问),那么这个进程就有权限访问这个文件。
比如说,如果一个进程被用户 `julia` 拥有并且 `julia` 在`awesome` 组,那么这个进程就能访问下面这个文件。
```
r--r--r-- 1 root awesome 6872 Sep 24 11:09 file.txt
```
然而上述的机制我并没有考虑得非常清楚,如果你硬要我阐述清楚,我会说进程可能会在**运行时**去检查 `/etc/group` 文件里是否有某些组拥有当前的用户。
### 然而这并不是 Linux 里“组”的工作机制
我在上个星期的工作中发现了一件有趣的事,事实证明我前面的理解错了,我对组的工作机制的描述并不准确。特别是 Linux **并不会**在进程每次试图访问一个文件时就去检查这个进程的用户属于哪些组。
我在读了《[Linux 编程接口][1]》这本书的第九章(“进程资格”)后才恍然大悟(这本书真是太棒了),这才是组真正的工作方式!我意识到之前我并没有真正理解用户和组是怎么工作的,我信心满满的尝试了下面的内容并且验证到底发生了什么,事实证明现在我的理解才是对的。
### 用户和组权限检查是怎么完成的
现在这些关键的知识在我看来非常简单! 这本书的第九章上来就告诉我如下事实:用户和组 ID 是**进程的属性**,它们是:
* 真实用户 ID 和组 ID
* 有效用户 ID 和组 ID
* 保存的 set-user-ID 和保存的 set-group-ID
* 文件系统用户 ID 和组 ID特定于 Linux);
* 补充的组 ID
这说明 Linux **实际上**检查一个进程能否访问一个文件所做的组检查是这样的:
* 检查一个进程的组 ID 和补充组 ID这些 ID 就在进程的属性里,**并不是**实时在 `/etc/group` 里查找这些 ID
* 检查要访问的文件的访问属性里的组设置
* 确定进程对文件是否有权限访问LCTT 译注:即文件的组是否是以上的组之一)
通常当访问控制的时候使用的是**有效**用户/组 ID而不是**真实**用户/组 ID。技术上来说当访问一个文件时使用的是**文件系统**的 ID它们通常和有效用户/组 ID 一样。LCTT 译注:这句话针对 Linux 而言。)
### 将一个用户加入一个组并不会将一个已存在的进程(的用户)加入那个组
下面是一个有趣的例子:如果我创建了一个新的组:`panda` 组并且将我自己(`bork`)加入到这个组,然后运行 `groups` 来检查我是否在这个组里:结果是我(`bork`)竟然不在这个组?!
```
bork@kiwi~> sudo addgroup panda
Adding group `panda' (GID 1001) ...
Done.
bork@kiwi~> sudo adduser bork panda
Adding user `bork' to group `panda' ...
Adding user bork to group panda
Done.
bork@kiwi~> groups
bork adm cdrom sudo dip plugdev lpadmin sambashare docker lxd
```
`panda` 并不在上面的组里!为了再次确定我们的发现,让我们建一个文件,这个文件被 `panda` 组拥有,看看我能否访问它。
```
$ touch panda-file.txt
$ sudo chown root:panda panda-file.txt
$ sudo chmod 660 panda-file.txt
$ cat panda-file.txt
cat: panda-file.txt: Permission denied
```
好吧,确定了,我(`bork`)无法访问 `panda-file.txt`。这一点都不让人吃惊,我的命令解释器并没有将 `panda` 组作为补充组 ID运行 `adduser bork panda` 并不会改变这一点。
### 那进程一开始是怎么得到用户的组的呢?
这真是个非常令人困惑的问题,对吗?如果进程会将组的信息预置到进程的属性里面,进程在初始化的时候怎么取到组的呢?很明显你无法给你自己指定更多的组(否则就会和 Linux 访问控制的初衷相违背了……)
有一点还是很清楚的:一个新的进程是怎么从我的命令行解释器(`/bash/fish`)里被**执行**而得到它的组的。(新的)进程将拥有我的用户 ID`bork`),并且进程属性里还有很多组 ID。从我的命令解释器里执行的所有进程是从这个命令解释器里 `fork()` 而来的,所以这个新进程得到了和命令解释器同样的组。
因此一定存在一个“第一个”进程来把你的组设置到进程属性里,而所有由此进程而衍生的进程将都设置这些组。而那个“第一个”进程就是你的<ruby>登录程序<rt>login shell</rt></ruby>,在我的笔记本电脑上,它是由 `login` 程序(`/bin/login`)实例化而来。登录程序以 root 身份运行,然后调用了一个 C 的库函数 —— `initgroups` 来设置你的进程的组(具体来说是通过读取 `/etc/group` 文件),因为登录程序是以 root 运行的,所以它能设置你的进程的组。
### 让我们再登录一次
好了!假如说我们正处于一个登录程序中,而我又想刷新我的进程的组设置,从我们前面所学到的进程是怎么初始化组 ID 的,我应该可以通过再次运行登录程序来刷新我的进程组并启动一个新的登录命令!
让我们试试下边的方法:
```
$ sudo login bork
$ groups
bork adm cdrom sudo dip plugdev lpadmin sambashare docker lxd panda
$ cat panda-file.txt # it works! I can access the file owned by `panda` now!
```
当然,成功了!现在由登录程序衍生的程序的用户是组 `panda` 的一部分了!太棒了!这并不会影响我其他的已经在运行的登录程序(及其子进程),如果我真的希望“所有的”进程都能对 `panda` 组有访问权限。我必须完全的重启我的登录会话这意味着我必须退出我的窗口管理器然后再重新登录。LCTT 译注:即更新进程树的树根进程,这里是窗口管理器进程。)
### newgrp 命令
在 Twitter 上有人告诉我如果只是想启动一个刷新了组信息的命令解释器的话,你可以使用 `newgrp`LCTT 译注:不启动新的命令解释器),如下:
```
sudo addgroup panda
sudo adduser bork panda
newgrp panda # starts a new shell, and you don't have to be root to run it!
```
你也可以用 `sg panda bash` 来完成同样的效果,这个命令能启动一个`bash` 登录程序,而这个程序就有 `panda` 组。
### seduid 将设置有效用户 ID
其实我一直对一个进程如何以 `setuid root` 的权限来运行意味着什么有点似是而非。现在我知道了,事实上所发生的是:`setuid` 设置了
“有效用户 ID”! 如果我(`julia`)运行了一个 `setuid root` 的进程( 比如 `passwd`),那么进程的**真实**用户 ID 将为 `julia`,而**有效**用户 ID 将被设置为 `root`
`passwd` 需要以 root 权限来运行,但是它能看到进程的真实用户 ID 是 `julia` ,是 `julia` 启动了这个进程,`passwd` 会阻止这个进程修改除了 `julia` 之外的用户密码。
### 就是这些了!
在《[Linux 编程接口][1]》这本书里有很多 Linux 上一些功能的罕见使用方法以及 Linux 上所有的事物到底是怎么运行的详细解释,这里我就不一一展开了。那本书棒极了,我上面所说的都在该书的第九章,这章在 1300 页的书里只占了 17 页。
我最爱这本书的一点是我只用读 17 页关于用户和组是怎么工作的内容,而这区区 17 页就能做到内容完备、详实有用。我不用读完所有的 1300 页书就能得到有用的东西,太棒了!
--------------------------------------------------------------------------------
via: https://jvns.ca/blog/2017/11/20/groups/
作者:[Julia Evans][a]
译者:[DavidChen](https://github.com/DavidChenLiang)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://jvns.ca/
[1]:http://man7.org/tlpi/

View File

@ -0,0 +1,66 @@
Scrot让你在命令行中进行截屏更加简单
======
> Scrot 是一个简单、灵活,并且提供了许多选项的 Linux 命令行截屏工具。
[![Original photo by Rikki Endsley. CC BY-SA 4.0](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/community-penguins-osdc-lead.png?itok=BmqsAF4A)][1]
Linux 桌面上有许多用于截屏的优秀工具,比如 [Ksnapshot][1] 和 [Shutter][2] 。甚至 GNOME 桌面自带的简易截屏工具也能够很好的工作。但是,如果你很少截屏,或者你使用的 Linux 发行版没有内建截屏工具,或者你使用的是一台资源有限的老电脑,那么你该怎么办呢?
或许你可以转向命令行,使用一个叫做 [Scrot][4] 的实用工具。它能够完成简单的截屏工作,同时它所具有的一些特性也许会让你感到非常惊喜。
### 走近 Scrot
许多 Linux 发行版都会预先安装上 Scrot ,可以输入 `which scrot` 命令来查看系统中是否安装有 Scrot 。如果没有,那么可以使用你的 Linux 发行版的包管理器来安装。如果你想从源代码编译安装,那么也可以从 [GitHub][5] 上下载源代码。
如果要进行截屏,首先打开一个终端窗口,然后输入 `scrot [filename]` `[filename]` 是你想要保存的图片文件的名字(比如 `desktop.png`)。如果缺省了该参数,那么 scrot 会自动创建一个名字,比如 `2017-09-24-185009_1687x938_scrot.png` 。(这个名字缺乏了对图片内容的描述,这就是为什么最好在命令中指定一个名字作为参数。)
如果不带任何参数运行 Scrot那么它将会对整个桌面进行截屏。如果不想这样那么你也可以对屏幕中的一个小区域进行截图。
### 对单一窗口进行截屏
可以通过输入 `scrot -u [filename]` 命令来对一个窗口进行截屏。
`-u` 选项告诉 Scrot 对当前窗口进行截屏,这通常是我们正在工作的终端窗口,也许不是你想要的。
如果要对桌面上的另一个窗口进行截屏,需要输入 `scrot -s [filename]`
`-s` 选项可以让你做下面两件事的其中一件:
* 选择一个打开着的窗口
* 在一个窗口的周围或一片区域画一个矩形进行捕获
你也可以设置一个时延,这样让你能够有时间来选择你想要捕获的窗口。可以通过 `scrot -u -d [num] [filename]` 来设置时延。
`-d` 选项告诉 Scrot 在捕获窗口前先等待一段时间,`[num]` 是需要等待的秒数。指定为 `-d 5` (等待 5 秒)应该能够让你有足够的时间来选择窗口。
### 更多有用的选项
Scrot 还提供了许多额外的特性(绝大多数我从来没有使用过)。下面是我发现的一些有用的选项:
* `-b` 捕获窗口的边界
* `-t` 捕获窗口并创建一个缩略图。当你需要把截图张贴到网上的时候,这会非常有用
* `-c` 当你同时使用了 `-d` 选项的时候,在终端中创建倒计时
如果你想了解 Scrot 的其他选项,可以在终端中输入 `man scrot` 来查看它的手册,或者[在线阅读][6]。然后开始使用 Scrot 进行截屏。
虽然 Scrot 很简单,但它的确能够工作得很好。
--------------------------------------------------------------------------------
via: https://opensource.com/article/17/11/taking-screen-captures-linux-command-line-scrot
作者:[Scott Nesbitt][a]
译者:[ucasFL](https://github.com/ucasFL)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/scottnesbitt
[1]:https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/community-penguins-osdc-lead.png?itok=BmqsAF4A
[2]:https://www.kde.org/applications/graphics/ksnapshot/
[3]:https://launchpad.net/shutter
[4]:https://github.com/dreamer/scrot
[5]:http://manpages.ubuntu.com/manpages/precise/man1/scrot.1.html
[6]:https://github.com/dreamer/scrot

View File

@ -0,0 +1,142 @@
面向敏捷开发团队的 7 个开源项目管理工具
======
> 在这篇开源项目管理工具的综述中,让我们来了解一下支持 Scrum、<ruby>看板<rt>Kanban</rt></ruby> 等敏捷开发模式的软件。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUSINESS_orgchart1.png?itok=tukiFj89)
Opensource.com 以前对流行的开源项目管理工具做过相应的调研。但是今年我们增加了一个特点。本次,我们特别关注支持[敏捷][1]方法的工具,包括相关的实践,如 [Scrum][2]、Lean 和 <ruby>看板<rt>Kanban</rt></ruby>
对敏捷开发的兴趣和使用的增长是我们今年决定专注于这些工具的原因。大多数组织71%)的人说他们至少[使用了敏捷方式][3]。此外,敏捷项目比传统方法管理的项目 [要高出 28% 的成功率][4] 。
我们查看了 [2014][5]、[2015][6] 和 [2016][7] 中涉及的项目管理工具,并挑选了支持敏捷的工具,然后对没有涉及的或变化了的进行了研究。不管您的组织是否已经在使用敏捷开发,或者在 2018 年的众多计划之一是采用敏捷方法,这七个开源项目管理工具之一可能正是您所要找寻的。
### MyCollab
![](https://opensource.com/sites/default/files/u128651/mycollab_kanban-board.png)
[MyCollab][8] 是一套针对中小型企业的三个协作模块套件项目管理、客户关系管理CRM和文档创建和编辑软件。有两个许可证选项一个商业的“终极”版本它更快可以在内部或云中运行另一个开源的“社区版本”这个正是我们感兴趣的版本。
由于没有使用查询缓存,社区版本没有云方式,并且速度较慢,但是提供了基本的项目管理特性,包括任务、问题管理、活动流、路线图视图和敏捷团队看板。虽然它没有单独的移动应用程序,但它也适用于移动设备,包括 Windows、Mac OS、Linux 和 UNIX 计算机。
MyCollab 的最新版本是 5.4.10,源代码可在 [GitHub][9] 上下载。它是在 AGPLv3 下进行授权的,需要 Java 运行时环境和 MySQL 支持。它可运行于 Windows、Linux、UNIX 和 MacOS。[下载地址][10]。
### Odoo
![](https://opensource.com/sites/default/files/u128651/odoo_projects_screenshots_01a.gif)
[Odoo][11] 不仅仅是项目管理软件它是一个完整的集成商业应用套件包括会计、人力资源、网站和电子商务、库存、制造、销售管理CRM和其它工具。
与付费企业套件相比,免费的开源社区版具有有限的 [特性][12] 。它的项目管理应用程序包括敏捷团队的看板式任务跟踪视图,在最新版本 Odoo 11.0 中更新了该视图以包括用于跟踪项目状态的进度条和动画。项目管理工具还包括甘特图、任务、问题、图表等等。Odoo 有一个繁荣的[社区][13],并提供 [用户指南][14] 及其他培训资源。
它是在 GPLv3 下授权的,需要 Python 和 PostgreSQL 支持。作为[Docker][16] 镜像 可以运行在 Windows、Linux 和 Red Hat 包管理器中,下载地址[download][15],源代码[GitHub][17]。
### OpenProject
![](https://opensource.com/sites/default/files/u128651/openproject-screenshot-agile-scrum.png)
[OpenProject][18] 是一个强大的开源项目管理工具,以其易用性和丰富的项目管理和团队协作特性而著称。
它的模块支持项目计划、调度、路线图和发布计划、时间跟踪、成本报告、预算、bug 跟踪以及敏捷和 Scrum。它的敏捷特性包括创建 Story、确定 sprint 的优先级以及跟踪任务,都与 OpenProject 的其他模块集成在一起。
OpenProject 在 GPLv3 下获得许可,其源代码可在[GitHub][19]上。最新版本 7.3.2 的 Linux 版本 [在此下载][20];您可以在 Birthe Lindenthal 的文章 “[OpenProject 入门][21]”中了解更多关于安装和配置它的信息。
### OrangeScrum
![](https://opensource.com/sites/default/files/u128651/orangescrum_kanban.png)
正如从其名称中猜到的,[OrangeScrum][22] 支持敏捷方法,特别是使用 Scrum 任务板和看板式工作流视图。它面向较小的组织自由职业者、中介机构和中小型企业。
开源版本提供了 OrangeScrum 付费版本中的许多 [特性][23],包括移动应用程序、资源利用率和进度跟踪。其他特性,包括甘特图、时间日志、发票和客户端管理,可以作为付费附加组件提供,付费版本包括云选项,而社区版本不提供。
OrangeScrum 是基于 GPLv3 授权的,是基于 CakePHP 框架开发。它需要 Apache、PHP 5.3 或更高版本和 MySQL 4.1 或更高版本支持,并可以在 Windows、Linux 和 Mac OS 上运行。其最新版本 1.1.1 [在此下载][24],其源码在 [GitHub] [25]。
### ]project-open[
![](https://opensource.com/sites/default/files/u128651/projectopen_dashboard.png)
[\]project-open\[][26] 是一个双许可证的企业项目管理工具,这意味着其核心是开源的,并且在商业许可的模块中可以使用一些附加特性。根据该项目的社区和企业版本的 [比较][27],开源核心为中小型组织提供了许多特性。
]project-open[ 支持带有 Scrum 和看板功能的 [敏捷][28] 项目,以及经典的甘特/瀑布项目和混合或混合项目。
该应用程序是在 GPL 下授权的,并且 [源代码][29]是通过 CVS 访问的。 ]project-open[ 在 Linux 和 Windows 的安装有 [安装程序][26],但也可以在云镜像和虚拟设备中使用。
### Taiga
![](https://opensource.com/sites/default/files/u128651/taiga_screenshot.jpg)
[Taiga][30] 是一个开源项目管理平台,它专注于 Scrum 和敏捷开发其特征包括看板、任务、sprints、问题、backlog 和 epics。其他功能包括凭证管理、多项目支持、Wiki 页面和第三方集成。
它还为 iOS、Android 和 Windows 设备提供免费的移动应用程序,并提供导入工具,使从其他流行的项目管理应用程序迁移变得容易。
Taiga 对于公共项目是免费的,对项目数量或用户数量没有限制。对于私有项目,在“免费增值”模式下,有很多 [付费计划][31] 可用,但是值得注意的是,无论您属于哪种类型,软件的功能特性都是一样的。
Taiga 是在 GNU Affero GPLv3 下授权的,并且软件需要 Nginx、Python 和 PostgreSQL 支持。最新版本[3.1.0 Perovskia atriplicifolia][32],可在 [GitHub][33] 上下载。
### Tuleap
![](https://opensource.com/sites/default/files/u128651/tuleap-scrum-prioritized-backlog.png)
[Tuleap][34] 是一个应用程序生命周期管理ALM平台旨在为每种类型的团队管理项目——小型、中型、大型、瀑布、敏捷或混合型——但是它对敏捷团队的支持是显著的。值得注意的是它为 Scrum、看板、sprints、任务、报告、持续集成、backlogs 等提供支持.
其他的 [特性][35] 包括问题跟踪、文档跟踪、协作工具,以及与 Git、SVN 和 Jenkins 的集成,所有这些都使它成为开放源码软件开发项目的吸引人的选择。
Tuleap 是在 GPLv2 下授权的。更多信息,包括 Docker 和 CentOS 下载,可以在他们的 [入门][36] 页面上找到。您还可以在 Tuleap 的 [Git][37] 上获取其最新版本 9.14 的源代码。
---
这种类型的文章的麻烦在于它一发布就过时了。您正在使用哪些开源项目管理工具,而被我们遗漏了?或者您对我们提到的有反馈意见吗?请在下面留下留言。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/2/agile-project-management-tools
作者:[Opensource.com][a]
译者:[heguangzhi](https://github.com/heguangzhi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com
[1]:http://agilemanifesto.org/principles.html
[2]:https://opensource.com/resources/scrum
[3]:https://www.pmi.org/-/media/pmi/documents/public/pdf/learning/thought-leadership/pulse/pulse-of-the-profession-2017.pdf
[4]:https://www.pwc.com/gx/en/actuarial-insurance-services/assets/agile-project-delivery-confidence.pdf
[5]:https://opensource.com/business/14/1/top-project-management-tools-2014
[6]:https://opensource.com/business/15/1/top-project-management-tools-2015
[7]:https://opensource.com/business/16/3/top-project-management-tools-2016
[8]:https://community.mycollab.com/
[9]:https://github.com/MyCollab/mycollab
[10]:https://www.mycollab.com/ce-registration/
[11]:https://www.odoo.com/
[12]:https://www.odoo.com/page/editions
[13]:https://www.odoo.com/page/community
[14]:https://www.odoo.com/documentation/user/11.0/
[15]:https://www.odoo.com/page/download
[16]:https://hub.docker.com/_/odoo/
[17]:https://github.com/odoo/odoo
[18]:https://www.openproject.org/
[19]:https://github.com/opf/openproject
[20]:https://www.openproject.org/download-and-installation/
[21]:https://opensource.com/article/17/11/how-install-and-use-openproject
[22]:https://www.orangescrum.org/
[23]:https://www.orangescrum.org/compare-orangescrum
[24]:http://www.orangescrum.org/free-download
[25]:https://github.com/Orangescrum/orangescrum/
[26]:http://www.project-open.com/en/list-installers
[27]:http://www.project-open.com/en/products/editions.html
[28]:http://www.project-open.com/en/project-type-agile
[29]:http://www.project-open.com/en/developers-cvs-checkout
[30]:https://taiga.io/
[31]:https://tree.taiga.io/support/subscription-and-plans/payment-process-faqs/#q.-what-s-about-custom-plans-private-projects-with-more-than-25-members-?
[32]:https://blog.taiga.io/taiga-perovskia-atriplicifolia-release-310.html
[33]:https://github.com/taigaio
[34]:https://www.tuleap.org/
[35]:https://www.tuleap.org/features/project-management
[36]:https://www.tuleap.org/get-started
[37]:https://tuleap.net/plugins/git/tuleap/tuleap/stable

View File

@ -0,0 +1,137 @@
我从编程面试中学到的
======
![](https://cdn-images-1.medium.com/max/1250/1*DXPdaGPM4oM6p5nSkup7IQ.jpeg)
*聊聊白板编程面试*
在 2017 年,我参加了 ‘计算机行业中的女性’ 的[Grace Hopper 庆祝活动][1]。这个活动是这类科技活动中最大的一个。共有 17,000 名女性IT工作者参加。
这个会议有个大型的配套招聘会,会上有招聘公司来面试会议参加者。有些人甚至现场拿到 offer。我在现场晃荡了一下注意到一些应聘者看上去非常紧张忧虑。我还隐隐听到应聘者之间的谈话其中一些人谈到在面试中做的并不好。
我走近我听到谈话的那群人并和她们聊了起来并给了一些面试上的小建议。我想我的建议还是比较偏基本的,如“(在面试时)一开始给出个能工作的解决方案也还说的过去”之类的,但是当她们听到我的一些其他的建议时还是颇为吃惊。
为了能更多的帮到像她们一样的小白面试者,我收集了一些过去对我有用的小点子,这些小点子我已经发表在了 [prodcast episode][2] 上。它们也是这篇文章的主题。
为了实习生职位和全职工作,我做过很多次的面试。当我还在大学主修计算机科学时,学校每个秋季学期都有招聘会,第一轮招聘会在校园里举行。(我在第一和最后一轮都搞砸过。)不过,每次面试后,我都会反思哪些方面我能做的更好,我还会和朋友们做模拟面试,这样我就能从他们那儿得到更多的面试反馈。
不管我们怎么样找工作: 工作中介、网络,或者学校招聘,他们的招聘流程中都会涉及到技术面试:
近年来,我注意到了一些新的不同的面试形式出现了:
* 与招聘方的一位工程师结对编程
* 网络在线测试及在线编码
* 白板编程LCTT 译注: 这种形式应该不新了)
我将重点谈谈白板面试,这种形式我经历的最多。我有过很多次面试,有些挺不错的,有些被我搞砸了。
#### 我做错的地方
首先,我想回顾一下我做的不好的地方。知错能改,善莫大焉。
当面试者提出一个要我解决的问题时, 我立即马上立刻开始在白板上写代码_什么都不问。_
这里我犯了两个错误:
#### 没有澄清对解决问题有关键作用的信息
比如,我们是否只用处理数字或者字符串?我们要支持多种数据类型吗?如果你在开始解题前不去问这些问题的话,你的面试官会有一种不好的印象:这个人在我们公司的话,他不会在开始项目工作之前不问清楚到底要做什么。而这恰恰是在工作场合很重要的一个工作习惯。公司可不像学校,你在开始工作前可不会得到写有所有详细步骤的作业说明。你得靠自己找到这些步骤并自己定义他们。
#### 只会默默思考,不去记录想法或和面试官沟通
在面试中,很多时候我也会傻傻站在那思考,什么都不写。我和一个朋友模拟面试的时候,他告诉我因为他曾经和我一起工作过所以他知道我在思考,但是如果他是个陌生的面试官的话,他会觉得我正站在那冥思苦想,毫无头绪。不要急匆匆的直奔解题而去是很重要的。花点时间多想想各种解题的可能性。有时候面试官会乐意和你一起探索解题的步骤。不管怎样,这就是在一家公司开工作会议的的普遍方式,大家各抒己见,一起讨论如何解决问题。
### 想到一个解题方法
在你开始写代码之前,如果你能总结一下要使用到的算法就太棒了。不要上来就写代码并认为你的代码肯定能解决问题。
这是对我管用的步骤:
1. 头脑风暴
2. 写代码
3. 处理错误路径
4. 测试
#### 1、 头脑风暴
对我来说,我会首先通过一些例子来视觉化我要解决的问题。比如说如果这个问题和数据结构中的树有关,我就会从树底层的空节点开始思考,如何处理一个节点的情况呢?两个节点呢?三个节点呢?这能帮助你从具体例子里抽象出你的解决方案。
在白板上先写下你的算法要做的事情列表。这样做,你往往能在开始写代码前就发现 bug 和缺陷(不过你可得掌握好时间)。我犯过的一个错误是我花了过多的时间在澄清问题和头脑风暴上,最后几乎没有留下时间给我写代码。你的面试官可能没有机会看你在白板上写下代码,这可太糟了。你可以带块手表,或者房间有钟的话,你也可以抬头看看时间。有些时候面试者会提醒你你已经得到了所有的信息(这时你就不要再问别的了),“我想我们已经把所有需要的信息都澄清了,让我们写代码实现吧”。
#### 2、 开始写代码,一气呵成
如果你还没有得到问题的完美解决方法,从最原始的解法开始总是可以的。当你在向面试官解释最显而易见的解法时,你要想想怎么去完善它,并指明这种做法是最原始的,未加优化的。(请熟悉算法中的 `O()` 的概念,这对面试非常有用。)在向面试者提交前请仔细检查你的解决方案两三遍。面试者有时会给你些提示, “还有更好的方法吗?”,这句话的意思是面试官提示你有更优化的解决方案。
#### 3、 错误处理
当你在编码时,对你想做错误处理的代码行做个注释。当面试者说,“很好,这里你想到了错误处理。你想怎么处理呢?抛出异常还是返回错误码?”,这将给你个机会去引出关于代码质量的一番讨论。当然,这种地方提出几个就够了。有时,面试者为了节省编码的时间,会告诉你可以假设外界输入的参数都已经通过了校验。不管怎样,你都要展现你对错误处理和编码质量的重要性的认识。
#### 4、 测试
在编码完成后,用你在前面头脑风暴中写的用例来在你脑子里“跑”一下你的代码,确定万无一失。例如你可以说,“让我用前面写下的树的例子来跑一下我的代码,如果是一个节点是什么结果,如果是两个节点是什么结果……”
在你结束之后,面试者有时会问你你将会怎么测试你的代码,你会涉及什么样的测试用例。我建议你用下面不同的分类来组织你的错误用例:
一些分类可以为:
1. 性能
2. 错误用例
3. 期望的正常用例
对于性能测试,要考虑极端数量下的情况。例如,如果问题是关于列表的,你可以说你将会使用一个非常大的列表以及的非常小的列表来测试。如果和数字有关,你将会测试系统中的最大整数和最小整数。我建议读一些有关软件测试的书来得到更多的知识。在这个领域我最喜欢的书是 《[我们在微软如何测试软件][3]》。
对于错误用例,想一下什么是期望的错误情况并一一写下。
对于正向期望用例,想想用户需求是什么?你的解决方案要解决什么问题?这些都可以成为正向期望用例。
### “你还有什么要问我的吗?”
面试最后总是会留几分钟给你问问题。我建议你在面试前写下你想问的问题。千万别说,“我没什么问题了”,就算你觉得面试砸了或者你对这间公司不怎么感兴趣,你总有些东西可以问问。你甚至可以问面试者他最喜欢自己的工作什么,最讨厌自己的工作什么。或者你可以问问面试官的工作具体是什么,在用什么技术和实践。不要因为觉得自己在面试中做的不好而心灰意冷,不想问什么问题。
### 申请一份工作
关于找工作和申请工作,有人曾经告诉我,你应该去找你真正有激情工作的地方。去找一家你喜欢的公司,或者你喜欢使用的产品,看看你能不能去那儿工作。
我个人并不推荐你用上述的方法去找工作。你会排除很多很好的公司,特别是你是在找实习工作或者入门级的职位时。
你也可以集中在其他的一些目标上。如我想从这个工作里得到哪方面的更多经验这个工作是关于云计算Web 开发?或是人工智能?当在招聘会上与招聘公司沟通时,看看他们的工作单位有没有在这些领域的。你可能会在一家并非在你的想去公司列表上的公司(或非盈利机构)里找到你想找的职位。
#### 换组
在这家公司里的第一个组里呆了一年半以后,我觉得是时候去探索一下不同的东西了。我找到了一个我喜欢的组并进行了 4 轮面试。结果我搞砸了。
我什么都没有准备,甚至都没在白板上练练手。我当时的逻辑是,如果我都已经在一家公司干了快 2 年了,我还需要练什么?我完全错了,我在接下去的白板面试中跌跌撞撞。我的板书写得太小,而且因为没有从最左上角开始写代码,我的代码大大超出了一个白板的空间,这些都导致了白板面试失败。
我在面试前也没有刷过数据结构和算法题。如果我做了的话,我将会在面试中更有信心。就算你已经在一家公司担任了软件工程师,在你去另外一个组面试前,我强烈建议你在一块白板上演练一下如何写代码。
对于换项目组这件事,如果你是在公司内部换组的话,事先能同那个组的人非正式聊聊会很有帮助。对于这一点,我发现几乎每个人都很乐于和你一起吃个午饭。人一般都会在中午有空,约不到人或者别人正好有会议冲突的风险会很低。这是一种非正式的途径来了解你想去的组正在干什么,以及这个组成员个性是怎么样的。相信我,你能从一次午餐中得到很多信息,这可会对你的正式面试帮助不小。
非常重要的一点是,你在面试一个特定的组时,就算你在面试中做的很好,因为文化不契合的原因,你也很可能拿不到 offer。这也是为什么我一开始就想去见见组里不同的人的原因有时这也不太可能我希望你不要被一次拒绝所击倒请保持开放的心态选择新的机会并多多练习。
以上内容选自 《[The Women in Tech Show: Technical Interviews with Prominent Women in Tech][5]》的 “[编程面试][4]”章节,
--------------------------------------------------------------------------------
作者简介:
微软研究院 Software Engineer II www.thewomenintechshow.com 站长,所有观点都只代表本人意见。
------------
via: https://medium.freecodecamp.org/what-i-learned-from-programming-interviews-29ba49c9b851
作者:[Edaena Salinas][a]
译者:[DavidChenLiang](https://github.com/DavidChenLiang)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://medium.freecodecamp.org/@edaenas
[1]:https://anitab.org/event/2017-grace-hopper-celebration-women-computing/
[2]:https://thewomenintechshow.com/2017/12/18/programming-interviews/
[3]:https://www.amazon.com/How-We-Test-Software-Microsoft/dp/0735624259
[4]:https://thewomenintechshow.com/2017/12/18/programming-interviews/
[5]:https://thewomenintechshow.com/

View File

@ -0,0 +1,201 @@
你没听说过的 Go 语言惊人优点
=========
![](https://cdn-images-1.medium.com/max/2000/1*NDXd5I87VZG0Z74N7dog0g.png)
*来自 [https://github.com/ashleymcnamara/gophers][1] 的图稿*
在这篇文章中,我将讨论为什么你需要尝试一下 Go 语言,以及应该从哪里学起。
Go 语言是可能是最近几年里你经常听人说起的编程语言。尽管它在 2009 年已经发布了,但它最近才开始流行起来。
![](https://cdn-images-1.medium.com/max/2000/1*cQ8QzhCPiFXqk_oQdUk_zw.png)
*根据 Google 趋势Go 语言非常流行。*
这篇文章不会讨论一些你经常看到的 Go 语言的主要特性。
相反,我想向您介绍一些相当小众但仍然很重要的功能。只有在您决定尝试 Go 语言后,您才会知道这些功能。
这些都是表面上没有体现出来的惊人特性,但它们可以为您节省数周或数月的工作量。而且这些特性还可以使软件开发更加愉快。
阅读本文不需要任何语言经验,所以不必担心你还不了解 Go 语言。如果你想了解更多,可以看看我在底部列出的一些额外的链接。
我们将讨论以下主题:
* GoDoc
* 静态代码分析
* 内置的测试和分析框架
* 竞争条件检测
* 学习曲线
* 反射
* Opinionatedness
* 文化
请注意,这个列表不遵循任何特定顺序来讨论。
### GoDoc
Go 语言非常重视代码中的文档,所以也很简洁。
[GoDoc][4] 是一个静态代码分析工具可以直接从代码中创建漂亮的文档页面。GoDoc 的一个显著特点是它不使用任何其他的语言,如 JavaDoc、PHPDoc 或 JSDoc 来注释代码中的结构,只需要用英语。
它使用从代码中获取的尽可能多的信息来概述、构造和格式化文档。它有多而全的功能,比如:交叉引用、代码示例,并直接链接到你的版本控制系统仓库。
而你需要做的只有添加一些像 `// MyFunc transforms Foo into Bar` 这样子的老牌注释,而这些注释也会反映在的文档中。你甚至可以添加一些通过网络界面或者在本地可以实际运行的 [代码示例][5]。
GoDoc 是 Go 的唯一文档引擎,整个社区都在使用。这意味着用 Go 编写的每个库或应用程序都具有相同的文档格式。从长远来看,它可以帮你在浏览这些文档时节省大量时间。
例如,这是我最近一个小项目的 GoDoc 页面:[pullkeeGoDoc][6]。
### 静态代码分析
Go 严重依赖于静态代码分析。例如用于文档的 [godoc][7],用于代码格式化的 [gofmt][8],用于代码风格的 [golint][9],等等。
它们是如此之多,甚至有一个总揽了它们的项目 [gometalinter][10] ,将它们组合成了单一的实用程序。
这些工具通常作为独立的命令行应用程序实现,并可轻松与任何编码环境集成。
静态代码分析实际上并不是现代编程的新概念,但是 Go 将其带入了绝对的范畴。我无法估量它为我节省了多少时间。此外,它给你一种安全感,就像有人在你背后支持你一样。
创建自己的分析器非常简单,因为 Go 有专门的内置包来解析和加工 Go 源码。
你可以从这个链接中了解到更多相关内容: [GothamGo Kickoff Meetup: Alan Donovan 的 Go 静态分析工具][11]。
### 内置的测试和分析框架
您是否曾尝试为一个从头开始的 JavaScript 项目选择测试框架?如果是这样,你或许会理解经历这种<ruby>过度分析<rt>analysis paralysis</rt></ruby>的痛苦。您可能也意识到您没有使用其中 80 的框架。
一旦您需要进行一些可靠的分析,问题就会重复出现。
Go 附带内置测试工具,旨在简化和提高效率。它为您提供了最简单的 API并做出最小的假设。您可以将它用于不同类型的测试、分析甚至可以提供可执行代码示例。
它可以开箱即用地生成便于持续集成的输出,而且它的用法很简单,只需运行 `go test`。当然,它还支持高级功能,如并行运行测试,跳过标记代码,以及其他更多功能。
### 竞争条件检测
您可能已经听说了 Goroutine它们在 Go 中用于实现并发代码执行。如果你未曾了解过,[这里][12]有一个非常简短的解释。
无论具体技术如何,复杂应用中的并发编程都不容易,部分原因在于竞争条件的可能性。
简单地说,当几个并发操作以不可预测的顺序完成时,竞争条件就会发生。它可能会导致大量的错误,特别难以追查。如果你曾经花了一天时间调试集成测试,该测试仅在大约 80 的执行中起作用?这可能是竞争条件引起的。
总而言之,在 Go 中非常重视并发编程,幸运的是,我们有一个强大的工具来捕捉这些竞争条件。它完全集成到 Go 的工具链中。
您可以在这里阅读更多相关信息并了解如何使用它:[介绍 Go 中的竞争条件检测 - Go Blog][13]。
### 学习曲线
您可以在一个晚上学习**所有**的 Go 语言功能。我是认真的。当然,还有标准库,以及不同的,更具体领域的最佳实践。但是两个小时就足以让你自信地编写一个简单的 HTTP 服务器或命令行应用程序。
Go 语言拥有[出色的文档][14],大部分高级主题已经在他们的博客上进行了介绍:[Go 编程语言博客][15]。
比起 Java以及 Java 家族的语言、Javascript、Ruby、Python 甚至 PHP你可以更轻松地把 Go 语言带到你的团队中。由于环境易于设置,您的团队在完成第一个生产代码之前需要进行的投资要小得多。
### 反射
代码反射本质上是一种隐藏在编译器下并访问有关语言结构的各种元信息的能力,例如变量或函数。
鉴于 Go 是一种静态类型语言,当涉及更松散类型的抽象编程时,它会受到许多各种限制。特别是与 Javascript 或 Python 等语言相比。
此外Go [没有实现一个名为泛型的概念][16],这使得以抽象方式处理多种类型更具挑战性。然而,由于泛型带来的复杂程度,许多人认为不实现泛型对语言实际上是有益的。我完全同意。
根据 Go 的理念(这是一个单独的主题),您应该努力不要过度设计您的解决方案。这也适用于动态类型编程。尽可能坚持使用静态类型,并在确切知道要处理的类型时使用<ruby>接口<rt>interface</rt></ruby>。接口在 Go 中非常强大且无处不在。
但是,仍然存在一些情况,你无法知道你处理的数据类型。一个很好的例子是 JSON。您可以在应用程序中来回转换所有类型的数据。字符串、缓冲区、各种数字、嵌套结构等。
为了解决这个问题,您需要一个工具来检查运行时的数据并根据其类型和结构采取不同行为。<ruby>反射<rt>Reflect</rt></ruby>可以帮到你。Go 拥有一流的反射包,使您的代码能够像 Javascript 这样的语言一样动态。
一个重要的警告是知道你使用它所带来的代价 —— 并且只有知道在没有更简单的方法时才使用它。
你可以在这里阅读更多相关信息: [反射的法则Go 博客][18].
您还可以在此处阅读 JSON 包源码中的一些实际代码: [src/encoding/json/encode.goSource Code][19]
### Opinionatedness专制独裁的 Go
顺便问一下,有这样一个单词吗?
来自 Javascript 世界,我面临的最艰巨的困难之一是决定我需要使用哪些约定和工具。我应该如何设计代码?我应该使用什么测试库?我该怎么设计结构?我应该依赖哪些编程范例和方法?
这有时候基本上让我卡住了。我需要花时间思考这些事情而不是编写代码并满足用户。
首先,我应该注意到我完全知道这些惯例的来源,它总是来源于你或者你的团队。无论如何,即使是一群经验丰富的 Javascript 开发人员也很容易发现他们在实现相同的结果时,而大部分的经验却是在完全不同的工具和范例上。
这导致整个团队中出现过度分析,并且使得个体之间更难以相互协作。
Go 是不同的。即使您对如何构建和维护代码有很多强烈的意见,例如:如何命名,要遵循哪些结构模式,如何更好地实现并发。但你只有一个每个人都遵循的风格指南。你只有一个内置在基本工具链中的测试框架。
虽然这似乎过于严格,但它为您和您的团队节省了大量时间。当你写代码时,受一点限制实际上是一件好事。在构建新代码时,它为您提供了一种更直接的方法,并且可以更容易地调试现有代码。
因此,大多数 Go 项目在代码方面看起来非常相似。
### 文化
人们说,每当你学习一门新的口语时,你也会沉浸在说这种语言的人的某些文化中。因此,您学习的语言越多,您可能会有更多的变化。
编程语言也是如此。无论您将来如何应用新的编程语言,它总能给你带来新的编程视角或某些特别的技术。
无论是函数式编程,<ruby>模式匹配<rt>pattern matching</rt></ruby>还是<ruby>原型继承<rt>prototypal inheritance</rt></ruby>。一旦你学会了它们,你就可以随身携带这些编程思想,这扩展了你作为软件开发人员所拥有的问题解决工具集。它们也改变了你阅读高质量代码的方式。
而 Go 在这方面有一项了不起的财富。Go 文化的主要支柱是保持简单,脚踏实地的代码,而不会产生许多冗余的抽象概念,并将可维护性放在首位。大部分时间花费在代码的编写工作上,而不是在修补工具和环境或者选择不同的实现方式上,这也是 Go 文化的一部分。
Go 文化也可以总结为:“应当只用一种方法去做一件事”。
一点注意事项。当你需要构建相对复杂的抽象代码时Go 通常会妨碍你。好吧,我会说这是简单的权衡。
如果你真的需要编写大量具有复杂关系的抽象代码,那么最好使用 Java 或 Python 等语言。然而,这种情况却很少。
在工作时始终使用最好的工具!
### 总结
你或许之前听说过 Go或者它暂时在你圈子以外的地方。但无论怎样在开始新项目或改进现有项目时Go 可能是您或您团队的一个非常不错的选择。
这不是 Go 的所有惊人的优点的完整列表,只是一些被人低估的特性。
请尝试一下从 [Go 之旅][20] 来开始学习 Go这将是一个令人惊叹的开始。
如果您想了解有关 Go 的优点的更多信息,可以查看以下链接:
* [你为什么要学习 Go - Keval Patel][2]
* [告别Node.js - TJ Holowaychuk][3]
并在评论中分享您的阅读感悟!
即使您不是为了专门寻找新的编程语言语言,也值得花一两个小时来感受它。也许它对你来说可能会变得非常有用。
不断为您的工作寻找最好的工具!
-------------------------------------------------------
via: https://medium.freecodecamp.org/here-are-some-amazing-advantages-of-go-that-you-dont-hear-much-about-1af99de3b23a
作者:[Kirill Rogovoy][a]
译者:[imquanquan](https://github.com/imquanquan)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://twitter.com/krogovoy
[1]:https://github.com/ashleymcnamara/gophers
[2]:https://medium.com/@kevalpatel2106/why-should-you-learn-go-f607681fad65
[3]:https://medium.com/@tjholowaychuk/farewell-node-js-4ba9e7f3e52b
[4]:https://godoc.org/
[5]:https://blog.golang.org/examples
[6]:https://godoc.org/github.com/kirillrogovoy/pullkee
[7]:https://godoc.org/
[8]:https://golang.org/cmd/gofmt/
[9]:https://github.com/golang/lint
[10]:https://github.com/alecthomas/gometalinter#supported-linters
[11]:https://vimeo.com/114736889
[12]:https://gobyexample.com/goroutines
[13]:https://blog.golang.org/race-detector
[14]:https://golang.org/doc/
[15]:https://blog.golang.org/
[16]:https://golang.org/doc/faq#generics
[17]:https://golang.org/pkg/reflect/
[18]:https://blog.golang.org/laws-of-reflection
[19]:https://golang.org/src/encoding/json/encode.go
[20]:https://tour.golang.org/
[21]:https://github.com/kirillrogovoy/
[22]:https://twitter.com/krogovoy

View File

@ -0,0 +1,262 @@
API Star一个 Python 3 的 API 框架
======
为了在 Python 中快速构建 API我主要依赖于 [Flask][1]。最近我遇到了一个名为 “API Star” 的基于 Python 3 的新 API 框架。由于几个原因,我对它很感兴趣。首先,该框架包含 Python 新特点,如类型提示和 asyncio。而且它再进一步为开发人员提供了很棒的开发体验。我们很快就会讲到这些功能但在我们开始之前我首先要感谢 Tom Christie感谢他为 Django REST Framework 和 API Star 所做的所有工作。
现在说回 API Star —— 我感觉这个框架很有成效。我可以选择基于 asyncio 编写异步代码,或者可以选择传统后端方式就像 WSGI 那样。它配备了一个命令行工具 —— `apistar` 来帮助我们更快地完成工作。它支持 Django ORM 和 SQLAlchemy这是可选的。它有一个出色的类型系统使我们能够定义输入和输出的约束API Star 可以自动生成 API 的模式(包括文档),提供验证和序列化功能等等。虽然 API Star 专注于构建 API但你也可以非常轻松地在其上构建 Web 应用程序。在我们自己构建一些东西之前,所有这些可能都没有意义的。
### 开始
我们将从安装 API Star 开始。为此实验创建一个虚拟环境是一个好主意。如果你不知道如何创建一个虚拟环境,不要担心,继续往下看。
```
pip install apistar
```
(译注:上面的命令是在 Python 3 虚拟环境下使用的)
如果你没有使用虚拟环境或者你的 Python 3 的 `pip` 名为 `pip3`,那么使用 `pip3 install apistar` 代替。
一旦我们安装了这个包,我们就应该可以使用 `apistar` 命令行工具了。我们可以用它创建一个新项目,让我们在当前目录中创建一个新项目。
```
apistar new .
```
现在我们应该创建两个文件:`app.py`,它包含主应用程序,然后是 `test.py`,它用于测试。让我们来看看 `app.py` 文件:
```
from apistar import Include, Route
from apistar.frameworks.wsgi import WSGIApp as App
from apistar.handlers import docs_urls, static_urls
def welcome(name=None):
if name is None:
return {'message': 'Welcome to API Star!'}
return {'message': 'Welcome to API Star, %s!' % name}
routes = [
Route('/', 'GET', welcome),
Include('/docs', docs_urls),
Include('/static', static_urls)
]
app = App(routes=routes)
if __name__ == '__main__':
app.main()
```
在我们深入研究代码之前,让我们运行应用程序并查看它是否正常工作。我们在浏览器中输入 `http://127.0.0.1:8080/`,我们将得到以下响应:
```
{"message": "Welcome to API Star!"}
```
如果我们输入:`http://127.0.0.1:8080/?name=masnun`
```
{"message": "Welcome to API Star, masnun!"}
```
同样的,输入 `http://127.0.0.1:8080/docs/`,我们将看到自动生成的 API 文档。
现在让我们来看看代码。我们有一个 `welcome` 函数,它接收一个名为 `name` 的参数,其默认值为 `None`。API Star 是一个智能的 API 框架。它将尝试在 url 路径或者查询字符串中找到 `name` 键并将其传递给我们的函数,它还基于其生成 API 文档。这真是太好了,不是吗?
然后,我们创建一个 `Route``Include` 实例的列表,并将列表传递给 `App` 实例。`Route` 对象用于定义用户自定义路由。顾名思义,`Include` 包含了在给定的路径下的其它 url 路径。
### 路由
路由很简单。当构造 `App` 实例时,我们需要传递一个列表作为 `routes` 参数,这个列表应该有我们刚才看到的 `Route``Include` 对象组成。对于 `Route`,我们传递一个 url 路径http 方法和可调用的请求处理程序(函数或者其他)。对于 `Include` 实例,我们传递一个 url 路径和一个 `Routes` 实例列表。
#### 路径参数
我们可以在花括号内添加一个名称来声明 url 路径参数。例如 `/user/{user_id}` 定义了一个 url其中 `user_id` 是路径参数,或者说是一个将被注入到处理函数(实际上是可调用的)中的变量。这有一个简单的例子:
```
from apistar import Route
from apistar.frameworks.wsgi import WSGIApp as App
def user_profile(user_id: int):
return {'message': 'Your profile id is: {}'.format(user_id)}
routes = [
Route('/user/{user_id}', 'GET', user_profile),
]
app = App(routes=routes)
if __name__ == '__main__':
app.main()
```
如果我们访问 `http://127.0.0.1:8080/user/23`,我们将得到以下响应:
```
{"message": "Your profile id is: 23"}
```
但如果我们尝试访问 `http://127.0.0.1:8080/user/some_string`,它将无法匹配。因为我们定义了 `user_profile` 函数,且为 `user_id` 参数添加了一个类型提示。如果它不是整数,则路径不匹配。但是如果我们继续删除类型提示,只使用 `user_profile(user_id)`,它将匹配此 url。这也展示了 API Star 的智能之处和利用类型和好处。
#### 包含/分组路由
有时候将某些 url 组合在一起是有意义的。假设我们有一个处理用户相关功能的 `user` 模块,将所有与用户相关的 url 分组在 `/user` 路径下可能会更好。例如 `/user/new`、`/user/1`、`/user/1/update` 等等。我们可以轻松地在单独的模块或包中创建我们的处理程序和路由,然后将它们包含在我们自己的路由中。
让我们创建一个名为 `user` 的新模块,文件名为 `user.py`。我们将以下代码放入这个文件:
```
from apistar import Route
def user_new():
return {"message": "Create a new user"}
def user_update(user_id: int):
return {"message": "Update user #{}".format(user_id)}
def user_profile(user_id: int):
return {"message": "User Profile for: {}".format(user_id)}
user_routes = [
Route("/new", "GET", user_new),
Route("/{user_id}/update", "GET", user_update),
Route("/{user_id}/profile", "GET", user_profile),
]
```
现在我们可以从 app 主文件中导入 `user_routes`,并像这样使用它:
```
from apistar import Include
from apistar.frameworks.wsgi import WSGIApp as App
from user import user_routes
routes = [
Include("/user", user_routes)
]
app = App(routes=routes)
if __name__ == '__main__':
app.main()
```
现在 `/user/new` 将委托给 `user_new` 函数。
### 访问查询字符串/查询参数
查询参数中传递的任何参数都可以直接注入到处理函数中。比如 url `/call?phone=1234`,处理函数可以定义一个 `phone` 参数,它将从查询字符串/查询参数中接收值。如果 url 查询字符串不包含 `phone` 的值,那么它将得到 `None`。我们还可以为参数设置一个默认值,如下所示:
```
def welcome(name=None):
if name is None:
return {'message': 'Welcome to API Star!'}
return {'message': 'Welcome to API Star, %s!' % name}
```
在上面的例子中,我们为 `name` 设置了一个默认值 `None`
### 注入对象
通过给一个请求程序添加类型提示我们可以将不同的对象注入到视图中。注入请求相关的对象有助于处理程序直接从内部访问它们。API Star 内置的 `http` 包中有几个内置对象。我们也可以使用它的类型系统来创建我们自己的自定义对象并将它们注入到我们的函数中。API Star 还根据指定的约束进行数据验证。
让我们定义自己的 `User` 类型,并将其注入到我们的请求处理程序中:
```
from apistar import Include, Route
from apistar.frameworks.wsgi import WSGIApp as App
from apistar import typesystem
class User(typesystem.Object):
properties = {
'name': typesystem.string(max_length=100),
'email': typesystem.string(max_length=100),
'age': typesystem.integer(maximum=100, minimum=18)
}
required = ["name", "age", "email"]
def new_user(user: User):
return user
routes = [
Route('/', 'POST', new_user),
]
app = App(routes=routes)
if __name__ == '__main__':
app.main()
```
现在如果我们发送这样的请求:
```
curl -X POST \
http://127.0.0.1:8080/ \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/json' \
-d '{"name": "masnun", "email": "masnun@gmail.com", "age": 12}'
```
猜猜发生了什么?我们得到一个错误,说年龄必须等于或大于 18。类型系允许我们进行智能数据验证。如果我们启用了 `docs` url我们还将自动记录这些参数。
### 发送响应
如果你已经注意到,到目前为止,我们只可以传递一个字典,它将被转换为 JSON 并作为默认返回。但是,我们可以使用 `apistar` 中的 `Response` 类来设置状态码和其它任意响应头。这有一个简单的例子:
```
from apistar import Route, Response
from apistar.frameworks.wsgi import WSGIApp as App
def hello():
return Response(
content="Hello".encode("utf-8"),
status=200,
headers={"X-API-Framework": "API Star"},
content_type="text/plain"
)
routes = [
Route('/', 'GET', hello),
]
app = App(routes=routes)
if __name__ == '__main__':
app.main()
```
它应该返回纯文本响应和一个自定义标响应头。请注意,`content` 应该是字节,而不是字符串。这就是我编码它的原因。
### 继续
我刚刚介绍了 API Star 的一些特性API Star 中还有许多非常酷的东西,我建议通过 [Github Readme][2] 文件来了解这个优秀框架所提供的不同功能的更多信息。我还将尝试在未来几天内介绍关于 API Star 的更多简短的,集中的教程。
--------------------------------------------------------------------------------
via: http://polyglot.ninja/api-star-python-3-api-framework/
作者:[MASNUN][a]
译者:[MjSeven](https://github.com/MjSeven)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:http://polyglot.ninja/author/masnun/
[1]:http://polyglot.ninja/rest-api-best-practices-python-flask-tutorial/
[2]:https://github.com/encode/apistar

View File

@ -0,0 +1,61 @@
Linux 虚拟机与 Linux 现场镜像版
======
> Linux 虚拟机与 Linux 现场镜像版各有优势,也有不足。
首先我得承认,我非常喜欢频繁尝试新的 [Linux 发行版本][1]。然而,我用来测试它们的方法根据每次目标而有所不同。在这篇文章中,我们来看看两种运行 Linux 的模式:虚拟机或<ruby>现场镜像版<rt>live image</rt></ruby>。每一种方式都存在优势,但是也有一些不足。
### 首次测试一个全新的 Linux 发行版
当我首次测试一个全新 Linux 发行版时,我使用的方法很大程度上依赖于我当前所拥有的 PC 资源。如果我使用台式机,我会在一台虚拟机中运行该发行版来测试。使用这种方法的原因是,我可以下载并测试该发行版,不只是在一个现场环境中,而且也可以作为一个带有持久存储的安装的系统。
另一方面,如果我的 PC 不具备强劲的硬件,那么通过 Linux 的虚拟机安装来测试发行版是适得其反的。我会将那台 PC 压榨到它的极限,诚然,更好的是使用现场版的 Linux 映像,而不是从闪存驱动器中运行。
### 体验新的 Linux 发行版本的软件
如果你有兴趣查看发行版本的桌面环境或可用的软件,那使用它的现场镜像版就没错了。一个现场版环境可以提供给你所预期的全局视角、其所提供的软件和用户体验的整体感受。
公平的说,你也可以在虚拟机上达到同样的效果,但是它有一点不好,如果这么做会让更多数据填满你的磁盘空间。毕竟这只是对发行版的一个简单体验。记得我在第一节说过:我喜欢在虚拟机上运行 Linux 来做测试。用这个方式我就能看到如何去安装它、分区是怎么样的等等,而使用现场镜像版时你就看不到这些。
这种体验方式通常表明你只想对该发行版本有个大致了解,所以在这种情况下,这种只需要付出最小的精力和时间的方式是一种不错的办法。
### 随身携带一个发行版
这种方式虽然不像几年前那样普遍,这种随身携带一个 Linux 发行版的能力也许是出于对某些用户的考虑。显然,虚拟机安装对于便携性并无太多帮助。不过,现场镜像版实际上是十分便携的。现场镜像版可以写入到 DVD 当中或复制到一个闪存盘中而便于携带。
从 Linux 的便携性这个概念上展开来说,当要在一个朋友的电脑上展示 Linux 如何工作,使用一个闪存盘上的现场镜像版也是很方便的。这可以使你能演示 Linux 如何丰富他们的生活,而不用必须在他们的 PC 上运行一个虚拟机。使用现场镜像版这就有点双赢的感觉了。
### 选择做双引导 Linux
这接下来的方式是个大工程。考虑一下,也许你是一个 Windows 用户。你喜欢玩 Linux但又不愿意冒险。除了在某些情况下会出些状况或者识别个别分区时遇到问题双引导方式就没啥挑剔的。无论如何使用 Linux 虚拟机或现场镜像版都对于你来说是一个很好的选择。
现在,我在某些事情上采取了奇怪的立场。我认为长期在闪存盘上运行现场镜像版要比虚拟机更有价值。这有两个原因。首先,您将会习惯于真正运行 Linux而不是在 Windows 之上的虚拟机中运行它。其次,您可以设置闪存盘以包含持久存储的用户数据。
我知道你会说用一个虚拟机运行 Linux 也是如此,然而,使用现场镜像版的方式,你绝不会因为更新而被破坏任何东西。为什么?因为你不会更新你的宿主系统或者客户系统。请记住,有整个 Linux 发行版本被设计为持久存储的 Linux 发行版。Puppy Linux 就是一个非常好的例子。它不仅能运行在要被回收或丢弃的个人 PC 上,它也可以让你永远不被频繁的系统升级所困扰,这要感谢该发行版处理安全更新的方式。这不是一个常规的 Linux 发行版,而是以这样的一种方式封闭了安全问题——即持久存储的现场镜像版中没有什么令人担心的坏东西。
### Linux 虚拟机绝对是一个最好的选择
在我结束这篇文章时,让我告诉你。有一种场景下,使用 Virtual Box 等虚拟机绝对比现场镜像版更好:记录 Linux 发行版的桌面环境。
例如,我制作了一个视频,里面介绍和点评了许多 Linux 发行版。使用现场镜像版进行此操作需要我用硬件设备捕获屏幕,或者从现场镜像版的软件仓库中安装捕获软件。显然,虚拟机比 Linux 发行版的现场镜像版更适合这项工作。
一旦你需要采集音频进行混音,毫无疑问,如果您要使用软件来捕获您的点评语音,那么您肯定希望拥有一个宿主操作系统,里面包含了一个起码的捕获环境的所有基本需求。同样,您可以使用硬件设备来完成所有这一切,但如果您只是做兼职的视频/音频捕获, 那么这可能要付出成本高昂的代价。
### Linux 虚拟机 VS. Linux 现场镜像版
你最喜欢尝试新发行版的方式是哪些?也许,你是那种可以很好地格式化磁盘、将风险置之脑后的人,所以这里说的这些都是没用的?
我在网上互动的大多数人都倾向于遵循我上面提及的方法,但是我很想知道哪种方式更加适合你。点击评论框,让我知道在体验 Linux 发行版世界最伟大和最新的版本时,您更喜欢哪种方法。
--------------------------------------------------------------------------------
via: https://www.datamation.com/open-source/linux-virtual-machines-vs-linux-live-images.html
作者:[Matt Hartley][a]
译者:[sober-wang](https://github.com/sober-wang)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.datamation.com/author/Matt-Hartley-3080.html
[1]:https://www.datamation.com/open-source/best-linux-distro.html

View File

@ -0,0 +1,89 @@
何谓开源编程?
======
> 开源就是丢一些代码到 GitHub 上。了解一下它是什么,以及不是什么?
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_computer_development_programming.png?itok=4OM29-82)
最简单的来说,开源编程就是编写一些大家可以随意取用、修改的代码。但你肯定听过关于 Go 语言的那个老笑话,说 Go 语言“简单到看一眼就可以明白规则,但需要一辈子去学会运用它”。其实写开源代码也是这样的。往 GitHub、Bitbucket、SourceForge 等网站或者是你自己的博客或网站上丢几行代码不是难事,但想要卓有成效,还需要个人的努力付出和高瞻远瞩。
![](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/floorgoban.jpeg?itok=r8gA5jOk)
### 我们对开源编程的误解
首先我要说清楚一点:把你的代码放在 GitHub 的公开仓库中并不意味着把你的代码开源了。在几乎全世界,根本不用创作者做什么,只要作品形成,版权就随之而生了。在创作者进行授权之前,只有作者可以行使版权相关的权力。未经创作者授权的代码,不论有多少人在使用,都是一颗定时炸弹,只有愚蠢的人才会去用它。
有些创作者很善良,认为“很明显我的代码是免费提供给大家使用的。”,他也并不想起诉那些用了他的代码的人,但这并不意味着这些代码可以放心使用。不论在你眼中创作者们多么善良,他们都 *有权力* 起诉任何使用、修改代码,或未经明确授权就将代码嵌入的人。
很明显,你不应该在没有指定开源许可证的情况下将你的源代码发布到网上然后期望别人使用它并为其做出贡献。我建议你也尽量避免使用这种代码,甚至疑似未授权的也不要使用。如果你开发了一个函数和例程,它和之前一个疑似未授权代码很像,源代码作者就可以对你就侵权提起诉讼。
举个例子Jill Schmill 写了 AwesomeLib 然后未明确授权就把它放到了 GitHub 上,就算 Jill Schmill 不起诉任何人,只要她把 AwesomeLib 的完整版权都卖给 EvilCorpEvilCorp 就会起诉之前违规使用这段代码的人。这种行为就好像是埋下了计算机安全隐患,总有一天会为人所用。
没有许可证的代码的危险的,切记。
### 选择恰当的开源许可证
假设你正要写一个新程序,而且打算让人们以开源的方式使用它,你需要做的就是选择最贴合你需求的[许可证][1]。和宣传中说的一样,你可以从 GitHub 所支持的 [choosealicense.com][2] 开始。这个网站设计得像个简单的问卷,特别方便快捷,点几下就能找到合适的许可证。
警示:在选择许可证时不要过于自负,如果你选的是 [Apache 许可证][3]或者 [GPLv3][4] 这种广为使用的许可证,人们很容易理解他们和你都有什么权利,你也不需要请律师来排查其中的漏洞。你选择的许可证使用的人越少,带来的麻烦就越多。
最重要的一点是: *千万不要试图自己制造许可证!* 自己制造许可证会给大家带来更多的困惑和困扰,不要这样做。如果在现有的许可证中确实找不到你需要的条款,你可以在现有的许可证中附加上你的要求,并且重点标注出来,提醒使用者们注意。
我知道有些人会站出来说:“我才懒得管什么许可证,我已经把代码发到<ruby>公开领域<rt>public domain</rt></ruby>了。”但问题是,公开领域的法律效力并不是受全世界认可的。在不同的国家,公开领域的效力和表现形式不同。在有些国家的政府管控下,你甚至不可以把自己的源代码发到公开领域。万幸,[Unlicense][5] 可以弥补这些漏洞,它语言简洁,使用几个词清楚地描述了“就把它放到公开领域”,但其效力为全世界认可。
### 怎样引入许可证
确定使用哪个许可证之后,你需要清晰而无疑义地指定它。如果你是在 GitHub、GitLab 或 BitBucket 这几个网站发布,你需要构建很多个文件夹,在根文件夹中,你应把许可证创建为一个以 `LICENSE.txt` 命名的明文文件。
创建 `LICENSE.txt` 这个文件之后还有其它事要做。你需要在每个重要文件的头部添加注释块来申明许可证。如果你使用的是一个现有的许可证,这一步对你来说十分简便。一个 `# 项目名 (c)2018 作者名GPLv3 许可证,详情见 https://www.gnu.org/licenses/gpl-3.0.en.html` 这样的注释块比隐约指代的许可证的效力要强得多。
如果你是要发布在自己的网站上,步骤也差不多。先创建 `LICENSE.txt` 文件,放入许可证,再表明许可证出处。
### 开源代码的不同之处
开源代码和专有代码的一个主要区别是开源代码写出来就是为了给别人看的。我是个 40 多岁的系统管理员,已经写过许许多多的代码。最开始我写代码是为了工作,为了解决公司的问题,所以其中大部分代码都是专有代码。这种代码的目的很简单,只要能在特定场合通过特定方式发挥作用就行。
开源代码则大不相同。在写开源代码时,你知道它可能会被用于各种各样的环境中。也许你的用例的环境条件很局限,但你仍旧希望它能在各种环境下发挥理想的效果。不同的人使用这些代码时会出现各种用例,你会看到各类冲突,还有你没有考虑过的思路。虽然代码不一定要满足所有人,但至少应该得体地处理他们遇到的问题,就算解决不了,也可以转换回常见的逻辑,不会给使用者添麻烦。(例如“第 583 行出现零除错误”就不能作为错误地提供命令行参数的响应结果)
你的源代码也可能逼疯你,尤其是在你一遍又一遍地修改错误的函数或是子过程后,终于出现了你希望的结果,这时你不会叹口气就继续下一个任务,你会把过程清理干净,因为你不会愿意别人看出你一遍遍尝试的痕迹。比如你会把 `$variable`、`$lol` 全都换成有意义的 `$iterationcounter``$modelname`。这意味着你要认真专业地进行注释(尽管对于你所处的背景知识热度来说它并不难懂),因为你期望有更多的人可以使用你的代码。
这个过程难免有些痛苦沮丧,毕竟这不是你常做的事,会有些不习惯。但它会使你成为一位更好的程序员,也会让你的代码升华。即使你的项目只有你一位贡献者,清理代码也会节约你后期的很多工作,相信我一年后你再看你的 app 代码时,你会庆幸自己写下的是 `$modelname`,还有清晰的注释,而不是什么不知名的数列,甚至连 `$lol` 也不是。
### 你并不是为你一人而写
开源的真正核心并不是那些代码,而是社区。更大的社区的项目维持时间更长,也更容易为人们所接受。因此不仅要加入社区,还要多多为社区发展贡献思路,让自己的项目能够为社区所用。
蝙蝠侠为了完成目标暗中独自花了很大功夫,你用不着这样,你可以登录 Twitter、Reddit或者给你项目的相关人士发邮件发布你正在筹备新项目的消息仔细聊聊项目的设计初衷和你的计划让大家一起帮忙向大家征集数据输入类似的使用案例把这些信息整合起来用在你的代码里。你不用接受所有的建议和请求但你要对它有个大概把握这样在你之后完善时可以躲过一些陷阱。
发布了首次通告这个过程还不算完整。如果你希望大家能够接受你的作品并且使用它,你就要以此为初衷来设计。公众说不定可以帮到你,你不必对公开这件事如临大敌。所以不要闭门造车,既然你是为大家而写,那就开设一个真实、公开的项目,想象你在社区的帮助和监督下,认真地一步步完成它。
### 建立项目的方式
你可以在 GitHub、GitLab 或 BitBucket 上免费注册账号来管理你的项目。注册之后,创建知识库,建立 `README` 文件,分配一个许可证,一步步写入代码。这样可以帮你建立好习惯,让你之后和现实中的团队一起工作时,也能目的清晰地朝着目标稳妥地开展工作。这样你做得越久,就越有兴趣 —— 通常会有用户先对你的项目产生兴趣。
用户会开始提一些问题,这会让你开心也会让你不爽,你应该亲切礼貌地对待他们,就算他们很多人对项目有很多误解甚至根本不知道你的项目做的是什么,你也应该礼貌专业地对待。一方面,你可以引导他们,让他们了解你在干什么。另一方面,他们也会慢慢地将你带入更大的社区。
如果你的项目很受用户青睐,总会有高级开发者出现,并表示出兴趣。这也许是好事,也可能激怒你。最开始你可能只会做简单的问题修复,但总有一天你会收到拉取请求,有可能是硬编码或特殊用例(可能会让项目变得难以维护),它可能改变你项目的作用域,甚至改变你项目的初衷。你需要学会分辨哪个有贡献,根据这个决定合并哪个,婉拒哪个。
### 我们为什么要开源?
开源听起来任务繁重,它也确实是这样。但它对你也有很多好处。它可以在无形之中磨练你,让你写出纯净持久的代码,也教会你与人沟通,团队协作。对于一个志向远大的专业开发者来说,它是最好的简历素材。你的未来雇主很有可能点开你的仓库,了解你的能力范围;而社区项目的开发者也有可能给你带来工作。
最后,为开源工作,意味着个人的提升,因为你在做的事不是为了你一个人,这比养活自己重要得多。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/3/what-open-source-programming
作者:[Jim Salter][a]
译者:[Valoniakim](https://github.com/Valoniakim)
校对:[wxy](https://github.com/wxy)、[pityonline](https://github.com/pityonline)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/jim-salter
[1]: https://opensource.com/tags/licensing
[2]: https://choosealicense.com/
[3]: https://choosealicense.com/licenses/apache-2.0/
[4]: https://choosealicense.com/licenses/gpl-3.0/
[5]: https://choosealicense.com/licenses/unlicense/

View File

@ -0,0 +1,142 @@
如何从 Linux 的文件管理器中加密文件
======
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/encryption.jpg?itok=Pk3_x5hz)
Linux 桌面版和服务器版具有卓越的安全性。然而这并不意味着你可以放松警惕。你应该一直认为你的数据总是很快就会被破坏。也就是说,你可能需要使用各种加密工具。比如 GnuPG它可以让你加密和解密文件等更多功能。GnuPG 的一个问题是一些用户不想在命令行输入那么复杂的命令。如果是这样的话,你可以转向桌面文件管理器。许多 Linux 桌面版包含了简易的加密和解密文件的功能,如果这种功能没有内置,那么也是很容易添加的。
我将引导你完成从三个流行的 Linux 文件管理器中对文件进行加密和解密过程:
* Nautilus (即 GNOME Files
* Dolphin
* Thunar
### 安装 GnuPG
在我们讨论如何处理这个问题之前,我们必须确保你的系统包含了必要的基本组件 —— [GnuPG][1]。大多数发行版本都包含 GnuPG。 在某些偶然情况下,你使用的是没有自带 GnuPG 的发行版,以下是安装方法:
* 基于 Ubuntu 的发行版: `sudo apt install gnupg`
* 基于 Fedora 的发行版: `sudo yum install gnupg`
* openSUSE `sudo zypper in gnupg`
* 基于 Arch 的发行版:`sudo pacman -S gnupg`
无论你是刚刚安装了 GnuPG还是默认安装的你都必须创建一个 GPG 密钥才能使用。每个桌面版都使用不同的 GUI 工具完成这个工作(或者甚至根本没有包含一个完成这个任务的 GUI 工具),所以让我们从命令行中创建这个密钥。打开终端窗口并输入以下指令:
```
gpg --gen-key
```
然后,你将被要求回答以下问题。除非你有充分的理由,否则你可以接受默认值:
* 你想要哪种密钥?
* 你想要多长的密钥?
* 密钥有效期?
一旦你回答了这些问题,输入 `y` 来表示答案是正确的。接下来你需要提供以下信息:
* 真实姓名。
* Email 地址。
* 备注。
完成上述操作后,然后在提示的时候输入 `O` (即 ok。然后你将被要求为新密钥输入一个密码。一旦系统收集到了足够的熵你需要在桌面上做一些工作才能做到这一点LCTT 译注:比如随便敲击键盘),你的密钥就会被创建,然后你就可以开始工作了。
让我们看看如何从文件管理器中加密/解密文件:
### Nautilus
让我们从默认的 GNOME 文件管理器开始因为它是最简单的。Nautilus 不需要额外安装什么或额外的工作就可以从精心设计的界面内加密/解密文件。一旦你创建完 gpg 密钥后,就可以打开文件管理器,导航到包含要加密的文件的目录,右键单击要加密的文件,然后从菜单中选择 “Encrypt” 图1
![nautilus][3]
*图1从 Nautilus 中加密文件。*
你将被要求选择一个收件人(或者收件人列表 —— 图2。注意收件人将是那些你已经导入了公钥的用户。选择所需的密钥然后从签名信息下拉列表中选择你的密钥电子邮件地址
![nautilus][6]
*图2选择收件人和签名者。*
注意:你还可以选择仅使用密码来加密文件。如果文件将保留在你的本地机器上,这一点非常重要(稍后将详细介绍)。一旦你设置好加密后,单击 “OK” 并(在提示时)输入 gpg 密钥的密码。文件将被加密(现在文件名以 .gpg 结尾)并保存在工作目录中。现在你可以将加密后的文件发送给在加密过程中已选择的收件人。
比如说(有你的公钥的)某人已经给你发送了一个加密文件。保存该文件,打开文件管理器,导航到该文件所在的目录,右击这个加密文件,选择 “Open With Decrypt File”给文件一个新名称不带 .gpg 的扩展名然后单击“Save”。当提示时输入你的 gpg 密钥的密码,该文件就会被解密并准备使用。
### Dolphin
在 KDE 前端,必须安装一个软件包才能使用 Dolphin 文件管理器进行加密/解密。 登录到你的 KDE 桌面,打开终端窗口,然后输入以下命令(我正在使用 Neon 进行演示。如果你的发行版不是基于 Ubuntu 的,则必须相应地更改命令):
```
sudo apt install kgpg
```
安装完毕后,注销并重新登录 KDE 桌面。 你可以打开 Dolphin 并右键单击要加密的文件。 由于这是你第一次使用 kgpg因此你必须完成快速设置向导不言自明。当完成该向导后你可以返回该文件右键单击它图3然后选择 Encrypt File。
![Dolphin][8]
*图3在 Dolphin 中加密文件。*
系统将提示你选择用于加密的密钥图4。 进行选择并单击 “OK”。 该文件将被加密,而且你已准备好将其发送给收件人。
注意:使用 KDE 的 Dolphin 文件管理器市,你无法仅使用密码加密。
![Dolphin][10]
*图4选择要加密的收件人。*
如果你收到来自有你的公钥的用户的加密文件(或者你有一个自己加密的文件),请打开 Dolphin导航到相关文件双击该文件为该文件指定一个新名称 ,键入加密密码并单击 “OK”。 你现在可以读取到新解密的文件。 如果你使用自己的密钥加密了该文件,则不会提示你键入密码(因为它已经被存储了)。
### Thunar
Thunar 文件管理器有点棘手。 没有任何额外的软件包可供安装;相反,你需要为了加密创建新的自定义操作。完成此操作后,你将能够在文件管理器中执行此操作。
要创建自定义操作,请打开 Thunar 文件管理器,然后单击 “Edit > Configure Custom Actions”。 在所得到的窗口中,单击 “+” 按钮图5并为加密操作输入以下内容
- 名称:加密
- 描述:文件加密
- 命令:`gnome-terminal -x gpg --encrypt --recipient f`
单击 “OK” 以保存此操作。
![Thunar][12]
*图5在Thunar中创建自定义操作。*
注意:如果 gnome-terminal 不是你的默认终端,请替换该命令以打开你的默认终端。
你还可以创建仅使用密码(而非密钥)加密的操作。 为此,该操作的详细动作将会是以下内容:
- 名称:加密密码
- 说明:仅使用密码加密
- 命令:`gnome-terminal -x gpg -c f`
你不需要为解密过程创建一个自定义操作,因为 Thunar 已经知道如何处理一个加密文件。 要解密文件,只需(在 Thunar 中)右键单击它,选择 “Open With Decrypt File”为解密文件命名然后在提示时键入加密密码。 Viola你的加密文件已被解密并可以使用。
### 一个警告
请注意:如果你使用自己的密钥加密自己的文件,则无需输入加密密码来解密它们(因为你的公钥已存储)。 但是,如果你收到(拥有你的公钥的)其他人的文件,则需要输入你的密码。 如果你想要存储自己的加密文件,而不是使用密钥来加密它们,请使用仅使用密码加密。 Nautilus 和Thunar但不是 KDE可以做到这一点。 通过选择密码加密(通过密钥加密),当你解密文件时,它将始终提示你输入密码。
### 其他文件管理器
还有很多其它的文件管理器,它们中的一些可以使用加密,有些则不能。 你很有可能正在使用这三种工具中的一种,因此不仅可以将加密 / 解密添加到上下文菜单,而且是非常容易。 尝试一下,看看它是否会使加密和解密的过程变得更容易。
从 Linux 基金会和 edX 免费提供的[“Linux 介绍”][13]课程了解更多关于 Linux 的信息。
--------------------------------------------------------------------------------
via: https://www.linux.com/learn/intro-to-linux/2018/3/how-encrypt-files-within-file-manager
作者:[JACK WALLEN][a]
译者:[Auk7f7](https://github.com/Auk7f7)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linux.com/users/jlwallen
[1]:https://www.gnupg.org/
[3]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/nautilus.jpg?itok=ae7Gtj60 "nautilus"
[4]:https://www.linux.com/licenses/category/used-permission
[6]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/nautilus_2.jpg?itok=3ht7j63n "nautilus"
[8]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/kde_0.jpg?itok=KSTctVw0 "Dolphin"
[10]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/kde_2.jpg?itok=CeqWikNl "Dolphin"
[12]:https://www.linux.com/sites/lcom/files/styles/rendered_file/public/thunar.jpg?itok=fXcHk08B "Thunar"
[13]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux

View File

@ -0,0 +1,198 @@
如何在 Linux 中压缩和解压缩文件
======
![](https://www.ostechnix.com/wp-content/uploads/2018/03/compress-720x340.jpg)
当在备份重要文件和通过网络发送大文件的时候,对文件进行压缩非常有用。请注意,压缩一个已经压缩过的文件会增加额外开销,因此你将会得到一个更大一些的文件。所以,请不要压缩已经压缩过的文件。在 GNU/Linux 中,有许多程序可以用来压缩和解压缩文件。在这篇教程中,我们仅学习其中两个应用程序。
在类 Unix 系统中,最常见的用来压缩文件的程序是:
1. gzip
2. bzip2
### 1. 使用 gzip 程序来压缩和解压缩文件
`gzip` 是一个使用 Lempel-Ziv 编码LZ77算法来压缩和解压缩文件的实用工具。
#### 1.1 压缩文件
如果要压缩一个名为 `ostechnix.txt` 的文件,使之成为 gzip 格式的压缩文件,那么只需运行如下命令:
```
$ gzip ostechnix.txt
```
上面的命令运行结束之后,将会出现一个名为 `ostechnix.txt.gz` 的 gzip 格式压缩文件,代替了原始的 `ostechnix.txt` 文件。
`gzip` 命令还可以有其他用法。一个有趣的例子是,我们可以将一个特定命令的输出通过管道传递,然后作为 `gzip` 程序的输入来创建一个压缩文件。看下面的命令:
```
$ ls -l Downloads/ | gzip > ostechnix.txt.gz
```
上面的命令将会创建一个 gzip 格式的压缩文件,文件的内容为 `Downloads` 目录的目录项。
#### 1.2 压缩文件并将输出写到新文件中(不覆盖原始文件)
默认情况下,`gzip` 程序会压缩给定文件,并以压缩文件替代原始文件。但是,你也可以保留原始文件,并将输出写到标准输出。比如,下面这个命令将会压缩 `ostechnix.txt` 文件,并将输出写入文件 `output.txt.gz`
```
$ gzip -c ostechnix.txt > output.txt.gz
```
类似地,要解压缩一个 `gzip` 格式的压缩文件并指定输出文件的文件名,只需运行:
```
$ gzip -c -d output.txt.gz > ostechnix1.txt
```
上面的命令将会解压缩 `output.txt.gz` 文件,并将输出写入到文件 `ostechnix1.txt` 中。在上面两个例子中,原始文件均不会被删除。
#### 1.3 解压缩文件
如果要解压缩 `ostechnix.txt.gz` 文件,并以原始未压缩版本的文件来代替它,那么只需运行:
```
$ gzip -d ostechnix.txt.gz
```
我们也可以使用 `gunzip` 程序来解压缩文件:
```
$ gunzip ostechnix.txt.gz
```
#### 1.4 在不解压缩的情况下查看压缩文件的内容
如果你想在不解压缩的情况下,使用 `gzip` 程序查看压缩文件的内容,那么可以像下面这样使用 `-c` 选项:
```
$ gunzip -c ostechnix1.txt.gz
```
或者,你也可以像下面这样使用 `zcat` 程序:
```
$ zcat ostechnix.txt.gz
```
你也可以通过管道将输出传递给 `less` 命令,从而一页一页的来查看输出,就像下面这样:
```
$ gunzip -c ostechnix1.txt.gz | less
$ zcat ostechnix.txt.gz | less
```
另外,`zless` 程序也能够实现和上面的管道同样的功能。
```
$ zless ostechnix1.txt.gz
```
#### 1.5 使用 gzip 压缩文件并指定压缩级别
`gzip` 的另外一个显著优点是支持压缩级别。它支持下面给出的 3 个压缩级别:
* **1** 最快 (最差)
* **9** 最慢 (最好)
* **6** 默认级别
要压缩名为 `ostechnix.txt` 的文件,使之成为“最好”压缩级别的 gzip 压缩文件,可以运行:
```
$ gzip -9 ostechnix.txt
```
#### 1.6 连接多个压缩文件
我们也可以把多个需要压缩的文件压缩到同一个文件中。如何实现呢?看下面这个例子。
```
$ gzip -c ostechnix1.txt > output.txt.gz
$ gzip -c ostechnix2.txt >> output.txt.gz
```
上面的两个命令将会压缩文件 `ostechnix1.txt``ostechnix2.txt`,并将输出保存到一个文件 `output.txt.gz` 中。
你可以通过下面其中任何一个命令,在不解压缩的情况下,查看两个文件 `ostechnix1.txt``ostechnix2.txt` 的内容:
```
$ gunzip -c output.txt.gz
$ gunzip -c output.txt
$ zcat output.txt.gz
$ zcat output.txt
```
如果你想了解关于 `gzip` 的更多细节,请参阅它的 man 手册。
```
$ man gzip
```
### 2. 使用 bzip2 程序来压缩和解压缩文件
`bzip2``gzip` 非常类似,但是 `bzip2` 使用的是 Burrows-Wheeler 块排序压缩算法,并使用<ruby>哈夫曼<rt>Huffman</rt></ruby>编码。使用 `bzip2` 压缩的文件以 “.bz2” 扩展结尾。
正如我上面所说的, `bzip2` 的用法和 `gzip` 几乎完全相同。只需在上面的例子中将 `gzip` 换成 `bzip2`,将 `gunzip` 换成 `bunzip2`,将 `zcat` 换成 `bzcat` 即可。
要使用 `bzip2` 压缩一个文件,并以压缩后的文件取而代之,只需运行:
```
$ bzip2 ostechnix.txt
```
如果你不想替换原始文件,那么可以使用 `-c` 选项,并把输出写入到新文件中。
```
$ bzip2 -c ostechnix.txt > output.txt.bz2
```
如果要解压缩文件,则运行:
```
$ bzip2 -d ostechnix.txt.bz2
```
或者,
```
$ bunzip2 ostechnix.txt.bz2
```
如果要在不解压缩的情况下查看一个压缩文件的内容,则运行:
```
$ bunzip2 -c ostechnix.txt.bz2
```
或者,
```
$ bzcat ostechnix.txt.bz2
```
如果你想了解关于 `bzip2` 的更多细节,请参阅它的 man 手册。
```
$ man bzip2
```
### 总结
在这篇教程中,我们学习了 `gzip``bzip2` 程序是什么,并通过 GNU/Linux 下的一些例子学习了如何使用它们来压缩和解压缩文件。接下来,我们将要学习如何在 Linux 中将文件和目录归档。
干杯!
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/how-to-compress-and-decompress-files-in-linux/
作者:[SK][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[ucasFL](https://github.com/ucasFL)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.ostechnix.com/author/sk/

View File

@ -0,0 +1,155 @@
用 Hugo 30 分钟搭建静态博客
======
> 了解 Hugo 如何使构建网站变得有趣。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/programming-code-keyboard-laptop-music-headphones.png?itok=EQZ2WKzy)
你是不是强烈地想搭建博客来将自己对软件框架等的探索学习成果分享呢?你是不是面对缺乏指导文档而一团糟的项目就有一种想去改变它的冲动呢?或者换个角度,你是不是十分期待能创建一个属于自己的个人博客网站呢?
很多人在想搭建博客之前都有一些严重的迟疑顾虑感觉自己缺乏内容管理系统CMS的相关知识更缺乏时间去学习这些知识。现在如果我说不用花费大把的时间去学习 CMS 系统、学习如何创建一个静态网站、更不用操心如何去强化网站以防止它受到黑客攻击的问题,你就可以在 30 分钟之内创建一个博客?你信不信?利用 Hugo 工具,就可以实现这一切。
![](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/hugo_1.png?itok=JgxBSOBG)
Hugo 是一个基于 Go 语言开发的静态站点生成工具。也许你会问,为什么选择它?
* 无需数据库、无需需要各种权限的插件、无需跑在服务器上的底层平台,更没有额外的安全问题。
* 都是静态站点,因此拥有轻量级、快速响应的服务性能。此外,所有的网页都是在部署的时候生成,所以服务器负载很小。
* 极易操作的版本控制。一些 CMS 平台使用它们自己的版本控制软件VCS或者在网页上集成 Git 工具。而 Hugo所有的源文件都可以用你所选的 VCS 软件来管理。
### 0-5 分钟:下载 Hugo生成一个网站
直白的说Hugo 使得写一个网站又一次变得有趣起来。让我们来个 30 分钟计时,搭建一个网站。
为了简化 Hugo 安装流程,这里直接使用 Hugo 可执行安装文件。
1. 下载和你操作系统匹配的 Hugo [版本][2]
2. 压缩包解压到指定路径,例如 windows 系统的 `C:\hugo_dir` 或者 Linux 系统的 `~/hugo_dir` 目录;下文中的变量 `${HUGO_HOME}` 所指的路径就是这个安装目录;
3. 打开命令行终端,进入安装目录:`cd ${HUGO_HOME}`
4. 确认 Hugo 已经启动:
* Unix 系统:`${HUGO_HOME}/[hugo version]`
* Windows 系统:`${HUGO_HOME}\[hugo.exe version]`例如cmd 命令行中输入:`c:\hugo_dir\hugo version`。
为了书写上的简化,下文中的 `hugo` 就是指 hugo 可执行文件所在的路径(包括可执行文件),例如命令 `hugo version` 就是指命令 `c:\hugo_dir\hugo version` 。(LCTT 译注:可以把 hugo 可执行文件所在的路径添加到系统环境变量下,这样就可以直接在终端中输入 `hugo version`
如果命令 `hugo version` 报错,你可能下载了错误的版本。当然,有很多种方法安装 Hugo更多详细信息请查阅 [官方文档][3]。最稳妥的方法就是把 Hugo 可执行文件放在某个路径下,然后执行的时候带上路径名
5. 创建一个新的站点来作为你的博客,输入命令:`hugo new site awesome-blog`
6. 进入新创建的路径下: `cd awesome-blog`
恭喜你!你已经创建了自己的新博客。
### 5-10 分钟:为博客设置主题
Hugo 中你可以自己构建博客的主题或者使用网上已经有的一些主题。这里选择 [Kiera][4] 主题,因为它简洁漂亮。按以下步骤来安装该主题:
1. 进入主题所在目录:`cd themes`
2. 克隆主题:`git clone https://github.com/avianto/hugo-kiera kiera`。如果你没有安装 Git 工具:
* 从 [Github][5] 上下载 hugo 的 .zip 格式的文件;
* 解压该 .zip 文件到你的博客主题 `theme` 路径;
* 重命名 `hugo-kiera-master``kiera`
3. 返回博客主路径:`cd awesome-blog`
4. 激活主题;通常来说,主题(包括 Kiera都自带文件夹 `exampleSite`,里面存放了内容配置的示例文件。激活 Kiera 主题需要拷贝它提供的 `config.toml` 到你的博客下:
* Unix 系统:`cp themes/kiera/exampleSite/config.toml .`
* Windows 系统:`copy themes\kiera\exampleSite\config.toml .`
* 选择 `Yes` 来覆盖原有的 `config.toml`
5. 可选操作 )你可以选择可视化的方式启动服务器来验证主题是否生效:`hugo server -D` 然后在浏览器中输入 `http://localhost:1313`。可用通过在终端中输入 `Crtl+C` 来停止服务器运行。现在你的博客还是空的,但这也给你留了写作的空间。它看起来如下所示:
![](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/hugo_2.png?itok=PINOIOSU)
你已经成功的给博客设置了主题!你可以在官方 [Hugo 主题][4] 网站上找到上百种漂亮的主题供你使用。
### 10-20 分钟:给博客添加内容
对于碗来说它是空的时候用处最大可以用来盛放东西但对于博客来说不是这样空博客几乎毫无用处。在这一步你将会给博客添加内容。Hugo 和 Kiera 主题都为这个工作提供了方便性。按以下步骤来进行你的第一次提交:
1. archetypes 将会是你的内容模板。
2. 添加主题中的 archtypes 至你的博客:
* Unix 系统: `cp themes/kiera/archetypes/* archetypes/`
* Windows 系统:`copy themes\kiera\archetypes\* archetypes\`
* 选择 `Yes` 来覆盖原来的 `default.md` 内容架构类型
3. 创建博客 posts 目录:
* Unix 系统: `mkdir content/posts`
* Windows 系统: `mkdir content\posts`
4. 利用 Hugo 生成你的 post
* Unix 系统:`hugo nes posts/first-post.md`;
* Windows 系统:`hugo new posts\first-post.md`;
5. 在文本编辑器中打开这个新建的 post 文件:
* Unix 系统:`gedit content/posts/first-post.md`
* Windows 系统:`notepadd content\posts\first-post.md`
此刻,你可以疯狂起来了。注意到你的提交文件中包括两个部分。第一部分是以 `+++` 符号分隔开的。它包括了提交文档的主要数据,例如名称、时间等。在 Hugo 中,这叫做前缀。在前缀之后,才是正文。下面编辑第一个提交文件内容:
```
+++
title = "First Post"
date = 2018-03-03T13:23:10+01:00
draft = false
tags = ["Getting started"]
categories = []
+++
Hello Hugo world! No more excuses for having no blog or documentation now!
```
现在你要做的就是启动你的服务器:`hugo server -D`;然后打开浏览器,输入 `http://localhost:1313/`
![](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/hugo_3.png?itok=I-_v0qLx)
### 20-30 分钟:调整网站
前面的工作很完美,但还有一些问题需要解决。例如,简单地命名你的站点:
1. 终端中按下 `Ctrl+C` 以停止服务器。
2. 打开 `config.toml`,编辑博客的名称,版权,你的姓名,社交网站等等。
当你再次启动服务器后,你会发现博客私人订制味道更浓了。不过,还少一个重要的基础内容:主菜单。快速的解决这个问题。返回 `config.toml` 文件,在末尾插入如下一段:
```
[[menu.main]]
name = "Home" #Name in the navigation bar
weight = 10 #The larger the weight, the more on the right this item will be
url = "/" #URL address
[[menu.main]]
name = "Posts"
weight = 20
url = "/posts/"
```
上面这段代码添加了 `Home``Posts` 到主菜单中。你还需要一个 `About` 页面。这次是创建一个 `.md` 文件,而不是编辑 `config.toml` 文件:
1. 创建 `about.md` 文件:`hugo new about.md` 。注意它是 `about.md`,不是 `posts/about.md`。该页面不是博客提交内容,所以你不想它显示到博客内容提交当中吧。
2. 用文本编辑器打开该文件,输入如下一段:
```
+++
title = "About"
date = 2018-03-03T13:50:49+01:00
menu = "main" #Display this page on the nav menu
weight = "30" #Right-most nav item
meta = "false" #Do not display tags or categories
+++
> Waves are the practice of the water. Shunryu Suzuki
```
当你启动你的服务器并输入:`http://localhost:1313/`,你将会看到你的博客。(访问我 Gihub 主页上的 [例子][6] )如果你想让文章的菜单栏和 Github 相似,给 `themes/kiera/static/css/styles.css` 打上这个 [补丁][7]。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/3/start-blog-30-minutes-hugo
作者:[Marek Czernek][a] 
译者:[jrg](https://github.com/jrglinux) 
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/mczernek
[1]:https://gohugo.io/
[2]:https://github.com/gohugoio/hugo/releases
[3]:https://gohugo.io/getting-started/installing/
[4]:https://themes.gohugo.io/
[5]:https://github.com/avianto/hugo-kiera
[6]:https://m-czernek.github.io/awesome-blog/
[7]:https://github.com/avianto/hugo-kiera/pull/18/files

View File

@ -0,0 +1,258 @@
理解 ext4 等 Linux 文件系统
======
> 了解 ext4 的历史,包括其与 ext3 和之前的其它文件系统之间的区别。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003499_01_linux11x_cc.png?itok=XMDOouJR)
目前的大部分 Linux 文件系统都默认采用 ext4 文件系统,正如以前的 Linux 发行版默认使用 ext3、ext2 以及更久前的 ext。
对于不熟悉 Linux 或文件系统的朋友而言,你可能不清楚 ext4 相对于上一版本 ext3 带来了什么变化。你可能还想知道在一连串关于替代的文件系统例如 Btrfs、XFS 和 ZFS 不断被发布的情况下ext4 是否仍然能得到进一步的发展。
在一篇文章中,我们不可能讲述文件系统的所有方面,但我们尝试让你尽快了解 Linux 默认文件系统的发展历史,包括它的诞生以及未来发展。
我仔细研究了维基百科里的各种关于 ext 文件系统文章、kernel.org 的 wiki 中关于 ext4 的条目以及结合自己的经验写下这篇文章。
### ext 简史
#### MINIX 文件系统
在有 ext 之前,使用的是 MINIX 文件系统。如果你不熟悉 Linux 历史,那么可以理解为 MINIX 是用于 IBM PC/AT 微型计算机的一个非常小的类 Unix 系统。Andrew Tannenbaum 为了教学的目的而开发了它,并于 1987 年发布了源代码(以印刷版的格式!)。
![](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/ibm_pc_at.jpg?itok=Tfk3hQYB)
*IBM 1980 中期的 PC/AT[MBlairMartin](https://commons.wikimedia.org/wiki/File:IBM_PC_AT.jpg)[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.en)*
虽然你可以细读 MINIX 的源代码但实际上它并不是自由开源软件FOSS。出版 Tannebaum 著作的出版商要求你花 69 美元的许可费来运行 MINIX而这笔费用包含在书籍的费用中。尽管如此在那时来说非常便宜并且 MINIX 的使用得到迅速发展,很快超过了 Tannebaum 当初使用它来教授操作系统编码的意图。在整个 20 世纪 90 年代,你可以发现 MINIX 的安装在世界各个大学里面非常流行。而此时,年轻的 Linus Torvalds 使用 MINIX 来开发原始 Linux 内核,并于 1991 年首次公布,而后在 1992 年 12 月在 GPL 开源协议下发布。
但是等等,这是一篇以 *文件系统* 为主题的文章不是吗是的MINIX 有自己的文件系统,早期的 Linux 版本依赖于它。跟 MINIX 一样Linux 的文件系统也如同玩具那般小 —— MINIX 文件系统最多能处理 14 个字符的文件名,并且只能处理 64MB 的存储空间。到了 1991 年,一般的硬盘尺寸已经达到了 40-140 MB。很显然Linux 需要一个更好的文件系统。
#### ext
当 Linus 开发出刚起步的 Linux 内核时Rémy Card 从事第一代的 ext 文件系统的开发工作。ext 文件系统在 1992 年首次实现并发布 —— 仅在 Linux 首次发布后的一年!—— ext 解决了 MINIX 文件系统中最糟糕的问题。
1992 年的 ext 使用在 Linux 内核中的新虚拟文件系统VFS抽象层。与之前的 MINIX 文件系统不同的是ext 可以处理高达 2 GB 存储空间并处理 255 个字符的文件名。
但 ext 并没有长时间占统治地位,主要是由于它原始的时间戳(每个文件仅有一个时间戳,而不是今天我们所熟悉的有 inode、最近文件访问时间和最新文件修改时间的时间戳。仅仅一年后ext2 就替代了它。
#### ext2
Rémy 很快就意识到 ext 的局限性,所以一年后他设计出 ext2 替代它。当 ext 仍然根植于 “玩具” 操作系统时ext2 从一开始就被设计为一个商业级文件系统,沿用 BSD 的 Berkeley 文件系统的设计原理。
ext2 提供了 GB 级别的最大文件大小和 TB 级别的文件系统大小,使其在 20 世纪 90 年代的地位牢牢巩固在文件系统大联盟中。很快它被广泛地使用,无论是在 Linux 内核中还是最终在 MINIX 中,且利用第三方模块可以使其应用于 MacOS 和 Windows。
但这里仍然有一些问题需要解决ext2 文件系统与 20 世纪 90 年代的大多数文件系统一样,如果在将数据写入到磁盘的时候,系统发生崩溃或断电,则容易发生灾难性的数据损坏。随着时间的推移,由于碎片(单个文件存储在多个位置,物理上其分散在旋转的磁盘上),它们也遭受了严重的性能损失。
尽管存在这些问题,但今天 ext2 还是用在某些特殊的情况下 —— 最常见的是,作为便携式 USB 驱动器的文件系统格式。
#### ext3
1998 年,在 ext2 被采用后的 6 年后Stephen Tweedie 宣布他正在致力于改进 ext2。这成了 ext3并于 2001 年 11 月在 2.4.15 内核版本中被采用到 Linux 内核主线中。
![Packard Bell 计算机][2]
*20 世纪 90 年代中期的 Packard Bell 计算机,[Spacekid][3][CC0][4]*
在大部分情况下ext2 在 Linux 发行版中工作得很好,但像 FAT、FAT32、HFS 和当时的其它文件系统一样 —— 在断电时容易发生灾难性的破坏。如果在将数据写入文件系统时候发生断电,则可能会将其留在所谓 *不一致* 的状态 —— 事情只完成一半而另一半未完成。这可能导致大量文件丢失或损坏,这些文件与正在保存的文件无关甚至导致整个文件系统无法卸载。
ext3 和 20 世纪 90 年代后期的其它文件系统,如微软的 NTFS使用 *日志* 来解决这个问题。日志是磁盘上的一种特殊的分配区域,其写入被存储在事务中;如果该事务完成磁盘写入,则日志中的数据将提交给文件系统自身。如果系统在该操作提交前崩溃,则重新启动的系统识别其为未完成的事务而将其进行回滚,就像从未发生过一样。这意味着正在处理的文件可能依然会丢失,但文件系统 *本身* 保持一致,且其它所有数据都是安全的。
在使用 ext3 文件系统的 Linux 内核中实现了三个级别的日志记录方式:<ruby>日记<rt>journal</rt></ruby><ruby>顺序<rt>ordered</rt></ruby><ruby>回写<rt>writeback</rt></ruby>
* **日记** 是最低风险模式,在将数据和元数据提交给文件系统之前将其写入日志。这可以保证正在写入的文件与整个文件系统的一致性,但其显著降低了性能。
* **顺序** 是大多数 Linux 发行版默认模式;顺序模式将元数据写入日志而直接将数据提交到文件系统。顾名思义,这里的操作顺序是固定的:首先,元数据提交到日志;其次,数据写入文件系统,然后才将日志中关联的元数据更新到文件系统。这确保了在发生崩溃时,那些与未完整写入相关联的元数据仍在日志中,且文件系统可以在回滚日志时清理那些不完整的写入事务。在顺序模式下,系统崩溃可能导致在崩溃期间文件的错误被主动写入,但文件系统它本身 —— 以及未被主动写入的文件 —— 确保是安全的。
* **回写** 是第三种模式 —— 也是最不安全的日志模式。在回写模式下,像顺序模式一样,元数据会被记录到日志,但数据不会。与顺序模式不同,元数据和数据都可以以任何有利于获得最佳性能的顺序写入。这可以显著提高性能,但安全性低很多。尽管回写模式仍然保证文件系统本身的安全性,但在崩溃或崩溃之前写入的文件很容易丢失或损坏。
跟之前的 ext2 类似ext3 使用 16 位内部寻址。这意味着对于有着 4K 块大小的 ext3 在最大规格为 16 TiB 的文件系统中可以处理的最大文件大小为 2 TiB。
#### ext4
Theodore Ts'o是当时 ext3 主要开发人员)在 2006 年发表的 ext4于两年后在 2.6.28 内核版本中被加入到了 Linux 主线。
Ts'o 将 ext4 描述为一个显著扩展 ext3 但仍然依赖于旧技术的临时技术。他预计 ext4 终将会被真正的下一代文件系统所取代。
![](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/dell_precision_380_workstation.jpeg?itok=3EjYXY2i)
*Dell Precision 380 工作站,[Lance Fisher](https://commons.wikimedia.org/wiki/File:Dell_Precision_380_Workstation.jpeg)[CC BY-SA 2.0](https://creativecommons.org/licenses/by-sa/2.0/deed.en)*
ext4 在功能上与 ext3 在功能上非常相似,但支持大文件系统,提高了对碎片的抵抗力,有更高的性能以及更好的时间戳。
### ext4 vs ext3
ext3 和 ext4 有一些非常明确的差别,在这里集中讨论下。
#### 向后兼容性
ext4 特地设计为尽可能地向后兼容 ext3。这不仅允许 ext3 文件系统原地升级到 ext4也允许 ext4 驱动程序以 ext3 模式自动挂载 ext3 文件系统,因此使它无需单独维护两个代码库。
#### 大文件系统
ext3 文件系统使用 32 位寻址,这限制它仅支持 2 TiB 文件大小和 16 TiB 文件系统系统大小(这是假设在块大小为 4 KiB 的情况下,一些 ext3 文件系统使用更小的块大小,因此对其进一步被限制)。
ext4 使用 48 位的内部寻址,理论上可以在文件系统上分配高达 16 TiB 大小的文件,其中文件系统大小最高可达 1000000 TiB1 EiB。在早期 ext4 的实现中有些用户空间的程序仍然将其限制为最大大小为 16 TiB 的文件系统,但截至 2011 年e2fsprogs 已经直接支持大于 16 TiB 大小的 ext4 文件系统。例如,红帽企业 Linux 在其合同上仅支持最高 50 TiB 的 ext4 文件系统,并建议 ext4 卷不超过 100 TiB。
#### 分配方式改进
ext4 在将存储块写入磁盘之前对存储块的分配方式进行了大量改进,这可以显著提高读写性能。
##### 区段
<ruby>区段<rt>extent</rt></ruby>是一系列连续的物理块 (最多达 128 MiB假设块大小为 4 KiB可以一次性保留和寻址。使用区段可以减少给定文件所需的 inode 数量,并显著减少碎片并提高写入大文件时的性能。
##### 多块分配
ext3 为每一个新分配的块调用一次块分配器。当多个写入同时打开分配器时很容易导致严重的碎片。然而ext4 使用延迟分配,这允许它合并写入并更好地决定如何为尚未提交的写入分配块。
##### 持久的预分配
在为文件预分配磁盘空间时大部分文件系统必须在创建时将零写入该文件的块中。ext4 允许替代使用 `fallocate()`,它保证了空间的可用性(并试图为它找到连续的空间),而不需要先写入它。这显著提高了写入和将来读取流和数据库应用程序的写入数据的性能。
##### 延迟分配
这是一个耐人寻味而有争议性的功能。延迟分配允许 ext4 等待分配将写入数据的实际块直到它准备好将数据提交到磁盘。相比之下即使数据仍然在往写入缓存中写入ext3 也会立即分配块。)
当缓存中的数据累积时,延迟分配块允许文件系统对如何分配块做出更好的选择,降低碎片(写入,以及稍后的读)并显著提升性能。然而不幸的是,它 *增加* 了还没有专门调用 `fsync()` 方法(当程序员想确保数据完全刷新到磁盘时)的程序的数据丢失的可能性。
假设一个程序完全重写了一个文件:
```
fd=open("file", O_TRUNC); write(fd, data); close(fd);
```
使用旧的文件系统,`close(fd);` 足以保证 `file` 中的内容刷新到磁盘。即使严格来说,写不是事务性的,但如果文件关闭后发生崩溃,则丢失数据的风险很小。
如果写入不成功(由于程序上的错误、磁盘上的错误、断电等),文件的原始版本和较新版本都可能丢失数据或损坏。如果其它进程在写入文件时访问文件,则会看到损坏的版本。如果其它进程打开文件并且不希望其内容发生更改 —— 例如,映射到多个正在运行的程序的共享库。这些进程可能会崩溃。
为了避免这些问题,一些程序员完全避免使用 `O_TRUNC`。相反,他们可能会写入一个新文件,关闭它,然后将其重命名为旧文件名:
```
fd=open("newfile"); write(fd, data); close(fd); rename("newfile", "file");
```
*没有* 延迟分配的文件系统下,这足以避免上面列出的潜在的损坏和崩溃问题:因为 `rename()` 是原子操作,所以它不会被崩溃中断;并且运行的程序将继续引用旧的文件。现在 `file` 的未链接版本只要有一个打开的文件文件句柄即可。但是因为 ext4 的延迟分配会导致写入被延迟和重新排序,`rename("newfile", "file")` 可以在 `newfile` 的内容实际写入磁盘内容之前执行,这出现了并行进行再次获得 `file` 坏版本的问题。
为了缓解这种情况Linux 内核(自版本 2.6.30)尝试检测这些常见代码情况并强制立即分配。这会减少但不能防止数据丢失的可能性 —— 并且它对新文件没有任何帮助。如果你是一位开发人员,请注意:保证数据立即写入磁盘的唯一方法是正确调用 `fsync()`
#### 无限制的子目录
ext3 仅限于 32000 个子目录ext4 允许无限数量的子目录。从 2.6.23 内核版本开始ext4 使用 HTree 索引来减少大量子目录的性能损失。
#### 日志校验
ext3 没有对日志进行校验,这给处于内核直接控制之外的磁盘或自带缓存的控制器设备带来了问题。如果控制器或具自带缓存的磁盘脱离了写入顺序,则可能会破坏 ext3 的日记事务顺序,从而可能破坏在崩溃期间(或之前一段时间)写入的文件。
理论上,这个问题可以使用写入<ruby>障碍<rt>barrier</rt></ruby> —— 在安装文件系统时,你在挂载选项设置 `barrier=1`,然后设备就会忠实地执行 `fsync` 一直向下到底层硬件。通过实践,可以发现存储设备和控制器经常不遵守写入障碍 —— 提高性能(和跟竞争对手比较的性能基准),但增加了本应该防止数据损坏的可能性。
对日志进行校验和允许文件系统崩溃后第一次挂载时意识到其某些条目是无效或无序的。因此,这避免了回滚部分条目或无序日志条目的错误,并进一步损坏的文件系统 —— 即使部分存储设备假做或不遵守写入障碍。
#### 快速文件系统检查
在 ext3 下,在 `fsck` 被调用时会检查整个文件系统 —— 包括已删除或空文件。相比之下ext4 标记了 inode 表未分配的块和扇区,从而允许 `fsck` 完全跳过它们。这大大减少了在大多数文件系统上运行 `fsck` 的时间,它实现于内核 2.6.24。
#### 改进的时间戳
ext3 提供粒度为一秒的时间戳。虽然足以满足大多数用途但任务关键型应用程序经常需要更严格的时间控制。ext4 通过提供纳秒级的时间戳,使其可用于那些企业、科学以及任务关键型的应用程序。
ext3 文件系统也没有提供足够的位来存储 2038 年 1 月 18 日以后的日期。ext4 在这里增加了两个位,将 [Unix 纪元][5]扩展了 408 年。如果你在公元 2446 年读到这篇文章,你很有可能已经转移到一个更好的文件系统 —— 如果你还在测量自 1970 年 1 月 1 日 00:00UTC以来的时间这会让我死后得以安眠。
#### 在线碎片整理
ext2 和 ext3 都不直接支持在线碎片整理 —— 即在挂载时会对文件系统进行碎片整理。ext2 有一个包含的实用程序 `e2defrag`,它的名字暗示 —— 它需要在文件系统未挂载时脱机运行。(显然,这对于根文件系统来说非常有问题。)在 ext3 中的情况甚至更糟糕 —— 虽然 ext3 比 ext2 更不容易受到严重碎片的影响,但 ext3 文件系统运行 `e2defrag` 可能会导致灾难性损坏和数据丢失。
尽管 ext3 最初被认为“不受碎片影响”,但对同一文件(例如 BitTorrent采用大规模并行写入过程的过程清楚地表明情况并非完全如此。一些用户空间的手段和解决方法例如 [Shake][6],以这样或那样方式解决了这个问题 —— 但它们比真正的、文件系统感知的、内核级碎片整理过程更慢并且在各方面都不太令人满意。
ext4 通过 `e4defrag` 解决了这个问题,且是一个在线、内核模式、文件系统感知、块和区段级别的碎片整理实用程序。
### 正在进行的 ext4 开发
ext4正如 Monty Python 中瘟疫感染者曾经说过的那样,“我还没死呢!”虽然它的[主要开发人员][7]认为它只是一个真正的[下一代文件系统][8]的权宜之计,但是在一段时间内,没有任何可能的候选人准备好(由于技术或许可问题)部署为根文件系统。
在未来的 ext4 版本中仍然有一些关键功能要开发,包括元数据校验和、一流的配额支持和大分配块。
#### 元数据校验和
由于 ext4 具有冗余超级块,因此为文件系统校验其中的元数据提供了一种方法,可以自行确定主超级块是否已损坏并需要使用备用块。可以在没有校验和的情况下,从损坏的超级块恢复 —— 但是用户首先需要意识到它已损坏,然后尝试使用备用方法手动挂载文件系统。由于在某些情况下,使用损坏的主超级块安装文件系统读写可能会造成进一步的损坏,即使是经验丰富的用户也无法避免,这也不是一个完美的解决方案!
与 Btrfs 或 ZFS 等下一代文件系统提供的极其强大的每块校验和相比ext4 的元数据校验和的功能非常弱。但它总比没有好。虽然校验 **所有的事情** 都听起来很简单!—— 事实上,将校验和与文件系统连接到一起有一些重大的挑战;请参阅[设计文档][9]了解详细信息。
#### 一流的配额支持
等等,配额?!从 ext2 出现的那天开始我们就有了这些!是的,但它们一直都是事后的添加的东西,而且它们总是犯傻。这里可能不值得详细介绍,但[设计文档][10]列出了配额将从用户空间移动到内核中的方式,并且能够更加正确和高效地执行。
#### 大分配块
随着时间的推移,那些讨厌的存储系统不断变得越来越大。由于一些固态硬盘已经使用 8K 硬件块大小,因此 ext4 对 4K 模块的当前限制越来越受到限制。较大的存储块可以显著减少碎片并提高性能,代价是增加“松弛”空间(当你只需要块的一部分来存储文件或文件的最后一块时留下的空间)。
你可以在[设计文档][11]中查看详细说明。
### ext4 的实际限制
ext4 是一个健壮、稳定的文件系统。如今大多数人都应该在用它作为根文件系统,但它无法处理所有需求。让我们简单地谈谈你不应该期待的一些事情 —— 现在或可能在未来:
虽然 ext4 可以处理高达 1 EiB 大小(相当于 1,000,000 TiB大小的数据但你 *真的* 不应该尝试这样做。除了能够记住更多块的地址之外,还存在规模上的问题。并且现在 ext4 不会处理(并且可能永远不会)超过 50-100 TiB 的数据。
ext4 也不足以保证数据的完整性。随着日志记录的重大进展又回到了 ext3 的那个时候,它并未涵盖数据损坏的许多常见原因。如果数据已经在磁盘上被[破坏][12] —— 由于故障硬件,宇宙射线的影响(是的,真的),或者只是数据随时间衰减 —— ext4 无法检测或修复这种损坏。
基于上面两点ext4 只是一个纯 *文件系统*,而不是存储卷管理器。这意味着,即使你有多个磁盘 —— 也就是奇偶校验或冗余,理论上你可以从 ext4 中恢复损坏的数据,但无法知道使用它是否对你有利。虽然理论上可以在不同的层中分离文件系统和存储卷管理系统而不会丢失自动损坏检测和修复功能,但这不是当前存储系统的设计方式,并且它将给新设计带来重大挑战。
### 备用文件系统
在我们开始之前,提醒一句:要非常小心,没有任何备用的文件系统作为主线内核的一部分而内置和直接支持!
即使一个文件系统是 *安全的*,如果在内核升级期间出现问题,使用它作为根文件系统也是非常可怕的。如果你没有充分的理由通过一个 chroot 去使用替代介质引导耐心地操作内核模块、grub 配置和 DKMS……不要在一个很重要的系统中去掉预留的根文件。
可能有充分的理由使用你的发行版不直接支持的文件系统 —— 但如果你这样做,我强烈建议你在系统启动并可用后再安装它。(例如,你可能有一个 ext4 根文件系统,但是将大部分数据存储在 ZFS 或 Btrfs 池中。)
#### XFS
XFS 与非 ext 文件系统在 Linux 中的主线中的地位一样。它是一个 64 位的日志文件系统,自 2001 年以来内置于 Linux 内核中,为大型文件系统和高度并发性提供了高性能(即大量的进程都会立即写入文件系统)。
从 RHEL 7 开始XFS 成为 Red Hat Enterprise Linux 的默认文件系统。对于家庭或小型企业用户来说,它仍然有一些缺点 —— 最值得注意的是,重新调整现有 XFS 文件系统是一件非常痛苦的事情,不如创建另一个并复制数据更有意义。
虽然 XFS 是稳定的且是高性能的,但它和 ext4 之间没有足够具体的最终用途差异,以值得推荐在非默认(如 RHEL7的任何地方使用它除非它解决了对 ext4 的特定问题,例如大于 50 TiB 容量的文件系统。
XFS 在任何方面都不是 ZFS、Btrfs 甚至 WAFL一个专有的 SAN 文件系统)的“下一代”文件系统。就像 ext4 一样,它应该被视为一种更好的方式的权宜之计。
#### ZFS
ZFS 由 Sun Microsystems 开发,以 zettabyte 命名 —— 相当于 1 万亿 GB —— 因为它理论上可以解决大型存储系统。
作为真正的下一代文件系统ZFS 提供卷管理(能够在单个文件系统中处理多个单独的存储设备),块级加密校验和(允许以极高的准确率检测数据损坏),[自动损坏修复][12](其中冗余或奇偶校验存储可用),[快速异步增量复制][13],内联压缩等,[以及更多][14]。
从 Linux 用户的角度来看ZFS 的最大问题是许可证问题。ZFS 许可证是 CDDL 许可证,这是一种与 GPL 冲突的半许可的许可证。关于在 Linux 内核中使用 ZFS 的意义存在很多争议,其争议范围从“它是 GPL 违规”到“它是 CDDL 违规”到“它完全没问题,它还没有在法庭上进行过测试。”最值得注意的是,自 2016 年以来 Canonical 已将 ZFS 代码内联在其默认内核中,而且目前尚无法律挑战。
此时,即使我作为一个非常狂热于 ZFS 的用户,我也不建议将 ZFS 作为 Linux 的根文件系统。如果你想在 Linux 上利用 ZFS 的优势,用 ext4 设置一个小的根文件系统,然后将 ZFS 用在你剩余的存储上,把数据、应用程序以及你喜欢的东西放在它上面 —— 但把 root 分区保留在 ext4 上,直到你的发行版明确支持 ZFS 根目录。
#### Btrfs
Btrfs 是 B-Tree Filesystem 的简称,通常发音为 “butter” —— 由 Chris Mason 于 2007 年在 Oracle 任职期间发布。Btrfs 旨在跟 ZFS 有大部分相同的目标,提供多种设备管理、每块校验、异步复制、直列压缩等,[还有更多][8]。
截至 2018 年Btrfs 相当稳定,可用作标准的单磁盘文件系统,但可能不应该依赖于卷管理器。与许多常见用例中的 ext4、XFS 或 ZFS 相比,它存在严重的性能问题,其下一代功能 —— 复制、多磁盘拓扑和快照管理 —— 可能非常多,其结果可能是从灾难性地性能降低到实际数据的丢失。
Btrfs 的维持状态是有争议的SUSE Enterprise Linux 在 2015 年采用它作为默认文件系统,而 Red Hat 于 2017 年宣布它从 RHEL 7.4 开始不再支持 Btrfs。可能值得注意的是该产品支持 Btrfs 部署用作单磁盘文件系统,而不是像 ZFS 中的多磁盘卷管理器,甚至 Synology 在它的存储设备使用 Btrfs但是它在传统 Linux 内核 RAIDmdraid之上分层来管理磁盘。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/4/ext4-filesystem
作者:[Jim Salter][a]
译者:[HardworkFish](https://github.com/HardworkFish)
校对:[wxy](https://github.com/wxy), [pityonline](https://github.com/pityonline)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/jim-salter
[1]: https://opensource.com/file/391546
[2]: https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/packard_bell_pc.jpg?itok=VI8dzcwp (Packard Bell computer)
[3]: https://commons.wikimedia.org/wiki/File:Old_packard_bell_pc.jpg
[4]: https://creativecommons.org/publicdomain/zero/1.0/deed.en
[5]: https://en.wikipedia.org/wiki/Unix_time
[6]: https://vleu.net/shake/
[7]: http://www.linux-mag.com/id/7272/
[8]: https://arstechnica.com/information-technology/2014/01/bitrot-and-atomic-cows-inside-next-gen-filesystems/
[9]: https://ext4.wiki.kernel.org/index.php/Ext4_Metadata_Checksums
[10]: https://ext4.wiki.kernel.org/index.php/Design_For_1st_Class_Quota_in_Ext4
[11]: https://ext4.wiki.kernel.org/index.php/Design_for_Large_Allocation_Blocks
[12]: https://en.wikipedia.org/wiki/Data_degradation#Visual_example_of_data_degradation
[13]: https://arstechnica.com/information-technology/2015/12/rsync-net-zfs-replication-to-the-cloud-is-finally-here-and-its-fast/
[14]: https://arstechnica.com/information-technology/2014/02/ars-walkthrough-using-the-zfs-next-gen-filesystem-on-linux/

View File

@ -0,0 +1,110 @@
FreeDOS 的简单介绍
======
> 学习如何穿行于 C:\ 提示符下,就像上世纪 90 年代的 DOS 高手一样。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/freedos-fish-laptop-color.png?itok=vfv_Lpph)
FreeDOS 是一个古老的操作系统,但是对于多数人而言它又是陌生的。在 1994 年,我和几个开发者一起 [开发了 FreeDOS][1] —— 这是一个完整、自由、兼容 DOS 的操作系统,你可以用它来玩经典的 DOS 游戏、运行过时的商业软件或者开发嵌入式系统。任何在 MS-DOS 下工作的程序在 FreeDOS 下也可以运行。
在 1994 年,任何一个曾经使用过微软的商业版 MS-DOS 的人都会迅速地熟悉 FreeDOS。这是设计而为之的FreeDOS 尽可能地去模仿 MS-DOS。结果1990 年代的 DOS 用户能够直接转换到 FreeDOS。但是时代变了。今天开源的开发者们对于 Linux 命令行更熟悉,或者他们可能倾向于像 [GNOME][2] 一样的图形桌面环境,这导致 FreeDOS 命令行界面最初看起来像个异类。
新的用户通常会问,“我已经安装了 [FreeDOS][3],但是如何使用呢?”。如果你之前并没有使用过 DOS那么闪烁的 `C:\>` DOS 提示符看起来会有点不太友好,而且可能有点吓人。这份 FreeDOS 的简单介绍将带你起步。它只提供了基础:如何浏览以及如何查看文件。如果你想了解比这里提及的更多的知识,访问 [FreeDOS 维基][4]。
### DOS 提示符
首先,让我们看一下空的提示符以及它的含义。
![](https://opensource.com/sites/default/files/u128651/0-prompt.png)
DOS 是在个人电脑从软盘运行时期创建的一个“<ruby>磁盘操作系统<rt>disk operating system</rt></ruby>”。甚至当电脑支持硬盘了,在 1980 年代和 1990 年代,频繁地在不同的驱动器之间切换也是很普遍的。举例来说,你可能想将最重要的文件都备份一份拷贝到软盘中。
DOS 使用一个字母来指代每个驱动器。早期的电脑仅拥有两个软盘驱动器,他们被分配了 `A:``B:` 盘符。硬盘上的第一个分区盘符是 `C:` ,然后其它的盘符依次这样分配下去。提示符中的 `C:` 表示你正在使用第一个硬盘的第一个分区。
从 1983 年的 PC-DOS 2.0 开始DOS 也支持目录和子目录,非常类似 Linux 文件系统中的目录和子目录。但是跟 Linux 不一样的是DOS 目录名由 `\` 分隔而不是 `/`。将这个与驱动器字母合起来看,提示符中的 `C:\` 表示你正在 `C:` 盘的顶端或者“根”目录。
`>` 符号是提示你输入 DOS 命令的地方,就像众多 Linux shell 的 `$`。`>` 前面的部分告诉你当前的工作目录,然后你在 `>` 提示符这输入命令。
### 在 DOS 中找到你的使用方式
在 DOS 中浏览目录的基本方式和你在 Linux 命令行下的步骤非常相似。你仅需要记住少数的命令。
#### 显示一个目录
当你想要查看当前目录的内容时,使用 `DIR` 命令。因为 DOS 命令是大小写不敏感的,你也可以输入 `dir`。默认地DOS 会显示每个文件和子目录的细节,包括了名字、扩展类型、大小以及最后一次更改的日期和时间。
![](https://opensource.com/sites/default/files/u128651/1-dir.png)
如果你不想显示单个文件大小的额外细节,你可以在 `DIR` 命令中使用 `/w` 选项来显示一个“宽”的目录列表。注意Linux 用户使用连字号(`-`)或者双连字号(`--`)来开始命令行选项,而 DOS 使用斜线字符(`/`)。
![](https://opensource.com/sites/default/files/u128651/2-dirw.png)
你可以将特定子目录的路径名作为参数传递给 `DIR` 命令来查看它。此外,另一个与 Linux 系统的区别是 Linux 文件和目录是大小写敏感的,而 DOS 下的名称是大小写不敏感的。DOS 通常将文件和目录使用全部大写的方式显示,不过你可以等同地用小写格式来使用它们。
![](https://opensource.com/sites/default/files/u128651/3-dir-fdos.png)
#### 切换当前工作目录
一旦你能够查看一个目录的内容,你就能够“移动到”任何其它的目录。在 DOS 上,使用 `CHDIR` 命令来切换工作目录,也可以简写为 `CD`。你可以使用类似 `CD CHOICE` 的命令进入到一个子目录或者使用 `CD \FDOS\DOC\CHOICE` 进入到一个新的路径。
![](https://opensource.com/sites/default/files/u128651/5-dir-choice.png)
就像在 Linux 命令行DOS 使用 `.` 来表示当前目录,而 `..` 表示父目录(当前目录的上一级)。你可以将这些组合起来使用。比如,`CD ..` 进入到父目录,然后 `CD ..\..` 由当前目录做两个“向上”目录级别的操作。
![](https://opensource.com/sites/default/files/u128651/11-cd.png)
FreeDOS 也从 Linux 那借鉴了一些特性:你可以使用 `CD -` 跳转回之前的工作目录。在你进入一个新的路径做完一件事之后,想要回退到之前工作状态的情况下,这会很方便。
#### 切换当前工作盘符
在 Linux 下,“磁盘”的概念是隐藏的。在 Linux 和其它 Unix 系统中,你“挂载”磁盘到一个目录,例如 `/backup`,或者系统自动帮你完成,比如 `/var/run/media/user/flashdrive`。但是 DOS 是一个相对简单的系统。使用 DOS你必须自行更改工作磁盘。
记住 DOS 分配第一块硬盘的第一个分区为 `C:` 盘,然后这样依次分配其它盘符。在现代系统中,人们很少将硬盘分割成多个 DOS 分区;他们简单地使用整个磁盘或者尽可能多地分配给 DOS。如今 `C:` 通常是第一块硬盘,而 `D:` 通常是另一块硬盘或者 CD-ROM 驱动器。其它的网络磁盘驱动器也可以被映射到别的盘符,比如 `E:` 或者 `Z:` 或者任何你想要的组织方式。
在 DOS 下切换磁盘很容易。只要在命令行输入盘符后附加一个冒号(`:`),然后 DOS 就会切换到该工作磁盘。举例来说,在我的 [QEMU][5] 系统上,我将 `D:` 设置到我的 Linux 主目录下的一个共享目录,那里存放了各种我想测试的 DOS 应用程序和游戏的安装文件。
![](https://opensource.com/sites/default/files/u128651/8-d-dirw.png)
小心不要尝试切换到一个不存在的磁盘。DOS 可能会将它设置为工作磁盘,但是如果你尝试在那做任何事,你将会遇到略微臭名昭著的“<ruby>退出、重试、失败<rt>Abort, Retry, Fail</rt></ruby>” DOS 错误信息。
![](https://opensource.com/sites/default/files/u128651/9-e-fail.png)
### 其它可以尝试的事情
使用 `CD``DIR` 命令,你就拥有了基础的浏览 DOS 能力。这些命令允许你查找 DOS 目录并查看其他子目录和文件的存在。一旦你熟悉基础浏览操作,你还可以尝试其它的这些基础 DOS 命令:
* `MKDIR``MD` 创建新的目录
* `RMDIR``RD` 删除目录
* `TREE` 以树状格式显示目录和子目录列表
* `TYPE``MORE` 显示文件内容
* `RENAME``REN` 重命名文件
* `DEL``ERASE` 删除文件
* `EDIT` 编辑文件
* `CLS` 清除屏幕
如果这些还不够,你可以在 FreeDOS 维基上面找到[所有 DOS 命令][6]的清单。
在 FreeDOS 下,针对每个命令你都能够使用 `/?` 参数来获取简要的说明。举例来说,`EDIT /?` 会告诉你编辑器的用法和选项。或者你可以输入 `HELP` 来使用交互式帮助系统。
像任何一个 DOS 一样FreeDOS 被认为是一个简单的操作系统。仅使用一些基本命令就可以轻松浏览 DOS 文件系统。那么,启动一个 QEMU 会话,安装 FreeDOS然后尝试一下 DOS 命令行界面吧。也许它现在看起来就没那么吓人了。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/4/gentle-introduction-freedos
作者:[Jim Hall][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[icecoobe](https://github.com/icecoobe)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/jim-hall
[1]:https://opensource.com/article/17/10/freedos
[2]:https://opensource.com/article/17/8/gnome-20-anniversary
[3]:http://www.freedos.org/
[4]:http://wiki.freedos.org/
[5]:https://www.qemu.org/
[6]:http://wiki.freedos.org/wiki/index.php/Dos_commands

View File

@ -0,0 +1,476 @@
理解监测指标,并使用 Python 去监测它们
======
> 通过学习这些关键的术语和概念来理解 Python 应用监测。
![Understanding metrics and monitoring with Python](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/metrics_graph_stats_blue.png?itok=OKCc_60D "Understanding metrics and monitoring with Python")
当我第一次看到术语“<ruby>计数器<rt>counter</rt></ruby>”和“<ruby>计量器<rt>gauge</rt></ruby>”和使用颜色及标记着“平均数”和“大于 90%”的数字图表时,我的反应之一是逃避。就像我看到它们一样,我并不感兴趣,因为我不理解它们是干什么的或如何去使用。因为我的工作不需要我去注意它们,它们被我完全无视。
这都是在两年以前的事了。随着我的职业发展,我希望去了解更多关于我们的网络应用程序的知识,而那个时候就是我开始去学习<ruby>监测指标<rt>metrics</rt></ruby>的时候。
我的理解监测的学习之旅共有三个阶段(到目前为止),它们是:
* 阶段 1什么王顾左右
* 阶段 2没有指标我们真的是瞎撞。
* 阶段 3出现不合理的指标我们该如何做
我现在处于阶段 2我将分享到目前为止我学到了些什么。我正在向阶段 3 进发,在本文结束的位置我提供了一些我正在使用的学习资源。
我们开始吧!
### 需要的软件
在文章中讨论时用到的 demo 都可以在 [我的 GitHub 仓库][6] 中找到。你需要安装 docker 和 docker-compose 才能使用它们。
### 为什么要监测?
关于监测的主要原因是:
* 理解 _正常的__不正常的_ 系统和服务的特征
* 做容量规划、弹性伸缩
* 有助于排错
* 了解软件/硬件改变的效果
* 测量响应中的系统行为变化
* 当系统出现意外行为时发出警报
### 指标和指标类型
从我们的用途来看,一个**指标**就是在一个给定*时间*点上的某些数量的 _测量_ 值。博客文章的总点击次数、参与讨论的总人数、在缓存系统中数据没有被找到的次数、你的网站上的已登录用户数 —— 这些都是指标的例子。
它们总体上可以分为三类:
#### 计数器
以你的个人博客为例。你发布一篇文章后,过一段时间后,你希望去了解有多少点击量,这是一个只会增加的数字。这就是一个<ruby>计数器<rt>counter</rt></ruby>指标。在你的博客文章的生命周期中,它的值从 0 开始增加。用图表来表示,一个计数器看起来应该像下面的这样:
![Counter metric](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/counter-graph.png?itok=BZYrB-Hn "Counter metric")
*一个计数器指标总是在增加的。*
#### 计量器
如果你想去跟踪你的博客每天或每周的点击量,而不是基于时间的总点击量。这种指标被称为一个<ruby>计量器<rt>gauge</rt></ruby>,它的值可上可下。用图表来表示,一个计量器看起来应该像下面的样子:
![gauge metric](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/gauge-graph.png?itok=UA4u4cwz "gauge metric")
*一个计量器指标可以增加或减少。*
一个计量器的值在某些时间窗口内通常有一个<ruby>最大值<rt>ceiling</rt></ruby><ruby最小值<rt>floor</rt></ruby>
#### 柱状图和计时器
<ruby>柱状图<rt>histogram</rt></ruby>(在 Prometheus 中这么叫它)或<ruby>计时器<rt> timer</rt></ruby>(在 StatsD 中这么叫它)是一个跟踪 _已采样的观测结果_ 的指标。不像一个计数器类或计量器类指标,柱状图指标的值并不是显示为上或下的样式。我知道这可能并没有太多的意义,并且可能和一个计量器图看上去没有什么不同。它们的不同之处在于,你期望使用柱状图数据来做什么,而不是与一个计量器图做比较。因此,监测系统需要知道那个指标是一个柱状图类型,它允许你去做哪些事情。
![Histogram metric](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/histogram-graph.png?itok=cHI1v7Ly "Histogram metric")
*一个柱状图指标可以增加或减少。*
### Demo 1计算和报告指标
[Demo 1][7] 是使用 [Flask][8] 框架写的一个基本的 web 应用程序。它演示了我们如何去 _计算__报告_ 指标。
`src` 目录中有 `app.py``src/helpers/middleware.py` 应用程序,包含以下内容:
```
from flask import request
import csv
import time
def start_timer():
    request.start_time = time.time()
def stop_timer(response):
    # convert this into milliseconds for statsd
    resp_time = (time.time() - request.start_time)*1000
    with open('metrics.csv', 'a', newline='') as f:
        csvwriter = csv.writer(f)
        csvwriter.writerow([str(int(time.time())), str(resp_time)])
    return response
def setup_metrics(app):
    app.before_request(start_timer)
    app.after_request(stop_timer)
```
当在应用程序中调用 `setup_metrics()` 时,它配置在一个请求被处理之前调用 `start_timer()` 函数,然后在该请求处理之后、响应发送之前调用 `stop_timer()` 函数。在上面的函数中,我们写了时间戳并用它来计算处理请求所花费的时间。
当我们在 `demo1` 目录中运行 `docker-compose up`,它会启动这个 web 应用程序,然后在一个客户端容器中可以生成一些对 web 应用程序的请求。你将会看到创建了一个 `src/metrics.csv` 文件,它有两个字段:`timestamp` 和 `request_latency`
通过查看这个文件,我们可以推断出两件事情:
* 生成了很多数据
* 没有观测到任何与指标相关的特征
没有观测到与指标相关的特征,我们就不能说这个指标与哪个 HTTP 端点有关联,或这个指标是由哪个应用程序的节点所生成的。因此,我们需要使用合适的元数据去限定每个观测指标。
### 《Statistics 101》
LCTT 译注:这是一本统计学入门教材的名字)
假如我们回到高中数学,我们应该回忆起一些统计术语,虽然不太确定,但应该包括平均数、中位数、百分位和柱状图。我们来简要地回顾一下它们,不用去管它们的用法,就像是在上高中一样。
#### 平均数
<ruby>平均数<rt>mean</rt></ruby>即一系列数字的平均值是将数字汇总然后除以列表的个数。3、2 和 10 的平均数是 (3+2+10)/3 = 5。
#### 中位数
<ruby>中位数<rt>median</rt></ruby>是另一种类型的平均但它的计算方式不同它是列表从小到大排序反之亦然后取列表的中间数字。以我们上面的列表中2、3、10中位数是 3。计算并不是非常直观它取决于列表中数字的个数。
#### 百分位
<ruby>百分位<rt>percentile</rt></ruby>是指那个百(千)分比数字低于我们给定的百分数的程度。在一些场景中,它是指这个测量值低于我们数据的百(千)分比数字的程度。比如,上面列表中 95% 是 9.29999。百分位的测量范围是 0 到 100不包括。0% 是一组数字的最小分数。你可能会想到它的中位数是 50%,它的结果是 3。
一些监测系统将百分位称为 `upper_X`,其中 _X_ 就是百分位;`upper 90` 指的是在 90% 的位置的值。
#### 分位数
“q-分位数”是将有 _N_ 个数的集合等分为 `qN` 级。`q` 的取值范围为 0 到 1全部都包括。当 `q` 取值为 0.5 时,值就是中位数。(<ruby>分位数<rt>quantile</rt></ruby>)和百分位数的关系是,分位数值 `q` 等于 `100` 百分位值。
#### 柱状图
<ruby柱状图<rt>histogram</rt></ruby>这个指标我们前面学习过它是监测系统中一个_实现细节_。在统计学中一个柱状图是一个将数据分组为 _桶_ 的图表。我们来考虑一个人为的不同示例:阅读你的博客的人的年龄。如果你有一些这样的数据,并想将它进行大致的分组,绘制成的柱状图将看起来像下面的这样:
![Histogram graph](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/histogram.png?itok=gqfhjB8p "Histogram graph")
#### 累积柱状图
一个<ruby>累积柱状图<rt>cumulative histogram</rt></ruby>也是一个柱状图它的每个桶的数包含前一个桶的数因此命名为_累积_。将上面的数据集做成累积柱状图后看起来应该是这样的
![Cumulative histogram](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/cumulative-histogram.png?itok=wIGQdZnT "Cumulative histogram")
#### 我们为什么需要做统计?
在上面的 Demo 1 中,我们注意到在我们报告指标时,这里生成了许多数据。当我们将它们用于指标时我们需要做统计,因为它们实在是太多了。我们需要的是整体行为,我们没法去处理单个值。我们预期展现出来的值的行为应该是代表我们观察的系统的行为。
### Demo 2在指标上增加特征
在我们上面的的 Demo 1 应用程序中当我们计算和报告一个请求的延迟时它指向了一个由一些_特征_ 唯一标识的特定请求。下面是其中一些:
* HTTP 端点
* HTTP 方法
* 运行它的主机/节点的标识符
如果我们将这些特征附加到要观察的指标上,每个指标将有更多的内容。我们来解释一下 [Demo 2][9] 中添加到我们的指标上的特征。
在写入指标时,`src/helpers/middleware.py` 文件将在 CSV 文件中写入多个列:
```
node_ids = ['10.0.1.1', '10.1.3.4']
def start_timer():
    request.start_time = time.time()
def stop_timer(response):
    # convert this into milliseconds for statsd
    resp_time = (time.time() - request.start_time)*1000
    node_id = node_ids[random.choice(range(len(node_ids)))]
    with open('metrics.csv', 'a', newline='') as f:
        csvwriter = csv.writer(f)
        csvwriter.writerow([
            str(int(time.time())), 'webapp1', node_id,
            request.endpoint, request.method, str(response.status_code),
            str(resp_time)
        ])
    return response
```
因为这只是一个演示,在报告指标时,我们将随意的报告一些随机 IP 作为节点的 ID。当我们在 `demo2` 目录下运行 `docker-compose up` 时,我们的结果将是一个有多个列的 CSV 文件。
#### 用 pandas 分析指标
我们将使用 [pandas][10] 去分析这个 CSV 文件。运行 `docker-compose up` 将打印出一个 URL我们将使用它来打开一个 [Jupyter][11] 会话。一旦我们上传 `Analysis.ipynb notebook` 到会话中,我们就可以将 CSV 文件读入到一个 pandas <ruby>数据帧<rt>DataFrame</rt></ruby>中:
```
import pandas as pd
metrics = pd.read_csv('/data/metrics.csv', index_col=0)
```
`index_col` 表明我们要指定时间戳作为索引。
因为每个特征我们都要在数据帧中添加一个列,因此我们可以基于这些列进行分组和聚合:
```
import numpy as np
metrics.groupby(['node_id', 'http_status']).latency.aggregate(np.percentile, 99.999)
```
更多内容请参考 Jupyter notebook 在数据上的分析示例。
### 我应该监测什么?
一个软件系统有许多的变量,这些变量的值在它的生命周期中不停地发生变化。软件是运行在某种操作系统上的,而操作系统同时也在不停地变化。在我看来,当某些东西出错时,你所拥有的数据越多越好。
我建议去监测的关键操作系统指标有:
* CPU 使用
* 系统内存使用
* 文件描述符使用
* 磁盘使用
还需要监测的其它关键指标根据你的软件应用程序不同而不同。
#### 网络应用程序
如果你的软件是一个监听客户端请求和为它提供服务的网络应用程序,需要测量的关键指标还有:
* 入站请求数(计数器)
* 未处理的错误(计数器)
* 请求延迟(柱状图/计时器)
* 排队时间,如果在你的应用程序中有队列(柱状图/计时器)
* 队列大小,如果在你的应用程序中有队列(计量器)
* 工作进程/线程用量(计量器)
如果你的网络应用程序在一个客户端请求的环境中向其它服务发送请求,那么它应该有一个指标去记录它与那个服务之间的通讯行为。需要监测的关键指标包括请求数、请求延迟、和响应状态。
#### HTTP web 应用程序后端
HTTP 应用程序应该监测上面所列出的全部指标。除此之外,还应该按 HTTP 状态代码分组监测所有非 200 的 HTTP 状态代码的大致数据。如果你的 web 应用程序有用户注册和登录功能,同时也应该为这个功能设置指标。
#### 长时间运行的进程
长时间运行的进程如 Rabbit MQ 消费者或任务队列的工作进程,虽然它们不是网络服务,它们以选取一个任务并处理它的工作模型来运行。因此,我们应该监测请求的进程数和这些进程的请求延迟。
不管是什么类型的应用程序,都有指标与合适的**元数据**相关联。
### 将监测集成到一个 Python 应用程序中
将监测集成到 Python 应用程序中需要涉及到两个组件:
* 更新你的应用程序去计算和报告指标
* 配置一个监测基础设施来容纳应用程序的指标,并允许去查询它们
下面是记录和报告指标的基本思路:
```
def work():
    requests += 1
    # report counter
    start_time = time.time()
   
    # < do the work >
    # calculate and report latency
    work_latency = time.time() - start_time
    ...
```
考虑到上面的模式,我们经常使用修饰符、内容管理器、中间件(对于网络应用程序)所带来的好处去计算和报告指标。在 Demo 1 和 Demo 2 中,我们在一个 Flask 应用程序中使用修饰符。
#### 指标报告时的拉取和推送模型
大体来说,在一个 Python 应用程序中报告指标有两种模式。在 _拉取_ 模型中,监测系统在一个预定义的 HTTP 端点上“刮取”应用程序。在_推送_ 模型中,应用程序发送数据到监测系统。
![Pull and push models](https://opensource.com/sites/default/files/styles/panopoly_image_original/public/u128651/pull_push_model.png?itok=U093wSy8 "Pull and push models")
工作在 _拉取_ 模型中的监测系统的一个例子是 [Prometheus][12]。而 [StatsD][13] 是 _推送_ 模型的一个例子。
#### 集成 StatsD
将 StatsD 集成到一个 Python 应用程序中,我们将使用 [StatsD Python 客户端][14],然后更新我们的指标报告部分的代码,调用合适的库去推送数据到 StatsD 中。
首先,我们需要去创建一个客户端实例:
```
statsd = statsd.StatsClient(host='statsd', port=8125, prefix='webapp1')
```
`prefix` 关键字参数将为通过这个客户端报告的所有指标添加一个指定的前缀。
一旦我们有了客户端,我们可以使用如下的代码为一个计时器报告值:
```
statsd.timing(key, resp_time)
```
增加计数器:
```
statsd.incr(key)
```
将指标关联到元数据上,一个键的定义为:`metadata1.metadata2.metric`,其中每个 metadataX 是一个可以进行聚合和分组的字段。
这个演示应用程序 [StatsD][15] 是将 statsd 与 Python Flask 应用程序集成的一个完整示例。
#### 集成 Prometheus
要使用 Prometheus 监测系统,我们使用 [Promethius Python 客户端][16]。我们将首先去创建有关的指标类对象:
```
REQUEST_LATENCY = Histogram('request_latency_seconds', 'Request latency',
    ['app_name', 'endpoint']
)
```
在上面的语句中的第三个参数是与这个指标相关的标识符。这些标识符是由与单个指标值相关联的元数据定义的。
去记录一个特定的观测指标:
```
REQUEST_LATENCY.labels('webapp', request.path).observe(resp_time)
```
下一步是在我们的应用程序中定义一个 Prometheus 能够刮取的 HTTP 端点。这通常是一个被称为 `/metrics` 的端点:
```
@app.route('/metrics')
def metrics():
    return Response(prometheus_client.generate_latest(), mimetype=CONTENT_TYPE_LATEST)
```
这个演示应用程序 [Prometheus][17] 是将 prometheus 与 Python Flask 应用程序集成的一个完整示例。
#### 哪个更好StatsD 还是 Prometheus
本能地想到的下一个问题便是:我应该使用 StatsD 还是 Prometheus关于这个主题我写了几篇文章你可能发现它们对你很有帮助
* [使用 Prometheus 监测多进程 Python 应用的方式][18]
* [使用 Prometheus 监测你的同步 Python 应用][19]
* [使用 Prometheus 监测你的异步 Python 应用][20]
### 指标的使用方式
我们已经学习了一些关于为什么要在我们的应用程序上配置监测的原因,而现在我们来更深入地研究其中的两个用法:报警和自动扩展。
#### 使用指标进行报警
指标的一个关键用途是创建警报。例如,假如过去的五分钟,你的 HTTP 500 的数量持续增加,你可能希望给相关的人发送一封电子邮件或页面提示。对于配置警报做什么取决于我们的监测设置。对于 Prometheus 我们可以使用 [Alertmanager][21],而对于 StatsD我们使用 [Nagios][22]。
#### 使用指标进行自动扩展
在一个云基础设施中,如果我们当前的基础设施供应过量或供应不足,通过指标不仅可以让我们知道,还可以帮我们实现一个自动伸缩的策略。例如,如果在过去的五分钟里,在我们服务器上的工作进程使用率达到 90%我们可以水平扩展。我们如何去扩展取决于云基础设施。AWS 的自动扩展,缺省情况下,扩展策略是基于系统的 CPU 使用率、网络流量、以及其它因素。然而,让基础设施伸缩的应用程序指标,我们必须发布 [自定义的 CloudWatch 指标][23]。
### 在多服务架构中的应用程序监测
当我们超越一个单应用程序架构时,比如当客户端的请求在响应被发回之前,能够触发调用多个服务,就需要从我们的指标中获取更多的信息。我们需要一个统一的延迟视图指标,这样我们就能够知道响应这个请求时每个服务花费了多少时间。这可以用 [分布式跟踪][24] 来实现。
你可以在我的博客文章 《[在你的 Python 应用程序中通过 Zipkin 引入分布式跟踪][25]》 中看到在 Python 中进行分布式跟踪的示例。
### 划重点
总之,你需要记住以下几点:
* 理解你的监测系统中指标类型的含义
* 知道监测系统需要的你的数据的测量单位
* 监测你的应用程序中的大多数关键组件
* 监测你的应用程序在它的大多数关键阶段的行为
以上要点是假设你不去管理你的监测系统。如果管理你的监测系统是你的工作的一部分,那么你还要考虑更多的问题!
### 其它资源
以下是我在我的监测学习过程中找到的一些非常有用的资源:
#### 综合的
* [监测分布式系统][26]
* [观测和监测最佳实践][27]
* [谁想使用秒?][28]
#### StatsD/Graphite
* [StatsD 指标类型][29]
#### Prometheus
* [Prometheus 指标类型][30]
* [Prometheus 计量器如何工作?][31]
* [为什么用 Prometheus 累积柱形图?][32]
* [在 Python 中监测批量作业][33]
* [Prometheus监测 SoundCloud][34]
### 避免犯错(即第 3 阶段的学习)
在我们学习监测的基本知识时,时刻注意不要犯错误是很重要的。以下是我偶然发现的一些很有见解的资源:
* [如何不测量延迟][35]
* [Prometheus 柱形图:悲伤的故事][36]
* [为什么平均值很讨厌,而百分位很棒][37]
* [对延迟的认知错误][38]
* [谁动了我的 99% 延迟?][39]
* [日志、指标和图形][40]
* [HdrHistogram一个更好的延迟捕获方式][41]
---
想学习更多内容,参与到 [PyCon Cleveland 2018][43] 上的 Amit Saha 的讨论,[Counter, gauge, upper 90—Oh my!][42]
## 关于作者
[![](https://opensource.com/sites/default/files/styles/profile_pictures/public/osdc_default_avatar_1.png?itok=mmbfqFXm)][44]
Amit Saha — 我是一名对基础设施、监测、和工具感兴趣的软件工程师。我是“用 Python 做数学”的作者和创始人,以及 Fedora Scientific Spin 维护者。
[关于我的更多信息][45]
* [Learn how you can contribute][46]
---
via: [https://opensource.com/article/18/4/metrics-monitoring-and-python][47]
作者: [Amit Saha][48] 选题者: [lujun9972][49] 译者: [qhwdw][50] 校对: [wxy][51]
本文由 [LCTT][52] 原创编译,[Linux中国][53] 荣誉推出
[1]: https://opensource.com/resources/python?intcmp=7016000000127cYAAQ
[2]: https://opensource.com/resources/python/ides?intcmp=7016000000127cYAAQ
[3]: https://opensource.com/resources/python/gui-frameworks?intcmp=7016000000127cYAAQ
[4]: https://opensource.com/tags/python?intcmp=7016000000127cYAAQ
[5]: https://developers.redhat.com/?intcmp=7016000000127cYAAQ
[6]: https://github.com/amitsaha/python-monitoring-talk
[7]: https://github.com/amitsaha/python-monitoring-talk/tree/master/demo1
[8]: http://flask.pocoo.org/
[9]: https://github.com/amitsaha/python-monitoring-talk/tree/master/demo2
[10]: https://pandas.pydata.org/
[11]: http://jupyter.org/
[12]: https://prometheus.io/
[13]: https://github.com/etsy/statsd
[14]: https://pypi.python.org/pypi/statsd
[15]: https://github.com/amitsaha/python-monitoring-talk/tree/master/statsd
[16]: https://pypi.python.org/pypi/prometheus_client
[17]: https://github.com/amitsaha/python-monitoring-talk/tree/master/prometheus
[18]: http://echorand.me/your-options-for-monitoring-multi-process-python-applications-with-prometheus.html
[19]: https://blog.codeship.com/monitoring-your-synchronous-python-web-applications-using-prometheus/
[20]: https://blog.codeship.com/monitoring-your-asynchronous-python-web-applications-using-prometheus/
[21]: https://github.com/prometheus/alertmanager
[22]: https://www.nagios.org/about/overview/
[23]: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html
[24]: http://opentracing.io/documentation/
[25]: http://echorand.me/introducing-distributed-tracing-in-your-python-application-via-zipkin.html
[26]: https://landing.google.com/sre/book/chapters/monitoring-distributed-systems.html
[27]: http://www.integralist.co.uk/posts/monitoring-best-practices/?imm_mid=0fbebf&amp;cmp=em-webops-na-na-newsltr_20180309
[28]: https://www.robustperception.io/who-wants-seconds/
[29]: https://github.com/etsy/statsd/blob/master/docs/metric_types.md
[30]: https://prometheus.io/docs/concepts/metric_types/
[31]: https://www.robustperception.io/how-does-a-prometheus-gauge-work/
[32]: https://www.robustperception.io/why-are-prometheus-histograms-cumulative/
[33]: https://www.robustperception.io/monitoring-batch-jobs-in-python/
[34]: https://developers.soundcloud.com/blog/prometheus-monitoring-at-soundcloud
[35]: https://www.youtube.com/watch?v=lJ8ydIuPFeU&amp;feature=youtu.be
[36]: http://linuxczar.net/blog/2017/06/15/prometheus-histogram-2/
[37]: https://www.dynatrace.com/news/blog/why-averages-suck-and-percentiles-are-great/
[38]: https://bravenewgeek.com/everything-you-know-about-latency-is-wrong/
[39]: https://engineering.linkedin.com/performance/who-moved-my-99th-percentile-latency
[40]: https://grafana.com/blog/2016/01/05/logs-and-metrics-and-graphs-oh-my/
[41]: http://psy-lob-saw.blogspot.com.au/2015/02/hdrhistogram-better-latency-capture.html
[42]: https://us.pycon.org/2018/schedule/presentation/133/
[43]: https://us.pycon.org/2018/
[44]: https://opensource.com/users/amitsaha
[45]: https://opensource.com/users/amitsaha
[46]: https://opensource.com/participate
[47]: https://opensource.com/article/18/4/metrics-monitoring-and-python
[48]: https://opensource.com/users/amitsaha
[49]: https://github.com/lujun9972
[50]: https://github.com/qhwdw
[51]: https://github.com/wxy
[52]: https://github.com/LCTT/TranslateProject
[53]: https://linux.cn/

View File

@ -0,0 +1,77 @@
Go 编译器介绍
======
`cmd/compile` 包含构成 Go 编译器主要的包。编译器在逻辑上可以被分为四个阶段,我们将简要介绍这几个阶段以及包含相应代码的包的列表。
在谈到编译器时,有时可能会听到<ruby>前端<rt>front-end</rt></ruby><ruby>后端<rt>back-end</rt></ruby>这两个术语。粗略地说,这些对应于我们将在此列出的前两个和后两个阶段。第三个术语<ruby>中间端<rt>middle-end</rt></ruby>通常指的是第二阶段执行的大部分工作。
请注意,`go/parser` 和 `go/types``go/*` 系列的包与编译器无关。由于编译器最初是用 C 编写的,所以这些 `go/*` 包被开发出来以便于能够写出和 `Go` 代码一起工作的工具,例如 `gofmt``vet`
需要澄清的是,名称 “gc” 代表 “<ruby>Go 编译器<rt>Go compiler</rt></ruby>”,与大写 GC 无关,后者代表<ruby>垃圾收集<rt>garbage collection</rt></ruby>
### 1、解析
* `cmd/compile/internal/syntax`<ruby>词法分析器<rt>lexer</rt></ruby><ruby>解析器<rt>parser</rt></ruby><ruby>语法树<rt>syntax tree</rt></ruby>
在编译的第一阶段源代码被标记化词法分析、解析语法分析并为每个源文件构造语法树LCTT 译注:这里标记指 token它是一组预定义的、能够识别的字符串通常由名字和值构成其中名字一般是词法的类别如标识符、关键字、分隔符、操作符、文字和注释等语法树以及下文提到的<ruby>抽象语法树<rt>Abstract Syntax Tree</rt></ruby>AST是指用树来表达程序设计语言的语法结构通常叶子节点是操作数其它节点是操作码
每个语法树都是相应源文件的确切表示,其中节点对应于源文件的各种元素,例如表达式、声明和语句。语法树还包括位置信息,用于错误报告和创建调试信息。
### 2、类型检查和 AST 变换
* `cmd/compile/internal/gc`(创建编译器 AST<ruby>类型检查<rt>type-checking</rt></ruby><ruby>AST 变换<rt>AST transformation</rt></ruby>
gc 包中包含一个继承自早期C 语言实现的版本的 AST 定义。所有代码都是基于它编写的,所以 gc 包必须做的第一件事就是将 syntax 包(定义)的语法树转换为编译器的 AST 表示法。这个额外步骤可能会在将来重构。
然后对 AST 进行类型检查。第一步是名字解析和类型推断,它们确定哪个对象属于哪个标识符,以及每个表达式具有的类型。类型检查包括特定的额外检查,例如“声明但未使用”以及确定函数是否会终止。
特定变换也基于 AST 完成。一些节点被基于类型信息而细化,例如把字符串加法从算术加法的节点类型中拆分出来。其它一些例子是<ruby>死代码消除<rt>dead code elimination</rt></ruby><ruby>函数调用内联<rt>function call inlining</rt></ruby><ruby>逃逸分析<rt>escape analysis</rt></ruby>LCTT 译注:逃逸分析是一种分析指针有效范围的方法)。
### 3、通用 SSA
* `cmd/compile/internal/gc`(转换成 SSA
* `cmd/compile/internal/ssa`SSA 相关的<ruby>环节<rt>pass</rt></ruby>和规则)
LCTT 译注:许多常见高级语言的编译器无法通过一次扫描源代码或 AST 就完成所有编译工作,取而代之的做法是多次扫描,每次完成一部分工作,并将输出结果作为下次扫描的输入,直到最终产生目标代码。这里每次扫描称作一个<ruby>环节<rt>pass</rt></ruby>;最后一个环节之前所有的环节得到的结果都可称作中间表示法,本文中 AST、SSA 等都属于中间表示法。SSA静态单赋值形式是中间表示法的一种性质它要求每个变量只被赋值一次且在使用前被定义
在此阶段AST 将被转换为<ruby>静态单赋值<rt>Static Single Assignment</rt></ruby>SSA形式这是一种具有特定属性的低级<ruby>中间表示法<rt>intermediate representation</rt></ruby>,可以更轻松地实现优化并最终从它生成机器码。
在这个转换过程中,将完成<ruby>内置函数<rt>function intrinsics</rt></ruby>的处理。这些是特殊的函数编译器被告知逐个分析这些函数并决定是否用深度优化的代码替换它们LCTT 译注:内置函数指由语言本身定义的函数,通常编译器的处理方式是使用相应实现函数的指令序列代替对函数的调用指令,有点类似内联函数)。
在 AST 转化成 SSA 的过程中,特定节点也被低级化为更简单的组件,以便于剩余的编译阶段可以基于它们工作。例如,内建的拷贝被替换为内存移动,`range` 循环被改写为 `for` 循环。由于历史原因,目前这里面有些在转化到 SSA 之前发生,但长期计划则是把它们都移到这里(转化 SSA
然后,一系列机器无关的规则和编译环节会被执行。这些并不考虑特定计算机体系结构,因此对所有 `GOARCH` 变量的值都会运行。
这类通用的编译环节的一些例子包括,死代码消除、移除不必要的空值检查,以及移除无用的分支等。通用改写规则主要考虑表达式,例如将一些表达式替换为常量,优化乘法和浮点操作。
### 4、生成机器码
* `cmd/compile/internal/ssa`SSA 低级化和架构特定的环节)
* `cmd/internal/obj`(机器码生成)
编译器中机器相关的阶段开始于“低级”的编译环节,该阶段将通用变量改写为它们的特定的机器码形式。例如,在 amd64 架构中操作数可以在内存中操作,这样许多<ruby>加载-存储<rt>load-store</rt></ruby>操作就可以被合并。
注意低级的编译环节运行所有机器特定的重写规则,因此当前它也应用了大量优化。
一旦 SSA 被“低级化”并且更具体地针对目标体系结构,就要运行最终代码优化的编译环节了。这包含了另外一个死代码消除的环节,它将变量移动到更靠近它们使用的地方,移除从来没有被读过的局部变量,以及<ruby>寄存器<rt>register</rt></ruby>分配。
本步骤中完成的其它重要工作包括<ruby>堆栈布局<rt>stack frame layout</rt></ruby>,它将堆栈偏移位置分配给局部变量,以及<ruby>指针活性分析<rt>pointer liveness analysis</rt></ruby>,后者计算每个垃圾收集安全点上的哪些堆栈上的指针仍然是活动的。
在 SSA 生成阶段结束时Go 函数已被转换为一系列 `obj.Prog` 指令。它们被传递给汇编程序(`cmd/internal/obj`),后者将它们转换为机器码并输出最终的目标文件。目标文件还将包含反射数据,导出数据和调试信息。
### 扩展阅读
要深入了解 SSA 包的工作方式,包括它的环节和规则,请转到 [cmd/compile/internal/ssa/README.md][1]。
--------------------------------------------------------------------------------
via: https://github.com/golang/go/blob/master/src/cmd/compile/README.md
作者:[mvdan][a]
译者:[stephenxs](https://github.com/stephenxs)
校对:[pityonline](https://github.com/pityonline), [wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://github.com/mvdan
[1]: https://github.com/golang/go/blob/master/src/cmd/compile/internal/ssa/README.md

View File

@ -0,0 +1,83 @@
极致技术探索:显卡工作原理
======
![AMD-Polaris][1]
自从 3dfx 推出最初的 Voodoo 加速器以来,不起眼的显卡对你的 PC 是否可以玩游戏起到决定性作用PC 上任何其它设备都无法与其相比。其它组件当然也很重要,但对于一个拥有 32GB 内存、价值 500 美金的 CPU 和 基于 PCIe 的存储设备的高端 PC如果使用 10 年前的显卡,都无法以最高分辨率和细节质量运行当前<ruby>最高品质的游戏<rt>AAA titles</rt></ruby>,会发生卡顿甚至无响应。显卡(也常被称为 GPU<ruby>图形处理单元<rt>Graphic Processing Unit</rt></ruby>),对游戏性能影响极大,我们反复强调这一点;但我们通常并不会深入了解显卡的工作原理。
出于实际考虑,本文将概述 GPU 的上层功能特性,内容包括 AMD 显卡、Nvidia 显卡、Intel 集成显卡以及 Intel 后续可能发布的独立显卡之间共同的部分。也应该适用于 Apple、Imagination Technologies、Qualcomm、ARM 和其它显卡生产商发布的移动平台 GPU。
### 我们为何不使用 CPU 进行渲染?
我要说明的第一点是我们为何不直接使用 CPU 完成游戏中的渲染工作。坦率的说,在理论上你确实可以直接使用 CPU 完成<ruby>渲染<rt>rendering</rt></ruby>工作。在显卡没有广泛普及之前,早期的 3D 游戏就是完全基于 CPU 运行的,例如 《<ruby>地下创世纪<rt>Ultima Underworld</rt></ruby>(下文中简称 UU。UU 是一个很特别的例子,原因如下:与《<ruby>毁灭战士<rt>Doom</rt></ruby>相比UU 具有一个更高级的渲染引擎,全面支持“向上或向下看”以及一些在当时比较高级的特性,例如<ruby>纹理映射<rt>texture mapping</rt></ruby>。但为支持这些高级特性,需要付出高昂的代价,很少有人可以拥有真正能运行起 UU 的 PC。
![](https://www.extremetech.com/wp-content/uploads/2018/05/UU.jpg)
*地下创世纪,图片来自 [GOG](https://www.gog.com/game/ultima_underworld_1_2)*
对于早期的 3D 游戏,包括《<ruby>半条命<rt>Half Life</rt></ruby>》和《<ruby>雷神之锤 2<rt>Quake II</rt></ruby>》在内的很多游戏,内部包含一个软件渲染器,让没有 3D 加速器的玩家也可以玩游戏。但现代游戏都弃用了这种方式原因很简单CPU 是设计用于通用任务的微处理器,意味着缺少 GPU 提供的<ruby>专用硬件<rt>specialized hardware</rt></ruby><ruby>功能<rt>capabilities</rt></ruby>。对于 18 年前使用软件渲染的那些游戏,当代 CPU 可以轻松胜任;但对于当代最高品质的游戏,除非明显降低<ruby>景象质量<rt>scene</rt></ruby>、分辨率和各种虚拟特效,否则现有的 CPU 都无法胜任。
### 什么是 GPU ?
GPU 是一种包含一系列专用硬件特性的设备,其中这些特性可以让各种 3D 引擎更好地执行代码,包括<ruby>形状构建<rt>geometry setup</rt></ruby>,纹理映射,<ruby>访存<rt>memory access</rt></ruby><ruby>着色器<rt>shaders</rt></ruby>等。3D 引擎的功能特性影响着设计者如何设计 GPU。可能有人还记得AMD HD5000 系列使用 VLIW5 <ruby>架构<rt>archtecture</rt></ruby>;但在更高端的 HD 6000 系列中使用了 VLIW4 架构。通过 GCN LCTT 译注GCN 是 Graphics Core Next 的缩写字面意思是“下一代图形核心”既是若干代微体系结构的代号也是指令集的名称AMD 改变了并行化的实现方法,提高了每个时钟周期的有效性能。
![](https://www.extremetech.com/wp-content/uploads/2018/05/GPU-Evolution.jpg)
*“GPU 革命”的前两块奠基石属于 AMD 和 NV而“第三个时代”则独属于 AMD。*
Nvidia 在发布首款 GeForce 256 时(大致对应 Microsoft 推出 DirectX7 的时间点)提出了 GPU 这个术语,这款 GPU 支持在硬件上执行转换和<ruby>光照计算<rt>lighting calculation</rt></ruby>。将专用功能直接集成到硬件中是早期 GPU 的显著技术特点。很多专用功能还在(以一种极为不同的方式)使用,毕竟对于特定类型的工作任务,使用<ruby>片上<rt>on-chip</rt></ruby>专用计算资源明显比使用一组<ruby>可编程单元<rt>programmable cores</rt></ruby>要更加高效和快速。
GPU 和 CPU 的核心有很多差异但我们可以按如下方式比较其上层特性。CPU 一般被设计成尽可能快速和高效的执行单线程代码。虽然 <ruby>同时多线程<rt> Simultaneous multithreading</rt></ruby>SMT<ruby>超线程<rt>Hyper-Threading</rt></ruby>HT在这方面有所改进但我们实际上通过堆叠众多高效率的单线程核心来扩展多线程性能。AMD 的 32 核心/64 线程 Epyc CPU 已经是我们能买到的核心数最多的 CPU相比而言Nvidia 最低端的 Pascal GPU 都拥有 384 个核心。但相比 CPU 的核心GPU 所谓的核心是处理能力低得多的的处理单元。
**注意:** 简单比较 GPU 核心数,无法比较或评估 AMD 与 Nvidia 的相对游戏性能。在同样 GPU 系列(例如 Nvidia 的 GeForce GTX 10 系列,或 AMD 的 RX 4xx 或 5xx 系列)的情况下,更高的 GPU 核心数往往意味着更高的性能。
你无法只根据核心数比较不同供应商或核心系列的 GPU 之间的性能,这是因为不同的架构对应的效率各不相同。与 CPU 不同GPU 被设计用于并行计算。AMD 和 Nvidia 在结构上都划分为计算资源<ruby><rt>block</rt></ruby>。Nvidia 将这些块称之为<ruby>流处理器<rt>Streaming Multiprocessor</rt></ruby>SM而 AMD 则称之为<ruby>计算单元<rt>Compute Unit</rt></ruby>CU
![](https://www.extremetech.com/wp-content/uploads/2018/05/PascalSM.png)
*一个 Pascal 流处理器SM。*
每个块都包含如下组件:一组核心、一个<ruby>调度器<rt>scheduler</rt></ruby>、一个<ruby>寄存器文件<rt>register file</rt></ruby>、指令缓存、纹理和 L1 缓存以及纹理<ruby>映射单元<rt>mapping unit</rt></ruby>。SM/CU 可以被认为是 GPU 中最小的可工作块。SM/CU 没有涵盖全部的功能单元,例如视频解码引擎,实际在屏幕绘图所需的渲染输出,以及与<ruby>板载<rt>onboard</rt></ruby><ruby>显存<rt>Video Memory</rt></ruby>VRAM通信相关的<ruby>内存接口<rt>memory interfaces</rt></ruby>都不在 SM/CU 的范围内;但当 AMD 提到一个 APU 拥有 8 或 11 个 Vega 计算单元时,所指的是(等价的)<ruby>硅晶块<rt>block of silicon</rt></ruby>数目。如果你查看任意一款 GPU 的模块设计图,你会发现图中 SM/CU 是反复出现很多次的部分。
![](https://www.extremetech.com/wp-content/uploads/2016/11/Pascal-Diagram.jpg)
*这是 Pascal 的全平面图*
GPU 中的 SM/CU 数目越多,每个时钟周期内可以并行完成的工作也越多。渲染是一种通常被认为是“高度并行”的计算问题,意味着随着核心数增加带来的可扩展性很高。
当我们讨论 GPU 设计时,我们通常会使用一种形如 4096:160:64 的格式,其中第一个数字代表核心数。在核心系列(如 GTX970/GTX 980/GTX 980 Ti如 RX 560/RX 580 等等一致的情况下核心数越高GPU 也就相对更快。
### 纹理映射和渲染输出
GPU 的另外两个主要组件是纹理映射单元和渲染输出。设计中的纹理映射单元数目决定了最大的<ruby>纹素<rt>texel</rt></ruby>输出以及可以多快的处理并将纹理映射到对象上。早期的 3D 游戏很少用到纹理,这是因为绘制 3D 多边形形状的工作有较大的难度。纹理其实并不是 3D 游戏必须的,但不使用纹理的现代游戏屈指可数。
GPU 中的纹理映射单元数目用 4096:160:64 指标中的第二个数字表示。AMD、Nvidia 和 Intel 一般都等比例变更指标中的数字。换句话说,如果你找到一个指标为 4096:160:64 的 GPU同系列中不会出现指标为 4096:320:64 的 GPU。纹理映射绝对有可能成为游戏的瓶颈但产品系列中次高级别的 GPU 往往提供更多的核心和纹理映射单元(是否拥有更高的渲染输出单元取决于 GPU 系列和显卡的指标)。
<ruby>渲染输出单元<rt>Render outputs</rt></ruby>ROP有时也叫做<ruby>光栅操作管道<rt>raster operations pipelines</rt></ruby>是 GPU 输出汇集成图像的场所,图像最终会在显示器或电视上呈现。渲染输出单元的数目乘以 GPU 的时钟频率决定了<ruby>像素填充速率<rt>pixel fill rate</rt></ruby>。渲染输出单元数目越多意味着可以同时输出的像素越多。渲染输出单元还处理<ruby>抗锯齿<rt>antialiasing</rt></ruby>,启用抗锯齿(尤其是<ruby>超级采样<rt>supersampled</rt></ruby>抗锯齿)会导致游戏填充速率受限。
### 显存带宽与显存容量
我们最后要讨论的是<ruby>显存带宽<rt>memory bandwidth</rt></ruby><ruby>显存容量<rt>memory capacity</rt></ruby>。显存带宽是指一秒时间内可以从 GPU 专用的显存缓冲区内拷贝进或拷贝出多少数据。很多高级视觉特效(以及更常见的高分辨率)需要更高的显存带宽,以便保证足够的<ruby>帧率<rt>frame rates</rt></ruby>,因为需要拷贝进和拷贝出 GPU 核心的数据总量增大了。
在某些情况下,显存带宽不足会成为 GPU 的显著瓶颈。以 Ryzen 5 2400G 为例的 AMD APU 就是严重带宽受限的,以至于提高 DDR4 的时钟频率可以显著提高整体性能。导致瓶颈的显存带宽阈值,也与游戏引擎和游戏使用的分辨率相关。
板载内存大小也是 GPU 的重要指标。如果按指定细节级别或分辨率运行所需的显存量超过了可用的资源量,游戏通常仍可以运行,但会使用 CPU 的主存来存储额外的纹理数据;而从 DRAM 中提取数据比从板载显存中提取数据要慢得多。这会导致游戏在板载的快速访问内存池和系统内存中共同提取数据时出现明显的卡顿。
有一点我们需要留意GPU 生产厂家通常为一款低端或中端 GPU 配置比通常更大的显存,这是他们为产品提价的一种常用手段。很难说大显存是否更具有吸引力,毕竟需要具体问题具体分析。大多数情况下,用更高的价格购买一款仅是显存更高的显卡是不划算的。经验规律告诉我们,低端显卡遇到显存瓶颈之前就会碰到其它瓶颈。如果存在疑问,可以查看相关评论,例如 4G 版本或其它数目的版本是否性能超过 2G 版本。更多情况下,如果其它指标都相同,购买大显存版本并不值得。
查看我们的[极致技术探索][2]系列,深入了解更多当前最热的技术话题。
--------------------------------------------------------------------------------
via: https://www.extremetech.com/gaming/269335-how-graphics-cards-work
作者:[Joel Hruska][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[pinewall](https://github.com/pinewall)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.extremetech.com/author/jhruska
[1]:https://www.extremetech.com/wp-content/uploads/2016/07/AMD-Polaris-640x353.jpg
[2]:http://www.extremetech.com/tag/extremetech-explains

View File

@ -0,0 +1,181 @@
在 Linux 上操作目录
======
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/branches-238379_1920_0.jpg?itok=2PlNpsVu)
> 让我们继续学习一下 Linux 文件系统的树形结构,并展示一下如何在其中创建你的目录。
如果你不熟悉本系列(以及 Linux[请查看我们的第一部分][1]。在那篇文章中,我们贯穿了 Linux 文件系统的树状结构(或者更确切地说是<ruby>文件层次结构标准<rt>File Hierarchy Standard</rt></ruby>FHS。我建议你仔细阅读确保你理解自己能安全的做哪些操作。因为这一次我将向你展示目录操作的魅力。
### 新建目录
在破坏之前,先让我们来创建。首先,打开一个终端窗口并使用命令 `mkdir` 创建一个新目录,如下所示:
```
mkdir <directoryname>
```
如果你只输入了目录名称,该目录将显示在您当前所在目录中。如果你刚刚打开一个终端,你当前位置为你的家目录。在这个例子中,我们展示了将要创建的目录与你当前所处位置的关系:
```
$ pwd # 告知你当前所在位置(参见第一部分)
/home/<username>
$ mkdir newdirectory # 创建 /home/<username>/newdirectory
```
(注:你不用输入 `` 后面的文本。`#` 后面的文本为注释内容,用于解释发生了什么。它会被 shell 忽略,不会被执行)。
你可以在当前位置中已经存在的某个目录下创建新的目录,方法是在命令行中指定它:
```
mkdir Documents/Letters
```
这将在 `Documents` 目录中创建 `Letters` 目录。
你还可以在路径中使用 `..` 在当前目录的上一级目录中创建目录。假设你进入刚刚创建的 `Documents/Letters/` 目录,并且想要创建`Documents/Memos/` 目录。你可以这样做:
```
cd Documents/Letters # 进入到你刚刚创建的 Letters/ 目录
mkdir ../Memos
```
同样,以上所有内容都是相对于你当前的位置做的。这就是使用了相对路径。
你还可以使用目录的绝对路径:这意味着告诉 `mkdir` 命令将目录放在和根目录(`/`)有关的位置:
```
mkdir /home/<username>/Documents/Letters
```
在上面的命令中将 `<username>` 更改为你的用户名,这相当于从你的主目录执行 `mkdir Documents/Letters`,通过使用绝对路径你可以在目录树中的任何位置完成这项工作。
无论你使用相对路径还是绝对路径,只要命令成功执行,`mkdir` 将静默的创建新目录,而没有任何明显的反馈。只有当遇到某种问题时,`mkdir`才会在你敲下回车键后打印一些反馈。
与大多数其他命令行工具一样,`mkdir` 提供了几个有趣的选项。 `-p` 选项特别有用,因为它允许你嵌套创建目录,即使目录不存在也可以。例如,要在 `Documents/` 中创建一个目录存放写给妈妈的信,你可以这样做:
```
mkdir -p Documents/Letters/Family/Mom
```
`mkdir` 会创建 `Mom/` 之上的整个目录分支,并且也会创建 `Mom/` 目录,无论其上的目录在你敲入该命令时是否已经存在。
你也可以用空格来分隔目录名,来同时创建几个目录:
```
mkdir Letters Memos Reports
```
这将在当前目录下创建目录 `Letters`、`Memos` 和 `Reports`
### 目录名中可怕的空格
……这带来了目录名称中关于空格的棘手问题。你能在目录名中使用空格吗?是的你可以。那么建议你使用空格吗?不,绝对不建议。空格使一切变得更加复杂,并且可能是危险的操作。
假设您要创建一个名为 `letters mom/` 的目录。如果你不知道如何更好处理,你可能会输入:
```
mkdir letters mom
```
但这是错误的!错误的!错误的!正如我们在上面介绍的,这将创建两个目录 `letters/``mom/`,而不是一个目录 `letters mom/`
得承认这是一个小麻烦:你所要做的就是删除这两个目录并重新开始,这没什么大不了。
可是等等!删除目录可是个危险的操作。想象一下,你使用图形工具[Dolphin][2] 或 [Nautilus][3] 创建了目录 `letters mom/`。如果你突然决定从终端删除目录 `letters mom`,并且您在同一目录下有另一个名为 `letters` 的目录,并且该目录中包含重要的文档,结果你为了删除错误的目录尝试了以下操作:
```
rmdir letters mom
```
你将会有删除目录 letters 的风险。这里说“风险”,是因为幸运的是`rmdir` 这条用于删除目录的指令,有一个内置的安全措施,如果你试图删除一个非空目录时,它会发出警告。
但是,下面这个:
```
rm -Rf letters mom
```
(注:这是删除目录及其内容的一种非常标准的方式)将完全删除 `letters/` 目录,甚至永远不会告诉你刚刚发生了什么。)
`rm` 命令用于删除文件和目录。当你将它与选项 `-R`(递归删除)和 `-f`(强制删除)一起使用时,它会深入到目录及其子目录中,删除它们包含的所有文件,然后删除子目录本身,然后它将删除所有顶层目录中的文件,再然后是删除目录本身。
`rm -Rf` 是你必须非常小心处理的命令。
我的建议是,你可以使用下划线来代替空格,但如果你仍然坚持使用空格,有两种方法可以使它们起作用。您可以使用单引号或双引号,如下所示:
```
mkdir 'letters mom'
mkdir "letters dad"
```
或者,你可以转义空格。有些字符对 shell 有特殊意义。正如你所见,空格用于在命令行上分隔选项和参数。 “分离选项和参数”属于“特殊含义”范畴。当你想让 shell 忽略一个字符的特殊含义时,你需要转义,你可以在它前面放一个反斜杠(`\`)如:
```
mkdir letters\ mom
mkdir letter\ dad
```
还有其他特殊字符需要转义,如撇号或单引号(`'`),双引号(`“`)和&符号(``
```
mkdir mom\ \&\ dad\'s\ letters
```
我知道你在想什么:如果反斜杠有一个特殊的含义(即告诉 shell 它必须转义下一个字符),这也使它成为一个特殊的字符。然后,你将如何转义转义字符(`\`
事实证明,你转义任何其他特殊字符都是同样的方式:
```
mkdir special\\characters
```
这将生成一个名为 `special\characters/` 的目录。
感觉困惑?当然。这就是为什么你应该避免在目录名中使用特殊字符,包括空格。
以防误操作你可以参考下面这个记录特殊字符的列表。LCTT 译注:此处原文链接丢失。)
### 总结
* 使用 `mkdir <directory name>` 创建新目录。
* 使用 `rmdir <directory name>` 删除目录(仅在目录为空时才有效)。
* 使用 `rm -Rf <directory name>` 来完全删除目录及其内容 —— 请务必谨慎使用。
* 使用相对路径创建相对于当前目录的目录: `mkdir newdir`
* 使用绝对路径创建相对于根目录(`/`)的目录: `mkdir /home/<username>/newdir`
* 使用 `..` 在当前目录的上级目录中创建目录: `mkdir ../newdir`
* 你可以通过在命令行上使用空格分隔目录名来创建多个目录: `mkdir onedir twodir threedir`
* 同时创建多个目录时,你可以混合使用相对路径和绝对路径: `mkdir onedir twodir /home/<username>/threedir`
* 在目录名称中使用空格和特殊字符真的会让你很头疼,你最好不要那样做。
有关更多信息,您可以查看 `mkdir`、`rmdir` 和 `rm` 的手册:
```
man mkdir
man rmdir
man rm
```
要退出手册页,请按键盘 `q` 键。
### 下次预告
在下一部分中,你将学习如何创建、修改和删除文件,以及你需要了解的有关权限和特权的所有信息!
通过 Linux 基金会和 edX 免费提供的[“Introduction to Linux”][4]课程了解有关Linux的更多信息。
--------------------------------------------------------------------------------
via: https://www.linux.com/blog/learn/2018/5/manipulating-directories-linux
作者:[Paul Brown][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[way-ww](https://github.com/way-ww)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linux.com/users/bro66
[1]:https://linux.cn/article-9798-1.html
[2]:https://userbase.kde.org/Dolphin
[3]:https://projects-old.gnome.org/nautilus/screenshots.html
[4]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux

View File

@ -0,0 +1,53 @@
在 OpenDev 大会上学习 CI/CD
======
> 未来的开发工作需要非常精通 CI/CD 流程。
![在OpenDev上掌握CI/CD](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUSINESS_opennature_3.png?itok=J1OSECM_)
在 2017 年启动后OpenDev 大会现在已是一个年度活动。在去年 9 月的首届活动上,会议的重点是边缘计算。今年的活动,于 5 月 22 - 23 日举行,会议的重点是持续集成和持续发布 (CI/CD),并与 OpenStack 峰会一起在温哥华举行。
基于我在 OpenStack 项目的 CI/CD 系统的技术背景和我近期进入容器下的 CI/CD 方面的经验,我被邀请加入 OpenDev CI/CD 计划委员会。今天我经常借助很多开源技术,例如 [Jenkins][3]、[GitLab][2]、[Spinnaker][4] 和 [Artifactory][5] 来讨论 CI/CD 流程。
这次活动对我来说是很激动人心的,因为我们将在这个活动中融合两个开源基础设施理念。首先,我们将讨论可以被任何组织使用的 CI/CD 工具。为此目的,在 [讲演][6] 中,我们将听到关于开源 CI/CD 工具的使用讲演,一场来自 Boris Renski 的关于 Spinnaker 的讲演,和一场来自 Jim Blair 的关于 [Zuul][7] 的讲演。同时讲演会涉及关于开源技术的偏好的高级别话题特别是那种跨社区的和本身就是开源项目的。从Fatih Degirmenci 和 Daniel Farrel 那里,我们将听到关于在不同社区分享持续发布实践经历,接着 Benjamin Mako Hill 会为我们带来一场关于为什么自由软件需要自由工具的分享。
在分享 CI/CD 相对新颖的特性后,接下来的活动是对话、研讨会和协作讨论的混合组合。当从人们所提交的讲座和研讨会中进行选择,并提出协作讨论主题时,我们希望确保有一个多样灵活的日程表,这样任何参与者都能在 CI/CD 活动进程中发现有趣的东西。
这些讲座会是标准的会议风格,选择涵盖关键主题,如制定 CI/CD 流程,在实践 DevOps 时提升安全性,以及更具体的解决方案,如基于容器关于 Kubernetes 的 [Aptomi][8] 和在 ETSI NFV 环境下 CI/CD。这些会话的大部分将会是作为给新接触 CI/CD 或这些特定技术的参与者关于这些话题和理念的简介。
交互式的研讨会会持续相对比较长的时间,参与者将会在思想上得到特定的体验。这些研讨会包括 “[在持续集成任务中的异常检测][9]”、“[如何安装 Zuul 和配置第一个任务][10]”,和“[Spinnake 101快速可靠的软件发布][11]”。(注意这些研讨会空间是有限的,所以设立了一个 RSVP 系统。你们将会在会议的链接里找到一个 RSVP 的按钮。)
可能最让我最兴奋的是协作讨论,这些协作讨论占据了一半以上的活动安排。协作讨论的主题由计划委员会选取。计划委员会根据我们在社区里所看到来选取对应的主题。这是“鱼缸”风格式的会议,通常是几个人聚在一个房间里围绕着 CI/CD 讨论某一个主题。
这次会议风格的理念是来自于开发者峰会,最初是由 Ubuntu 社区提出,接着 OpenStack 社区也在活动上采纳。这些协作讨论的主题包含不同的会议,这些会议是关于 CI/CD 基础,可以鼓励跨社区协作的提升举措,在组织里推行 CI/CD 文化,和为什么开源 CI/CD 工具如此重要。采用共享文档来做会议笔记,以确保尽可能的在会议的过程中分享知识。在讨论过程中,提出行动项目也是很常见的,因此社区成员可以推动和所涉及的主题相关的倡议。
活动将以联合总结会议结束。联合总结会议将总结来自协同讨论的关键点和为即将在这个领域工作的参与者指出可选的职业范围。
可以在 [OpenStack 峰会注册页][13] 上注册参加活动。或者可以在温哥华唯一指定售票的会议中心购买活动的入场券,价格是 $199。更多关于票和全部的活动安排见官网 [OpenDev 网站][1]。
我希望你们能够加入我们,并在温哥华渡过令人激动的两天,并且在这两天的活动中学习,协作和在 CI/CD 取得进展。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/5/opendev
作者:[Elizabeth K.Joseph][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[jamelouis](https://github.com/jamelouis)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/pleia2
[1]:http://2018.opendevconf.com/
[2]:https://about.gitlab.com/
[3]:https://jenkins.io/
[4]:https://www.spinnaker.io/
[5]:https://jfrog.com/artifactory/
[6]:http://2018.opendevconf.com/schedule/
[7]:https://zuul-ci.org/
[8]:http://aptomi.io/
[9]:https://www.openstack.org/summit/vancouver-2018/summit-schedule/events/21692/anomaly-detection-in-continuous-integration-jobs
[10]:https://www.openstack.org/summit/vancouver-2018/summit-schedule/events/21693/how-to-install-zuul-and-configure-your-first-jobs
[11]:https://www.openstack.org/summit/vancouver-2018/summit-schedule/events/21699/spinnaker-101-releasing-software-with-velocity-and-confidence
[12]:https://www.openstack.org/summit/vancouver-2018/summit-schedule/events/21831/opendev-cicd-joint-collab-conclusion
[13]:https://www.eventbrite.com/e/openstack-summit-may-2018-vancouver-tickets-40845826968?aff=VancouverSummit2018

View File

@ -0,0 +1,279 @@
Python 调试器入门
======
![](https://fedoramagazine.org/wp-content/uploads/2018/05/pdb-816x345.jpg)
Python 生态系统包含丰富的工具和库,可以让开发人员更加舒适。 例如,我们之前已经介绍了如何[使用交互式 shell 增强 Python][1]。本文重点介绍另一种可以节省时间并提高 Python 技能的工具Python 调试器。
### Python 调试器
Python 标准库提供了一个名为 pdb 的调试器。此调试器提供了调试所需的大多数功能,如断点、单行步进、堆栈帧的检查等等。
了解一些pdb 的基本知识很有用,因为它是标准库的一部分。 你可以在无法安装其他增强的调试器的环境中使用它。
#### 运行 pdb
运行 pdb 的最简单方法是从命令行,将程序作为参数传递来调试。 看看以下脚本:
```
# pdb_test.py
#!/usr/bin/python3
from time import sleep
def countdown(number):
for i in range(number, 0, -1):
print(i)
sleep(1)
if __name__ == "__main__":
seconds = 10
countdown(seconds)
```
你可以从命令行运行 pdb如下所示
```
$ python3 -m pdb pdb_test.py
> /tmp/pdb_test.py(1)<module>()
-> from time import sleep
(Pdb)
```
使用 pdb 的另一种方法是在程序中设置断点。为此,请导入 `pdb` 模块并使用`set_trace` 函数:
```
# pdb_test.py
#!/usr/bin/python3
from time import sleep
def countdown(number):
for i in range(number, 0, -1):
import pdb; pdb.set_trace()
print(i)
sleep(1)
if __name__ == "__main__":
seconds = 10
countdown(seconds)
```
```
$ python3 pdb_test.py
> /tmp/pdb_test.py(6)countdown()
-> print(i)
(Pdb)
```
脚本在断点处停止pdb 显示脚本中的下一行。 你也可以在失败后执行调试器。 这称为<ruby>事后调试<rt>postmortem debugging</rt></ruby>
#### 穿行于执行堆栈
调试中的一个常见用例是在执行堆栈中穿行。 Python 调试器运行后,可以使用以下命令:
+ `w(here)`:显示当前执行的行以及执行堆栈的位置。
```
$ python3 test_pdb.py
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb) w
/tmp/test_pdb.py(16)<module>()
-> countdown(seconds)
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb)
```
+ `l(ist)`:显示当前位置周围更多的上下文(代码)。
```
$ python3 test_pdb.py
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb) l
5
6
7 def countdown(number):
8 for i in range(number, 0, -1):
9 import pdb; pdb.set_trace()
10 -> print(i)
11 sleep(1)
12
13
14 if __name__ == "__main__":
15 seconds = 10
```
+ `u(p)`/`d(own)`:向上或向下穿行调用堆栈。
```
$ py3 test_pdb.py
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb) up
> /tmp/test_pdb.py(16)<module>()
-> countdown(seconds)
(Pdb) down
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb)
```
#### 单步执行程序
pdb提供以下命令来执行和单步执行代码
+ `n(ext)`:继续执行,直到达到当前函数中的下一行,或者返回
+ `s(tep)`:执行当前行并在第一个可能的场合停止(在被调用的函数或当前函数中)
+ `c(ontinue)`:继续执行,仅在断点处停止。
```
$ py3 test_pdb.py
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb) n
10
> /tmp/test_pdb.py(11)countdown()
-> sleep(1)
(Pdb) n
> /tmp/test_pdb.py(8)countdown()
-> for i in range(number, 0, -1):
(Pdb) n
> /tmp/test_pdb.py(9)countdown()
-> import pdb; pdb.set_trace()
(Pdb) s
--Call--
> /usr/lib64/python3.6/pdb.py(1584)set_trace()
-> def set_trace():
(Pdb) c
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb) c
9
> /tmp/test_pdb.py(9)countdown()
-> import pdb; pdb.set_trace()
(Pdb)
```
该示例显示了 `next``step` 之间的区别。 实际上,当使用 `step` 时,调试器会进入 `pdb` 模块源代码,而接下来就会执行 `set_trace` 函数。
#### 检查变量内容
+ pdb 非常有用的地方是检查执行堆栈中存储的变量的内容。 例如,`a(rgs)` 命令打印当前函数的变量,如下所示:
```
py3 test_pdb.py
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb) where
/tmp/test_pdb.py(16)<module>()
-> countdown(seconds)
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb) args
number = 10
(Pdb)
```
pdb 打印变量的值,在本例中是 10。
+ 可用于打印变量值的另一个命令是 `p(rint)`
```
$ py3 test_pdb.py
> /tmp/test_pdb.py(10)countdown()
-> print(i)
(Pdb) list
5
6
7 def countdown(number):
8 for i in range(number, 0, -1):
9 import pdb; pdb.set_trace()
10 -> print(i)
11 sleep(1)
12
13
14 if __name__ == "__main__":
15 seconds = 10
(Pdb) print(seconds)
10
(Pdb) p i
10
(Pdb) p number - i
0
(Pdb)
```
如示例中最后的命令所示,`print` 可以在显示结果之前计算表达式。
[Python 文档][2]包含每个 pdb 命令的参考和示例。 对于开始使用 Python 调试器人来说,这是一个有用的读物。
### 增强的调试器
一些增强的调试器提供了更好的用户体验。 大多数为 pdb 添加了有用的额外功能,例如语法突出高亮、更好的回溯和自省。 流行的增强调试器包括 [IPython 的 ipdb][3] 和 [pdb++][4]。
这些示例显示如何在虚拟环境中安装这两个调试器。 这些示例使用新的虚拟环境,但在调试应用程序的情况下,应使用应用程序的虚拟环境。
#### 安装 IPython 的 ipdb
要安装 IPython ipdb请在虚拟环境中使用 `pip`
```
$ python3 -m venv .test_pdb
$ source .test_pdb/bin/activate
(test_pdb)$ pip install ipdb
```
要在脚本中调用 ipdb必须使用以下命令。 请注意,该模块称为 ipdb 而不是 pdb
```
import ipdb; ipdb.set_trace()
```
IPython 的 ipdb 也可以用 Fedora 包安装,所以你可以使用 Fedora 的包管理器 `dnf` 来安装它:
```
$ sudo dnf install python3-ipdb
```
#### 安装 pdb++
你可以类似地安装 pdb++
```
$ python3 -m venv .test_pdb
$ source .test_pdb/bin/activate
(test_pdb)$ pip install pdbp
```
pdb++ 重写了 pdb 模块,因此你可以使用相同的语法在程序中添加断点:
```
import pdb; pdb.set_trace()
```
### 总结
学习如何使用 Python 调试器可以节省你在排查应用程序问题时的时间。 对于了解应用程序或某些库的复杂部分如何工作也是有用的,从而提高 Python 开发人员的技能。
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/getting-started-python-debugger/
作者:[Clément Verna][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[Flowsnow](https://github.com/Flowsnow)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://fedoramagazine.org
[1]:https://fedoramagazine.org/enhance-python-interactive-shell
[2]:https://docs.python.org/3/library/pdb.html
[3]:https://github.com/gotcha/ipdb
[4]:https://github.com/antocuni/pdb

View File

@ -0,0 +1,341 @@
如何在 Ubuntu 系统中添加一个辅助 IP 地址
======
Linux 管理员应该意识到这一点,因为这是一项例行任务。很多人想知道为什么我们需要在服务器中添加多个 IP 地址,以及为什么我们需要将它添加到单块网卡中?我说的对吗?
你可能也会有类似的问题:在 Linux 中如何为单块网卡分配多个 IP 地址?在本文中,你可以得到答案。
当我们对一个新服务器进行设置时,理想情况下它将有一个 IP 地址,即服务器主 IP 地址,它与服务器主机名对应。
我们不应在服务器主 IP 地址上托管任何应用程序,这是不可取的。如果要在服务器上托管任何应用程序,我们应该为此添加辅助 IP。
这是业界的最佳实践,它允许用户安装 SSL 证书。大多数系统都配有单块网卡,这足以添加额外的 IP 地址。
**建议阅读:**
- [在 Linux 命令行中 9 种方法检查公共 IP 地址][1]
- [在 Linux 终端中 3 种简单的方式来检查 DNS域名服务器记录][2]
- [在 Linux 上使用 Dig 命令检查 DNS域名服务器记录][3]
- [在 Linux 上使用 Nslookup 命令检查 DNS域名服务器记录][4]
- [在 Linux 上使用 Host 命令检查 DNS域名服务器记录][5]
我们可以在同一个接口上添加 IP 地址,或者在同一设备上创建子接口,然后在其中添加 IP。默认情况下一直到 Ubuntu 14.04 LTS接口给名称为 `ethX (eth0)`,但是从 Ubuntu 15.10 之后网络接口名称已从 `ethX` 更改为 `enXXXXX`(对于服务器是 ens33桌面版是 enp0s3
在本文中,我们将教你如何在 Ubuntu 上执行此操作并且衍生到其它发行版to 校正:这句自己加的)。
**注意:**别在 DNS 详细信息后添加 IP 地址。如果是这样DNS 将无法正常工作。
### 如何在 Ubuntu 14.04 LTS 中添加临时辅助 IP 地址
在系统中添加 IP 地址之前,运行以下任一命令即可验证服务器主 IP 地址:
```
# ifconfig
# ip addr
# ip addr
eth0 Link encap:Ethernet HWaddr 08:00:27:98:b7:36
inet addr:192.168.56.150 Bcast:192.168.56.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe98:b736/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:4 errors:0 dropped:0 overruns:0 frame:0
TX packets:105 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:902 (902.0 B) TX bytes:16423 (16.4 KB)
eth1 Link encap:Ethernet HWaddr 08:00:27:6a:cf:d3
inet addr:10.0.3.15 Bcast:10.0.3.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe6a:cfd3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:80 errors:0 dropped:0 overruns:0 frame:0
TX packets:146 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:8698 (8.6 KB) TX bytes:17047 (17.0 KB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:25 errors:0 dropped:0 overruns:0 frame:0
TX packets:25 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:1730 (1.7 KB) TX bytes:1730 (1.7 KB)
```
如我所见,服务器主 IP 地址是 `192.168.56.150`,我将下一个 IP `192.168.56.151` 作为辅助 IP使用以下方法完成
```
# ip addr add 192.168.56.151/24 broadcast 192.168.56.255 dev eth0 label eth0:1
```
输入以下命令以检查新添加的 IP 地址。如果你重新启动服务器,那么新添加的 IP 地址会消失,因为我们的 IP 是临时添加的。
```
# ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:98:b7:36 brd ff:ff:ff:ff:ff:ff
inet 192.168.56.150/24 brd 192.168.56.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.56.151/24 brd 192.168.56.255 scope global secondary eth0:1
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe98:b736/64 scope link
valid_lft forever preferred_lft forever
3: eth1: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:6a:cf:d3 brd ff:ff:ff:ff:ff:ff
inet 10.0.3.15/24 brd 10.0.3.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe6a:cfd3/64 scope link
valid_lft forever preferred_lft forever
```
### 如何在 Ubuntu 14.04 LTS 中添加永久辅助 IP 地址
要在 Ubuntu 系统上添加永久辅助 IP 地址,只需编辑 `/etc/network/interfaces` 文件并添加所需的 IP 详细信息。
```
# vi /etc/network/interfaces
```
```
# vi /etc/network/interfaces
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
auto eth0
iface eth0 inet static
address 192.168.56.150
netmask 255.255.255.0
network 192.168.56.0
broadcast 192.168.56.255
gateway 192.168.56.1
auto eth0:1
iface eth0:1 inet static
address 192.168.56.151
netmask 255.255.255.0
```
保存并关闭文件,然后重启网络接口服务。
```
# service networking restart
# ifdown eth0:1 && ifup eth0:1
```
验证新添加的 IP 地址:
```
# ifconfig
eth0 Link encap:Ethernet HWaddr 08:00:27:98:b7:36
inet addr:192.168.56.150 Bcast:192.168.56.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe98:b736/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:5 errors:0 dropped:0 overruns:0 frame:0
TX packets:84 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:962 (962.0 B) TX bytes:11905 (11.9 KB)
eth0:1 Link encap:Ethernet HWaddr 08:00:27:98:b7:36
inet addr:192.168.56.151 Bcast:192.168.56.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
eth1 Link encap:Ethernet HWaddr 08:00:27:6a:cf:d3
inet addr:10.0.3.15 Bcast:10.0.3.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe6a:cfd3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:4924 errors:0 dropped:0 overruns:0 frame:0
TX packets:3185 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:4037636 (4.0 MB) TX bytes:422516 (422.5 KB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
```
### 如何在 Ubuntu 16.04 LTS 中临时添加辅助 IP 地址
正如本文开头所述,网络接口名称从 Ubuntu 15.10 就开始从 ethX 更改为 enXXXX (enp0s3),所以,替换你的接口名称。
在执行此操作之前,先检查系统上的 IP 信息:
```
# ifconfig
# ip addr
enp0s3: flags=4163 mtu 1500
inet 192.168.56.201 netmask 255.255.255.0 broadcast 192.168.56.255
inet6 fe80::a00:27ff:fe97:132e prefixlen 64 scopeid 0x20
ether 08:00:27:97:13:2e txqueuelen 1000 (Ethernet)
RX packets 7 bytes 420 (420.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 294 bytes 24747 (24.7 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp0s8: flags=4163 mtu 1500
inet 10.0.3.15 netmask 255.255.255.0 broadcast 10.0.3.255
inet6 fe80::344b:6259:4dbe:eabb prefixlen 64 scopeid 0x20
ether 08:00:27:12:e8:c1 txqueuelen 1000 (Ethernet)
RX packets 1 bytes 590 (590.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 97 bytes 10209 (10.2 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73 mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10
loop txqueuelen 1000 (Local Loopback)
RX packets 325 bytes 24046 (24.0 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 325 bytes 24046 (24.0 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
```
如我所见,服务器主 IP 地址是 `192.168.56.201`,所以,我将下一个 IP `192.168.56.202` 作为辅助 IP使用以下命令完成。
```
# ip addr add 192.168.56.202/24 broadcast 192.168.56.255 dev enp0s3
```
运行以下命令来检查是否已分配了新的 IP。当你重启机器时它会消失。
```
# ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s3: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:97:13:2e brd ff:ff:ff:ff:ff:ff
inet 192.168.56.201/24 brd 192.168.56.255 scope global enp0s3
valid_lft forever preferred_lft forever
inet 192.168.56.202/24 brd 192.168.56.255 scope global secondary enp0s3
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe97:132e/64 scope link
valid_lft forever preferred_lft forever
3: enp0s8: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:12:e8:c1 brd ff:ff:ff:ff:ff:ff
inet 10.0.3.15/24 brd 10.0.3.255 scope global dynamic enp0s8
valid_lft 86353sec preferred_lft 86353sec
inet6 fe80::344b:6259:4dbe:eabb/64 scope link
valid_lft forever preferred_lft forever
```
### 如何在 Ubuntu 16.04 LTS 中添加永久辅助 IP 地址
要在 Ubuntu 系统上添加永久辅助 IP 地址,只需编辑 `/etc/network/interfaces` 文件并添加所需 IP 的详细信息。
我们不应该在 `dns-nameservers` 行之后添加辅助 IP 地址,因为它不会起作用,应该以下面的格式添加 IP 详情。
此外,我们不需要添加子接口(我们之前在 Ubuntu 14.04 LTS 中的做法):
```
# vi /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback
# The primary network interface
auto enp0s3
iface enp0s3 inet static
address 192.168.56.201
netmask 255.255.255.0
iface enp0s3 inet static
address 192.168.56.202
netmask 255.255.255.0
gateway 192.168.56.1
network 192.168.56.0
broadcast 192.168.56.255
dns-nameservers 8.8.8.8 8.8.4.4
dns-search 2daygeek.local
```
保存并关闭文件,然后重启网络接口服务:
```
# systemctl restart networking
# ifdown enp0s3 && ifup enp0s3
```
运行以下命令来检查是否已经分配了新的 IP
```
# ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s3: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:97:13:2e brd ff:ff:ff:ff:ff:ff
inet 192.168.56.201/24 brd 192.168.56.255 scope global enp0s3
valid_lft forever preferred_lft forever
inet 192.168.56.202/24 brd 192.168.56.255 scope global secondary enp0s3
valid_lft forever preferred_lft forever
inet6 fe80::a00:27ff:fe97:132e/64 scope link
valid_lft forever preferred_lft forever
3: enp0s8: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 08:00:27:12:e8:c1 brd ff:ff:ff:ff:ff:ff
inet 10.0.3.15/24 brd 10.0.3.255 scope global dynamic enp0s8
valid_lft 86353sec preferred_lft 86353sec
inet6 fe80::344b:6259:4dbe:eabb/64 scope link
valid_lft forever preferred_lft forever
```
让我来 ping 一下新 IP 地址:
```
# ping 192.168.56.202 -c 4
PING 192.168.56.202 (192.168.56.202) 56(84) bytes of data.
64 bytes from 192.168.56.202: icmp_seq=1 ttl=64 time=0.019 ms
64 bytes from 192.168.56.202: icmp_seq=2 ttl=64 time=0.087 ms
64 bytes from 192.168.56.202: icmp_seq=3 ttl=64 time=0.034 ms
64 bytes from 192.168.56.202: icmp_seq=4 ttl=64 time=0.042 ms
--- 192.168.56.202 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3068ms
rtt min/avg/max/mdev = 0.019/0.045/0.087/0.026 ms
```
--------------------------------------------------------------------------------
via: https://www.2daygeek.com/how-to-add-additional-ip-secondary-ip-in-ubuntu-debian-system/
作者:[Prakash Subramanian][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[MjSeven](https://github.com/MjSeven)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.2daygeek.com/author/prakash/
[1]:https://www.2daygeek.com/check-find-server-public-ip-address-linux/
[2]:https://www.2daygeek.com/check-find-dns-records-of-domain-in-linux-terminal/
[3]:https://www.2daygeek.com/dig-command-check-find-dns-records-lookup-linux/
[4]:https://www.2daygeek.com/nslookup-command-check-find-dns-records-lookup-linux/
[5]:https://www.2daygeek.com/host-command-check-find-dns-records-lookup-linux/

View File

@ -0,0 +1,206 @@
用 NodeJS 进行 Twitter 情感分析
============================================================
![](https://i.imgur.com/7hIfpzt.png)
如果你想知道大家对某件事情的看法Twitter 是最好的地方了。Twitter 是观点持续不断的涌现出来的地方,每秒钟大概有 6000 条新 Twitter 发送出来。因特网上的发展很快如果你想与时俱进或者跟上潮流Twitter 就是你要去的地方。
现在,我们生活在一个数据为王的时代,很多公司都善于运用 Twitter 上的数据。根据测量到的他们新产品的人气,尝试预测之后的市场趋势,分析 Twitter 上的数据有很多用处。通过数据,商人把产品卖给合适的用户,收集关于他们品牌和改进的反馈,或者获取他们产品或促销活动失败的原因。不仅仅是商人,很多政治和经济上的决定是在观察人们意见的基础上所作的。今天,我会试着让你感受下关于 Twitter 的简单 [情感分析][1],判断这个 Twitter 是正能量、负能量还是中性的。这不会像专业人士所用的那么复杂,但至少,它会让你知道挖掘观念的想法。
我们将使用 NodeJs因为 JavaScript 太常用了,而且它还是最容易入门的语言。
### 前置条件:
* 安装了 NodeJs 和 NPM
* 有 NodeJs 和 NPM 包的经验
* 熟悉命令行。
好了,就是这样。开始吧。
### 开始
为了你的项目新建一个目录,进入这个目录下面。打开终端(或是命令行)。进入刚创建的目录下面,运行命令 `npm init -y`。这会在这个目录下创建一个 `package.json` 文件。现在我们可以安装需要的 npm 包了。只需要创建一个新文件,命名为 `index.js` 然后我们就完成了初始的编码。
### 获取推文
好了,我们想要分析 Twitter ,为了实现这个目的,我们需要以编程的方式访问 Twitter。为此我们要用到 [twit][2] 包。因此,先用 `npm i wit` 命令安装它。我们还需要注册一个 App以通过我们的账户来访问 Twitter 的 API。点击这个 [链接][3],填写所有项目,从 “Keys and Access Token” 标签页中复制 “Consumer Key”、“Consumer Secret”、“Access token” 和 “Access Token Secret” 这几项到一个 `.env` 文件中,就像这样:
```
# .env
# replace the stars with values you copied
CONSUMER_KEY=************
CONSUMER_SECRET=************
ACCESS_TOKEN=************
ACCESS_TOKEN_SECRET=************
```
现在开始。
用你最喜欢的代码编辑器打开 `index.js`。我们需要用 `npm i dotenv` 命令安装 `dotenv` 包来读取 `.env` 文件。好了,创建一个 API 实例。
```
const Twit = require('twit');
const dotenv = require('dotenv');
dotenv.config();
const { CONSUMER_KEY
, CONSUMER_SECRET
, ACCESS_TOKEN
, ACCESS_TOKEN_SECRET
} = process.env;
const config_twitter = {
consumer_key: CONSUMER_KEY,
consumer_secret: CONSUMER_SECRET,
access_token: ACCESS_TOKEN,
access_token_secret: ACCESS_TOKEN_SECRET,
timeout_ms: 60*1000
};
let api = new Twit(config_twitter);
```
这里已经用所需的配置文件建立了到 Twitter 上的连接。但我们什么事情都没做。先定义个获取推文的函数:
```
async function get_tweets(q, count) {
let tweets = await api.get('search/tweets', {q, count, tweet_mode: 'extended'});
return tweets.data.statuses.map(tweet => tweet.full_text);
}
```
这是个 async 函数,因为 `api.get` 函数返回一个 promise 对象,而不是 `then` 链,我想通过这种简单的方式获取推文。它接收两个参数 `q``count``q` 是查询或者我们想要搜索的关键字,`count` 是让这个 `api` 返回的推文数量。
目前为止我们拥有了一个从 Twitter 上获取完整文本的简单方法。不过这里有个问题,现在我们要获取的文本中可能包含某些连接或者由于转推而被截断了。所以我们会编写另一个函数,拆解并返回推文的文本,即便是转发的推文,并且其中有链接的话就删除。
```
function get_text(tweet) {
let txt = tweet.retweeted_status ? tweet.retweeted_status.full_text : tweet.full_text;
return txt.split(/ |\n/).filter(v => !v.startsWith('http')).join(' ');
}
async function get_tweets(q, count) {
let tweets = await api.get('search/tweets', {q, count, 'tweet_mode': 'extended'});
return tweets.data.statuses.map(get_text);
}
```
现在我们拿到了文本。下一步是从文本中获取情感。为此我们会使用 `npm` 中的另一个包 —— [`sentiment`][4]。让我们像安装其他包那样安装 `sentiment`,添加到脚本中。
```
const sentiment = require('sentiment')
```
`sentiment` 用起来很简单。我们只用把 `sentiment` 函数用在我们想要分析的文本上,它就能返回文本的相对分数。如果分数小于 0它表达的就是消极情感大于 0 的分数是积极情感,而 0如你所料表示中性的情感。基于此我们将会把推文打印成不同的颜色 —— 绿色表示积极,红色表示消极,蓝色表示中性。为此,我们会用到 [`colors`][5] 包。先安装这个包,然后添加到脚本中。
```
const colors = require('colors/safe');
```
好了,现在把所有东西都整合到 `main` 函数中。
```
async function main() {
let keyword = \* define the keyword that you want to search for *\;
let count = \* define the count of tweets you want *\;
let tweets = await get_tweets(keyword, count);
for (tweet of tweets) {
let score = sentiment(tweet).comparative;
tweet = `${tweet}\n`;
if (score > 0) {
tweet = colors.green(tweet);
} else if (score < 0) {
tweet = colors.red(tweet);
} else {
tweet = colors.blue(tweet);
}
console.log(tweet);
}
}
```
最后,执行 `main` 函数。
```
main();
```
就是这样,一个简单的分析推文中的基本情感的脚本。
```
\\ full script
const Twit = require('twit');
const dotenv = require('dotenv');
const sentiment = require('sentiment');
const colors = require('colors/safe');
dotenv.config();
const { CONSUMER_KEY
, CONSUMER_SECRET
, ACCESS_TOKEN
, ACCESS_TOKEN_SECRET
} = process.env;
const config_twitter = {
consumer_key: CONSUMER_KEY,
consumer_secret: CONSUMER_SECRET,
access_token: ACCESS_TOKEN,
access_token_secret: ACCESS_TOKEN_SECRET,
timeout_ms: 60*1000
};
let api = new Twit(config_twitter);
function get_text(tweet) {
let txt = tweet.retweeted_status ? tweet.retweeted_status.full_text : tweet.full_text;
return txt.split(/ |\n/).filter(v => !v.startsWith('http')).join(' ');
}
async function get_tweets(q, count) {
let tweets = await api.get('search/tweets', {q, count, 'tweet_mode': 'extended'});
return tweets.data.statuses.map(get_text);
}
async function main() {
let keyword = 'avengers';
let count = 100;
let tweets = await get_tweets(keyword, count);
for (tweet of tweets) {
let score = sentiment(tweet).comparative;
tweet = `${tweet}\n`;
if (score > 0) {
tweet = colors.green(tweet);
} else if (score < 0) {
tweet = colors.red(tweet);
} else {
tweet = colors.blue(tweet)
}
console.log(tweet)
}
}
main();
```
--------------------------------------------------------------------------------
via: https://boostlog.io/@anshulc95/twitter-sentiment-analysis-using-nodejs-5ad1331247018500491f3b6a
作者:[Anshul Chauhan][a]
译者:[BriFuture](https://github.com/BriFuture)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://boostlog.io/@anshulc95
[1]:https://en.wikipedia.org/wiki/Sentiment_analysis
[2]:https://github.com/ttezel/twit
[3]:https://boostlog.io/@anshulc95/apps.twitter.com
[4]:https://www.npmjs.com/package/sentiment
[5]:https://www.npmjs.com/package/colors
[6]:https://boostlog.io/tags/nodejs
[7]:https://boostlog.io/tags/twitter
[8]:https://boostlog.io/@anshulc95

View File

@ -0,0 +1,87 @@
在开源“集市”工作时如何建立一个职业网络
======
> 在组织内建立联系遇到问题了吗?你或许是采用了错误的策略。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/connection_people_team_collaboration.png?itok=0_vQT8xV)
职业社交网络 —— 在同事或专业人员之间建立人际联系 —— 可以采用多种形式、在产业内跨组织进行。建立职业网络需要花费时间和精力,并且当某位成员加入或离开一个组织时,此人的网络通常需要被在一个新的工作环境中重建。
职业社交网络在不同组织中起相似作用 —— 信息共享、导师制、机会、工作利益和其他作用 —— 然而传统组织与开放组织在组织内构建特定联系的*方法*和*原因*可能不尽相同。这些差异有其影响:同事联系方式、如何建立信任、组织内多元化的程度和种类以及建立合作的能力,所有这些因素都是相互关联的,而且它们参与并塑造了人们所建立的社交网络。
一个开放的组织对包容性的强调可以使社交网络在解决商业问题上比传统等级制组织更加高效。这种观念在开源的思考中有很久的历史。例如,在<ruby>[《教堂与集市》][1]<rt>The Cathedral and the Bazaar</rt></ruby>中,埃里克·雷蒙德写道:“许多年前社会学家发现,相比一个随机选择的观察者的观点,许多同等专业的(或是同等无知的)观察家的普遍观点是可靠得多的预言。”所以让我们了解社交网络的结构和目的如何影响各类组织的价值观。
### 传统组织中的社交网络
当我在传统组织工作并要描述我为工作做了什么时,人们问我的第一件事就是我与其他人(通常是总监级的领导)的关系。“你在希拉手下吗?”他们会这么问。“你为马尔科姆工作吗?”这意味着以一种上下级的视角看待传统组织的作用;当试图安排工作或雇员时,人们想要从上下级的角度理解网络结构。
换言之,在传统组织中社交网络依赖于等级制结构,因此他们彼此跟随。事实上,甚至弄清一个雇员在关系网中处于怎样的位置也算得上是一种“上下级组织”式的担忧。
然而并非所有潜在等级制都是如此。它还视相关人员而定。对于上下级网络的关注会决定雇员在网络中的“价值”,因为网络本身是一个持续的权力关系的系统,它会根据人不同水平的价值给予他们不同的定位。它淡化了个人的能力和技能的重要性。因此,一个人在传统组织的联系促使其能力具有前瞻性,为人所知,有影响力并在其事业中起到支持作用。
相比传统等级制组织,一个开放的组织对包容性的强调能使网络解决商业问题更加高效。
传统组织的正式结构以特定方式决定着雇员的社交网络 —— 有些可能是优点,有些可能是缺点,这取决于具体环境——例如:
* 要更快速地了解“谁是谁”并看到人们如何关联是较为便捷的(通常这在特定层级内建立信任网络)。
* 通常,这种对关系的进一步的理解意味着会有更少的过剩工作(在一个特定网络中项目有清晰的相应的归属者)和过多交流(人们知道谁对交流什么负责)。
* 相关人员会感到在一个权力结构中感到束手无策,或好像他们不能“闯入”权力结构中,这些结构有时(或更多时候)因为裁员并不起作用。
* 完成大量的工作和努力是困难的,并且合作会很艰难。
* 权力转让缓慢;一个人的参与能力更多地决定于等级结构所创造的网络的结盟而非其他因素(比如个人能力),减少了被看做社区和成员利益的东西。
* 竞争似乎更加清晰;理解“谁在竞争什么”通常发生在一个公认的、被限定了的等级结构中(权力网络中职位的缺乏增进了竞争因此竞争会更激烈)。
* 当更严格的网络决定了灵活性的限度时,适应能力会受损。网络的“夙愿”和合作的限度也会以同样的方式受影响。
* 在严格的网络中,方向明确,并且领导人通常靠过度指导来进行管理,在这里,破坏更容易发生。
* 当社交网络不那么灵活时,风险下降;人们知道什么需要发生,怎样发生,何时发生(但是考虑到在一个组织中工作的广度,这不见得总是“坏事”;一些工作的职能需要较小的风险,例如:人力资源管理 HR,企业并购和法律工作等。
* 在网络中的信任是更大的,尤其当受雇者是正式网络的一部分的时候(当某人不是网络的一份子时,被排斥的人可能特别难管理或改正)。
### 开放组织中的社交网络
尽管开放组织必定会有等级结构,但他们并不根据那个网络运作。他们的职业网络结构更加灵活(或者说是“随时随地”)。
在一个开放的组织中,当我描述我做了什么工作时,几乎没人问我“我为谁而干?”一个开放的组织更多的以伙伴为中心,而不是以领导为中心。开放的价值观比如包容和特定的治理系统比如强人治理有助于此;那并不是你了解谁而是你了解什么,你怎样使用(比如:“自底而上的设计”)。在一个开放的组织当中,我并不感觉我在为展示自己的价值而奋斗;我的想法有内在的价值。有时我必须示范说明为何使用我的观点比使用别人的更加有用——但是那意味着我正在同事的社区里面诊疗我自己(包括领导层),而不是单独被自上而下的领导层诊疗。
如此说来,开放的组织并不基于网络评估员工,而是基于他们对作为个人的同事的了解。这个人有想法吗?她会努力通过利用开放组织的价值实现那些想法吗(领导它们)(也就是说,在开放组织中分享那些观点并且实践以将他人囊括并透明公开的工作等等)
开放组织也会以特定的方式构造社交网络(这种方式同样可能会视个人的目的性和渴望程度而很有益或很有害),这包括:
* 人们会对他们的网络、声望、技能和事业更加负责。
* 竞争(为了资源、权力、晋升等)会因这些组织天性更具合作性而变得更少。最好的结果是协商,而不是单赢,并且竞争会磨练创意,而不会在人与人之间筑篱设笆。
* 权力是更加流动和有活力的,在人与人之间流动(但这同时也意味着可能有对可说明性或者责任的误解,而且活动可能会因为没有明晰的[主人翁意识][2]而不被完成)。
* 信任是“一次一同事”地被建立起来的而不会借助社交网络,在网络中,人是被定位着的。
* 网络在多样的运转和事件中会自配置,一有机会便会反应性地自启(这帮助了更新但却会造成混乱,因为谁在决策、谁在“受控”是不那么明确的)。
* 执行速度在混乱的环境中会下降,因为所做之事、做事方式和处事时间需要在制定目标和涵养好整以暇的员工方面上的领导力。
* 灵活的社交网络同样会增加变革和风险;创意会流通得更快而且更神奇,并且执行会更加自信。
* 信任建立在同事合作之上(它本该如此!),而不是在对架构的尊重之上。
### 让它有效
如果你正在考虑从一种组织架构转变为另一种,当你在构建并维持你的职业社交网络时思考一下如下所述内容。
#### 来自传统组织的小建议
* 对决策的架构和管控不是坏事;运作中的框架需要明晰透明,而且决策者需要考虑他们的决定。
* 在执行上突出需要经理提供关注,还需要有在滤出任何让人分心或混乱的事务的同时仍能提供足够的来龙去脉的能力。
* 已经确立的网络帮助了一大批人同步工作并且能管控风险。
#### 来自开放组织的小建议
* 能力强的领导人是那些可以根据多样的风格和对同事、团队的不同偏好提供不同层次的透明度和指导,同时又不会构建出不灵活的网络的人。
* 伟大的想法比已建立的组织会赢得更多。
* 人们对他们的名声会更加负责任。
* 创意和信息的流转是变革的关键。松散组织中的关系网络可以使这两种元素生发的频度更高、幅度更广。
--------------------------------------------------------------------------------
via: https://opensource.com/open-organization/18/6/building-professional-social-networks-openly
作者:[Heidi Hess von Ludewig][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[ZenMoore](https://github.com/ZenMoore)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/heidi-hess-von-ludewig
[1]:http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html
[2]:https://opensource.com/open-organization/18/4/rethinking-ownership-across-organization

View File

@ -0,0 +1,75 @@
使用 Ledger 记录(财务)情况
======
自 2005 年搬到加拿大以来,我使用 [Ledger CLI][1] 来跟踪我的财务状况。我喜欢纯文本的方式,它支持虚拟信封意味着我可以同时将我的银行帐户余额和我的虚拟分配到不同的目录下。以下是我们如何使用这些虚拟信封分别管理我们的财务状况。
每个月我都有一个条目将我生活开支分配到不同的目录中包括家庭开支的分配。W- 不要求太多, 所以我要谨慎地处理这两者之间的差别和我自己的生活费用。我们处理它的方式是我支付固定金额,这是贷记我支付的杂货。由于我们的杂货总额通常低于我预算的家庭开支,因此任何差异都会留在标签上。我过去常常给他写支票,但最近我只是支付偶尔额外的大笔费用。
这是个示例信封分配:
```
2014.10.01 * Budget
[Envelopes:Living]
[Envelopes:Household] $500
;; More lines go here
```
这是设置的信封规则之一。它鼓励我正确地分类支出。所有支出都从我的 “Play” 信封中取出。
```
= /^Expenses/
(Envelopes:Play) -1.0
```
这个为家庭支出报销 “Play” 信封,将金额从 “Household” 信封转移到 “Play” 信封。
```
= /^Expenses:House$/
(Envelopes:Play) 1.0
(Envelopes:Household) -1.0
```
我有一套定期的支出来模拟我的预算中的家庭开支。例如,这是 10 月份的。
```
2014.10.1 * House
Expenses:House
Assets:Household $-500
```
这是杂货交易的形式:
```
2014.09.28 * No Frills
Assets:Household:Groceries $70.45
Liabilities:MBNA:September $-70.45
```
接着 `ledger bal Assets:Household` 就会告诉我是否欠他钱(负余额)。如果我支付大笔费用(例如:机票、通管道),那么正常家庭开支预算会逐渐减少余额。
我从 W- 那找到了一个为我的信用卡交易添加一个月标签的技巧,他还使用 Ledger 跟踪他的交易。它允许我再次检查条目的余额,看看前一个条目是否已被正确清除。
这个资产分类使用有点奇怪,但它在精神上对我有用。
使用 Ledger 以这种方式跟踪它可以让我跟踪我们的杂货费用以及我实际支付费用和我预算费用之间的差额。如果我最终支出超出预期,我可以从更多可自由支配的信封中移动虚拟货币,因此我的预算始终保持平衡。
Ledger 是一个强大的工具。相当极客,但也许更多的工作流描述可能会帮助那些正在搞清楚它的人!
--------------------------------------------------------------------------------
via: http://sachachua.com/blog/2014/11/keeping-financial-score-ledger/
作者:[Sacha Chua][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:http://sachachua.com
[1]:http://www.ledger-cli.org/
[2]:http://sachachua.com/blog/category/finance/
[3]:http://sachachua.com/blog/tag/ledger/
[4]:http://pages.sachachua.com/sharing/blog.html?url=http://sachachua.com/blog/2014/11/keeping-financial-score-ledger/
[5]:http://sachachua.com/blog/2014/11/keeping-financial-score-ledger/#comments

View File

@ -1,49 +1,45 @@
使用 Ftrace 跟踪内核
使用 ftrace 跟踪内核
============================================================
标签: [ftrace][8][kernel][9][kernel profiling][10][kernel tracing][11][linux][12][tracepoints][13]
![](https://blog.selectel.com/wp-content/uploads/2017/04/PR-1801-2-2.png)
在内核级别上分析事件有很多的工具:[SystemTap][14][ktap][15][Sysdig][16][LTTNG][17]等等,并且你也可以在网络上找到关于这些工具的大量介绍文章和资料。
在内核层面上分析事件有很多的工具:[SystemTap][14]、[ktap][15]、[Sysdig][16]、[LTTNG][17] 等等,你也可以在网络上找到关于这些工具的大量介绍文章和资料。
而对于使用 Linux 原生机制去跟踪系统事件以及检索/分析故障信息的方面的资料却很少找的到。这就是 [ftrace][18],它是添加到内核中的第一款跟踪工具,今天我们来看一下它都能做什么,让我们从它的一些重要术语开始吧。
### 内核跟踪和分析
内核分析可以发现性能“瓶颈”。分析能够帮我们发现在一个程序中性能损失的准确位置。特定的程序生成一个概述 — 一个事件总结 — 它能够用于帮我们找出哪个函数占用了大量的运行时间。尽管这些程序并不能识别出为什么会损失性能。
<ruby>内核分析<rt>Kernel profiling</rt></ruby>可以发现性能“瓶颈”。分析能够帮我们发现在一个程序中性能损失的准确位置。特定的程序生成一个<ruby>概述<rt>profile</rt></ruby>这是一个事件总结 — 它能够用于帮我们找出哪个函数占用了大量的运行时间。尽管这些程序并不能识别出为什么会损失性能。
瓶颈经常发生在无法通过分析来识别的情况下。去推断出为什么会发生事件,去保存发生事件时的相关上下文,这就需要去跟踪。
瓶颈经常发生在无法通过分析来识别的情况下。要推断出为什么会发生事件,就必须保存发生事件时的相关上下文,这就需要去<ruby>跟踪<rt>tracing</rt></ruby>
跟踪可以理解为在一个正常工作的系统上活动的信息收集程。它使用特定的工具来完成这项工作,就像录音机来记录声音一样,用它来记录各种注册的系统事件。
跟踪可以理解为在一个正常工作的系统上活动的信息收集程。它使用特定的工具来完成这项工作,就像录音机来记录声音一样,用它来记录各种系统事件。
跟踪程序能够同时跟踪应用级和操作系统级的事件。它们收集的信息能够用于诊断多种系统问题。
有时候会将跟踪与日志比较。它们两者确时很相似,但是也有不同的地方。
对于跟踪,记录的信息都是些低级别事件。它们的数量是成百上千的,甚至是成千上万的。对于日志,记录的信息都是些高级别事件,数量上通常少多了。这些包含用户登系统、应用程序错误、数据库事务等等。
对于跟踪,记录的信息都是些低级别事件。它们的数量是成百上千的,甚至是成千上万的。对于日志,记录的信息都是些高级别事件,数量上通常少多了。这些包含用户登系统、应用程序错误、数据库事务等等。
就像日志一样,跟踪数据可以被原样读取,但是用特定的应用程序提取的信息更有用。所有的跟踪程序都能这样做。
在内核跟踪和分析方面Linux 内核有三个主要的机制:
* 跟踪点 —— 一种基于静态测试代码的工作机制
* 探针 —— 一种动态跟踪机制,用于在任意时刻中断内核代码的运行,调用它自己的处理程序,在完成需要的操作之后再返回。
* perf_events —— 一个访问 PMU性能监视单元的接口
* <ruby>跟踪点<rt>tracepoint</rt></ruby>:一种基于静态测试代码的工作机制
* <ruby>探针<rt>kprobe</rt></ruby>:一种动态跟踪机制,用于在任意时刻中断内核代码的运行,调用它自己的处理程序,在完成需要的操作之后再返回
* perf_events —— 一个访问 PMU<ruby>性能监视单元<rt>Performance Monitoring Unit</rt></ruby>)的接口
我并不想在这里写关于这些机制方面的内容,任何对它们感兴趣的人可以去访问 [Brendan Gregg 的博客][19]。
使用 ftrace我们可以与这些机制进行交互并可以从用户空间直接得到调试信息。下面我们将讨论这方面的详细内容。示例中的所有命令行都是在内核版本为 3.13.0-24 的 Ubuntu 14.04 中运行的。
### Ftrace常用信息
### ftrace常用信息
Ftrace 是函数 Trace 的简写,但它能做的远不止这些:它可以跟踪上下文切换、测量进程阻塞时间、计算高优先级任务的活动时间等等。
ftrace 是 Function Trace 的简写,但它能做的远不止这些:它可以跟踪上下文切换、测量进程阻塞时间、计算高优先级任务的活动时间等等。
Ftrace 是由 Steven Rostedt 开发的,从 2008 年发布的内核 2.6.27 中开始就内置了。这是为记录数据提供的一个调试 `Ring` 缓冲区的框架。这些数据由集成到内核中的跟踪程序来采集。
ftrace 是由 Steven Rostedt 开发的,从 2008 年发布的内核 2.6.27 中开始就内置了。这是为记录数据提供的一个调试 Ring 缓冲区的框架。这些数据由集成到内核中的跟踪程序来采集。
Ftrace 工作在 debugfs 文件系统上,这是在大多数现代 Linux 分发版中默认挂载的文件系统。为开始使用 ftrace你将进入到 `sys/kernel/debug/tracing` 目录(仅对 root 用户可用):
ftrace 工作在 debugfs 文件系统上,在大多数现代 Linux 发行版中都默认挂载了。要开始使用 ftrace你将进入到 `sys/kernel/debug/tracing` 目录(仅对 root 用户可用):
```
# cd /sys/kernel/debug/tracing
@ -70,16 +66,13 @@ kprobe_profile stack_max_size uprobe_profile
我不想去描述这些文件和子目录;它们的描述在 [官方文档][20] 中已经写的很详细了。我只想去详细介绍与我们这篇文章相关的这几个文件:
* available_tracers —— 可用的跟踪程序
* current_tracer —— 正在运行的跟踪程序
* tracing_on —— 负责启用或禁用数据写入到 `Ring` 缓冲区的系统文件(如果启用它,在文件中添加数字 1禁用它添加数字 0
* tracing_on —— 负责启用或禁用数据写入到 Ring 缓冲区的系统文件(如果启用它,数字 1 被添加到文件中,禁用它,数字 0 被添加)
* trace —— 以人类友好格式保存跟踪数据的文件
### 可用的跟踪程序
我们可以使用如下的命令去查看可用的跟踪程序的一个列表
我们可以使用如下的命令去查看可用的跟踪程序的一个列表
```
root@andrei:/sys/kernel/debug/tracing#: cat available_tracers
@ -89,18 +82,14 @@ blk mmiotrace function_graph wakeup_rt wakeup function nop
我们来快速浏览一下每个跟踪程序的特性:
* function —— 一个无需参数的函数调用跟踪程序
* function_graph —— 一个使用子调用的函数调用跟踪程序
* blk —— 一个与块 I/O 跟踪相关的调用和事件跟踪程序(它是 blktrace 的用途)
* blk —— 一个与块 I/O 跟踪相关的调用和事件跟踪程序(它是 blktrace 使用的)
* mmiotrace —— 一个内存映射 I/O 操作跟踪程序
* nop —— 简化的跟踪程序,就像它的名字所暗示的那样,它不做任何事情(尽管在某些情况下可能会派上用场,我们将在后文中详细解释)
* nop —— 最简单的跟踪程序,就像它的名字所暗示的那样,它不做任何事情(尽管在某些情况下可能会派上用场,我们将在后文中详细解释)
### 函数跟踪程序
在开始介绍函数跟踪程序 ftrace 之前,我们先看一测试脚本:
在开始介绍函数跟踪程序 ftrace 之前,我们先看一测试脚本:
```
#!/bin/sh
@ -117,7 +106,7 @@ less ${dir}/trace
这个脚本是非常简单的,但是还有几个需要注意的地方。命令 `sysctl ftrace.enabled=1` 启用了函数跟踪程序。然后我们通过写它的名字到 `current_tracer` 文件来启用 `current tracer`
接下来,我们写入一个 `1``tracing_on`,它启用了 `Ring` 缓冲区。这些语法都要求在 `1``>` 符号前后有一个空格;写成像 `echo1> tracing_on` 这样将不能工作。一行之后我们禁用它(如果 `0` 写入到 `tracing_on` 缓冲区不会被清除并且 ftrace 并不会被禁用)。
接下来,我们写入一个 `1``tracing_on`,它启用了 Ring 缓冲区。这些语法都要求在 `1``>` 符号前后有一个空格;写成像 `echo 1> tracing_on` 这样将不能工作。一行之后我们禁用它(如果 `0` 写入到 `tracing_on` 缓冲区不会被清除并且 ftrace 并不会被禁用)。
我们为什么这样做呢?在两个 `echo` 命令之间,我们看到了命令 `sleep 1`。我们启用了缓冲区,运行了这个命令,然后禁用它。这将使跟踪程序采集了这个命令运行期间发生的所有系统调用的信息。
@ -156,21 +145,18 @@ less ${dir}/trace
trace.sh-1295 [000] d... 90.502879: __acct_update_integrals <-acct_account_cputime
```
这个输出以缓冲区中的信息条目数量和写入的条目数量开始。这两者的数据差异是缓冲区中事件的丢失数量(在我们的示例中没有发生丢失)。
这个输出以缓冲区中的信息条目数量写入的全部条目数量开始。这两者的数据差异是缓冲区中事件的丢失数量(在我们的示例中没有发生丢失)。
在这里有一个包含下列信息的函数列表:
* 进程标识符PID
* 运行这个进程的 CPUCPU#
* 进程开始时间TIMESTAMP
* 被跟踪函数的名字以及调用它的父级函数;例如,在我们输出的第一行,`rb_simple_write` 调用了 `mutex-unlock` 函数。
### Function_graph 跟踪程序
### function_graph 跟踪程序
`function_graph` 跟踪程序的工作和函数一样,但是它更详细:它显示了每个函数的进入和退出点。使用这个跟踪程序,我们可以跟踪函数的子调用并且测量每个函数的运行时间。
function_graph 跟踪程序的工作和函数跟踪程序一样,但是它更详细:它显示了每个函数的进入和退出点。使用这个跟踪程序,我们可以跟踪函数的子调用并且测量每个函数的运行时间。
我们来编辑一下最后一个示例的脚本:
@ -215,11 +201,11 @@ less ${dir}/trace
0) ! 208.154 us | } /* ip_local_deliver_finish */
```
在这个图中,`DURATION` 展示了花费在每个运行的函数上的时间。注意使用 `+``!` 符号标记的地方。加号(+)意思是这个函数花费的时间超过 10 毫秒;而感叹号()意思是这个函数花费的时间超过了 100 毫秒。
在这个图中,`DURATION` 展示了花费在每个运行的函数上的时间。注意使用 `+``!` 符号标记的地方。加号(`+`)意思是这个函数花费的时间超过 10 毫秒;而感叹号(`!`)意思是这个函数花费的时间超过了 100 毫秒。
`FUNCTION_CALLS` 下面,我们可以看到每个函数调用的信息。
和 C 语言一样使用了花括号({)标记每个函数的边界,它展示了每个函数的开始和结束,一个用于开始,一个用于结束;不能调用其它任何函数的叶子函数用一个分号()标记。
和 C 语言一样使用了花括号(`{`)标记每个函数的边界,它展示了每个函数的开始和结束,一个用于开始,一个用于结束;不能调用其它任何函数的叶子函数用一个分号(`;`)标记。
### 函数过滤器
@ -249,13 +235,13 @@ ftrace 还有很多过滤选项。对于它们更详细的介绍,你可以去
### 跟踪事件
我们在上面提到到跟踪点机制。跟踪点是插入的由系统事件触发的特定代码。跟踪点可以是动态的(意味着可能会在它们上面附加几个检查),也可以是静态的(意味着不会附加任何检查)。
我们在上面提到到跟踪点机制。跟踪点是插入的触发系统事件的特定代码。跟踪点可以是动态的(意味着可能会在它们上面附加几个检查),也可以是静态的(意味着不会附加任何检查)。
静态跟踪点不会对系统有任何影响;它们只是增加几个字节用于调用测试函数以及在一个独立的节上增加一个数据结构。
静态跟踪点不会对系统有任何影响;它们只是在测试的函数末尾增加几个字节的函数调用以及在一个独立的节上增加一个数据结构。
当相关代码片断运行时,动态跟踪点调用一个跟踪函数。跟踪数据是写入到 `Ring` 缓冲区。
当相关代码片断运行时,动态跟踪点调用一个跟踪函数。跟踪数据是写入到 Ring 缓冲区。
跟踪点可以设置在代码的任何位置;事实上,它们确实可以在许多的内核函数中找到。我们来看一下 `kmem_cache_alloc` 函数(它在 [这里][22]
跟踪点可以设置在代码的任何位置;事实上,它们确实可以在许多的内核函数中找到。我们来看一下 `kmem_cache_alloc` 函数(取自 [这里][22]
```
{
@ -294,7 +280,7 @@ fs kvm power scsi vfs
ftrace kvmmmu printk signal vmscan
```
所有可能的事件都按子系统分组到子目录中。在我们开始跟踪事件之前,我们要先确保启用了 `Ring` 缓冲区写入:
所有可能的事件都按子系统分组到子目录中。在我们开始跟踪事件之前,我们要先确保启用了 Ring 缓冲区写入:
```
root@andrei:/sys/kernel/debug/tracing# cat tracing_on
@ -306,25 +292,25 @@ root@andrei:/sys/kernel/debug/tracing# cat tracing_on
root@andrei:/sys/kernel/debug/tracing# echo 1 > tracing_on
```
在我们上一篇的文章中,我们写了关于 `chroot()` 系统调用的内容;我们来跟踪访问一下这个系统调用。为了跟踪,我们使用 `nop` 因为函数跟踪程序和 `function_graph` 跟踪程序记录的信息太多,它包含了我们不感兴趣的事件信息。
在我们上一篇的文章中,我们写了关于 `chroot()` 系统调用的内容;我们来跟踪访问一下这个系统调用。对于我们的跟踪程序,我们使用 `nop` 因为函数跟踪程序和 `function_graph` 跟踪程序记录的信息太多,它包含了我们不感兴趣的事件信息。
```
root@andrei:/sys/kernel/debug/tracing# echo nop > current_tracer
```
所有事件相关的系统调用都保存在系统调用目录下。在这里我们将找到一个进入和退出多个系统调用的目录。我们需要在相关的文件中通过写入数字 `1` 来激活跟踪点:
所有事件相关的系统调用都保存在系统调用目录下。在这里我们将找到一个进入和退出各种系统调用的目录。我们需要在相关的文件中通过写入数字 `1` 来激活跟踪点:
```
root@andrei:/sys/kernel/debug/tracing# echo 1 > events/syscalls/sys_enter_chroot/enable
```
然后我们使用 `chroot` 来创建一个独立的文件系统(更多内容,请查看 [这篇文章][23])。在我们执行完我们需要的命令之后,我们将禁用跟踪程序,以便于不需要的信息或者过量信息出现在输出中:
然后我们使用 `chroot` 来创建一个独立的文件系统(更多内容,请查看 [之前这篇文章][23])。在我们执行完我们需要的命令之后,我们将禁用跟踪程序,以便于不需要的信息或者过量信息不会出现在输出中:
```
root@andrei:/sys/kernel/debug/tracing# echo 0 > tracing_on
```
然后,我们去查看 `Ring` 缓冲区的内容。在输出的结束部分,我们找到了有关的系统调用信息(这里只是一个节选)。
然后,我们去查看 Ring 缓冲区的内容。在输出的结束部分,我们找到了有关的系统调用信息(这里只是一个节选)。
```
root@andrei:/sys/kernel/debug/tracing# сat trace
@ -343,15 +329,10 @@ root@andrei:/sys/kernel/debug/tracing# сat trace
在这篇文篇中,我们做了一个 ftrace 的功能概述。我们非常感谢你的任何意见或者补充。如果你想深入研究这个主题,我们为你推荐下列的资源:
* [https://www.kernel.org/doc/Documentation/trace/tracepoints.txt][1] — 一个跟踪点机制的详细描述
* [https://www.kernel.org/doc/Documentation/trace/events.txt][2] — 在 Linux 中跟踪系统事件的指南
* [https://www.kernel.org/doc/Documentation/trace/ftrace.txt][3] — ftrace 的官方文档
* [https://lttng.org/files/thesis/desnoyers-dissertation-2009-12-v27.pdf][4] — Mathieu Desnoyers作者是跟踪点和 LTTNG 的创建者)的关于内核跟踪和分析的学术论文。
* [https://lwn.net/Articles/370423/][5] — Steven Rostedt 的关于 ftrace 功能的文章
* [http://alex.dzyoba.com/linux/profiling-ftrace.html][6] — 用 ftrace 分析实际案例的一个概述
--------------------------------------------------------------------------------
@ -360,7 +341,7 @@ via:https://blog.selectel.com/kernel-tracing-ftrace/
作者:[Andrej Yemelianov][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,129 @@
Ubunsys面向 Ubuntu 资深用户的一个高级系统配置工具
======
![](https://www.ostechnix.com/wp-content/uploads/2017/08/Ubunsys-4-1-720x340.png)
**Ubunsys** 是一个面向 Ubuntu 及其衍生版的基于 Qt 的高级系统工具。高级用户可以使用命令行轻松完成大多数配置。不过为了以防万一某天,你突然不想用命令行了,就可以用 Ubnusys 这个程序来配置你的系统或其衍生系统,如 Linux Mint、Elementary OS 等。Ubunsys 可用来修改系统配置,安装、删除、更新包和旧内核,启用或禁用 `sudo` 权限,安装主线内核,更新软件安装源,清理垃圾文件,将你的 Ubuntu 系统升级到最新版本等等。以上提到的所有功能都可以通过鼠标点击完成。你不需要再依赖于命令行模式,下面是你能用 Ubunsys 做到的事:
* 安装、删除、更新包
* 更新和升级软件源
* 安装主线内核
* 删除旧的和不再使用的内核
* 系统整体更新
* 将系统升级到下一个可用的版本
* 将系统升级到最新的开发版本
* 清理系统垃圾文件
* 在不输入密码的情况下启用或者禁用 `sudo` 权限
* 当你在终端输入密码时使 `sudo` 密码可见
* 启用或禁用系统休眠
* 启用或禁用防火墙
* 打开、备份和导入 `sources.list.d``sudoers` 文件
* 显示或者隐藏启动项
* 启用或禁用登录音效
* 配置双启动
* 启用或禁用锁屏
* 智能系统更新
* 使用脚本管理器更新/一次性执行脚本
* 从 `git` 执行常规用户安装脚本
* 检查系统完整性和缺失的 GPG 密钥
* 修复网络
* 修复已破损的包
* 还有更多功能在开发中
**重要提示:** Ubunsys 不适用于 Ubuntu 新手。它很危险并且仍然不是稳定版。它可能会使你的系统崩溃。如果你刚接触 Ubuntu 不久,不要使用。但如果你真的很好奇这个应用能做什么,仔细浏览每一个选项,并确定自己能承担风险。在使用这一应用之前记着备份你自己的重要数据。
### 安装 Ubunsys
Ubunsys 开发者制作了一个 PPA 来简化安装过程Ubunsys 现在可以在 Ubuntu 16.04 LTS、 Ubuntu 17.04 64 位版本上使用。
逐条执行下面的命令,将 Ubunsys 的 PPA 添加进去,并安装它。
```
sudo add-apt-repository ppa:adgellida/ubunsys
sudo apt-get update
sudo apt-get install ubunsys
```
如果 PPA 无法使用,你可以在[发布页面][1]根据你自己当前系统,选择正确的安装包,直接下载并安装 Ubunsys。
### 用途
一旦安装完成,从菜单栏启动 Ubunsys。下图是 Ubunsys 主界面。
![][3]
你可以看到Ubunsys 有四个主要部分,分别是 Packages、Tweaks、System 和 Repair。在每一个标签项下面都有一个或多个子标签项以对应不同的操作。
**Packages**
这一部分允许你安装、删除和更新包。
![][4]
**Tweaks**
在这一部分,我们可以对系统进行多种调整,例如:
* 打开、备份和导入 `sources.list.d``sudoers` 文件;
* 配置双启动;
* 启用或禁用登录音效、防火墙、锁屏、系统休眠、`sudo` 权限(在不需要密码的情况下)同时你还可以针对某一用户启用或禁用 `sudo` 权限(在不需要密码的情况下);
* 在终端中输入密码时可见(禁用星号)。
![][5]
**System**
这一部分被进一步分成 3 个部分,每个都是针对某一特定用户类型。
**Normal user** 这一标签下的选项可以:
* 更新、升级包和软件源
* 清理系统
* 执行常规用户安装脚本
**Advanced user** 这一标签下的选项可以:
* 清理旧的/无用的内核
* 安装主线内核
* 智能包更新
* 升级系统
**Developer** 这一部分可以将系统升级到最新的开发版本。
![][6]
**Repair**
这是 Ubunsys 的第四个也是最后一个部分。正如名字所示,这一部分能让我们修复我们的系统、网络、缺失的 GPG 密钥,和已经缺失的包。
![][7]
正如你所见Ubunsys 可以在几次点击下就能完成诸如系统配置、系统维护和软件维护之类的任务。你不需要一直依赖于终端。Ubunsys 能帮你完成任何高级任务。再次声明,我警告你,这个应用不适合新手,而且它并不稳定。所以当你使用的时候,能会出现 bug 或者系统崩溃。在仔细研究过每一个选项的影响之后再使用它。
谢谢阅读!
### 参考资源
- [Ubunsys GitHub Repository][8]
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/ubunsys-advanced-system-configuration-utility-ubuntu-power-users/
作者:[SK][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[wenwensnow](https://github.com/wenwensnow)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.ostechnix.com/author/sk/
[1]:https://github.com/adgellida/ubunsys/releases
[2]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
[3]:http://www.ostechnix.com/wp-content/uploads/2017/08/Ubunsys-1.png
[4]:http://www.ostechnix.com/wp-content/uploads/2017/08/Ubunsys-2.png
[5]:http://www.ostechnix.com/wp-content/uploads/2017/08/Ubunsys-5.png
[6]:http://www.ostechnix.com/wp-content/uploads/2017/08/Ubunsys-9.png
[7]:http://www.ostechnix.com/wp-content/uploads/2017/08/Ubunsys-11.png
[8]:https://github.com/adgellida/ubunsys

View File

@ -0,0 +1,183 @@
Streams一个新的 Redis 通用数据结构
======
直到几个月以前,对于我来说,在消息传递的环境中,<ruby><rt>streams</rt></ruby>只是一个有趣且相对简单的概念。这个概念在 Kafka 流行之后,我主要研究它们在 Disque 案例中的应用Disque 是一个消息队列,它将在 Redis 4.2 中被转换为 Redis 的一个模块。后来我决定让 Disque 都用 AP 消息LCTT 译注:参见 [CAP 定理][1] ,也就是说,它将在不需要客户端过多参与的情况下实现容错和可用性,这样一来,我更加确定地认为流的概念在那种情况下并不适用。
然而在那时 Redis 有个问题,那就是缺省情况下导出数据结构并不轻松。它在 Redis <ruby>列表<rt>list</rt></ruby><ruby>有序集<rt>sorted list</rt></ruby><ruby>发布/订阅<rt>Pub/Sub</rt></ruby>功能之间有某些缺陷。你可以权衡使用这些工具对一系列消息或事件建模。
有序集是内存消耗大户,那自然就不能对投递的相同消息进行一次又一次的建模,客户端不能阻塞新消息。因为有序集并不是一个序列化的数据结构,它是一个元素可以根据它们量的变化而移动的集合:所以它不像时序性的数据那样。
列表有另外的问题,它在某些特定的用例中会产生类似的适用性问题:你无法浏览列表中间的内容,因为在那种情况下,访问时间是线性的。此外,没有任何指定输出的功能,列表上的阻塞操作仅为单个客户端提供单个元素。列表中没有固定的元素标识,也就是说,不能指定从哪个元素开始给我提供内容。
对于一对多的工作任务,有发布/订阅机制,它在大多数情况下是非常好的,但是,对于某些不想<ruby>“即发即弃”<rt>fire-and-forget</rt></ruby>的东西:保留一个历史是很重要的,不只是因为是断开之后会重新获得消息,也因为某些如时序性的消息列表,用范围查询浏览是非常重要的:比如在这 10 秒范围内温度读数是多少?
我试图解决上述问题我想规划一个通用的有序集合并列入一个独特的、更灵活的数据结构然而我的设计尝试最终以生成一个比当前的数据结构更加矫揉造作的结果而告终。Redis 有个好处,它的数据结构导出更像自然的计算机科学的数据结构,而不是 “Salvatore 发明的 API”。因此我最终停止了我的尝试并且说“ok这是我们目前能提供的”或许我会为发布/订阅增加一些历史信息,或者为列表访问增加一些更灵活的方式。然而,每次在会议上有用户对我说 “你如何在 Redis 中模拟时间系列” 或者类似的问题时,我的脸就绿了。
### 起源
在 Redis 4.0 中引入模块之后,用户开始考虑他们自己怎么去修复这些问题。其中一个用户 Timothy Downs 通过 IRC 和我说道:
\<forkfork> 我计划给这个模块增加一个事务日志式的数据类型 —— 这意味着大量的订阅者可以在不导致 redis 内存激增的情况下做一些像发布/订阅那样的事情
\<forkfork> 订阅者持有他们在消息队列中的位置,而不是让 Redis 必须维护每个消费者的位置和为每个订阅者复制消息
他的思路启发了我。我想了几天,并且意识到这可能是我们马上同时解决上面所有问题的契机。我需要去重新构思 “日志” 的概念是什么。日志是个基本的编程元素,每个人都使用过它,因为它只是简单地以追加模式打开一个文件,并以一定的格式写入数据。然而 Redis 数据结构必须是抽象的。它们在内存中,并且我们使用内存并不是因为我们懒,而是因为使用一些指针,我们可以概念化数据结构并把它们抽象,以使它们摆脱明确的限制。例如,一般来说日志有几个问题:偏移不是逻辑化的,而是真实的字节偏移,如果你想要与条目插入的时间相关的逻辑偏移应该怎么办?我们有范围查询可用。同样,日志通常很难进行垃圾回收:在一个只能进行追加操作的数据结构中怎么去删除旧的元素?好吧,在我们理想的日志中,我们只需要说,我想要数字最大的那个条目,而旧的元素一个也不要,等等。
当我从 Timothy 的想法中受到启发,去尝试着写一个规范的时候,我使用了 Redis 集群中的 radix 树去实现,优化了它内部的某些部分。这为实现一个有效利用空间的日志提供了基础,而且仍然有可能在<ruby>对数时间<rt>logarithmic time</rt></ruby>内访问范围。同时,我开始去读关于 Kafka 的流相关的内容以获得另外的灵感,它也非常适合我的设计,最后借鉴了 Kafka <ruby>消费组<rt>consumer groups</rt></ruby>的概念,并且再次针对 Redis 进行优化,以适用于 Redis 在内存中使用的情况。然而,该规范仅停留在纸面上,在一段时间后我几乎把它从头到尾重写了一遍,以便将我与别人讨论的所得到的许多建议一起增加到 Redis 升级中。我希望 Redis 流能成为对于时间序列有用的特性,而不仅是一个常见的事件和消息类的应用程序。
### 让我们写一些代码吧
从 Redis 大会回来后,整个夏天我都在实现一个叫 listpack 的库。这个库是 `ziplist.c` 的继任者,那是一个表示在单个分配中的字符串元素列表的数据结构。它是一个非常特殊的序列化格式,其特点在于也能够以逆序(从右到左)解析:以便在各种用例中替代 ziplists。
结合 radix 树和 listpacks 的特性,它可以很容易地去构建一个空间高效的日志,并且还是可索引的,这意味着允许通过 ID 和时间进行随机访问。自从这些就绪后,我开始去写一些代码以实现流数据结构。我还在完成这个实现,不管怎样,现在在 Github 上的 Redis 的 streams 分支里它已经可以跑起来了。我并没有声称那个 API 是 100% 的最终版本,但是,这有两个有意思的事实:一,在那时只有消费群组是缺失的,加上一些不太重要的操作流的命令,但是,所有的大的方面都已经实现了。二,一旦各个方面比较稳定了之后,我决定大概用两个月的时间将所有的流的特性<ruby>向后移植<rt>backport</rt></ruby>到 4.0 分支。这意味着 Redis 用户想要使用流,不用等待 Redis 4.2 发布,它们在生产环境马上就可用了。这是可能的,因为作为一个新的数据结构,几乎所有的代码改变都出现在新的代码里面。除了阻塞列表操作之外:该代码被重构了,我们对于流和列表阻塞操作共享了相同的代码,而极大地简化了 Redis 内部实现。
### 教程:欢迎使用 Redis 的 streams
在某些方面,你可以认为流是 Redis 列表的一个增强版本。流元素不再是一个单一的字符串,而是一个<ruby>字段<rt>field</rt></ruby><ruby><rt>value</rt></ruby>组成的对象。范围查询更适用而且更快。在流中,每个条目都有一个 ID它是一个逻辑偏移量。不同的客户端可以<ruby>阻塞等待<rt>blocking-wait</rt></ruby>比指定的 ID 更大的元素。Redis 流的一个基本的命令是 `XADD`。是的,所有的 Redis 流命令都是以一个 `X` 为前缀的。
```
> XADD mystream * sensor-id 1234 temperature 10.5
1506871964177.0
```
这个 `XADD` 命令将追加指定的条目作为一个指定的流 —— “mystream” 的新元素。上面示例中的这个条目有两个字段:`sensor-id` 和 `temperature`,每个条目在同一个流中可以有不同的字段。使用相同的字段名可以更好地利用内存。有意思的是,字段的排序是可以保证顺序的。`XADD` 仅返回插入的条目的 ID因为在第三个参数中是星号`*`),表示由命令自动生成 ID。通常这样做就够了但是也可以去强制指定一个 ID这种情况用于复制这个命令到<ruby>从服务器<rt>slave server</rt></ruby><ruby>AOF<rt>append-only file</rt></ruby> 文件。
这个 ID 是由两部分组成的:一个毫秒时间和一个序列号。`1506871964177` 是毫秒时间,它只是一个毫秒级的 UNIX 时间戳。圆点(`.`)后面的数字 `0` 是一个序号,它是为了区分相同毫秒数的条目增加上去的。这两个数字都是 64 位的无符号整数。这意味着我们可以在流中增加所有想要的条目即使是在同一毫秒中。ID 的毫秒部分使用 Redis 服务器的当前本地时间生成的 ID 和流中的最后一个条目 ID 两者间的最大的一个。因此,举例来说,即使是计算机时间回跳,这个 ID 仍然是增加的。在某些情况下,你可以认为流条目的 ID 是完整的 128 位数字。然而,事实上它们与被添加到的实例的本地时间有关,这意味着我们可以在毫秒级的精度的范围随意查询。
正如你想的那样,快速添加两个条目后,结果是仅一个序号递增了。我们可以用一个 `MULTI`/`EXEC` 块来简单模拟“快速插入”:
```
> MULTI
OK
> XADD mystream * foo 10
QUEUED
> XADD mystream * bar 20
QUEUED
> EXEC
1) 1506872463535.0
2) 1506872463535.1
```
在上面的示例中,也展示了无需指定任何初始<ruby>模式<rt>schema</rt></ruby>的情况下,对不同的条目使用不同的字段。会发生什么呢?就像前面提到的一样,只有每个块(它通常包含 50-150 个消息内容)的第一个消息被使用。并且,相同字段的连续条目都使用了一个标志进行了压缩,这个标志表示与“它们与这个块中的第一个条目的字段相同”。因此,使用相同字段的连续消息可以节省许多内存,即使是字段集随着时间发生缓慢变化的情况下也很节省内存。
为了从流中检索数据,这里有两种方法:范围查询,它是通过 `XRANGE` 命令实现的;<ruby>流播<rt>streaming</rt></ruby>,它是通过 `XREAD` 命令实现的。`XRANGE` 命令仅取得包括从开始到停止范围内的全部条目。因此,举例来说,如果我知道它的 ID我可以使用如下的命名取得单个条目
```
> XRANGE mystream 1506871964177.0 1506871964177.0
1) 1) 1506871964177.0
2) 1) "sensor-id"
2) "1234"
3) "temperature"
4) "10.5"
```
不管怎样,你都可以使用指定的开始符号 `-` 和停止符号 `+` 表示最小和最大的 ID。为了限制返回条目的数量也可以使用 `COUNT` 选项。下面是一个更复杂的 `XRANGE` 示例:
```
> XRANGE mystream - + COUNT 2
1) 1) 1506871964177.0
2) 1) "sensor-id"
2) "1234"
3) "temperature"
4) "10.5"
2) 1) 1506872463535.0
2) 1) "foo"
2) "10"
```
这里我们讲的是 ID 的范围,然后,为了取得在一个给定时间范围内的特定范围的元素,你可以使用 `XRANGE`,因为 ID 的“序号” 部分可以省略。因此,你可以只指定“毫秒”时间即可,下面的命令的意思是:“从 UNIX 时间 1506872463 开始给我 10 个条目”:
```
127.0.0.1:6379> XRANGE mystream 1506872463000 + COUNT 10
1) 1) 1506872463535.0
2) 1) "foo"
2) "10"
2) 1) 1506872463535.1
2) 1) "bar"
2) "20"
```
关于 `XRANGE` 需要注意的最重要的事情是,假设我们在回复中收到 ID随后连续的 ID 只是增加了序号部分,所以可以使用 `XRANGE` 遍历整个流接收每个调用的指定个数的元素。Redis 中的`*SCAN` 系列命令允许迭代 Redis 数据结构,尽管事实上它们不是为迭代设计的,但这样可以避免再犯相同的错误。
### 使用 XREAD 处理流播:阻塞新的数据
当我们想通过 ID 或时间去访问流中的一个范围或者是通过 ID 去获取单个元素时,使用 `XRANGE` 是非常完美的。然而,在使用流的案例中,当数据到达时,它必须由不同的客户端来消费时,这就不是一个很好的解决方案,这需要某种形式的<ruby>汇聚池<rt>pooling</rt></ruby>。(对于 *某些* 应用程序来说,这可能是个好主意,因为它们仅是偶尔连接查询的)
`XREAD` 命令是为读取设计的,在同一个时间,从多个流中仅指定我们从该流中得到的最后条目的 ID。此外如果没有数据可用我们可以要求阻塞当数据到达时就解除阻塞。类似于阻塞列表操作产生的效果但是这里并没有消费从流中得到的数据并且多个客户端可以同时访问同一份数据。
这里有一个典型的 `XREAD` 调用示例:
```
> XREAD BLOCK 5000 STREAMS mystream otherstream $ $
```
它的意思是:从 `mystream``otherstream` 取得数据。如果没有数据可用,阻塞客户端 5000 毫秒。在 `STREAMS` 选项之后指定我们想要监听的关键字,最后的是指定想要监听的 ID指定的 ID 为 `$` 的意思是:假设我现在需要流中的所有元素,因此,只需要从下一个到达的元素开始给我。
如果我从另一个客户端发送这样的命令:
```
> XADD otherstream * message “Hi There”
```
`XREAD` 侧会出现什么情况呢?
```
1) 1) "otherstream"
2) 1) 1) 1506935385635.0
2) 1) "message"
2) "Hi There"
```
与收到的数据一起,我们也得到了数据的关键字。在下次调用中,我们将使用接收到的最新消息的 ID
```
> XREAD BLOCK 5000 STREAMS mystream otherstream $ 1506935385635.0
```
依次类推。然而需要注意的是使用方式,客户端有可能在一个非常大的延迟之后再次连接(因为它处理消息需要时间,或者其它什么原因)。在这种情况下,期间会有很多消息堆积,为了确保客户端不被消息淹没,以及服务器不会因为给单个客户端提供大量消息而浪费太多的时间,使用 `XREAD``COUNT` 选项是非常明智的。
### 流封顶
目前看起来还不错……然而,有些时候,流需要删除一些旧的消息。幸运的是,这可以使用 `XADD` 命令的 `MAXLEN` 选项去做:
```
> XADD mystream MAXLEN 1000000 * field1 value1 field2 value2
```
它是基本意思是,如果在流中添加新元素后发现消息数量超过了 `1000000` 个,那么就删除旧的消息,以便于元素总量重新回到 `1000000` 以内。它很像是在列表中使用的 `RPUSH` + `LTRIM`,但是,这次我们是使用了一个内置机制去完成的。然而,需要注意的是,上面的意思是每次我们增加一个新的消息时,我们还需要另外的工作去从流中删除旧的消息。这将消耗一些 CPU 资源,所以在计算 `MAXLEN` 之前,尽可能使用 `~` 符号,以表明我们不要求非常 *精确* 的 1000000 个消息,就是稍微多一些也不是大问题:
```
> XADD mystream MAXLEN ~ 1000000 * foo bar
```
这种方式的 XADD 仅当它可以删除整个节点的时候才会删除消息。相比普通的 `XADD`,这种方式几乎可以自由地对流进行封顶。
### 消费组(开发中)
这是第一个 Redis 中尚未实现而在开发中的特性。灵感也是来自 Kafka尽管在这里是以不同的方式实现的。重点是使用了 `XREAD`,客户端也可以增加一个 `GROUP <name>` 选项。相同组的所有客户端将自动得到 *不同的* 消息。当然,同一个流可以被多个组读取。在这种情况下,所有的组将收到流中到达的消息的相同副本。但是,在每个组内,消息是不会重复的。
当指定组时,能够指定一个 `RETRY <milliseconds>` 选项去扩展组:在这种情况下,如果消息没有通过 `XACK` 进行确认,它将在指定的毫秒数后进行再次投递。这将为消息投递提供更佳的可靠性,这种情况下,客户端没有私有的方法将消息标记为已处理。这一部分也正在开发中。
### 内存使用和节省加载时间
因为用来建模 Redis 流的设计,内存使用率是非常低的。这取决于它们的字段、值的数量和长度,对于简单的消息,每使用 100MB 内存可以有几百万条消息。此外该格式设想为需要极少的序列化listpack 块以 radix 树节点方式存储在磁盘上和内存中都以相同方式表示的因此它们可以很轻松地存储和读取。例如Redis 可以在 0.3 秒内从 RDB 文件中读取 500 万个条目。这使流的复制和持久存储非常高效。
我还计划允许从条目中间进行部分删除。现在仅实现了一部分,策略是在条目在标记中标识条目为已删除,并且,当已删除条目占全部条目的比例达到指定值时,这个块将被回收重写,如果需要,它将被连到相邻的另一个块上,以避免碎片化。
### 关于最终发布时间的结论
Redis 的流特性将包含在年底前LCTT 译注:本文原文发布于 2017 年 10 月)推出的 Redis 4.0 系列的稳定版中。我认为这个通用的数据结构将为 Redis 提供一个巨大的补丁,以用于解决很多现在很难以解决的情况:那意味着你(之前)需要创造性地“滥用”当前提供的数据结构去解决那些问题。一个非常重要的使用场景是时间序列,但是,我觉得对于其它场景来说,通过 `TREAD` 来流播消息将是非常有趣的,因为对于那些需要更高可靠性的应用程序,可以使用发布/订阅模式来替换“即用即弃”,还有其它全新的使用场景。现在,如果你想在有问题环境中评估这个新数据结构,可以更新 GitHub 上的 streams 分支开始试用。欢迎向我们报告所有的 bug。:-)
如果你喜欢观看视频的方式这里有一个现场演示https://www.youtube.com/watch?v=ELDzy9lCFHQ
---
via: http://antirez.com/news/114
作者:[antirez][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[wxy](https://github.com/wxy), [pityonline](https://github.com/pityonline)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: http://antirez.com/
[1]: https://zh.wikipedia.org/wiki/CAP%E5%AE%9A%E7%90%86

View File

@ -1,40 +1,41 @@
通过构建一个区块链来学习区块链技术
想学习区块链?那就用 Python 构建一个
======
> 了解区块链是如何工作的最快的方法是构建一个。
![](https://cdn-images-1.medium.com/max/2000/1*zutLn_-fZZhy7Ari-x-JWQ.jpeg)
你看到这篇文章是因为和我一样,对加密货币的大热而感到兴奋。并且想知道区块链是如何工作的 —— 它们背后的技术是什么。
你看到这篇文章是因为和我一样,对加密货币的大热而感到兴奋。并且想知道区块链是如何工作的 —— 它们背后的技术基础是什么。
但是理解区块链并不容易 —— 至少对我来说是这样。我徜徉在各种难懂的视频中,并且因为示例太少而陷入深深的挫败感中。
我喜欢在实践中学习。这迫使我去处理被卡在代码级别上的难题。如果你也是这么做的,在本指南结束的时候,你将拥有一个功能正常的区块链,并且实实在在地理解了它的工作原理。
我喜欢在实践中学习。这会使得我在代码层面上处理主要问题,从而可以让我坚持到底。如果你也是这么做的,在本指南结束的时候,你将拥有一个功能正常的区块链,并且实实在在地理解了它的工作原理。
### 开始之前 …
记住,区块链是一个 _不可更改的、有序的_ 被称为区块的记录链。它们可以包括事务~~(交易???校对确认一下,下同)~~、文件或者任何你希望的真实数据。最重要的是它们是通过使用_哈希_链接到一起的。
记住,区块链是一个 _不可更改的、有序的_ 记录(被称为区块)的链。它们可以包括<ruby>交易<rt>transaction</rt></ruby>、文件或者任何你希望的真实数据。最重要的是它们是通过使用_哈希_链接到一起的。
如果你不知道哈希是什么,[这里有解释][1]。
**_本指南的目标读者是谁_** 你应该能很容易地读和写一些基本的 Python 代码,并能够理解 HTTP 请求是如何工作的,因为我们讨论的区块链将基于 HTTP。
**_本指南的目标读者是谁_** 你应该能轻松地读、写一些基本的 Python 代码,并能够理解 HTTP 请求是如何工作的,因为我们讨论的区块链将基于 HTTP。
**_我需要做什么_** 确保安装了 [Python 3.6][2]+(以及 `pip`),还需要去安装 Flask 和非常好用的 Requests 库:
```
pip install Flask==0.12.2 requests==2.18.4
pip install Flask==0.12.2 requests==2.18.4
```
当然,你也需要一个 HTTP 客户端,像 [Postman][3] 或者 cURL。哪个都行。
**_最终的代码在哪里可以找到_** 源代码在 [这里][4]。
* * *
### 第 1 步:构建一个区块链
打开你喜欢的文本编辑器或者 IDE我个人 ❤️ [PyCharm][5]。创建一个名为 `blockchain.py` 的新文件。我将使用一个单个的文件,如果你看晕了,可以去参考 [源代码][6]。
打开你喜欢的文本编辑器或者 IDE我个人喜欢 [PyCharm][5]。创建一个名为 `blockchain.py` 的新文件。我将使用一个文件,如果你看晕了,可以去参考 [源代码][6]。
#### 描述一个区块链
我们将创建一个 `Blockchain` 类,它的构造函数将去初始化一个空列表(去存储我们的区块链),以及另一个列表去保存事务。下面是我们的类规划:
我们将创建一个 `Blockchain` 类,它的构造函数将去初始化一个空列表(去存储我们的区块链),以及另一个列表去保存交易。下面是我们的类规划:
```
class Blockchain(object):
@ -58,15 +59,16 @@ class Blockchain(object):
@property
def last_block(self):
# Returns the last Block in the chain
pass
pass
```
*我们的 Blockchain 类的原型*
我们的区块链类负责管理链。它将存储事务并且有一些为链中增加新区块的助理性质的方法。现在我们开始去充实一些类的方法。
我们的 `Blockchain` 类负责管理链。它将存储交易并且有一些为链中增加新区块的辅助性质的方法。现在我们开始去充实一些类的方法。
#### 一个区块是什么样子的?
#### 区块是什么样子的?
每个区块有一个索引、一个时间戳Unix 时间)、一个事务的列表、一个证明(后面会详细解释)、以及前一个区块的哈希。
每个区块有一个索引、一个时间戳Unix 时间)、一个交易的列表、一个证明(后面会详细解释)、以及前一个区块的哈希。
单个区块的示例应该是下面的样子:
@ -86,13 +88,15 @@ block = {
}
```
此刻,链的概念应该非常明显 —— 每个新区块包含它自身的信息和前一个区域的哈希。这一点非常重要,因为这就是区块链不可更改的原因:如果攻击者修改了一个早期的区块,那么所有的后续区块将包含错误的哈希。
*我们的区块链中的块示例*
这样做有意义吗?如果没有,就让时间来埋葬它吧 —— 这就是区块链背后的核心思想
此刻,链的概念应该非常明显 —— 每个新区块包含它自身的信息和前一个区域的哈希。**这一点非常重要,因为这就是区块链不可更改的原因**:如果攻击者修改了一个早期的区块,那么**所有**的后续区块将包含错误的哈希
#### 添加事务到一个区块
*这样做有意义吗?如果没有,就让时间来埋葬它吧 —— 这就是区块链背后的核心思想。*
我们将需要一种区块中添加事务的方式。我们的 `new_transaction()` 就是做这个的,它非常简单明了:
#### 添加交易到一个区块
我们将需要一种区块中添加交易的方式。我们的 `new_transaction()` 就是做这个的,它非常简单明了:
```
class Blockchain(object):
@ -113,14 +117,14 @@ class Blockchain(object):
'amount': amount,
})
return self.last_block['index'] + 1
return self.last_block['index'] + 1
```
`new_transaction()` 运行后将在列表中添加一个事务,它返回添加事务后的那个区块的索引 —— 那个区块接下来将被挖矿。提交事务的用户后面会用到这些。
`new_transaction()` 运行后将在列表中添加一个交易,它返回添加交易后的那个区块的索引 —— 那个区块接下来将被挖矿。提交交易的用户后面会用到这些。
#### 创建新区块
当我们的区块链被实例化后,我们需要一个创世区块(一个没有祖先的区块)来播种它。我们也需要去添加一些 “证明” 到创世区块,它是挖矿(工作量证明 PoW的成果。我们在后面将讨论更多挖矿的内容。
当我们的 `Blockchain` 被实例化后,我们需要一个创世区块(一个没有祖先的区块)来播种它。我们也需要去添加一些 “证明” 到创世区块,它是挖矿(工作量证明 PoW的成果。我们在后面将讨论更多挖矿的内容。
除了在我们的构造函数中创建创世区块之外,我们还需要写一些方法,如 `new_block()`、`new_transaction()` 以及 `hash()`
@ -190,18 +194,18 @@ class Blockchain(object):
# We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
return hashlib.sha256(block_string).hexdigest()
```
上面的内容简单明了 —— 我添加了一些注释和文档字符串,以使代码清晰可读。到此为止,表示我们的区块链基本上要完成了。但是,你肯定想知道新区块是如何被创建、打造或者挖矿的。
#### 理解工作量证明
一个工作量证明PoW算法是在区块链上创建或者挖出新区块的方法。PoW 的目标是去撞出一个能够解决问题的数字。这个数字必须满足“找到它很困难但是验证它很容易”的条件 —— 网络上的任何人都可以计算它。这就是 PoW 背后的核心思想。
<ruby>工作量证明<rt>Proof of Work</rt></ruby>PoW算法是在区块链上创建或者挖出新区块的方法。PoW 的目标是去撞出一个能够解决问题的数字。这个数字必须满足“找到它很困难但是验证它很容易”的条件 —— 网络上的任何人都可以计算它。这就是 PoW 背后的核心思想。
我们来看一个非常简单的示例来帮助你了解它。
我们来解决一个问题,一些整数 x 乘以另外一个整数 y 的结果的哈希值必须以 0 结束。因此hash(x * y) = ac23dc…0。为简单起见我们先把 x = 5 固定下来。在 Python 中的实现如下:
我们来解决一个问题,一些整数 `x` 乘以另外一个整数 `y` 的结果的哈希值必须以 `0` 结束。因此,`hash(x * y) = ac23dc…0`。为简单起见,我们先把 `x = 5` 固定下来。在 Python 中的实现如下:
```
from hashlib import sha256
@ -215,19 +219,21 @@ while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":
print(f'The solution is y = {y}')
```
在这里的答案是 y = 21。因为它产生的哈希值是以 0 结尾的:
在这里的答案是 `y = 21`。因为它产生的哈希值是以 0 结尾的:
```
hash(5 * 21) = 1253e9373e...5e3600155e860
```
在比特币中,工作量证明算法被称之为 [Hashcash][10]。与我们上面的例子没有太大的差别。这就是矿工们进行竞赛以决定谁来创建新块的算法。一般来说,其难度取决于在一个字符串中所查找的字符数量。然后矿工会因其做出的求解而得到奖励的币——在一个交易当中。
网络上的任何人都可以很容易地去核验它的答案。
#### 实现基本的 PoW
为我们的区块链来实现一个简单的算法。我们的规则与上面的示例类似:
> 找出一个数字 p它与前一个区块的答案进行哈希运算得到一个哈希值这个哈希值的前四位必须是由 0 组成。
> 找出一个数字 `p`,它与前一个区块的答案进行哈希运算得到一个哈希值,这个哈希值的前四位必须是由 `0` 组成。
```
import hashlib
@ -266,25 +272,21 @@ class Blockchain(object):
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
return guess_hash[:4] == "0000"
```
为了调整算法的难度,我们可以修改前导 0 的数量。但是 4 个零已经足够难了。你会发现,将前导 0 的数量每增加一,那么找到正确答案所需要的时间难度将大幅增加。
我们的类基本完成了,现在我们开始去使用 HTTP 请求与它交互。
* * *
### 第 2 步:以 API 方式去访问我们的区块链
我们将使用 Python Flask 框架。它是个微框架,使用它去做端点到 Python 函数的映射很容易。这样我们可以使用 HTTP 请求基于 web 来与我们的区块链对话。
我们将使用 Python Flask 框架。它是个微框架,使用它去做端点到 Python 函数的映射很容易。这样我们可以使用 HTTP 请求基于 web 来与我们的区块链对话。
我们将创建三个方法:
* `/transactions/new` 在一个区块上创建一个新事务
* `/transactions/new` 在一个区块上创建一个新交易
* `/mine` 告诉我们的服务器去挖矿一个新区块
* `/chain` 返回完整的区块链
#### 配置 Flask
@ -332,33 +334,33 @@ def full_chain():
return jsonify(response), 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
app.run(host='0.0.0.0', port=5000)
```
对上面的代码,我们做添加一些详细的解释:
* Line 15实例化我们的节点。更多关于 Flask 的知识读 [这里][7]。
* Line 18为我们的节点创建一个随机的名字。
* Line 21实例化我们的区块链类。
* Line 2426创建 /mine 端点,这是一个 GET 请求。
* Line 2830创建 /transactions/new 端点,这是一个 POST 请求,因为我们要发送数据给它。
* Line 3238创建 /chain 端点,它返回全部区块链。
* Line 2426创建 `/mine` 端点,这是一个 GET 请求。
* Line 2830创建 `/transactions/new` 端点,这是一个 POST 请求,因为我们要发送数据给它。
* Line 3238创建 `/chain` 端点,它返回全部区块链。
* Line 4041在 5000 端口上运行服务器。
#### 事务端点
#### 交易端点
这就是对一个事务的请求,它是用户发送给服务器的:
这就是对一个交易的请求,它是用户发送给服务器的:
```
{ "sender": "my address", "recipient": "someone else's address", "amount": 5}
{
"sender": "my address",
"recipient": "someone else's address",
"amount": 5
}
```
因为我们已经有了添加交易到块中的类方法,剩下的就很容易了。让我们写个函数来添加交易:
```
import hashlib
import json
@ -383,18 +385,17 @@ def new_transaction():
index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])
response = {'message': f'Transaction will be added to Block {index}'}
return jsonify(response), 201
return jsonify(response), 201
```
创建事务的方法
*创建交易的方法*
#### 挖矿端点
我们的挖矿端点是见证奇迹的地方,它实现起来很容易。它要做三件事情:
1. 计算工作量证明
2. 因为矿工(我们)添加一个事务而获得报酬,奖励矿工(我们) 1 个硬币
2. 因为矿工(我们)添加一个交易而获得报酬,奖励矿工(我们) 1 个币
3. 通过将它添加到链上而打造一个新区块
```
@ -434,10 +435,10 @@ def mine():
'proof': block['proof'],
'previous_hash': block['previous_hash'],
}
return jsonify(response), 200
return jsonify(response), 200
```
注意,挖掘出的区块的接收方是我们的节点地址。现在,我们所做的大部分工作都只是与我们的区块链类的方法进行交互的。到目前为止,我们已经做到了,现在开始与我们的区块链去交互。
注意,挖掘出的区块的接收方是我们的节点地址。现在,我们所做的大部分工作都只是与我们的 `Blockchain` 类的方法进行交互的。到目前为止,我们已经做完了,现在开始与我们的区块链去交互。
### 第 3 步:与我们的区块链去交互
@ -447,24 +448,33 @@ return jsonify(response), 200
```
$ python blockchain.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```
我们通过生成一个 GET 请求到 http://localhost:5000/mine 去尝试挖一个区块:
我们通过生成一个 `GET` 请求到 `http://localhost:5000/mine` 去尝试挖一个区块:
![](https://cdn-images-1.medium.com/max/1600/1*ufYwRmWgQeA-Jxg0zgYLOA.png)
使用 Postman 去生成一个 GET 请求
我们通过生成一个 POST 请求到 http://localhost:5000/transactions/new 去创建一个区块,它带有一个包含我们的事务结构的 `Body`
*使用 Postman 去生成一个 GET 请求*
我们通过生成一个 `POST` 请求到 `http://localhost:5000/transactions/new` 去创建一个区块,请求数据包含我们的交易结构:
![](https://cdn-images-1.medium.com/max/1600/1*O89KNbEWj1vigMZ6VelHAg.png)
使用 Postman 去生成一个 POST 请求
*使用 Postman 去生成一个 POST 请求*
如果你不使用 Postman也可以使用 cURL 去生成一个等价的请求:
```
$ curl -X POST -H "Content-Type: application/json" -d '{ "sender": "d4ee26eee15148ee92c6cd394edd974e", "recipient": "someone-other-address", "amount": 5}' "http://localhost:5000/transactions/new"
$ curl -X POST -H "Content-Type: application/json" -d '{
"sender": "d4ee26eee15148ee92c6cd394edd974e",
"recipient": "someone-other-address",
"amount": 5
}' "http://localhost:5000/transactions/new"
```
我重启动我的服务器然后我挖到了两个区块这样总共有了3 个区块。我们通过请求 http://localhost:5000/chain 来检查整个区块链:
我重启动我的服务器,然后我挖到了两个区块,这样总共有了 3 个区块。我们通过请求 `http://localhost:5000/chain` 来检查整个区块链:
```
{
"chain": [
@ -503,18 +513,18 @@ $ curl -X POST -H "Content-Type: application/json" -d '{ "sender": "d4ee26eee151
}
],
"length": 3
}
```
### 第 4 步:共识
这是很酷的一个地方。我们已经有了一个基本的区块链,它可以接收事务并允许我们去挖掘出新区块。但是区块链的整个重点在于它是去中心化的。而如果它们是去中心化的,那我们如何才能确保它们表示在同一个区块链上?这就是共识问题,如果我们希望在我们的网络上有多于一个的节点运行,那么我们将必须去实现一个共识算法。
这是很酷的一个地方。我们已经有了一个基本的区块链,它可以接收交易并允许我们去挖掘出新区块。但是区块链的整个重点在于它是<ruby>去中心化的<rt>decentralized</rt></ruby>。而如果它们是去中心化的,那我们如何才能确保它们表示在同一个区块链上?这就是<ruby>共识<rt>Consensus</rt></ruby>问题,如果我们希望在我们的网络上有多于一个的节点运行,那么我们将必须去实现一个共识算法。
#### 注册新节点
在我们能实现一个共识算法之前,我们需要一个办法去让一个节点知道网络上的邻居节点。我们网络上的每个节点都保留有一个该网络上其它节点的注册信息。因此,我们需要更多的端点:
1. /nodes/register 以 URLs 的形式去接受一个新节点列表
2. /nodes/resolve 去实现我们的共识算法,由它来解决任何的冲突 —— 确保节点有一个正确的链。
1. `/nodes/register` 以 URL 的形式去接受一个新节点列表
2. `/nodes/resolve` 去实现我们的共识算法,由它来解决任何的冲突 —— 确保节点有一个正确的链。
我们需要去修改我们的区块链的构造函数,来提供一个注册节点的方法:
@ -538,11 +548,12 @@ class Blockchain(object):
"""
parsed_url = urlparse(address)
self.nodes.add(parsed_url.netloc)
self.nodes.add(parsed_url.netloc)
```
一个添加邻居节点到我们的网络的方法
注意,我们将使用一个 `set()` 去保存节点列表。这是一个非常合算的方式,它将确保添加的内容是幂等的 —— 这意味着不论你将特定的节点添加多少次,它都是精确地只出现一次。
*一个添加邻居节点到我们的网络的方法*
注意,我们将使用一个 `set()` 去保存节点列表。这是一个非常合算的方式,它将确保添加的节点是<ruby>幂等<rt>idempotent</rt></ruby>的 —— 这意味着不论你将特定的节点添加多少次,它都是精确地只出现一次。
#### 实现共识算法
@ -615,12 +626,12 @@ class Blockchain(object)
self.chain = new_chain
return True
return False
return False
```
第一个方法 `valid_chain()` 是负责来检查链是否有效,它通过遍历区块链上的每个区块并验证它们的哈希和工作量证明来检查这个区块链是否有效。
`resolve_conflicts()` 方法用于遍历所有的邻居节点,下载它们的链并使用上面的方法去验证它们是否有效。如果找到有效的链,确定谁是最长的链,然后我们就用最长的链来替换我们的当前的链。
`resolve_conflicts()` 方法用于遍历所有的邻居节点,下载它们的链并使用上面的方法去验证它们是否有效。**如果找到有效的链,确定谁是最长的链,然后我们就用最长的链来替换我们的当前的链。**
在我们的 API 上来注册两个端点,一个用于添加邻居节点,另一个用于解决冲突:
@ -658,18 +669,20 @@ def consensus():
'chain': blockchain.chain
}
return jsonify(response), 200
return jsonify(response), 200
```
这种情况下,如果你愿意可以使用不同的机器来做,然后在你的网络上启动不同的节点。或者是在同一台机器上使用不同的端口启动另一个进程。我是在我的机器上使用了不同的端口启动了另一个节点,并将它注册到了当前的节点上。因此,我现在有了两个节点:[http://localhost:5000][9] 和 http://localhost:5001
这种情况下,如果你愿意可以使用不同的机器来做,然后在你的网络上启动不同的节点。或者是在同一台机器上使用不同的端口启动另一个进程。我是在我的机器上使用了不同的端口启动了另一个节点,并将它注册到了当前的节点上。因此,我现在有了两个节点:`http://localhost:5000` 和 `http://localhost:5001`
![](https://cdn-images-1.medium.com/max/1600/1*Dd78u-gmtwhQWHhPG3qMTQ.png)
注册一个新节点
*注册一个新节点*
我接着在节点 2 上挖出一些新区块,以确保这个链是最长的。之后我在节点 1 上以 `GET` 方式调用了 `/nodes/resolve`,这时,节点 1 上的链被共识算法替换成节点 2 上的链了:
![](https://cdn-images-1.medium.com/max/1600/1*SGO5MWVf7GguIxfz6S8NVw.png)
工作中的共识算法
*工作中的共识算法*
然后将它们封装起来 … 找一些朋友来帮你一起测试你的区块链。
@ -677,7 +690,7 @@ return jsonify(response), 200
我希望以上内容能够鼓舞你去创建一些新的东西。我是加密货币的狂热拥护者,因此我相信区块链将迅速改变我们对经济、政府和记录保存的看法。
**更新:** 我正计划继续它的第二部分,其中我将扩展我们的区块链,使它具备事务验证机制,同时讨论一些你可以在其上产生你自己的区块链的方式。
**更新:** 我正计划继续它的第二部分,其中我将扩展我们的区块链,使它具备交易验证机制,同时讨论一些你可以在其上产生你自己的区块链的方式。LCTT 译注:第二篇并没有~
--------------------------------------------------------------------------------
@ -685,7 +698,7 @@ via: https://hackernoon.com/learn-blockchains-by-building-one-117428612f46
作者:[Daniel van Flymen][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
@ -699,3 +712,4 @@ via: https://hackernoon.com/learn-blockchains-by-building-one-117428612f46
[7]:http://flask.pocoo.org/docs/0.12/quickstart/#a-minimal-application
[8]:http://localhost:5000/transactions/new
[9]:http://localhost:5000
[10]:https://en.wikipedia.org/wiki/Hashcash

View File

@ -1,12 +1,15 @@
如何提升自动化的 ROI4 个小提示
======
> 想要在你的自动化项目上达成强 RIO采取如下步骤来规避失败。
![](https://enterprisersproject.com/sites/default/files/styles/620x350/public/cio_it_investments_2.png?itok=Ut1XIIBN)
在过去的几年间有关自动化技术的讨论已经很多了。COO 们和运营团队(事实上还有其它的业务部门)对成本随着工作量的增加而增加的这一事实可以重新定义而感到震惊。
机器人流程自动化RPA似乎预示着运营的圣杯Holy Grail“我们提供了开箱即用的功能来满足你的日常操作所需 —— 检查电子邮件、保存附件、取数据、更新表格、生成报告、文件以及目录操作。构建一个机器人就像配置这些功能一样简单,然后用机器人将这些操作链接到一起,而不用去请求 IT 部门来构建它们。”这是一个多么诱人的话题
在过去的几年间有关自动化技术的讨论已经很多了。COO 们和运营团队(事实上还有其它的业务部门)对于可以重新定义成本随着工作量的增加而增加的这一事实而感到震惊
低成本、几乎不出错、非常遵守流程 —— 对 COO 们和运营领导来说这些好处即实用可行度又高。RPA 工具承诺,它从运营中节省下来的费用就足够支付它的成本(有一个短的回报期),这一事实使得业务的观点更具有吸引力。
<ruby>机器人流程自动化<rt>Robotic Process Automation</rt></ruby>RPA似乎预示着运营的<ruby>圣杯<rt>Holy Grail</rt></ruby>:“我们提供了开箱即用的功能来满足你的日常操作所需 —— 检查电子邮件、保存附件、取数据、更新表格、生成报告、文件以及目录操作。构建一个机器人就像配置这些功能一样简单,然后用机器人将这些操作链接到一起,而不用去请求 IT 部门来构建它们。”这是一个多么诱人的话题。
低成本、几乎不出错、非常遵守流程 —— 对 COO 们和运营领导来说这些好处真实可及。RPA 工具承诺,它从运营中节省下来的费用就足够支付它的成本(有一个短的回报期),这一事实使得业务的观点更具有吸引力。
自动化的谈论都趋向于类似的话题COO 们和他们的团队想知道,自动化操作能够给他们带来什么好处。他们想知道 RPA 平台特性和功能,以及自动化在现实中的真实案例。从这一点到概念验证的实现过程通常很短暂。
@ -14,7 +17,7 @@
但是自动化带来的现实好处有时候可能比你所预期的时间要晚。采用 RPA 的公司在其实施后可能会对它们自身的 ROI 提出一些质疑。一些人没有看到预期之中的成本节省,并对其中的原因感到疑惑。
## 你是不是自动化了错误的东西?
### 你是不是自动化了错误的东西?
在这些情况下,自动化的愿景和现实之间的差距是什么呢?我们来分析一下它,在决定去继续进行一个自动化验证项目(甚至是一个成熟的实践)之后,我们来看一下通常会发生什么。
@ -26,7 +29,7 @@
那么,对于领导们来说,怎么才能确保实施自动化能够带来他们想要的 ROI 呢?实现这个目标有四步:
## 1. 教育团队
### 1. 教育团队
在你的团队中,从 COO 职位以下的人中,很有可能都听说过 RPA 和运营自动化。同样很有可能他们都有许多的问题和担心。在你开始启动实施之前解决这些问题和担心是非常重要的。
@ -36,23 +39,23 @@
“实施自动化的第一步是更好地理解你的流程。”
## 2. 审查内部流程
### 2. 审查内部流程
实施自动化的第一步是更好地理解你的流程。每个 RPA 实施之前都应该进行流程清单、动作分析、以及成本/价值的绘制练习。
这些练习对于理解流程中何处价值产生(或成本,如果没有价值的情况下)是至关重要的。并且这些练习需要在每个流程或者每个任务这样的粒度级别上来做。
这些练习对于理解流程中何处产生价值(或成本,如果没有价值的情况下)是至关重要的。并且这些练习需要在每个流程或者每个任务这样的粒度级别上来做。
这将有助你去识别和优先考虑最合适的自动化候选者。由于能够或者可能需要自动化的任务数量较多,流程一般需要分段实施自动化,因此优先级很重要。
**建议**:设置一个小的工作团队,每个运营团队都参与其中。从每个运营团队中提名一个协调人 —— 一般是运营团队的领导或者团队管理者。在团队级别上组织一次研讨会,去构建流程清单、识别候选流程、以及推动购买。你的自动化合作伙伴很可能有“加速器” —— 调查问卷、计分卡等等 —— 这些将帮助你加速完成这项活动。
## 3. 为优先业务提供强有力的指导
### 3. 为优先业务提供强有力的指导
实施自动化经常会涉及到在运营团队之间,基于业务价值对流程选择和自动化优先级上要达成共识(有时候是打破平衡)虽然团队的参与仍然是分析和实施的关键部分,但是领导仍然应该是最终的决策者。
**建议**:安排定期会议从工作团队中获取最新信息。除了像推动达成共识和购买之外,工作团队还应该在团队层面上去查看领导们关于 ROI、平台选择、以及自动化优先级上的指导性决定。
## 4. 应该推动 CIO 和 COO 的紧密合作
### 4. 应该推动 CIO 和 COO 的紧密合作
当运营团队和技术团队紧密合作时自动化的实施将异常顺利。COO 需要去帮助推动与 CIO 团队的合作。
@ -68,7 +71,7 @@ via: https://enterprisersproject.com/article/2017/11/how-improve-roi-automation-
作者:[Rajesh Kamath][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,34 +1,40 @@
How To Find The Installed Proprietary Packages In Arch Linux
如何在 Arch Linux 中查找已安装的专有软件包?
======
![](https://www.ostechnix.com/wp-content/uploads/2018/01/Absolutely-Proprietary-720x340.jpg)
Are you an avid free software supporter and currently using any Arch based distribution? I've got a small tip for you! Now, you can easily find the installed proprietary packages in Arch Linux and its variants such as Antergos, Manjaro Linux etc. You don't need to refer the license details of the installed package in its website or use any external tool to find out whether the package is free or proprietary.
### Find The Installed Proprietary Packages In Arch Linux
你是狂热的自由软件支持者吗?你目前在使用任何基于 Arch 的 Linux 发行版吗?我有一个小小的提示送给你!现在,你可以轻松地在 Arch Linux 及其变体(如 Antergos、Manjaro Linux 等中找到已安装的专有软件包。你无需在已安装软件包的网站中参考其许可细节也无需使用任何其它外部工具来查明软件包是自由的还是专有的。LCTT 译注:其实下面还是借助了一个外部程序)
A fellow developer has developed an utility named **" Absolutely Proprietary"**, a proprietary package detector for arch-based distributions. It compares all installed packages in your Arch based system against Parabola's package [blacklist][1] and [aur-blacklist][2] and then prints your **Stallman Freedom Index** (free/total). Additionally, you can save the list to a file and share or compare it with other systems/users.
### 在 Arch Linux 中查找已安装的专有软件包
Before installing it, Make sure you have installed **python** and **git**.
一位开发人员开发了一个名为 “[Absolutely Proprietary][5]” 的实用程序,它是一种用于基于 Arch 发行版的专有软件包检测器。它将基于 Arch 系统中的所有安装包与 Parabola 的软件包 [blacklist][1]和 [aur-blacklist][2] 进行比较,然后显示出你的<ruby>斯托曼自由指数<rt>Stallman Freedom Index</rt></ruby>(“自由/总计”比分)。此外,你可以将该列表保存到文件中,并与其他系统/用户共享或比较。
在安装之前,确保你安装了 Python 和 Git。
然后,`git clone` 仓库:
Then, git clone the repository:
```
git clone https://github.com/vmavromatis/absolutely-proprietary.git
```
This command will download all contents in a directory called 'absolutely-proprietary' in your current working directory.
这条命令将会下载所有内容到你当前工作目录中的 `absolutely-proprietary` 目录。
进入此目录:
Change to that directory:
```
cd absolutely-proprietary
```
And, find the installed proprietary packages using command:
接着,使用以下命令查找已安装的专有软件:
```
python main.py
```
This command will download the blacklist.txt, aur-blacklist.txt and compare the locally installed packages with the remote packages and displays the
这条命令将会下载 `blacklist.txt`、`aur-blacklist.txt`,并将本地已安装的软件包与远程软件包进行比较并显示其指数。
以下是在我的 Arch Linux 桌面的示例输出:
Here is the sample output from my Arch Linux desktop:
```
Retrieving local packages (including AUR)...
Downloading https://git.parabola.nu/blacklist.git/plain/blacklist.txt
@ -73,9 +79,10 @@ Your Stallman Freedom Index is 96.57
Save list to file? (Y/n)
```
[![][3]][4]
![][4]
如你所见,我的系统中有 47 个专有软件包。就像我说的那样,我们可以将它保存到文件中稍后查看。为此,当提示你将列表保存在文件时,请按 `y`。然后按 `y` 接受默认值,或按 `n` 以你喜欢的格式和位置来保存它。
As you can see, I have 47 proprietary packages in my system. Like I said already, we can save it to a file and review them later. To do so, jut press 'y' when you are prompted to save the list in a file. Then press 'y' to accept the defaults or hit 'n' to save it in your preferred format and location.
```
Save list to file? (Y/n) y
Save as markdown table? (Y/n) y
@ -87,29 +94,29 @@ using the "less -S /home/sk/absolutely-proprietary/y.md"
or, if installed, the "most /home/sk/absolutely-proprietary/y.md" commands
```
As you may noticed, I have only the **nonfree** packages. It will display two more type of packages such as semifree, uses-nonfree.
你可能已经注意到,我只有 **nonfree** 包。它还会显示另外两种类型的软件包,例如 semifree、 uses-nonfree。
* **nonfree** : This package is blatantly nonfree software.
* **semifree** : This package is mostly free, but contains some nonfree software.
* **uses-nonfree** : This package depends on, recommends, or otherwise inappropriately integrates with other nonfree software or services.
* **nonfree**:这个软件包是公然的非自由软件。
* **semifree**:这个软件包大部分是自由的,但包含一些非自由软件。
* **uses-nonfree**:这个软件包依赖、推荐或不恰当地与其他自由软件或服务集成。
该使用程序的另一个显著特点是它不仅显示了专有软件包,而且还显示这些包的替代品。
希望这有些帮助。我很快就会在这里提供另一份有用的指南。敬请关注!
Another notable feature of this utility is it's not just displays the propriety packages, but also alternatives to such packages.
Hope this helps. I will be soon here with another useful guide soon. Stay tuned!
Cheers!
干杯!
资源:
- [Absolutely Proprietary][5]
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/find-installed-proprietary-packages-arch-linux/
作者:[SK][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
译者:[MjSeven](https://github.com/MjSeven)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
@ -117,4 +124,5 @@ via: https://www.ostechnix.com/find-installed-proprietary-packages-arch-linux/
[1]:https://git.parabola.nu/blacklist.git/plain/blacklist.txt
[2]:https://git.parabola.nu/blacklist.git/plain/aur-blacklist.txt
[3]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
[4]:http://www.ostechnix.com/wp-content/uploads/2018/01/Proprietary-Packages-1-1.png ()
[4]:http://www.ostechnix.com/wp-content/uploads/2018/01/Proprietary-Packages-1-1.png
[5]:https://github.com/vmavromatis/absolutely-proprietary

View File

@ -1,13 +1,15 @@
调试器到底怎样工作
======
> 你也许用过调速器检查过你的代码,但你知道它们是如何做到的吗?
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/annoyingbugs.png?itok=ywFZ99Gs)
供图opensource.com
调试器是那些大多数(即使不是每个)开发人员在软件工程职业生涯中至少使用过一次的软件之一,但是你们中有多少人知道它们到底是如何工作的?我在悉尼 [linux.conf.au 2018][1] 的演讲中,将讨论从头开始编写调试器...使用 [Rust][2]
调试器是大多数(即使不是每个)开发人员在软件工程职业生涯中至少使用过一次的那些软件之一,但是你们中有多少人知道它们到底是如何工作的?我在悉尼 [linux.conf.au 2018][1] 的演讲中,将讨论从头开始编写调试器……使用 [Rust][2]
在本文中,术语调试器/跟踪器可以互换。 “被跟踪者”是指正在被跟踪者跟踪的进程。
在本文中,术语<ruby>调试器<rt>debugger</rt></ruby><ruby>跟踪器<rt>tracer</rt></ruby>可以互换。 “<ruby>被跟踪者<rt>Tracee</rt></ruby>”是指正在被跟踪器跟踪的进程。
### ptrace 系统调用
@ -17,59 +19,46 @@
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
```
这是一个可以操纵进程几乎所有方面的系统调用;但是,在调试器可以连接到一个进程之前,“被跟踪者”必须以请求 `PTRACE_TRACEME` 调用 `ptrace`。这告诉 Linux父进程通过 `ptrace` 连接到这个进程是合法的。但是......我们如何强制一个进程调用 `ptrace`?很简单!`fork/execve` 提供了在 `fork` 之后但在被跟踪者真正开始使用 `execve` 之前调用 `ptrace` 的简单方法。很方便地,`fork` 还会返回被跟踪者的 `pid`,这是后面使用 `ptrace` 所必需的。
这是一个可以操纵进程几乎所有方面的系统调用;但是,在调试器可以连接到一个进程之前,“被跟踪者”必须以请求 `PTRACE_TRACEME` 调用 `ptrace`。这告诉 Linux父进程通过 `ptrace` 连接到这个进程是合法的。但是……我们如何强制一个进程调用 `ptrace`?很简单!`fork/execve` 提供了在 `fork` 之后但在被跟踪者真正开始使用 `execve` 之前调用 `ptrace` 的简单方法。很方便地,`fork` 还会返回被跟踪者的 `pid`,这是后面使用 `ptrace` 所必需的。
现在被跟踪者可以被调试器追踪,重要的变化发生了:
* 每当一个信号被传送到被调试者时,它就会停止,并且一个可以被 `wait` 系列系统调用捕获的等待事件被传送给跟踪器。
* 每当一个信号被传送到被跟踪者时,它就会停止,并且一个可以被 `wait` 系列系统调用捕获的等待事件被传送给跟踪器。
* 每个 `execve` 系统调用都会导致 `SIGTRAP` 被传递给被跟踪者。(与之前的项目相结合,这意味着被跟踪者在一个 `execve` 完全发生之前停止。)
这意味着,一旦我们发出 `PTRACE_TRACEME` 请求并调用 `execve` 系统调用来实际在被跟踪者(进程上下文)中启动程序时,被跟踪者将立即停止,因为 `execve` 会传递一个 `SIGTRAP`,并且会被跟踪器中的等待事件捕获。我们如何继续?正如人们所期望的那样,`ptrace` 有大量的请求可以用来告诉被跟踪者可以继续:
* `PTRACE_CONT`:这是最简单的。 被跟踪者运行,直到它接收到一个信号,此时等待事件被传递给跟踪器。这是最常见的实现真实世界调试器的“继续直至断点”和“永远继续”选项的方式。断点将在下面介绍。
* `PTRACE_SYSCALL`:与 `PTRACE_CONT` 非常相似,但在进入系统调用之前以及在系统调用返回到用户空间之前停止。它可以与其他请求(我们将在本文后面介绍)结合使用来监视和修改系统调用的参数或返回值。系统调用追踪程序 `strace` 很大程度上使用这个请求来获知进程发起了哪些系统调用。
* `PTRACE_SINGLESTEP`:这个很好理解。如果您之前使用过调试器(你会知道),此请求会执行下一条指令,然后立即停止。
我们可以通过各种各样的请求停止进程,但我们如何获得被调试者的状态?进程的状态大多是通过其寄存器捕获的,所以当然 `ptrace` 有一个请求来获得(或修改)寄存器:
* `PTRACE_GETREGS`:这个请求将给出被跟踪者刚刚被停止时的寄存器的状态。
* `PTRACE_SETREGS`:如果跟踪器之前通过调用 `PTRACE_GETREGS` 得到了寄存器的值,它可以在参数结构中修改相应寄存器的值并使用 `PTRACE_SETREGS` 将寄存器设为新值。
* `PTRACE_SETREGS`:如果跟踪器之前通过调用 `PTRACE_GETREGS` 得到了寄存器的值,它可以在参数结构中修改相应寄存器的值并使用 `PTRACE_SETREGS` 将寄存器设为新值。
* `PTRACE_PEEKUSER``PTRACE_POKEUSER`:这些允许从被跟踪者的 `USER` 区读取信息,这里保存了寄存器和其他有用的信息。 这可以用来修改单一寄存器,而避免使用更重的 `PTRACE_{GET,SET}REGS` 请求。
在调试器仅仅修改寄存器是不够的。调试器有时需要读取一部分内存甚至对其进行修改。GDB 可以使用 `print` 得到一个内存位置或变量的值。`ptrace` 通过下面的方法实现这个功能:
* `PTRACE_PEEKTEXT``PTRACE_POKETEXT`:这些允许读取和写入被跟踪者地址空间中的一个字。当然,使用这个功能时被跟踪者要被暂停。
真实世界的调试器也有类似断点和观察点的功能。 在接下来的部分中我将深入体系结构对调试器支持的细节。为了清晰和简洁本文将只考虑x86。
真实世界的调试器也有类似断点和观察点的功能。 在接下来的部分中,我将深入体系结构对调试器支持的细节。为了清晰和简洁,本文将只考虑 x86。
### 体系结构的支持
`ptrace` 很酷,但它是如何工作? 在前面的部分中,我们已经看到 `ptrace` 跟信号有很大关系:`SIGTRAP` 可以在单步跟踪、`execve` 之前以及系统调用前后被传送。信号可以通过一些方式产生,但我们将研究两个具体的例子,以展示信号可以被调试器用来在给定的位置停止程序(有效地创建一个断点!):
* **未定义的指令**当一个进程尝试执行一个未定义的指令CPU 将产生一个异常。此异常通过 CPU 中断处理,内核中相应的中断处理程序被调用。这将导致一个 `SIGILL` 信号被发送给进程。 这依次导致进程被停止,跟踪器通过一个等待事件被通知,然后它可以决定后面做什么。在 x86 上,指令 `ud2` 被确保始终是未定义的。
* **调试中断**:前面的方法的问题是,`ud2` 指令需要占用两个字节的机器码。存在一条特殊的单字节指令能够触发一个中断,它是 `int $3`,机器码是 `0xCC`。 当该中断发出时,内核向进程发送一个 `SIGTRAP`,如前所述,跟踪器被通知。
这很好,但如何做我们胁迫的被跟踪者执行这些指令? 这很简单:利用 `ptrace``PTRACE_POKETEXT` 请求,它可以覆盖内存中的一个字。 调试器将使用 `PTRACE_PEEKTEXT` 读取该位置原来的值并替换为 `0xCC` ,然后在其内部状态中记录该处原来的值,以及它是一个断点的事实。 下次被跟踪者执行到该位置时,它将被通过 `SIGTRAP` 信号自动停止。 然后调试器的最终用户可以决定如何继续(例如,检查寄存器)。
这很好,但如何我们才能胁迫被跟踪者执行这些指令? 这很简单:利用 `ptrace``PTRACE_POKETEXT` 请求,它可以覆盖内存中的一个字。 调试器将使用 `PTRACE_PEEKTEXT` 读取该位置原来的值并替换为 `0xCC` ,然后在其内部状态中记录该处原来的值,以及它是一个断点的事实。 下次被跟踪者执行到该位置时,它将被通过 `SIGTRAP` 信号自动停止。 然后调试器的最终用户可以决定如何继续(例如,检查寄存器)。
好吧,我们已经讲过了断点,那观察点呢? 当一个特定的内存位置被读或写,调试器如何停止程序? 当然你不可能为了能够读或写内存而去把每一个指令都覆盖为 `int $3`。有一组调试寄存器为了更有效的满足这个目的而被设计出来:
* `DR0``DR3`:这些寄存器中的每个都包含一个地址(内存位置),调试器因为某种原因希望被跟踪者在那些地址那里停止。 其原因以掩码方式被设定在 `DR7` 寄存器中。
* `DR4``DR5`:这些分别是 `DR6``DR7`过时的别名。
* `DR4``DR5`:这些分别是 `DR6``DR7` 过时的别名。
* `DR6`:调试状态。包含有关 `DR0``DR3` 中的哪个寄存器导致调试异常被引发的信息。这被 Linux 用来计算与 `SIGTRAP` 信号一起传递给被跟踪者的信息。
* `DR7`调试控制。通过使用这些寄存器中的位调试器可以控制如何解释DR0至DR3中指定的地址。位掩码控制监视点的尺寸监视1,2,4或8个字节以及是否在执行、读取、写入时引发异常或在读取或写入时引发异常。
* `DR7`:调试控制。通过使用这些寄存器中的位,调试器可以控制如何解释 `DR0``DR3` 中指定的地址。位掩码控制监视点的尺寸监视1、2、4 或 8 个字节)以及是否在执行、读取、写入时引发异常,或在读取或写入时引发异常。
由于调试寄存器是进程的 `USER` 区域的一部分,调试器可以使用 `PTRACE_POKEUSER` 将值写入调试寄存器。调试寄存器只与特定进程相关,因此在进程抢占并重新获得 CPU 控制权之前,调试寄存器会被恢复。
@ -88,7 +77,7 @@ via: https://opensource.com/article/18/1/how-debuggers-really-work
作者:[Levente Kurusa][a]
译者:[stephenxs](https://github.com/stephenxs)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,87 @@
为什么 DevSecOps 对 IT 领导来说如此重要
======
> DevSecOps 也许不是一个优雅的词汇,但是其结果很吸引人:更强的安全、提前出现在开发周期中。来看看一个 IT 领导与 Meltdown 的拼搏。
![](https://enterprisersproject.com/sites/default/files/styles/620x350/public/images/TEP_SecurityTraining1_620x414_1014.png?itok=zqxqJGDG)
如果 [DevOps][1] 最终是关于创造更好的软件,那也就意味着是更安全的软件。
而到了术语 “DevSecOps”就像任何其他 IT 术语一样DevSecOps —— 一个更成熟的 DevOps 的后代 ——可能容易受到炒作和盗用。但这个术语对那些拥抱了 DevOps 文化的领导者们来说具有重要的意义,并且其实践和工具可以帮助他们实现其承诺。
说道这里“DevSecOps”是什么意思
“DevSecOps 是开发、安全、运营的混合,”来自 [Datical][2] 的首席技术官和联合创始人 Robert 说。“这提醒我们,对我们的应用程序来说安全和创建并部署应用到生产中一样重要。”
**[想阅读其他首席技术官的 DevOps 文章吗?查阅我们丰富的资源,[DevOpsIT 领导者指南][3]]**
向非技术人员解释 DevSecOps 的一个简单的方法是:它是指将安全有意并提前加入到开发过程中。
“安全团队从历史上一直都被孤立于开发团队——每个团队在 IT 的不同领域都发展了很强的专业能力”,来自红帽安全策的专家 Kirsten 最近告诉我们。“不需要这样,非常关注安全也关注他们通过软件来兑现商业价值的能力的企业正在寻找能够在应用开发生命周期中加入安全的方法。他们通过在整个 CI/CD 管道中集成安全实践、工具和自动化来采用 DevSecOps。”
“为了能够做的更好,他们正在整合他们的团队——专业的安全人员从开始设计到部署到生产中都融入到了开发团队中了,”她说,“双方都收获了价值——每个团队都拓展了他们的技能和基础知识,使他们自己都成更有价值的技术人员。 DevOps 做的很正确——或者说 DevSecOps——提高了 IT 的安全性。”
IT 团队比任何以往都要求要快速频繁的交付服务。DevOps 在某种程度上可以成为一个很棒的推动者,因为它能够消除开发和运营之间通常遇到的一些摩擦,运营一直被排挤在整个过程之外直到要部署的时候,开发者把代码随便一放之后就不再去管理,他们承担更少的基础架构的责任。那种孤立的方法引起了很多问题,委婉的说,在数字时代,如果将安全孤立起来同样的情况也会发生。
“我们已经采用了 DevOps因为它已经被证明通过移除开发和运营之间的阻碍来提高 IT 的绩效”Reevess 说,“就像我们不应该在开发周期要结束时才加入运营,我们不应该在快要结束时才加入安全。”
### 为什么 DevSecOps 必然出现
或许会把 DevSecOps 看作是另一个时髦词但对于安全意识很强的IT领导者来说它是一个实质性的术语在软件开发管道中安全必须是第一层面的要素而不是部署前的最后一步的螺栓或者更糟的是作为一个团队只有当一个实际的事故发生的时候安全人员才会被重用争抢。
“DevSecOps 不只是一个时髦的术语——因为多种原因它是现在和未来 IT 将呈现的状态”,来自 [Sumo Logic] 的安全和合规副总裁 George 说道,“最重要的好处是将安全融入到开发和运营当中开提供保护的能力”
此外DevSecOps 的出现可能是 DevOps 自身逐渐成熟并扎根于 IT 之中的一个征兆。
“企业中的 DevOps 文化已成定局,而且那意味着开发者们正以不断增长的速度交付功能和更新,特别是自我管理的组织会对合作和衡量的结果更加满意”,来自 [CYBRIC] 的首席技术官和联合创始人 Mike 说道。
在实施 DevOps 的同时继续保留原有安全措施的团队和公司,随着他们继续部署的更快更频繁可能正在经历越来越多的安全管理风险上的痛苦。
“现在的手工的安全测试方法会继续远远被甩在后面。”
“如今,手动的安全测试方法正被甩得越来越远,利用自动化和协作将安全测试转移到软件开发生命周期中,因此推动 DevSecOps 的文化是 IT 领导者们为增加整体的灵活性提供安全保证的唯一途径”Kail 说。
转移安全测试也使开发者受益:他们能够在开放的较早的阶段验证并解决潜在的问题——这样很少需要或者甚至不需要安全人员的介入,而不是在一个新的服务或者更新部署之前在他们的代码中发现一个明显的漏洞。
“做的正确DevSecOps 能够将安全融入到开发生命周期中,允许开发者们在没有安全中断的情况下更加快速容易的保证他们应用的安全”,来自 [SAS][8] 的首席信息安全员 Wilson 说道。
Wilson 指出静态SAST和源组合分析SCA工具集成到团队的持续交付管道中作为有用的技术通过给予开发者关于他们的代码中的潜在问题和第三方依赖中的漏洞的反馈来使之逐渐成为可能。
“因此,开发者们能够主动和迭代的缓解应用安全的问题,然后在不需要安全人员介入的情况下重新进行安全扫描。” Wilson 说。他同时指出 DevSecOps 能够帮助开发者简化更新和打补丁。
DevSecOps 并不意味着你不再需要安全组的意见了,就如同 DevOps 并不意味着你不再需要基础架构专家;它只是帮助你减少在生产中发现缺陷的可能性,或者减少导致降低部署速度的阻碍,因为缺陷已经在开发周期中被发现解决了。
“如果他们有问题或者需要帮助我们就在这儿但是因为已经给了开发者他们需要的保护他们应用安全的工具我们很少在一个深入的测试中发现一个导致中断的问题”Wilson 说道。
### DevSecOps 遇到 Meltdown
Sumo Locic 的 Gerchow 向我们分享了一个在运转中的 DevSecOps 文化的一个及时案例:当最近 [Meltdown 和 Spectre] 的消息传来的时候,团队的 DevSecOps 方法使得有了一个快速的响应来减轻风险没有任何的通知去打扰内部或者外部的顾客Gerchow 所说的这点对原生云、高监管的公司来说特别的重要。
第一步Gerchow 的小型安全团队都具有一定的开发能力,能够通过 Slack 和它的主要云供应商协同工作来确保它的基础架构能够在 24 小时之内完成修复。
“接着我的团队立即开始进行系统级的修复,实现终端客户的零停机时间,不需要去开工单给工程师,如果那样那意味着你需要等待很长的变更过程。所有的变更都是通过 Slack 的自动 jira 票据进行通过我们的日志监控和分析解决方案”Gerchow 解释道。
在本质上,它听起来非常像 DevOps 文化,匹配正确的人员、过程和工具,但它明确的将安全作为文化中的一部分进行了混合。
“在传统的环境中这将花费数周或数月的停机时间来处理因为开发、运维和安全三者是相互独立的”Gerchow 说道,“通过一个 DevSecOps 的过程和习惯,终端用户可以通过简单的沟通和当日修复获得无缝的体验。”
--------------------------------------------------------------------------------
via: https://enterprisersproject.com/article/2018/1/why-devsecops-matters-it-leaders
作者:[Kevin Casey][a]
译者:[FelixYFZ](https://github.com/FelixYFZ)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://enterprisersproject.com/user/kevin-casey
[1]:https://enterprisersproject.com/tags/devops
[2]:https://www.datical.com/
[3]:https://enterprisersproject.com/devops?sc_cid=70160000000h0aXAAQ
[4]:https://www.redhat.com/en?intcmp=701f2000000tjyaAAA
[5]:https://enterprisersproject.com/article/2017/10/what-s-next-devops-5-trends-watch
[6]:https://www.sumologic.com/
[7]:https://www.cybric.io/
[8]:https://www.sas.com/en_us/home.html
[9]:https://www.redhat.com/en/blog/what-are-meltdown-and-spectre-heres-what-you-need-know?intcmp=701f2000000tjyaAAA

View File

@ -0,0 +1,276 @@
在 Kubernetes 上运行一个 Python 应用程序
============================================================
> 这个分步指导教程教你通过在 Kubernetes 上部署一个简单的 Python 应用程序来学习部署的流程。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/build_structure_tech_program_code_construction.png?itok=nVsiLuag)
Kubernetes 是一个具备部署、维护和可伸缩特性的开源平台。它在提供可移植性、可扩展性以及自我修复能力的同时,简化了容器化 Python 应用程序的管理。
不论你的 Python 应用程序是简单还是复杂Kubernetes 都可以帮你高效地部署和伸缩它们,在有限的资源范围内滚动升级新特性。
在本文中,我将描述在 Kubernetes 上部署一个简单的 Python 应用程序的过程,它包括:
* 创建 Python 容器镜像
* 发布容器镜像到镜像注册中心
* 使用持久卷
* 在 Kubernetes 上部署 Python 应用程序
### 必需条件
你需要 Docker、`kubectl` 以及这个 [源代码][10]。
Docker 是一个构建和承载已发布的应用程序的开源平台。可以参照 [官方文档][11] 去安装 Docker。运行如下的命令去验证你的系统上运行的 Docker
```
$ docker info
Containers: 0
Images: 289
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Dirs: 289
Execution Driver: native-0.2
Kernel Version: 3.16.0-4-amd64
Operating System: Debian GNU/Linux 8 (jessie)
WARNING: No memory limit support
WARNING: No swap limit support
```
`kubectl` 是在 Kubernetes 集群上运行命令的一个命令行界面。运行下面的 shell 脚本去安装 `kubectl`
```
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
```
部署到 Kubernetes 的应用要求必须是一个容器化的应用程序。我们来回顾一下 Python 应用程序的容器化过程。
### 一句话了解容器化
容器化是指将一个应用程序所需要的东西打包进一个自带操作系统的容器中。这种完整机器虚拟化的好处是,一个应用程序能够在任何机器上运行而无需考虑它的依赖项。
我们以 Roman Gaponov 的 [文章][12] 为参考,来为我们的 Python 代码创建一个容器。
### 创建一个 Python 容器镜像
为创建这些镜像,我们将使用 Docker它可以让我们在一个隔离的 Linux 软件容器中部署应用程序。Docker 可以使用来自一个 Dockerfile 中的指令来自动化构建镜像。
这是我们的 Python 应用程序的 Dockerfile
```
FROM python:3.6
MAINTAINER XenonStack
# Creating Application Source Code Directory
RUN mkdir -p /k8s_python_sample_code/src
# Setting Home Directory for containers
WORKDIR /k8s_python_sample_code/src
# Installing python dependencies
COPY requirements.txt /k8s_python_sample_code/src
RUN pip install --no-cache-dir -r requirements.txt
# Copying src code to Container
COPY . /k8s_python_sample_code/src/app
# Application Environment variables
ENV APP_ENV development
# Exposing Ports
EXPOSE 5035
# Setting Persistent data
VOLUME ["/app-data"]
# Running Python Application
CMD ["python", "app.py"]
```
这个 Dockerfile 包含运行我们的示例 Python 代码的指令。它使用的开发环境是 Python 3.5。
### 构建一个 Python Docker 镜像
现在,我们可以使用下面的这个命令按照那些指令来构建 Docker 镜像:
```
docker build -t k8s_python_sample_code .
```
这个命令为我们的 Python 应用程序创建了一个 Docker 镜像。
### 发布容器镜像
我们可以将我们的 Python 容器镜像发布到不同的私有/公共云仓库中,像 Docker Hub、AWS ECR、Google Container Registry 等等。本教程中我们将发布到 Docker Hub。
在发布镜像之前,我们需要给它标记一个版本号:
```
docker tag k8s_python_sample_code:latest k8s_python_sample_code:0.1
```
### 推送镜像到一个云仓库
如果使用一个 Docker 注册中心而不是 Docker Hub 去保存镜像,那么你需要在你本地的 Docker 守护程序和 Kubernetes Docker 守护程序上添加一个容器注册中心。对于不同的云注册中心,你可以在它上面找到相关信息。我们在示例中使用的是 Docker Hub。
运行下面的 Docker 命令去推送镜像:
```
docker push k8s_python_sample_code
```
### 使用 CephFS 持久卷
Kubernetes 支持许多的持久存储提供商,包括 AWS EBS、CephFS、GlusterFS、Azure Disk、NFS 等等。我在示例中使用 CephFS 做为 Kubernetes 的持久卷。
为使用 CephFS 存储 Kubernetes 的容器数据,我们将创建两个文件:
`persistent-volume.yml`
```
apiVersion: v1
kind: PersistentVolume
metadata:
name: app-disk1
namespace: k8s_python_sample_code
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
cephfs:
monitors:
- "172.17.0.1:6789"
user: admin
secretRef:
name: ceph-secret
readOnly: false
```
`persistent_volume_claim.yaml`
```
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: appclaim1
namespace: k8s_python_sample_code
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
```
现在,我们将使用 `kubectl` 去添加持久卷并声明到 Kubernetes 集群中:
```
$ kubectl create -f persistent-volume.yml
$ kubectl create -f persistent-volume-claim.yml
```
现在,我们准备去部署 Kubernetes。
### 在 Kubernetes 上部署应用程序
为管理部署应用程序到 Kubernetes 上的最后一步,我们将创建两个重要文件:一个服务文件和一个部署文件。
使用下列的内容创建服务文件,并将它命名为 `k8s_python_sample_code.service.yml`
```
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: k8s_python_sample_code
name: k8s_python_sample_code
namespace: k8s_python_sample_code
spec:
type: NodePort
ports:
- port: 5035
selector:
k8s-app: k8s_python_sample_code
```
使用下列的内容创建部署文件并将它命名为 `k8s_python_sample_code.deployment.yml`
```
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: k8s_python_sample_code
  namespace: k8s_python_sample_code
spec:
  replicas: 1
  template:
  metadata:
    labels:
    k8s-app: k8s_python_sample_code
  spec:
    containers:
    - name: k8s_python_sample_code
      image: k8s_python_sample_code:0.1
      imagePullPolicy: "IfNotPresent"
      ports:
      - containerPort: 5035
      volumeMounts:
        - mountPath: /app-data
          name: k8s_python_sample_code
     volumes: 
         - name: <name of application>
           persistentVolumeClaim:
             claimName: appclaim1
```
最后,我们使用 `kubectl` 将应用程序部署到 Kubernetes
```
$ kubectl create -f k8s_python_sample_code.deployment.yml $ kubectl create -f k8s_python_sample_code.service.yml
```
现在,你的应用程序已经成功部署到 Kubernetes。
你可以通过检查运行的服务来验证你的应用程序是否在运行:
```
kubectl get services
```
或许 Kubernetes 可以解决未来你部署应用程序的各种麻烦!
_想学习更多关于 Python 的知识Nanjekye 的书,[和平共处的 Python 2 和 3][7] 提供了完整的方法,让你写的代码在 Python 2 和 3 上完美运行,包括如何转换已有的 Python 2 代码为能够可靠运行在 Python 2 和 3 上的代码的详细示例。_
### 关于作者
[![](https://opensource.com/sites/default/files/styles/profile_pictures/public/pictures/joannah-nanjekye.jpg?itok=F4RqEjoA)][13] Joannah Nanjekye - Straight Outta 256只要结果不问原因充满激情的飞行员喜欢用代码说话。[关于我的更多信息][8]
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/1/running-python-application-kubernetes
作者:[Joannah Nanjekye][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/nanjekyejoannah
[1]:https://opensource.com/resources/python?intcmp=7016000000127cYAAQ
[2]:https://opensource.com/resources/python/ides?intcmp=7016000000127cYAAQ
[3]:https://opensource.com/resources/python/gui-frameworks?intcmp=7016000000127cYAAQ
[4]:https://opensource.com/tags/python?intcmp=7016000000127cYAAQ
[5]:https://developers.redhat.com/?intcmp=7016000000127cYAAQ
[6]:https://opensource.com/article/18/1/running-python-application-kubernetes?rate=D9iKksKbd9q9vOVb92Mg-v0Iyqn0QVO5fbIERTbSHz4
[7]:https://www.apress.com/gp/book/9781484229545
[8]:https://opensource.com/users/nanjekyejoannah
[9]:https://opensource.com/user/196386/feed
[10]:https://github.com/jnanjekye/k8s_python_sample_code/tree/master
[11]:https://docs.docker.com/engine/installation/
[12]:https://hackernoon.com/docker-tutorial-getting-started-with-python-redis-and-nginx-81a9d740d091
[13]:https://opensource.com/users/nanjekyejoannah
[14]:https://opensource.com/users/nanjekyejoannah
[15]:https://opensource.com/users/nanjekyejoannah
[16]:https://opensource.com/tags/python
[17]:https://opensource.com/tags/kubernetes

View File

@ -0,0 +1,95 @@
对数据隐私持开放的态度
======
> 尽管有包括 GDPR 在内的法规,数据隐私对于几乎所有的人来说都是很重要的事情。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/GOV_opendata.png?itok=M8L2HGVx)
今天LCTT 译注:本文发表于 2018/1/28<ruby>[数据隐私日][1]<rt>Data Privacy Day</rt></ruby>(在欧洲叫“<ruby>数据保护日<rt>Data Protection Day</rt></ruby>”),你可能会认为现在我们处于一个开源的世界中,所有的数据都应该是自由的,[就像人们想的那样][2],但是现实并没那么简单。主要有两个原因:
1. 我们中的大多数(不仅仅是在开源中)认为至少有些关于我们自己的数据是不愿意分享出去的(我在之前发表的一篇文章中列举了一些例子[3]
2. 我们很多人虽然在开源中工作,但事实上是为了一些商业公司或者其他一些组织工作,也是在合法的要求范围内分享数据。
所以实际上,数据隐私对于每个人来说是很重要的。
事实证明,在美国和欧洲之间,人们和政府认为让组织使用哪些数据的出发点是有些不同的。前者通常为商业实体(特别是愤世嫉俗的人们会指出是大型的商业实体)利用他们所收集到的关于我们的数据提供了更多的自由度。在欧洲,完全是另一观念,一直以来持有的多是有更多约束限制的观念,而且在 5 月 25 日,欧洲的观点可以说取得了胜利。
### 通用数据保护条例GDPR的影响
那是一个相当全面的声明,其实事实上这是 2016 年欧盟通过的一项称之为<ruby>通用数据保护条例<rt>General Data Protection Regulation</rt></ruby>GDPR的立法的日期。数据通用保护条例在私人数据怎样才能被保存如何才能被使用谁能使用能被持有多长时间这些方面设置了严格的规则。它描述了什么数据属于私人数据——而且涉及的条目范围非常广泛从你的姓名、家庭住址到你的医疗记录以及接通你电脑的 IP 地址。
通用数据保护条例的重要之处是它并不仅仅适用于欧洲的公司,如果你是阿根廷人、日本人、美国人或者是俄罗斯的公司而且你正在收集涉及到欧盟居民的数据,你就要受到这个条例的约束管辖。
“哼!” 你可能会这样说^注1 ,“我的业务不在欧洲:他们能对我有啥约束?” 答案很简单:如果你想继续在欧盟做任何生意,你最好遵守,因为一旦你违反了通用数据保护条例的规则,你将会受到你的全球总收入百分之四的惩罚。是的,你没听错,是全球总收入,而不是仅仅在欧盟某一国家的的收入,也不只是净利润,而是全球总收入。这将会让你去叮嘱告知你的法律团队,他们就会知会你的整个团队,同时也会立即去指引你的 IT 团队,确保你的行为在相当短的时间内合规。
看上去这和非欧盟公民没有什么相关性,但其实不然,对大多数公司来说,对所有的他们的顾客、合作伙伴以及员工实行同样的数据保护措施是件既简单又有效的事情,而不是仅针对欧盟公民实施,这将会是一件很有利的事情。^注2
然而,数据通用保护条例不久将在全球实施并不意味着一切都会变的很美好^注3 :事实并非如此,我们一直在丢弃关于我们自己的信息——而且允许公司去使用它。
有一句话是这么说的(尽管很争议):“如果你没有在付费,那么你就是产品。”这句话的意思就是如果你没有为某一项服务付费,那么其他的人就在付费使用你的数据。你有付费使用 Facebook、推特、谷歌邮箱你觉得他们是如何赚钱的大部分是通过广告一些人会争论那是他们向你提供的一项服务而已但事实上是他们在利用你的数据从广告商里获取收益。你不是一个真正的广告的顾客——只有当你从看了广告后买了他们的商品之后你才变成了他们的顾客但直到这个发生之前都是广告平台和广告商的关系。
有些服务是允许你通过付费来消除广告的(流媒体音乐平台声破天就是这样的),但从另一方面来讲,即使你认为付费的服务也可以启用广告(例如,亚马逊正在努力让 Alexa 发广告),除非我们想要开始为这些所有的免费服务付费,我们需要清楚我们所放弃的,而且在我们暴露的和不想暴露的之间做一些选择。
### 谁是顾客?
关于数据的另一个问题一直在困扰着我们,它是产生的数据量的直接结果。有许多组织一直在产生巨量的数据,包括公共的组织比如大学、医院或者是政府部门^注4 ——而且他们没有能力去储存这些数据。如果这些数据没有长久的价值也就没什么要紧的,但事实正好相反,随着处理大数据的工具正在开发中,而且这些组织也认识到他们现在以及在不久的将来将能够去挖掘这些数据。
然而他们面临的是,随着数据的增长和存储量无法跟上该怎么办。幸运的是——而且我是带有讽刺意味的使用了这个词^注5 ,大公司正在介入去帮助他们。“把你们的数据给我们,”他们说,“我们将免费保存。我们甚至让你随时能够使用你所收集到的数据!”这听起来很棒,是吗?这是大公司^注6 的一个极具代表性的例子,站在慈善的立场上帮助公共组织管理他们收集到的关于我们的数据。
不幸的是,慈善不是唯一的理由。他们是附有条件的:作为同意保存数据的交换条件,这些公司得到了将数据访问权限出售给第三方的权利。你认为公共组织,或者是被收集数据的人在数据被出售使用权使给第三方,以及在他们如何使用上能有发言权吗?我将把这个问题当做一个练习留给读者去思考。^注7
### 开放和积极
然而并不只有坏消息。政府中有一项在逐渐发展起来的“开放数据”运动鼓励各个部门免费开放大量他们的数据给公众或者其他组织。在某些情况下,这是专门立法的。许多志愿组织——尤其是那些接受公共资金的——正在开始这样做。甚至商业组织也有感兴趣的苗头。而且,有一些技术已经可行了,例如围绕不同的隐私和多方计算上,正在允许跨越多个数据集挖掘数据,而不用太多披露个人的信息——这个计算问题从未如现在比你想象的更容易。
这些对我们来说意味着什么呢?我之前在网站 Opensource.com 上写过关于[开源的共享福利][4],而且我越来越相信我们需要把我们的视野从软件拓展到其他区域:硬件、组织,和这次讨论有关的,数据。让我们假设一下你是 A 公司要提向另一家公司客户 B^注8 提供一项服务 。在此有四种不同类型的数据:
1. 数据完全开放:对 A 和 B 都是可得到的,世界上任何人都可以得到
2. 数据是已知的、共享的和机密的A 和 B 可得到,但其他人不能得到
3. 数据是公司级别上保密的A 公司可以得到,但 B 顾客不能
4. 数据是顾客级别保密的B 顾客可以得到,但 A 公司不能
首先,也许我们对数据应该更开放些,将数据默认放到选项 1 中。如果那些数据对所有人开放——在无人驾驶、语音识别,矿藏以及人口数据统计会有相当大的作用的。^注9 如果我们能够找到方法将数据放到选项 2、3 和 4 中,不是很好吗?——或者至少它们中的一些——在选项 1 中是可以实现的,同时仍将细节保密?这就是研究这些新技术的希望。
然而有很长的路要走,所以不要太兴奋,同时,开始考虑将你的的一些数据默认开放。
### 一些具体的措施
我们如何处理数据的隐私和开放?下面是我想到的一些具体的措施:欢迎大家评论做出更多的贡献。
* 检查你的组织是否正在认真严格的执行通用数据保护条例。如果没有,去推动实施它。
* 要默认加密敏感数据(或者适当的时候用散列算法),当不再需要的时候及时删掉——除非数据正在被处理使用,否则没有任何借口让数据清晰可见。
* 当你注册了一个服务的时候考虑一下你公开了什么信息,特别是社交媒体类的。
* 和你的非技术朋友讨论这个话题。
* 教育你的孩子、你朋友的孩子以及他们的朋友。然而最好是去他们的学校和他们的老师谈谈在他们的学校中展示。
* 鼓励你所服务和志愿贡献的组织,或者和他们沟通一些推动数据的默认开放。不是去思考为什么我要使数据开放,而是从我为什么不让数据开放开始。
* 尝试去访问一些开源数据。挖掘使用它、开发应用来使用它,进行数据分析,画漂亮的图,^注10 制作有趣的音乐,考虑使用它来做些事。告诉组织去使用它们,感谢它们,而且鼓励他们去做更多。
**注:**
1. 我承认你可能尽管不会。
2. 假设你坚信你的个人数据应该被保护。
3. 如果你在思考“极好的”的寓意,在这点上你并不孤独。
4. 事实上这些机构能够有多开放取决于你所居住的地方。
5. 假设我是英国人,那是非常非常大的剂量。
6. 他们可能是巨大的公司:没有其他人能够负担得起这么大的存储和基础架构来使数据保持可用。
7. 不,答案是“不”。
8. 尽管这个例子也同样适用于个人。看看A 可能是 AliceB 可能是 BOb……
9. 并不是说我们应该暴露个人的数据或者是这样的数据应该被保密,当然——不是那类的数据。
10. 我的一个朋友当她接孩子放学的时候总是下雨,所以为了避免确认失误,她在整个学年都访问天气信息并制作了图表分享到社交媒体上。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/1/being-open-about-data-privacy
作者:[Mike Bursell][a]
译者:[FelixYFZ](https://github.com/FelixYFZ)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/mikecamel
[1]:https://en.wikipedia.org/wiki/Data_Privacy_Day
[2]:https://en.wikipedia.org/wiki/Information_wants_to_be_free
[3]:https://aliceevebob.wordpress.com/2017/06/06/helping-our-governments-differently/
[4]:https://opensource.com/article/17/11/commonwealth-open-source
[5]:http://www.outpost9.com/reference/jargon/jargon_40.html#TAG2036

View File

@ -1,101 +1,101 @@
为什么 Python 开发人员应该使用 Pipenv
=====
> 只用了一年, Pipenv 就变成了管理软件包依赖关系的 Python 官方推荐资源。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python-programming-code-keyboard.png?itok=fxiSpmnd)
这篇文章是与 [Jeff Triplett][1] 共同撰写的。
Pipenv 是由 Kenneth Reitz 在一年多前创建的“面向人类to校正者这里为人类感觉翻译为为开发者更好一点而生的 Python 开发工作流”,它已经成为管理软件包依赖关系的[ Python 官方推荐资源][2]。但是对于它解决了什么问题,以及它如何比使用 `pip``requirements.txt` 文件的标准工作流更有用处,这两点仍然存在困惑。在本月的 Python 专栏中,我们将填补这些空白。
Pipenv 是由 Kenneth Reitz 在一年多前创建的“面向开发者而生的 Python 开发工作流”,它已经成为管理软件包依赖关系的[ Python 官方推荐资源][2]。但是对于它解决了什么问题,以及它如何比使用 `pip``requirements.txt` 文件的标准工作流更有用处,这两点仍然存在困惑。在本月的 Python 专栏中,我们将填补这些空白。
### Python 包安装简史
为了理解 Pipenv 所解决的问题,看一看 Python 包管理如何发展十分有用的。
让我们回到第一个 Python 版本,我们有 Python但是没有干净的方法来安装软件包。
让我们回到第一个 Python 版本,这时我们有 Python但是没有干净的方法来安装软件包。
然后有了 [Easy Install][3],这是一个可以相对容易地安装其他 Python 包的软件包,但它也带来了一个问题:卸载不需要的包并不容易。
[pip][4] 登场,绝大多数 Python 用户都熟悉它。`pip` 可以让我们安装和卸载包。我们可以指定版本,运行 `pip freeze > requirements.txt` 来输出一个已安装包列表到一个文本文件,还可以用相同的文本文件配合 `pip install -r requirements.txt` 来安装一个应用程序需要的所有包。
但是 `pip` 并没有包含将包彼此隔离的方法。我们可能会开发使用相同库的不同版本的应用程序,因此我们需要一种方法来实现这一点。随之而来的是[虚拟环境][5],它使我们能够为我们开发的每个应用程序创建一个小型的,隔离的环境。我们已经看到了许多管理虚拟环境的工具:[virtualenv][6], [venv][7], [virtualenvwrapper][8], [pyenv][9], [pyenv-virtualenv][10], [pyenv-virtualenvwrapper][11] 等等。它们都可以很好地使用 `pip``requirements.txt` 文件。
但是 `pip` 并没有包含将软件包彼此隔离的方法。我们可能会开发使用相同库的不同版本的应用程序,因此我们需要一种方法来实现这一点。随之而来的是[虚拟环境][5],它使我们能够为我们开发的每个应用程序创建一个小型的、隔离的环境。我们已经看到了许多管理虚拟环境的工具:[virtualenv][6]、 [venv][7]、 [virtualenvwrapper][8]、 [pyenv][9]、 [pyenv-virtualenv][10]、 [pyenv-virtualenvwrapper][11] 等等。它们都可以很好地使用 `pip``requirements.txt` 文件。
### 新方法Pipenv
Pipenv 旨在解决几个问题:
首先,问题是需要 `pip` 库来安装包,外加一个用于创建虚拟环境的库,以及用于管理虚拟环境的库,以及与这些库相关的所有命令。这些都需要管理。Pipenv 附带包管理和虚拟环境支持,因此你可以使用一个工具来安装、卸载、跟踪和记录依赖性,并创建、使用和组织你的虚拟环境。当你使用它启动一个项目时,如果你还没有使用的话Pipenv 将自动为该项目创建一个虚拟环境。
首先,需要 `pip` 库来安装包,外加一个用于创建虚拟环境的库,以及用于管理虚拟环境的库,再有与这些库相关的所有命令。这些都需要管理。Pipenv 附带包管理和虚拟环境支持,因此你可以使用一个工具来安装、卸载、跟踪和记录依赖性,并创建、使用和组织你的虚拟环境。当你使用它启动一个项目时,如果你还没有使用虚拟环境的话Pipenv 将自动为该项目创建一个虚拟环境。
Pipenv 通过放弃 `requirements.txt` 规范转而将其移动到一个名为 [Pipfile][12] 的新文档中来完成这种依赖管理。当你使用 Pipenv 安装一个库时,项目的 `Pipfile` 会自动更新安装细节,包括版本信息,还有可能的 Git 仓库位置文件路径和其他信息。
Pipenv 通过放弃 `requirements.txt` 规范转而将其移动到一个名为 [Pipfile][12] 的新文档中来完成这种依赖管理。当你使用 Pipenv 安装一个库时,项目的 `Pipfile` 会自动更新安装细节,包括版本信息,还有可能的 Git 仓库位置文件路径和其他信息。
其次Pipenv 希望能更容易地管理复杂的相互依赖关系。你的应用程序可能依赖于某个特定版本的库,而那个库可能依赖于另一个特定版本的库,而它只是依赖关系to 校正者:这句话不太理解)。当你的应用程序使用的两个库有冲突的依赖关系时你的情况会变得很艰难。Pipenv 希望通过在一个名为 `Pipfile.lock` 的文件中跟踪应用程序相互依赖关系树来减轻这种痛苦。`Pipfile.lock` 还会验证生产中是否使用了正确版本的依赖关系。
其次Pipenv 希望能更容易地管理复杂的相互依赖关系。你的应用程序可能依赖于某个特定版本的库,而那个库可能依赖于另一个特定版本的库,这些依赖关系如海龟般堆叠起来。当你的应用程序使用的两个库有冲突的依赖关系时你的情况会变得很艰难。Pipenv 希望通过在一个名为 `Pipfile.lock` 的文件中跟踪应用程序相互依赖关系树来减轻这种痛苦。`Pipfile.lock` 还会验证生产中是否使用了正确版本的依赖关系。
另外当多个开发人员在开发一个项目时Pipenv 很方便。通过 `pip` 工作流,Casey 可能会安装一个库,并花两天时间使用该库实现一个新功能。当 Casey 提交更改时,他可能会忘记运行 `pip freeze` 来更新 requirements 文件。第二天Jamie 拉取 Casey 的变化,突然测试失败。这样会花费好一会儿才能意识到问题是在 requirements 文件中缺少相关库,而 Jamie 尚未在虚拟环境中安装这些文件。
另外当多个开发人员在开发一个项目时Pipenv 很方便。通过 `pip` 工作流,凯西可能会安装一个库,并花两天时间使用该库实现一个新功能。当凯西提交更改时,他可能会忘记运行 `pip freeze` 来更新 `requirements.txt` 文件。第二天,杰米拉取凯西的改变,测试就突然失败了。这样会花费好一会儿才能意识到问题是在 `requirements.txt` 文件中缺少相关库,而杰米尚未在虚拟环境中安装这些文件。
因为 Pipenv 会在安装时自动记录依赖性,如果 Jamie 和 Casey 使用了 Pipenv`Pipfile` 会自动更新并包含在 Casey 的提交中。这样 Jamie 和 Casey 就可以节省时间并更快地运送他们的产品。
因为 Pipenv 会在安装时自动记录依赖性,如果杰米和凯西使用了 Pipenv`Pipfile` 会自动更新并包含在凯西的提交中。这样杰米和凯西就可以节省时间并更快地运送他们的产品。
最后,将 Pipenv 推荐给在你项目上工作的其他人,因为它使用标准化的方式来安装项目依赖项,开发和测试需求。使用 `pip` 工作流和 requirements 文件意味着你可能只有一个 `requirements.txt` 文件,或针对不同环境的多个 requirements 文件。例如,你的同事可能不清楚他们是否应该在他们的笔记本电脑上运行项目时运行 `dev.txt` 还是 `local.txt`。当两个相似的 requirements 文件彼此不同步时它也会造成混淆:`local.txt` 是否过时了,还是真的应该与 `dev.txt` 不同?多个 requirements 文件需要更多的上下文和文档,以使其他人能够按照预期正确安装依赖关系。这个工作流程有可能会混淆同时并增加你的维护负担。
最后,将 Pipenv 推荐给在你项目上工作的其他人,因为它使用标准化的方式来安装项目依赖项和开发和测试的需求。使用 `pip` 工作流和 `requirements.txt` 文件意味着你可能只有一个 `requirements.txt` 文件,或针对不同环境的多个 `requirements.txt` 文件。例如,你的同事可能不清楚他们是否应该在他们的笔记本电脑上运行项目时运行 `dev.txt` 还是 `local.txt`。当两个相似的 `requirements.txt` 文件彼此不同步时它也会造成混淆:`local.txt` 是否过时了,还是真的应该与 `dev.txt` 不同?多个 `requirements.txt` 文件需要更多的上下文和文档,以使其他人能够按照预期正确安装依赖关系。这个工作流程有可能会混淆同时并增加你的维护负担。
使用 Pipenv它会生成 `Pipfile`,通过为你管理对不同环境的依赖关系,可以避免这些问题。该命令将安装主项目依赖项:
```
pipenv install
```
添加 `--dev` 标志将安装 dev/testing requirements
添加 `--dev` 标志将安装开发/测试的 `requirements.txt`
```
pipenv install --dev
```
使用 Pipenv 还有其他好处:它具有更好的安全特性,以易于理解的格式绘制你的依赖关系,无缝处理 `.env` 文件,并且可以在一个文件中自动处理开发与生产环境的不同依赖关系。你可以在[文档][13]中阅读更多内容。
### Pipenv 行动
### 使用 Pipenv
使用 Pipenv 的基础知识在官方 Python 包管理教程[管理应用程序依赖关系][14]部分中详细介绍。要安装 Pipenv使用 `pip`
```
pip install pipenv
```
要安装在项目中使用的包,请更改为项目的目录。然后安装一个包(我们将使用 Django 作为例子),运行:
```
pipenv install django
```
你会看到一些输出,表明 Pipenv 正在为你的项目创建一个 `Pipfile`
如果你还没有使用虚拟环境,你还会看到 Pipenv 的一些输出,说明它正在为你创建一个虚拟环境。
然后,你将看到你在安装包时习惯看到的输出。
然后,你将看到你在安装包时看到的输出。
为了生成 `Pipfile.lock` 文件,运行:
```
pipenv lock
```
你也可以使用 Pipenv 运行 Python 脚本。运行名为 `hello.py`to 校正者:这里 top-level该怎么翻译Python 脚本:
你也可以使用 Pipenv 运行 Python 脚本。运行名为 `hello.py` 的上层 Python 脚本:
```
pipenv run python hello.py
```
你将在控制台中看到预期结果。
启动一个 shell运行
```
pipenv shell
```
如果你想将当前使用 `requirements.txt` 文件的项目转换为使用 Pipenv请安装 Pipenv 并运行:
```
pipenv install requirements.txt
```
这将创建一个 Pipfile 并安装指定的 requirements。考虑一下升级你的项目
这将创建一个 Pipfile 并安装指定的 `requirements.txt`。考虑一下升级你的项目!
### 了解更多
@ -106,9 +106,9 @@ pipenv install requirements.txt
via: https://opensource.com/article/18/2/why-python-devs-should-use-pipenv
作者:[Lacey Williams Henschel][a]
作者:[Lacey Williams Henschel][a], [Jeff Triplett][1]
译者:[MjSeven](https://github.com/MjSeven)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,8 +1,7 @@
云计算的成本
============================================================
### 两个开发团队的一天
> 两个开发团队的一天
![](https://cdn-images-1.medium.com/max/2000/1*nBZJgNXl54jzFKa91s1KfQ.png)
@ -12,103 +11,108 @@
这两个团队被要求为一家全球化企业开发一个新的服务,该企业目前为全球数百万消费者提供服务。要开发的这项新服务需要满足以下基本需求:
1. 能够随时扩展以满足弹性需求
2. 具备应对数据中心故障的弹性
3. 确保数据安全以及数据受到保护
4. 为排错提供深入的调试功能
5. 项目必须能迅速分发
6. 服务构建和维护的性价比要高
1. 能够随时**扩展**以满足弹性需求
2. 具备应对数据中心故障的**弹性**
3. 确保数据**安全**以及数据受到保护
4. 为排错提供深入的**调试**功能
5. 项目必须能**迅速分发**
6. 服务构建和维护的**性价比**要高
就新服务来说,这看起来是非常标准的需求 — 从本质上看传统专用基础设备上没有什么东西可以超越公共云了。
![](https://cdn-images-1.medium.com/max/1600/1*DgnAPA6P5R0yQiV8n6siJw.png)
* * *
#### 1 — 扩展以满足客户需求
当说到可扩展性时,这个新服务需要去满足客户变化无常的需求。我们构建的服务不可以拒绝任何请求,以防让公司遭受损失或者声誉受到影响。
传统的团队使用的是专用基础设施,架构体系的计算能力需要与峰值数据需求相匹配。对于负载变化无常的服务来说,大量昂贵的计算能力在低利用率的时间被浪费掉。
**传统团队**
使用的是专用基础设施,架构体系的计算能力需要与峰值数据需求相匹配。对于负载变化无常的服务来说,大量昂贵的计算能力在低利用率时被浪费掉。
这是一种很浪费的方法  —  并且大量的资本支出会侵蚀掉你的利润。另外,这些未充分利用的庞大的服务器资源的维护也是一项很大的运营成本。这是一项你无法忽略的成本  —  我不得不再强调一下,为支持一个单一服务去维护一机柜的服务器是多么的浪费时间和金钱。
云团队使用的是基于云的自动伸缩解决方案,应用会按需要进行自动扩展和收缩。也就是说你只需要支付你所消费的计算资源的费用。
**云团队**
使用的是基于云的自动伸缩解决方案,应用会按需要进行自动扩展和收缩。也就是说你只需要支付你所消费的计算资源的费用。
一个架构良好的基于云的应用可以实现无缝地伸缩 —  并且还是自动进行的。开发团队只需要定义好自动伸缩的资源组即可,即当你的应用 CPU 利用率达到某个高位、或者每秒有多大请求数时启动多少实例,并且你可以根据你的意愿去定制这些规则。
* * *
#### 2 — 应对故障的弹性
当说到弹性时,将托管服务的基础设施放在同一个房间里并不是一个好的选择。如果你的应用托管在一个单一的数据中心  —  (不是如果)发生某些失败时(译注:指坍塌、地震、洪灾等),你的所有的东西都被埋了。
当说到弹性时,将托管服务的基础设施放在同一个房间里并不是一个好的选择。如果你的应用托管在一个单一的数据中心  —  (不是如果)发生某些失败时(LCTT 译注:指坍塌、地震、洪灾等),你的所有的东西都被埋了。
传统的团队去满足这种基本需求的标准解决方案是,为实现局部弹性建立至少两个服务器  —  在地理上冗余的数据中心之间实施秒级复制。
**传统团队**
开发团队需要一个负载均衡解决方案,以便于在发生饱合或者故障等事件时将流量转向到另一个节点  —  并且还要确保镜像节点之间,整个栈是持续完全同步的
满足这种基本需求的标准解决方案是,为实现局部弹性建立至少两个服务器  —  在地理上冗余的数据中心之间实施秒级复制
在全球 50 个区域中的每一个云团队,都由 AWS 提供多个_有效区域_。每个区域由多个容错数据中心组成  — 通过自动故障切换功能AWS 可以在区域内将服务无缝地转移到其它的区中。
开发团队需要一个负载均衡解决方案,以便于在发生饱和或者故障等事件时将流量转向到另一个节点  —  并且还要确保镜像节点之间,整个栈是持续完全同步的。
**云团队**
在 AWS 全球 50 个地区中他们都提供多个_可用区_。每个区域由多个容错数据中心组成  — 通过自动故障切换功能AWS 可以将服务无缝地转移到该地区的其它区中。
在一个 `CloudFormation` 模板中定义你的_基础设施即代码_确保你的基础设施在自动伸缩事件中跨区保持一致而对于流量的流向管理AWS 负载均衡服务仅需要做很少的配置即可。
* * *
#### 3安全和数据保护
安全是一个组织中任何一个系统的基本要求。我想你肯定不想成为那些不幸遭遇安全问题的公司之一的。
传统团队为保证运行他们服务的基础服务器安全,他们不得不持续投入成本。这意味着将不得不向监视、识别、以及为来自不同数据源的跨多个供应商解决方案的安全威胁打补丁的团队上投资。
**传统团队**
使用公共云的团队并不能免除来自安全方面的责任。云团队仍然需要提高警惕但是并不需要去担心为底层基础设施打补丁的问题。AWS 将积极地对付各种 0 日漏洞 — 最近的一次是 Spectre 和 Meltdown
为保证运行他们服务的基础服务器安全,他们不得不持续投入成本。这意味着将需要投资一个团队,以监视和识别安全威胁,并用来自不同数据源的跨多个供应商解决方案打上补丁
利用来自 AWS 的识别管理和加密安全服务,可以让云团队专注于他们的应用 —  而不是无差别的安全管理。使用 `CloudTrail` 对 API 到 AWS 服务的调用做全面审计,可以实现透明地监视。
**云团队**
* * *
使用公共云并不能免除来自安全方面的责任。云团队仍然需要提高警惕但是并不需要去担心为底层基础设施打补丁的问题。AWS 将积极地对付各种零日漏洞 — 最近的一次是 Spectre 和 Meltdown。
利用来自 AWS 的身份管理和加密安全服务,可以让云团队专注于他们的应用 —  而不是无差别的安全管理。使用 CloudTrail 对 API 到 AWS 服务的调用做全面审计,可以实现透明地监视。
#### 4监视和日志
任何基础设施和部署为服务的应用都需要严密监视实时数据。团队应该有一个可以访问的仪表板,当超过指标阈值时仪表板会显示警报,并能够在排错时提供与事件相关的日志。
使用传统基础设施的传统团队,将不得不在跨不同供应商和“雪花状”的解决方案上配置监视和报告解决方案。配置这些“见鬼的”解决方案将花费你大量的时间和精力 —  并且能够正确地实现你的目的是相当困难的。
**传统团队**
对于传统基础设施,将不得不在跨不同供应商和“雪花状”的解决方案上配置监视和报告解决方案。配置这些“见鬼的”解决方案将花费你大量的时间和精力 —  并且能够正确地实现你的目的是相当困难的。
对于大多数部署在专用基础设施上的应用来说,为了搞清楚你的应用为什么崩溃,你可以通过搜索保存在你的服务器文件系统上的日志文件来找到答案。为此你的团队需要通过 SSH 进入服务器,导航到日志文件所在的目录,然后浪费大量的时间,通过 `grep` 在成百上千的日志文件中寻找。如果你在一个横跨 60 台服务器上部署的应用中这么做  —  我能负责任地告诉你,这是一个极差的解决方案。
云团队利用原生的 AWS 服务,如 CloudWatch 和 CloudTrail来做云应用程序的监视是非常容易。不需要很多的配置开发团队就可以监视部署的服务上的各种指标问题的排除过程也不再是个恶梦了。
**云团队**
利用原生的 AWS 服务,如 CloudWatch 和 CloudTrail来做云应用程序的监视是非常容易。不需要很多的配置开发团队就可以监视部署的服务上的各种指标  —  问题的排除过程也不再是个恶梦了。
对于传统的基础设施,团队需要构建自己的解决方案,配置他们的 REST API 或者服务去推送日志到一个聚合器。而得到这个“开箱即用”的解决方案将对生产力有极大的提升。
* * *
#### 5加速开发进程
现在的商业环境中,快速上市的能力越来越重要。由于实施延误所失去的机会成本,可能成为影响最终利润的一个主要因素。
现在的商业环境中,快速上市的能力越来越重要。由于实施延误所失去的机会成本,可能成为影响最终利润的一个主要因素。
大多数组织的这种传统团队,他们需要在新项目所需要的硬件采购、配置和部署上花费很长的时间 — 并且由于预测能力差,提前获得的额外的性能将造成大量的浪费。
**传统团队**
对于大多数组织,他们需要在新项目所需要的硬件采购、配置和部署上花费很长的时间 — 并且由于预测能力差,提前获得的额外的性能将造成大量的浪费。
而且还有可能的是,传统的开发团队在无数的“筒仓”中穿梭以及在移交创建的服务上花费数月的时间。项目的每一步都会在数据库、系统、安全、以及网络管理方面需要一个独立工作。
**云团队**
而云团队开发新特性时,拥有大量的随时可投入生产系统的服务套件供你使用。这是开发者的天堂。每个 AWS 服务一般都有非常好的文档并且可以通过你选择的语言以编程的方式去访问。
使用新的云架构,例如无服务器,开发团队可以在最小化冲突的前提下构建和部署一个可扩展的解决方案。比如,只需要几天时间就可以建立一个 [Imgur 的无服务器克隆][4],它具有图像识别的特性,内置一个产品级的监视/日志解决方案,并且它的弹性极好。
![](https://cdn-images-1.medium.com/max/1600/1*jHmtrp1OKM4mZVn-gSNoQg.png)
如果必须要我亲自去设计弹性和可伸缩性,我可以向你保证,我仍然在开发这个项目 — 而且最终的产品将远不如目前的这个好。
*如何建立一个 Imgur 的无服务器克隆*
如果必须要我亲自去设计弹性和可伸缩性,我可以向你保证,我会陷在这个项目的开发里 — 而且最终的产品将远不如目前的这个好。
从我实践的情况来看,使用无服务器架构的交付时间远小于在大多数公司中提供硬件所花费的时间。我只是简单地将一系列 AWS 服务与 Lambda 功能 — 以及 ta-da 耦合到一起而已!我只专注于开发解决方案,而无差别的可伸缩性和弹性是由 AWS 为我处理的。
* * *
#### 关于云计算成本的结论
就弹性而言,云计算团队的按需扩展是当之无愧的赢家 — 因为他们仅为需要的计算能力埋单。而不需要为维护和底层的物理基础设施打补丁付出相应的资源。
云计算也为开发团队提供一个可使用多个有效区的弹性架构、为每个服务构建的安全特性、持续的日志和监视工具、随用随付的服务、以及低成本的加速分发实践。
云计算也为开发团队提供一个可使用多个可用区的弹性架构、为每个服务构建的安全特性、持续的日志和监视工具、随用随付的服务、以及低成本的加速分发实践。
大多数情况下,云计算的成本要远低于为你的应用运行所需要的购买、支持、维护和设计的按需基础架构的成本 —  并且云计算的麻烦事更少。
@ -116,17 +120,17 @@
也有一些云计算比传统基础设施更昂贵的例子,一些情况是在周末忘记关闭运行的一些极其昂贵的测试机器。
[Dropbox 在决定推出自己的基础设施并减少对 AWS 服务的依赖之后,在两年的时间内节省近 7500 万美元的费用Dropbox…www.geekwire.com][5][][6]
[Dropbox 在决定推出自己的基础设施并减少对 AWS 服务的依赖之后,在两年的时间内节省近 7500 万美元的费用Dropbox…——www.geekwire.com][5][][6]
即便如此,这样的案例仍然是非常少见的。更不用说当初 Dropbox 也是从 AWS 上开始它的业务的  —  并且当它的业务达到一个临界点时,才决定离开这个平台。即便到现在,他们也已经进入到云计算的领域了,并且还在 AWS 和 GCP 上保留了 40% 的基础设施。
将云服务与基于单一“成本”指标(译注:此处的“成本”仅指物理基础设施的购置成本)的传统基础设施比较的想法是极其幼稚的  —  公然无视云为开发团队和你的业务带来的一些主要的优势。
将云服务与基于单一“成本”指标(LCTT 译注:此处的“成本”仅指物理基础设施的购置成本)的传统基础设施比较的想法是极其幼稚的  —  公然无视云为开发团队和你的业务带来的一些主要的优势。
在极少数的情况下,云服务比传统基础设施产生更多的绝对成本  —  它在开发团队的生产力、速度和创新方面仍然贡献着更好的价值。
在极少数的情况下,云服务比传统基础设施产生更多的绝对成本  —  它在开发团队的生产力、速度和创新方面仍然贡献着更好的价值。
![](https://cdn-images-1.medium.com/max/1600/1*IlrOdfYiujggbsYynTzzEQ.png)
客户才不在乎你的数据中心呢
*客户才不在乎你的数据中心呢*
_我非常乐意倾听你在云中开发的真实成本相关的经验和反馈请在下面的评论区、Twitter  _ [_@_ _Elliot_F_][7] 上、或者直接在 _ [_LinkedIn_][8] 上联系我。
@ -136,7 +140,7 @@ via: https://read.acloud.guru/the-true-cost-of-cloud-a-comparison-of-two-develop
作者:[Elliot Forbes][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,23 +1,25 @@
供应链管理方面的 5 个开源软件工具
======
> 跟踪您的库存和您需要的材料,用这些供应链管理工具制造产品。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BIZ_Maze2.png?itok=EH_L-J6Q)
本文最初发表于 2016 年 1 月 14 日,最后的更新日期为 2018 年 3 月 2 日。
如果你正在管理着处理实体货物的业务,[供应链管理][1] 是你的业务流程中非常重要的一部分。不论你是经营着一个只有几个客户的小商店,还是在世界各地拥有数百万计客户和成千上万产品的世界财富 500 强的制造商或零售商,很清楚地知道你的库存和制造产品所需要的零部件,对你来说都是非常重要的事情。
如果你正在管理着处理实体货物的业务,[供应链管理][1] 是你的业务流程中非常重要的一部分。不论你是经营着一个只有几个客户的小商店,还是在世界各地拥有数百万计客户和成千上万产品的世界财富 500 强的制造商或零售商,很清楚地知道你的库存和制造产品所需要的零部件,对你来说都是非常重要的事情。
保持对货品、供应商、客户的持续跟踪,并且所有与它们相关的变动部分都会从中受益,并且,在某些情况下完全依赖专门的软件来帮助管理这些工作流。在本文中,我们将去了解一些免费的和开源的供应链管理方面的软件,以及它们的其中一些功能。
保持对货品、供应商、客户的持续跟踪,而且所有与它们相关的变动部分都会受益于这些用来帮助管理工作流的专门软件,而在某些情况下需要完全依赖这些软件。在本文中,我们将去了解一些自由及开源的供应链管理方面的软件,以及它们的其中一些功能。
供应链管理比单纯的库存管理更为强大。它能帮你去跟踪货物流以降低成本,以及为可能发生的各种糟糕的变化来制定应对计划。它能够帮你对出口合规性进行跟踪,不论是合法性、最低品质要求、还是社会和环境的合规性。它能够帮你计划最低供应量,让你能够在订单数量和交付时间之间做出明智的决策。
供应链管理比单纯的库存管理更为强大。它能帮你去跟踪货物流以降低成本,以及为可能发生的各种糟糕的变化来制定应对计划。它能够帮你对出口合规性进行跟踪,不论是否是出于法律要求、最低品质要求、还是社会和环境责任。它能够帮你计划最低供应量,让你能够在订单数量和交付时间之间做出明智的决策。
由于它的本质决定了许多供应链管理软件是与类似的软件捆绑在一起的,比如,[客户关系管理][2]CRM和 [企业资源计划管理][3] ERP。因此当你选择哪个工具更适合你的组织时你可能会考虑与其它工具集成作为你的决策依据之一。
由于本质决定了许多供应链管理软件是与类似的软件捆绑在一起的,比如,[客户关系管理][2]CRM和 [企业资源计划管理][3] ERP。因此当你选择哪个工具更适合你的组织时你可能会考虑与其它工具集成作为你的决策依据之一。
### Apache OFBiz
[Apache OFBiz][4] 是一套帮你管理多种业务流程的相关工具。虽然它能管理多种相关问题,比如,目录、电子商务网站、帐户、和销售点,它在供应链管理方面的主要功能关注于仓库管理、履行、订单和生产管理。它的可定制性很强,但是,它需要大量的规划去设置和集成到你现有的流程中。这就是它适用于中大型业务的原因之一。项目的功能构建于三个层面:展示层、业务层和数据层,它是一个弹性很好的解决方案,但是,再强调一遍,它也很复杂。
[Apache OFBiz][4] 是一套帮你管理多种业务流程的相关工具。虽然它能管理多种相关问题,比如,分类、电子商务网站、会计和 POS,它在供应链管理方面的主要功能关注于仓库管理、履行、订单和生产管理。它的可定制性很强,但是,对应的它需要大量的规划去设置和集成到你现有的流程中。这就是它适用于中大型业务的原因之一。项目的功能构建于三个层面:展示层、业务层和数据层,它是一个弹性很好的解决方案,但是,再强调一遍,它也很复杂。
Apache OFBiz 的源代码在 [项目仓库][5] 中可以找到。Apache OFBiz 是用 Java 写的,并且它是按 [Apache 2.0 license][6] 授权的。
Apache OFBiz 的源代码在 [项目仓库][5] 中可以找到。Apache OFBiz 是用 Java 写的,并且它是按 [Apache 2.0 许可证][6] 授权的。
如果你对它感兴趣,你也可以去查看 [opentaps][7],它是在 OFBiz 之上构建的。Opentaps 强化了 OFBiz 的用户界面,并且添加了 ERP 和 CRM 的核心功能,包括仓库管理、采购和计划。它是按 [AGPL 3.0][8] 授权使用的,对于不接受开源授权的组织,它也提供了商业授权。
@ -25,25 +27,25 @@ Apache OFBiz 的源代码在 [项目仓库][5] 中可以找到。Apache OFBiz
[OpenBoxes][9] 是一个供应链管理和存货管理项目,最初的主要设计目标是为了医疗行业中的药品跟踪管理,但是,它可以通过修改去跟踪任何类型的货品和相关的业务流。它有一个需求预测工具,可以基于历史订单数量、存储跟踪、支持多种场所、过期日期跟踪、销售点支持等进行预测,并且它还有许多其它功能,这使它成为医疗行业的理想选择,但是,它也可以用于其它行业。
它在 [Eclipse Public License][10] 下可用OpenBoxes 主要是由 Groovy 写的,它的源代码可以在 [GitHub][11] 上看到。
它在 [Eclipse 公开许可证][10] 下可用OpenBoxes 主要是由 Groovy 写的,它的源代码可以在 [GitHub][11] 上看到。
### OpenLMIS
与 OpenBoxes 类似,[OpenLMIS][12] 也是一个医疗行业的供应链管理工具,但是,它专用设计用于在非洲的资源缺乏地区使用,以确保有限的药物和医疗用品能够用到需要的病人上。它是 API 驱动的,这样用户可以去定制和扩展 OpenLMIS同时还能维护一个与通用基准代码的连接。它是由克菲勒基金会开发的,其它的贡献者包括联合国、美国国际开发署、和比尔 & 梅林达 盖茨基金会。
与 OpenBoxes 类似,[OpenLMIS][12] 也是一个医疗行业的供应链管理工具,但是,它专用设计用于在非洲的资源缺乏地区使用,以确保有限的药物和医疗用品能够用到需要的病人上。它是 API 驱动的,这样用户可以去定制和扩展 OpenLMIS同时还能维护一个与通用基准代码的连接。它是由克菲勒基金会开发的,其它的贡献者包括联合国、美国国际开发署、和比尔 & 梅林达·盖茨基金会。
OpenLMIS 是用 Java 和 JavaScript 的 AngularJS 写的。它在 [AGPL 3.0 license][13] 下使用,它的源代码在 [GitHub][13] 上可以找到。
OpenLMIS 是用 Java 和 JavaScript 的 AngularJS 写的。它在 [AGPL 3.0 许可证][13] 下使用,它的源代码在 [GitHub][13] 上可以找到。
### Odoo
你可能在我们以前的 [ERP 项目][3] 榜的文章上见到过 [Odoo][14]。事实上,根据你的需要,一个全功能的 ERP 对你来说是最适合的。Odoo 的供应链管理工具主要围绕存货和采购管理,同时还与电子商务网站和销售点连接,但是,它也可以与其它的工具连接,比如,与 [frePPLe][15] 连接,它是一个开源的生产计划工具。
你可能在我们以前的 [ERP 项目][3] 榜的文章上见到过 [Odoo][14]。事实上,根据你的需要,一个全功能的 ERP 对你来说是最适合的。Odoo 的供应链管理工具主要围绕存货和采购管理,同时还与电子商务网站和 POS 连接,但是,它也可以与其它的工具连接,比如,与 [frePPLe][15] 连接,它是一个开源的生产计划工具。
Odoo 既有软件即服务的解决方案,也有开源的社区版本。开源的版本是以 [LGPL][16] 版本 3 下发行的,源代码在 [GitHub][17] 上可以找到。Odoo 主要是用 Python 来写的。
Odoo 既有软件即服务SaaS的解决方案,也有开源的社区版本。开源的版本是以 [LGPL][16] 版本 3 下发行的,源代码在 [GitHub][17] 上可以找到。Odoo 主要是用 Python 来写的。
### xTuple
[xTuple][18] 标称自己是“为成长中的企业提供供应链管理软件”,它专注于已经超越了传统的小型企业 ERP 和 CRM 解决方案的企业。它的开源版本称为 Postbooks添加了一些存货、分销、采购、以及供应商报告的功能它提供的核心功能是帐务、CRM、以及 ERP 功能,而它的商业版本扩展了制造和分销的 [功能][19]。
[xTuple][18] 标称自己是“为成长中的企业提供供应链管理软件”,它专注于已经超越了传统的小型企业 ERP 和 CRM 解决方案的企业。它的开源版本称为 Postbooks添加了一些存货、分销、采购、以及供应商报告的功能它提供的核心功能是会计、CRM、以及 ERP 功能,而它的商业版本扩展了制造和分销的 [功能][19]。
xTuple 在 [CPAL][20] 下使用,这个项目欢迎开发者去 fork 它,为基于存货的制造商去创建其它的业务软件。它的 Web 应用核心是用 JavaScript 写的,它的源代码在 [GitHub][21] 上可以找到。
xTuple 在 [CPAL][20] 下使用,这个项目欢迎开发者去复刻它,为基于存货的制造商去创建其它的业务软件。它的 Web 应用核心是用 JavaScript 写的,它的源代码在 [GitHub][21] 上可以找到。
就这些,当然了,还有其它的可以帮你处理供应链管理的开源软件。如果你知道还有更好的软件,请在下面的评论区告诉我们。
@ -53,14 +55,14 @@ via: https://opensource.com/tools/supply-chain-management
作者:[Jason Baker][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/jason-baker
[1]:https://en.wikipedia.org/wiki/Supply_chain_management
[2]:https://opensource.com/business/14/7/top-5-open-source-crm-tools
[3]:https://opensource.com/resources/top-4-open-source-erp-systems
[3]:https://linux.cn/article-9785-1.html
[4]:http://ofbiz.apache.org/
[5]:http://ofbiz.apache.org/source-repositories.html
[6]:http://www.apache.org/licenses/LICENSE-2.0

View File

@ -0,0 +1,132 @@
IT 自动化的下一步是什么: 6 大趋势
======
> 自动化专家分享了一点对 [自动化][6]不远的将来的看法。请将这些保留在你的视线之内。
![](https://enterprisersproject.com/sites/default/files/styles/620x350/public/cio_ai_artificial_intelligence.png?itok=o0csm9l2)
我们最近讨论了 [推动 IT 自动化的因素][1],可以看到[当前趋势][2]正在增长,以及那些给刚开始使用自动化部分流程的组织的 [有用的技巧][3] 。
噢,我们也分享了如何在贵公司[进行自动化的案例][4]及 [长期成功的关键][5]的专家建议。
现在,只有一个问题:自动化的下一步是什么? 我们邀请一系列专家分享一下 [自动化][6]不远的将来的看法。 以下是他们建议 IT 领域领导需密切关注的六大趋势。
### 1、 机器学习的成熟
对于关于 [机器学习][7](与“自我学习系统”相似的定义)的讨论,对于绝大多数组织的项目来说,实际执行起来它仍然为时过早。但预计这将发生变化,机器学习将在下一次 IT 自动化浪潮中将扮演着至关重要的角色。
[Advanced Systems Concepts, Inc.][8] 公司的工程总监 Mehul Amin 指出机器学习是 IT 自动化下一个关键增长领域之一。
“随着数据化的发展自动化软件理应可以自我决策否则这就是开发人员的责任了”Amin 说。 “例如,开发者构建了需要执行的内容,但通过使用来自系统内部分析的软件,可以确定执行该流程的最佳系统。”
假设将这个系统延伸到其他地方中。Amin 指出,机器学习可以使自动化系统在必要的时候提供额外的资源,以需要满足时间线或 SLA同样在不需要资源以及其他的可能性的时候退出。
显然不只有 Amin 一个人这样认为。
“IT 自动化正在走向自我学习的方向” [Sungard Availability Services][9] 公司首席架构师 Kiran Chitturi 表示,“系统将会能测试和监控自己,加强业务流程和软件交付能力。”
Chitturi 指出自动化测试就是个例子。脚本测试已经被广泛采用,但很快这些自动化测试流程将会更容易学习,更快发展,例如开发出新的代码或将更为广泛地影响生产环境。
### 2、 人工智能催生的自动化
上述原则同样适合与相关的(但是独立的) [人工智能][10]的领域。根据对人工智能的定义,机器学习在短时间内可能会对 IT 领域产生巨大的影响(并且我们可能会看到这两个领域的许多重叠的定义和理解)。假定新兴的人工智能技术将也会产生新的自动化机会。
[SolarWinds][11] 公司技术负责人 Patrick Hubbard 说,“人工智能和机器学习的整合普遍被认为对未来几年的商业成功起至关重要的作用。”
### 3、 这并不意味着不再需要人力
让我们试着安慰一下那些不知所措的人:前两种趋势并不一定意味着我们将失去工作。
这很可能意味着各种角色的改变,以及[全新角色][12]的创造。
但是在可预见的将来,至少,你不必需要对机器人鞠躬。
“一台机器只能运行在给定的环境变量中——它不能选择包含新的变量,在今天只有人类可以这样做,” Hubbard 解释说。“但是,对于 IT 专业人员来说,这将需要培养 AI 和自动化技能,如对程序设计、编程、管理人工智能和机器学习功能算法的基本理解,以及用强大的安全状态面对更复杂的网络攻击。”
Hubbard 分享一些新的工具或功能例子,例如支持人工智能的安全软件或机器学习的应用程序,这些应用程序可以远程发现石油管道中的维护需求。两者都可以提高效益和效果,自然不会代替需要信息安全或管道维护的人员。
“许多新功能仍需要人工监控”Hubbard 说。“例如,为了让机器确定一些‘预测’是否可能成为‘规律’,人为的管理是必要的。”
即使你把机器学习和 AI 先放在一边,看待一般的 IT 自动化,同样原理也是成立的,尤其是在软件开发生命周期中。
[Juniper Networks][13] 公司自动化首席架构师 Matthew Oswalt ,指出 IT 自动化增长的根本原因是它通过减少操作基础设施所需的人工工作量来创造直接价值。
> 在代码上,操作工程师可以使用事件驱动的自动化提前定义他们的工作流程,而不是在凌晨 3 点来应对基础设施的问题。
“它也将操作工作流程作为代码而不再是容易过时的文档或系统知识阶段”Oswalt 解释说。“操作人员仍然需要在[自动化]工具响应事件方面后发挥积极作用。采用自动化的下一个阶段是建立一个能够跨 IT 频谱识别发生的有趣事件的系统,并以自主方式进行响应。在代码上,操作工程师可以使用事件驱动的自动化提前定义他们的工作流程,而不是在凌晨 3 点来应对基础设施的问题。他们可以依靠这个系统在任何时候以同样的方式作出回应。”
### 4、 对自动化的焦虑将会减少
SolarWinds 公司的 Hubbard 指出,“自动化”一词本身就产生大量的不确定性和担忧,不仅仅是在 IT 领域,而且是跨专业领域,他说这种担忧是合理的。但一些随之而来的担忧可能被夸大了,甚至与科技产业本身共存。现实可能实际上是这方面的镇静力:当自动化的实际实施和实践帮助人们认识到这个列表中的第 3 项时,我们将看到第 4 项的出现。
“今年我们可能会看到对自动化焦虑的减少更多的组织开始接受人工智能和机器学习作为增加现有人力资源的一种方式”Hubbard 说。“自动化历史上为更多的工作创造了空间,通过降低成本和时间来完成较小任务,并将劳动力重新集中到无法自动化并需要人力的事情上。人工智能和机器学习也是如此。”
自动化还将减少令 IT 领导者神经紧张的一些焦虑:安全。正如[红帽][14]公司首席架构师 Matt Smith 最近[指出][15]的那样,自动化将越来越多地帮助 IT 部门降低与维护任务相关的安全风险。
他的建议是:“首先在维护活动期间记录和自动化 IT 资产之间的交互。通过依靠自动化,您不仅可以消除之前需要大量手动操作和手术技巧的任务,还可以降低人为错误的风险,并展示当您的 IT 组织采纳变更和新工作方法时可能发生的情况。最终,这将迅速减少对应用安全补丁的抵制。而且它还可以帮助您的企业在下一次重大安全事件中摆脱头条新闻。”
**[ 阅读全文: [12个企业安全坏习惯要打破。][16] ] **
### 5、 脚本和自动化工具将持续发展
许多组织看到了增加自动化的第一步,通常以脚本或自动化工具(有时称为配置管理工具)的形式作为“早期”工作。
但是随着各种自动化技术的使用,对这些工具的观点也在不断发展。
[DataVision][18] 首席运营官 Mark Abolafia 表示:“数据中心环境中存在很多重复性过程,容易出现人为错误,[Ansible][17] 等技术有助于缓解这些问题。“通过 Ansible ,人们可以为一组操作编写特定的步骤,并输入不同的变量,例如地址等,使过去长时间的过程链实现自动化,而这些过程以前都需要人为触摸和更长的交付时间。”
**[想了解更多关于 Ansible 这个方面的知识吗?阅读相关文章:[使用 Ansible 时的成功秘诀][19]。 ]**
另一个因素是:工具本身将继续变得更先进。
“使用先进的 IT 自动化工具,开发人员将能够在更短的时间内构建和自动化工作流程,减少易出错的编码,” ASCI 公司的 Amin 说。“这些工具包括预先构建的、预先测试过的拖放式集成API 作业,丰富的变量使用,参考功能和对象修订历史记录。”
### 6、 自动化开创了新的指标机会
正如我们在此前所说的那样IT 自动化不是万能的。它不会修复被破坏的流程,或者以其他方式为您的组织提供全面的灵丹妙药。这也是持续不断的:自动化并不排除衡量性能的必要性。
**[ 参见我们的相关文章 [DevOps 指标:你在衡量什么重要吗?][20] ]**
实际上,自动化应该打开了新的机会。
[Janeiro Digital][21] 公司架构师总裁 Josh Collins 说,“随着越来越多的开发活动 —— 源代码管理、DevOps 管道、工作项目跟踪等转向 API 驱动的平台,将这些原始数据拼接在一起以描绘组织效率提升的机会和图景”。
Collins 认为这是一种可能的新型“开发组织度量指标”。但不要误认为这意味着机器和算法可以突然预测 IT 所做的一切。
“无论是衡量个人资源还是整体团队,这些指标都可以很强大 —— 但应该用大量的背景来衡量。”Collins 说,“将这些数据用于高层次趋势并确认定性观察 —— 而不是临床评级你的团队。”
**想要更多这样知识, IT 领导者?[注册我们的每周电子邮件通讯][22]。**
--------------------------------------------------------------------------------
via: https://enterprisersproject.com/article/2018/3/what-s-next-it-automation-6-trends-watch
作者:[Kevin Casey][a]
译者:[MZqk](https://github.com/MZqk)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://enterprisersproject.com/user/kevin-casey
[1]:https://enterprisersproject.com/article/2017/12/5-factors-fueling-automation-it-now
[2]:https://enterprisersproject.com/article/2017/12/4-trends-watch-it-automation-expands
[3]:https://enterprisersproject.com/article/2018/1/getting-started-automation-6-tips
[4]:https://enterprisersproject.com/article/2018/1/how-make-case-it-automation
[5]:https://enterprisersproject.com/article/2018/1/it-automation-best-practices-7-keys-long-term-success
[6]:https://enterprisersproject.com/tags/automation
[7]:https://enterprisersproject.com/article/2018/2/how-spot-machine-learning-opportunity
[8]:https://www.advsyscon.com/en-us/
[9]:https://www.sungardas.com/en/
[10]:https://enterprisersproject.com/tags/artificial-intelligence
[11]:https://www.solarwinds.com/
[12]:https://enterprisersproject.com/article/2017/12/8-emerging-ai-jobs-it-pros
[13]:https://www.juniper.net/
[14]:https://www.redhat.com/en?intcmp=701f2000000tjyaAAA
[15]:https://enterprisersproject.com/article/2018/2/12-bad-enterprise-security-habits-break
[16]:https://enterprisersproject.com/article/2018/2/12-bad-enterprise-security-habits-break?sc_cid=70160000000h0aXAAQ
[17]:https://opensource.com/tags/ansible
[18]:https://datavision.com/
[19]:https://opensource.com/article/18/2/tips-success-when-getting-started-ansible?intcmp=701f2000000tjyaAAA
[20]:https://enterprisersproject.com/article/2017/7/devops-metrics-are-you-measuring-what-matters?sc_cid=70160000000h0aXAAQ
[21]:https://www.janeirodigital.com/
[22]:https://enterprisersproject.com/email-newsletter?intcmp=701f2000000tsjPAAQ

View File

@ -0,0 +1,81 @@
迁移到 Linux使用 sudo
======
> sudo 机制可以让你轻松以普通用户偶尔执行管理任务。让我们来学习一下。
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ray-hennessy-233438-unsplash.jpg?itok=d4l7QUtF)
本文是我们关于迁移到 Linux 的系列文章的第五篇。如果你错过了之前的那些,你可以在这里赶上:
[第1部分 - 入门介绍][1]
[第2部分 - 磁盘、文件和文件系统][2]
[第3部分 - 图形操作环境][3]
[第4部分 - 命令行][4]
你可能一直想了解 Linux。也许它在你的工作场所使用如果你每天使用它你的工作效率会更高。或者也许你想在家里的某些计算机上安装 Linux。无论是什么原因这一系列文章都是为了让过渡更容易。
与许多其他操作系统一样Linux 支持多用户。它甚至支持多个用户同时登录。
用户帐户通常会被分配一个可以存储文件的家目录。通常这个家目​​录位于:
```
/home/<login name>
```
这样,每个用户都有存储自己的文档和其他文件的独立位置。
### 管理任务
在传统的 Linux 安装中,常规用户帐户无权在系统上执行管理任务。典型的安装 Linux 的系统会要求用户以管理员身份登录以执行某些任务,而不是为每个用户分配权限以执行各种任务。
Linux 上的管理员帐户称为 root。
### Sudo 解释
从历史上看,要执行管理任务,必须以 root 身份登录,执行任务,然后登出。这个过程有点乏味,所以很多人以 root 登录并且整天都以管理员身份工作。这种做法可能会导致灾难性的后果例如意外删除系统中的所有文件。当然root 用户可以做任何事情,因此没有任何保护措施可以防止有人意外地执行影响很大的操作。
创建 `sudo` 工具是为了使你更容易以常规用户帐户登录,偶尔以 root 身份执行管理任务,而无需登录、执行任务然后登出。具体来说,`sudo` 允许你以不同的用户身份运行命令。如果你未指定特定用户,则假定你指的是 root 用户。
`sudo` 可以有复杂的设置,允许用户有权限使用 `sudo` 运行某些命令,而其他的不行。通常,安装的桌面系统会使创建的第一个帐户在 `sudo` 中有完全的权限,因此你作为主要用户可以完全管理 Linux 安装。
### 使用 Sudo
某些安装 Linux 的系统设置了 `sudo`,因此你仍需要知道 root 帐户的密码才能执行管理任务。其他人,设置 `sudo` 输入自己的密码。这里有不同的哲学。
当你尝试在图形环境中执行管理任务时,通常会打开一个要求输入密码的对话框。输入你自己的密码(例如,在 Ubuntu 上)或 root 帐户的密码例如Red Hat
当你尝试在命令行中执行管理任务时,它通常只会给你一个 “permission denied” 错误。然后你在前面用 `sudo` 重新运行命令。例如:
```
systemctl start vsftpd
Failed to start vsftpd.service: Access denied
sudo systemctl start vsftpd
[sudo] password for user1:
```
### 何时使用 Sudo
以 root 身份运行命令(在 `sudo` 或其他情况下)并不总是解决权限错误的最佳解决方案。虽然将以 root 身份运行会消除 “permission denied” 错误,但有时最好寻找根本原因而不是仅仅解决症状。有时文件拥有错误的所有者和权限。
当你在尝试一个需要 root 权限来执行操作的任务或者程序时使用 `sudo`。如果文件恰好由另一个用户(包括 root 用户)拥有,请不要使用 `sudo`。在第二种情况下,最好正确设置文件的权限。
通过 Linux 基金会和 edX 的免费[“Linux 介绍”][5]课程了解有关 Linux 的更多信息。
--------------------------------------------------------------------------------
via: https://www.linux.com/blog/learn/2018/3/migrating-linux-using-sudo
作者:[John Bonesio][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linux.com/users/johnbonesio
[1]:https://linux.cn/article-9212-1.html
[2]:https://linux.cn/article-9213-1.html
[3]:https://linux.cn/article-9293-1.html
[4]:https://linux.cn/article-9565-1.html
[5]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux

View File

@ -1,9 +1,11 @@
Kubernetes 分布式应用部署实战 -- 以人脸识别应用为例
Kubernetes 分布式应用部署实战以人脸识别应用为例
============================================================
# 简介
![](https://skarlso.github.io/img/2018/03/kube_overview.png)
伙计们,请做好准备,下面将是一段漫长的旅程,期望你能够乐在其中。
## 简介
伙计们,请搬好小板凳坐好,下面将是一段漫长的旅程,期望你能够乐在其中。
我将基于 [Kubernetes][5] 部署一个分布式应用。我曾试图编写一个尽可能真实的应用,但由于时间和精力有限,最终砍掉了很多细节。
@ -11,17 +13,17 @@ Kubernetes 分布式应用部署实战 -- 以人脸识别应用为例
让我们开始吧。
# 应用
## 应用
### TL;DR
![kube overview](https://skarlso.github.io/img/kube_overview.png)
应用本身由 6 个组件构成。代码可以从如下链接中找到:[Kubenetes 集群示例][6]。
应用本身由 6 个组件构成。代码可以从如下链接中找到:[Kubenetes 集群示例][6]。
这是一个人脸识别服务,通过比较已知个人的图片,识别给定图片对应的个人。前端页面用表格形式简要的展示图片及对应的个人。具体而言,向 [接收器][6] 发送请求,请求包含指向一个图片的链接。图片可以位于任何位置。接受器将图片地址存储到数据库 (MySQL) 中,然后向队列发送处理请求,请求中包含已保存图片的 ID。这里我们使用 [NSQ][8] 建立队列。
[图片处理][9]服务一直监听处理请求队列,从中获取任务。处理过程包括如下几步:获取图片 ID读取图片通过 [gRPC][11] 将图片路径发送至 Python 编写的[人脸识别][10]后端。如果识别成功,后端给出图片对应个人的名字。图片处理器进而根据个人 ID 更新图片记录,将其标记为处理成功。如果识别不成功,图片被标记为待解决。如果图片识别过程中出现错误,图片被标记为失败。
[图片处理][9] 服务一直监听处理请求队列,从中获取任务。处理过程包括如下几步:获取图片 ID读取图片通过 [gRPC][11] 将图片路径发送至 Python 编写的 [人脸识别][10] 后端。如果识别成功,后端给出图片对应个人的名字。图片处理器进而根据个人 ID 更新图片记录,将其标记为处理成功。如果识别不成功,图片被标记为待解决。如果图片识别过程中出现错误,图片被标记为失败。
标记为失败的图片可以通过计划任务等方式进行重试。
@ -33,39 +35,31 @@ Kubernetes 分布式应用部署实战 -- 以人脸识别应用为例
```
curl -d '{"path":"/unknown_images/unknown0001.jpg"}' http://127.0.0.1:8000/image/post
```
此时,接收器将<ruby>路径<rt>path</rt></ruby>存储到共享数据库集群中,对应的条目包括数据库服务提供的 ID。本应用采用”持久层提供条目对象唯一标识“的模型。获得条目 ID 后,接收器向 NSQ 发送消息,至此接收器的工作完成。
此时,接收器将<ruby>路径<rt>path</rt></ruby>存储到共享数据库集群中,该实体存储后将从数据库服务收到对应的 ID。本应用采用“<ruby>实体对象<rt>Entity Object</rt></ruby>的唯一标识由持久层提供”的模型。获得实体 ID 后,接收器向 NSQ 发送消息,至此接收器的工作完成。
### 图片处理器
从这里开始变得有趣起来。图片处理器首次运行时会创建两个 Go routines,具体为:
从这里开始变得有趣起来。图片处理器首次运行时会创建两个 Go <ruby>协程<rt>routine</rt></ruby>,具体为:
### Consume
这是一个 NSQ 消费者,需要完成三项任务。首先,监听队列中的消息。其次,当有新消息到达时,将对应的 ID 追加到一个线程安全的 ID 片段中,以供第二个 routine 处理。最后,告知第二个 routine 处理新任务,方法为 [sync.Condition][12]。
这是一个 NSQ 消费者,需要完成三项必需的任务。首先,监听队列中的消息。其次,当有新消息到达时,将对应的 ID 追加到一个线程安全的 ID 片段中,以供第二个协程处理。最后,告知第二个协程处理新任务,方法为 [sync.Condition][12]。
### ProcessImages
routine 会处理指定 ID 片段,直到对应片段全部处理完成。当处理完一个片段后,该 routine 并不是在一个通道上睡眠等待,而是进入悬挂状态。对每个 ID按如下步骤顺序处理
协程会处理指定 ID 片段,直到对应片段全部处理完成。当处理完一个片段后,该协程并不是在一个通道上睡眠等待,而是进入悬挂状态。对每个 ID按如下步骤顺序处理
* 与人脸识别服务建立 gRPC 连接,其中人脸识别服务会在人脸识别部分进行介绍
* 从数据库获取图片对应的条目
* 从数据库获取图片对应的实体
* 为 [断路器][1] 准备两个函数
* 函数 1: 用于 RPC 方法调用的主函数
* 函数 2: 基于 ping 的断路器健康检查
* 调用函数 1 将图片路径发送至人脸识别服务,其中路径应该是人脸识别服务可以访问的,最好是共享的,例如 NFS
* 如果调用失败,将图片条目状态更新为 FAILEDPROCESSING
* 如果调用失败,将图片实体状态更新为 FAILEDPROCESSING
* 如果调用成功,返回值是一个图片的名字,对应数据库中的一个个人。通过联合 SQL 查询,获取对应个人的 ID
* 将数据库中的图片条目状态更新为 PROCESSED更新图片被识别成的个人的 ID
* 将数据库中的图片实体状态更新为 PROCESSED更新图片被识别成的个人的 ID
这个服务可以复制多份同时运行。
@ -89,7 +83,7 @@ curl -d '{"path":"/unknown_images/unknown0001.jpg"}' http://127.0.0.1:8000/image
注意:我曾经试图使用 [GoCV][14],这是一个极好的 Go 库,但欠缺所需的 C 绑定。推荐马上了解一下这个库,它会让你大吃一惊,例如编写若干行代码即可实现实时摄像处理。
这个 Python 库的工作方式本质上很简单。准备一些你认识的人的图片,把信息记录下来。对于我而言,我有一个图片文件夹,包含若干图片,名称分别为 `hannibal_1.jpg, hannibal_2.jpg, gergely_1.jpg, john_doe.jpg`。在数据库中,我使用两个表记录信息,分别为 `person, person_images`,具体如下:
这个 Python 库的工作方式本质上很简单。准备一些你认识的人的图片,把信息记录下来。对于我而言,我有一个图片文件夹,包含若干图片,名称分别为 `hannibal_1.jpg`、 `hannibal_2.jpg``gergely_1.jpg``john_doe.jpg`。在数据库中,我使用两个表记录信息,分别为 `person``person_images`,具体如下:
```
+----+----------+
@ -126,13 +120,13 @@ NSQ 是 Go 编写的小规模队列可扩展且占用系统内存较少。NSQ
### 配置
为了尽可能增加灵活性以及使用 Kubernetes 的 ConfigSet 特性,我在开发过程中使用 .env 文件记录配置信息,例如数据库服务的地址以及 NSQ 的查询地址。在生产环境或 Kubernetes 环境中,我将使用环境变量属性配置。
为了尽可能增加灵活性以及使用 Kubernetes 的 ConfigSet 特性,我在开发过程中使用 `.env` 文件记录配置信息,例如数据库服务的地址以及 NSQ 的查询地址。在生产环境或 Kubernetes 环境中,我将使用环境变量属性配置。
### 应用小结
这就是待部署应用的全部架构信息。应用的各个组件都是可变更的,他们之间仅通过数据库、消息队列和 gRPC 进行耦合。考虑到更新机制的原理,这是部署分布式应用所必须的;在部署部分我会继续分析。
# 使用 Kubernetes 部署应用
## 使用 Kubernetes 部署应用
### 基础知识
@ -144,55 +138,51 @@ Kubernetes 是容器化服务及应用的管理器。它易于扩展,可以管
在 Kubernetes 中你给出期望的应用状态Kubernetes 会尽其所能达到对应的状态。状态可以是已部署、已暂停,有 2 个副本等,以此类推。
Kubernetes 使用标签和注释标记组件,包括服务,部署,副本组,守护进程组等在内的全部组件都被标记。考虑如下场景,为了识别 pod 与 应用的对应关系,使用 `app: myapp` 标签。假设应用已部署 2 个容器,如果你移除其中一个容器的 `app` 标签Kubernetes 只能识别到一个容器(隶属于应用),进而启动一个新的具有 `myapp` 标签的实例。
Kubernetes 使用标签和注释标记组件,包括服务、部署、副本组、守护进程组等在内的全部组件都被标记。考虑如下场景,为了识别 pod 与应用的对应关系,使用 `app: myapp` 标签。假设应用已部署 2 个容器,如果你移除其中一个容器的 `app` 标签Kubernetes 只能识别到一个容器(隶属于应用),进而启动一个新的具有 `myapp` 标签的实例。
### Kubernetes 集群
要使用 Kubernetes需要先搭建一个 Kubernetes 集群。搭建 Kubernetes 集群可能是一个痛苦的经历但所幸有工具可以帮助我们。Minikube 为我们在本地搭建一个单节点集群。AWS 的一个 beta 服务工作方式类似于 Kubernetes 集群,你只需请求 Nodes 并定义你的部署即可。Kubernetes 集群组件的文档如下:[Kubernetes 集群组件][17]。
要使用 Kubernetes需要先搭建一个 Kubernetes 集群。搭建 Kubernetes 集群可能是一个痛苦的经历但所幸有工具可以帮助我们。Minikube 为我们在本地搭建一个单节点集群。AWS 的一个 beta 服务工作方式类似于 Kubernetes 集群,你只需请求节点并定义你的部署即可。Kubernetes 集群组件的文档如下:[Kubernetes 集群组件][17]。
### 节点 (Nodes)
### 节点
节点是工作单位,形式可以是虚拟机、物理机,也可以是各种类型的云主机。
<ruby>节点<rt>node</rt></ruby>是工作单位,形式可以是虚拟机、物理机,也可以是各种类型的云主机。
### Pods
### Pod
Pods 是本地容器组成的集合,即一个 Pod 中可能包含若干个容器。Pod 创建后具有自己的 DNS 和 虚拟 IP这样 Kubernetes 可以对到达流量进行负载均衡。你几乎不需要直接和容器打交道;即使是调试的时候,例如查看日志,你通常调用 `kubectl logs deployment/your-app -f` 查看部署日志,而不是使用 `-c container_name` 查看具体某个容器的日志。`-f` 参数表示从日志尾部进行流式输出。
Pod 是本地容器逻辑上组成的集合,即一个 Pod 中可能包含若干个容器。Pod 创建后具有自己的 DNS 和虚拟 IP这样 Kubernetes 可以对到达流量进行负载均衡。你几乎不需要直接和容器打交道;即使是调试的时候,例如查看日志,你通常调用 `kubectl logs deployment/your-app -f` 查看部署日志,而不是使用 `-c container_name` 查看具体某个容器的日志。`-f` 参数表示从日志尾部进行流式输出。
### 部署 (Deployments)
### 部署
在 Kubernetes 中创建任何类型的资源时,后台使用一个部署,它指定了资源的期望状态。使用部署对象,你可以将 Pod 或服务变更为另外的状态,也可以更新应用或上线新版本应用。你一般不会直接操作副本组 (后续会描述),而是通过部署对象创建并管理。
在 Kubernetes 中创建任何类型的资源时,后台使用一个<ruby>部署<rt>deployment</rt></ruby>组件,它指定了资源的期望状态。使用部署对象,你可以将 Pod 或服务变更为另外的状态,也可以更新应用或上线新版本应用。你一般不会直接操作副本组 (后续会描述),而是通过部署对象创建并管理。
### 服务 (Services)
### 服务
默认情况下Pod 会获取一个 IP 地址。但考虑到 Pod 是 Kubernetes 中的易失性组件,我们需要更加持久的组件。不论是队列,mysql内部 API 或前端,都需要长期运行并使用保持不变的 IP 或 更佳的 DNS 记录。
默认情况下Pod 会获取一个 IP 地址。但考虑到 Pod 是 Kubernetes 中的易失性组件,我们需要更加持久的组件。不论是队列,MySQL、内部 API 或前端,都需要长期运行并使用保持不变的 IP 或更好的 DNS 记录。
为解决这个问题Kubernetes 提供了服务组件,可以定义访问模式,支持的模式包括负载均衡,简单 IP 或 内部 DNS。
为解决这个问题Kubernetes 提供了<ruby>服务<rt>service</rt></ruby>组件,可以定义访问模式,支持的模式包括负载均衡、简单 IP 或内部 DNS。
Kubernetes 如何获知服务运行正常呢?你可以配置健康性检查和可用性检查。健康性检查是指检查容器是否处于运行状态,但容器处于运行状态并不意味着服务运行正常。对此,你应该使用可用性检查,即请求应用的一个特别<ruby>接口<rt>endpoint</rt></ruby>
由于服务非常重要,推荐你找时间阅读以下文档:[服务][18]。严肃的说,需要阅读的东西很多,有 24 页 A4 纸的篇幅,涉及网络服务及自动发现。这也有助于你决定是否真的打算在生产环境中使用 Kubernetes。
由于服务非常重要,推荐你找时间阅读以下文档:[服务][18]。严肃的说,需要阅读的东西很多,有 24 页 A4 纸的篇幅,涉及网络服务及自动发现。这也有助于你决定是否真的打算在生产环境中使用 Kubernetes。
### DNS / 服务发现
在 Kubernetes 集群中创建服务后,该服务会从名为 kube-proxy 和 kube-dns 的特殊 Kubernetes 部署中获取一个 DNS 记录。他们两个用于提供集群内的服务发现。如果你有一个正在运行的 mysql 服务并配置 `clusterIP: no`,那么集群内部任何人都可以通过 `mysql.default.svc.cluster.local` 访问该服务,其中:
在 Kubernetes 集群中创建服务后,该服务会从名为 `kube-proxy``kube-dns` 的特殊 Kubernetes 部署中获取一个 DNS 记录。它们两个用于提供集群内的服务发现。如果你有一个正在运行的 MySQL 服务并配置 `clusterIP: no`,那么集群内部任何人都可以通过 `mysql.default.svc.cluster.local` 访问该服务,其中:
* `mysql`  服务的名称
* `default`  命名空间的名称
* `svc`  对应服务分类
* `cluster.local`  本地集群的域名
可以使用自定义设置更改本地集群的域名。如果想让服务可以从集群外访问,需要使用 DNS 提供程序并使用例如 Nginx 将 IP 地址绑定至记录。服务对应的对外 IP 地址可以使用如下命令查询:
可以使用自定义设置更改本地集群的域名。如果想让服务可以从集群外访问,需要使用 DNS 服务,并使用例如 Nginx 将 IP 地址绑定至记录。服务对应的对外 IP 地址可以使用如下命令查询:
* 节点端口方式  `kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services mysql`
* 负载均衡方式  `kubectl get -o jsonpath="{.spec.ports[0].LoadBalancer}" services mysql`
### 模板文件
类似 Docker Compose, TerraForm 或其它的服务管理工具Kubernetes 也提供了基础设施描述模板。这意味着,你几乎不用手动操作。
类似 Docker ComposeTerraForm 或其它的服务管理工具Kubernetes 也提供了基础设施描述模板。这意味着,你几乎不用手动操作。
以 Nginx 部署为例,查看下面的 yaml 模板:
@ -218,26 +208,26 @@ spec: #(4)
image: nginx:1.7.9
ports:
- containerPort: 80
```
在这个示例部署中,我们做了如下操作:
* (1) 使用 kind 关键字定义模板类型
* (2) 使用 metadata 关键字,增加该部署的识别信息,使用 labels 标记每个需要创建的资源 (3)
* (4) 然后使用 spec 关键字描述所需的状态
* (5) nginx 应用需要 3 个副本
* (6) Pod 中容器的模板定义部分
* 容器名称为 nginx
* 容器模板为 nginx:1.7.9 (本例使用 Docker 镜像)
* (1) 使用 `kind` 关键字定义模板类型
* (2) 使用 `metadata` 关键字,增加该部署的识别信息
* (3) 使用 `labels` 标记每个需要创建的资源
* (4) 然后使用 `spec` 关键字描述所需的状态
* (5) nginx 应用需要 3 个副本
* (6) Pod 中容器的模板定义部分
* 容器名称为 nginx
* 容器模板为 nginx:1.7.9 (本例使用 Docker 镜像)
### 副本组 (ReplicaSet)
### 副本组
副本组是一个底层的副本管理器,用于保证运行正确数目的应用副本。相比而言,部署是更高层级的操作,应该用于管理副本组。除非你遇到特殊的情况,需要控制副本的特性,否则你几乎不需要直接操作副本组。
<ruby>副本组<rt>ReplicaSet</rt></ruby>是一个底层的副本管理器,用于保证运行正确数目的应用副本。相比而言,部署是更高层级的操作,应该用于管理副本组。除非你遇到特殊的情况,需要控制副本的特性,否则你几乎不需要直接操作副本组。
### 守护进程组 (DaemonSet)
### 守护进程组
上面提到 Kubernetes 始终使用标签,还有印象吗?守护进程组是一个控制器,用于确保守护进程化的应用一直运行在具有特定标签的节点中。
上面提到 Kubernetes 始终使用标签,还有印象吗?<ruby>守护进程组<rt>DaemonSet</rt></ruby>是一个控制器,用于确保守护进程化的应用一直运行在具有特定标签的节点中。
例如,你将所有节点增加 `logger``mission_critical` 的标签,以便运行日志 / 审计服务的守护进程。接着,你创建一个守护进程组并使用 `logger``mission_critical` 节点选择器。Kubernetes 会查找具有该标签的节点,确保守护进程的实例一直运行在这些节点中。因而,节点中运行的所有进程都可以在节点内访问对应的守护进程。
@ -253,7 +243,7 @@ spec: #(4)
### Kubernetes 部分小结
Kubernetes 是容器编排的便捷工具,工作单元为 Pods具有分层架构。最顶层是部署用于操作其它资源具有高度可配置性。对于你的每个命令调用Kubernetes 提供了对应的 API故理论上你可以编写自己的代码向 Kubernetes API 发送数据,得到与 `kubectl` 命令同样的效果。
Kubernetes 是容器编排的便捷工具,工作单元为 Pod具有分层架构。最顶层是部署用于操作其它资源具有高度可配置性。对于你的每个命令调用Kubernetes 提供了对应的 API故理论上你可以编写自己的代码向 Kubernetes API 发送数据,得到与 `kubectl` 命令同样的效果。
截至目前Kubernetes 原生支持所有主流云服务供应商,而且完全开源。如果你愿意,可以贡献代码;如果你希望对工作原理有深入了解,可以查阅代码:[GitHub 上的 Kubernetes 项目][22]。
@ -272,7 +262,7 @@ kubectl get nodes -o yaml
### 构建容器
Kubernetes 支持大多数现有的容器技术。我这里使用 Docker。每一个构建的服务容器对应代码库中的一个 Dockerfile 文件。我推荐你仔细阅读它们,其中大多数都比较简单。对于 Go 服务我采用了最近引入的多步构建的方式。Go 服务基于 Alpine Linux 镜像创建。人脸识别程序使用 PythonNSQ 和 MySQL 使用对应的容器。
Kubernetes 支持大多数现有的容器技术。我这里使用 Docker。每一个构建的服务容器对应代码库中的一个 Dockerfile 文件。我推荐你仔细阅读它们,其中大多数都比较简单。对于 Go 服务我采用了最近引入的多步构建的方式。Go 服务基于 Alpine Linux 镜像创建。人脸识别程序使用 PythonNSQ 和 MySQL 使用对应的容器。
### 上下文
@ -293,9 +283,9 @@ Switched to context "kube-face-cluster".
```
此后,所有 `kubectl` 命令都会使用 `face` 命名空间。
(译注:作者后续并没有使用 face 命名空间,模板文件中的命名空间仍为 default可能 face 命名空间用于开发环境。如果希望使用 face 命令空间,需要将内部 DNS 地址中的 default 改成 face如果只是测试可以不执行这两条命令。
LCTT 译注:作者后续并没有使用 face 命名空间,模板文件中的命名空间仍为 default可能 face 命名空间用于开发环境。如果希望使用 face 命令空间,需要将内部 DNS 地址中的 default 改成 face如果只是测试可以不执行这两条命令。
### 应用部署
## 应用部署
Pods 和 服务概览:
@ -318,7 +308,6 @@ type: Opaque
data:
mysql_password: base64codehere
mysql_userpassword: base64codehere
```
其中 base64 编码通过如下命令生成:
@ -326,10 +315,9 @@ data:
```
echo -n "ubersecurepassword" | base64
echo -n "root:ubersecurepassword" | base64
```
LCTT 译注secret yaml 文件中的 data 应该有两条,一条对应 mysql_password, 仅包含密码;另一条对应 mysql_userpassword包含用户和密码。后文会用到 mysql_userpassword,但没有提及相应的生成)
LCTT 译注secret yaml 文件中的 data 应该有两条,一条对应 `mysql_password`,仅包含密码;另一条对应 `mysql_userpassword`,包含用户和密码。后文会用到 `mysql_userpassword`,但没有提及相应的生成)
我的部署 yaml 对应部分如下:
@ -362,13 +350,12 @@ echo -n "root:ubersecurepassword" | base64
其中 `presistentVolumeClain` 是关键,告知 Kubernetes 当前资源需要持久化存储。持久化存储的提供方式对用户透明。类似 Pods如果想了解更多细节参考文档[Kubernetes 持久化存储][27]。
LCTT 译注:使用 presistentVolumeClain 之前需要创建 presistentVolume对于单节点可以使用本地存储对于多节点需要使用共享存储因为 Pod 可以能调度到任何一个节点)
LCTT 译注:使用 `presistentVolumeClain` 之前需要创建 `presistentVolume`,对于单节点可以使用本地存储,对于多节点需要使用共享存储,因为 Pod 可以能调度到任何一个节点)
使用如下命令部署 MySQL 服务:
```
kubectl apply -f mysql.yaml
```
这里比较一下 `create``apply`。`apply` 是一种<ruby>宣告式<rt>declarative</rt></ruby>的对象配置命令,而 `create`<ruby>命令式<rt>imperative</rt>的命令。当下我们需要知道的是,`create` 通常对应一项任务,例如运行某个组件或创建一个部署;相比而言,当我们使用 `apply` 的时候用户并没有指定具体操作Kubernetes 会根据集群目前的状态定义需要执行的操作。故如果不存在名为 `mysql` 的服务,当我执行 `apply -f mysql.yaml`Kubernetes 会创建该服务。如果再次执行这个命令Kubernetes 会忽略该命令。但如果我再次运行 `create`Kubernetes 会报错,告知服务已经创建。
@ -460,7 +447,7 @@ volumes:
```
LCTT 译注:数据库初始化脚本需要改成对应的路径,如果是多节点,需要是共享存储中的路径。另外,作者给的 sql 文件似乎有误person_images 表中的 person_id 列数字都小 1作者默认 id 从 0 开始,但应该是从 1 开始)
LCTT 译注:数据库初始化脚本需要改成对应的路径,如果是多节点,需要是共享存储中的路径。另外,作者给的 sql 文件似乎有误,`person_images` 表中的 `person_id` 列数字都小 1作者默认 `id` 从 0 开始,但应该是从 1 开始)
运行如下命令查看引导脚本是否正确执行:
@ -489,7 +476,6 @@ mysql>
```
kubectl logs deployment/mysql -f
```
### NSQ 查询
@ -505,7 +491,7 @@ NSQ 查询将以内部服务的形式运行。由于不需要外部访问,这
```
那么,内部 DNS 对应的条目类似于:`nsqlookup.default.svc.cluster.local`。
那么,内部 DNS 对应的实体类似于:`nsqlookup.default.svc.cluster.local`。
无头服务的更多细节,可以参考:[无头服务][32]。
@ -517,7 +503,7 @@ args: ["--broadcast-address=nsqlookup.default.svc.cluster.local"]
```
你可能会疑惑,`--broadcast-address` 参数是做什么用的默认情况下nsqlookup 使用 `hostname` LCTT 译注:这里是指容器的主机名,而不是 hostname 字符串本身)作为广播地址;这意味着,当用户运行回调时,回调试图访问的地址类似于 `http://nsqlookup-234kf-asdf:4161/lookup?topics=image`,但这显然不是我们期望的。将广播地址设置为内部 DNS 后,回调地址将是 `http://nsqlookup.default.svc.cluster.local:4161/lookup?topic=images`,这正是我们期望的。
你可能会疑惑,`--broadcast-address` 参数是做什么用的?默认情况下,`nsqlookup` 使用容器的主机名作为广播地址;这意味着,当用户运行回调时,回调试图访问的地址类似于 `http://nsqlookup-234kf-asdf:4161/lookup?topics=image`,但这显然不是我们期望的。将广播地址设置为内部 DNS 后,回调地址将是 `http://nsqlookup.default.svc.cluster.local:4161/lookup?topic=images`,这正是我们期望的。
NSQ 查询还需要转发两个端口,一个用于广播,另一个用于 nsqd 守护进程的回调。在 Dockerfile 中暴露相应端口,在 Kubernetes 模板中使用它们,类似如下:
@ -533,6 +519,7 @@ NSQ 查询还需要转发两个端口,一个用于广播,另一个用于 nsq
```
服务模板:
```
spec:
ports:
@ -592,13 +579,13 @@ NSQ 守护进程也需要一些调整的参数配置:
```
其中我们配置了 lookup-tcp-address 和 broadcast-address 参数。前者是 nslookup 服务的 DNS 地址,后者用于回调,就像 nsqlookupd 配置中那样。
其中我们配置了 `lookup-tcp-address``broadcast-address` 参数。前者是 nslookup 服务的 DNS 地址,后者用于回调,就像 nsqlookupd 配置中那样。
#### 对外公开
下面即将创建第一个对外公开的服务。有两种方式可供选择。考虑到该 API 负载较高,可以使用负载均衡的方式。另外,如果希望将其部署到生产环境中的任选节点,也应该使用负载均衡方式。
但由于我使用的本地集群只有一个节点,那么使用 `节点端口` 的方式就足够了。`节点端口` 方式将服务暴露在对应节点的固定端口上。如果未指定端口,将从 30000-32767 数字范围内随机选其一个。也可以指定端口,可以在模板文件中使用 `nodePort` 设置即可。可以通过 `<NodeIP>:<NodePort>` 访问该服务。如果使用多个节点,负载均衡可以将多个 IP 合并为一个 IP。
但由于我使用的本地集群只有一个节点,那么使用 `NodePort` 的方式就足够了。`NodePort` 方式将服务暴露在对应节点的固定端口上。如果未指定端口,将从 30000-32767 数字范围内随机选其一个。也可以指定端口,可以在模板文件中使用 `nodePort` 设置即可。可以通过 `<NodeIP>:<NodePort>` 访问该服务。如果使用多个节点,负载均衡可以将多个 IP 合并为一个 IP。
更多信息,请参考文档:[服务发布][33]。
@ -643,7 +630,7 @@ spec:
### 图片处理器
图片处理器用于将图片传送至识别组件。它需要访问 nslookupd, mysql 以及后续部署的人脸识别服务的 gRPC 接口。事实上这是一个无聊的服务甚至其实并不是服务LCTT 译注:第一个服务是指在整个架构中,图片处理器作为一个服务;第二个服务是指 Kubernetes 服务)。它并需要对外暴露端口,这是第一个只包含部署的组件。长话短说,下面是完整的模板:
图片处理器用于将图片传送至识别组件。它需要访问 nslookupd mysql 以及后续部署的人脸识别服务的 gRPC 接口。事实上这是一个无聊的服务甚至其实并不是服务LCTT 译注:第一个服务是指在整个架构中,图片处理器作为一个服务;第二个服务是指 Kubernetes 服务)。它并需要对外暴露端口,这是第一个只包含部署的组件。长话短说,下面是完整的模板:
```
---
@ -781,7 +768,7 @@ curl -d '{"path":"/unknown_people/unknown220.jpg"}' http://192.168.99.100:30251/
```
图像处理器会在 `/unknown_people` 目录搜索名为 unknown220.jpg 的图片,接着在 known_foler 文件中找到 unknown220.jpg 对应个人的图片,最后返回匹配图片的名称。
图像处理器会在 `/unknown_people` 目录搜索名为 unknown220.jpg 的图片,接着在 `known_folder` 文件中找到 `unknown220.jpg` 对应个人的图片,最后返回匹配图片的名称。
查看日志,大致信息如下:
@ -861,9 +848,9 @@ receiver-deployment-5cb4797598-sf5ds 1/1 Running 0 26s
```
### 滚动更新 (Rolling Update)
## 滚动更新
滚动更新过程中会发生什么呢?
<ruby>滚动更新<rt>Rolling Update</rt></ruby>过程中会发生什么呢?
![kube rotate](https://skarlso.github.io/img/kube_rotate.png)
@ -871,7 +858,7 @@ receiver-deployment-5cb4797598-sf5ds 1/1 Running 0 26s
目前的 API 一次只能处理一个图片,不能批量处理,对此我并不满意。
#### 代码
### 代码
目前,我们使用下面的代码段处理单个图片的情形:
@ -900,7 +887,7 @@ func main() {
这里,你可能会说你并不需要保留旧代码;某些情况下,确实如此。因此,我们打算直接修改旧代码,让其通过少量参数调用新代码。这样操作操作相当于移除了旧代码。当所有客户端迁移完毕后,这部分代码也可以安全地删除。
#### 新的 Endpoint
### 新的接口
让我们添加新的路由方法:
@ -941,7 +928,7 @@ func PostImage(w http.ResponseWriter, r *http.Request) {
```
当然,方法名可能容易混淆,但你应该能够理解我想表达的意思。我将请求中的单个路径封装成新方法所需格式,然后将其作为请求发送给新接口处理。仅此而已。在 [滚动更新批量图片 PR][34] 中可以找到更多的修改方式。
当然,方法名可能容易混淆,但你应该能够理解我想表达的意思。我将请求中的单个路径封装成新方法所需格式,然后将其作为请求发送给新接口处理。仅此而已。在 [滚动更新批量图片 PR][34] 中可以找到更多的修改方式。
至此,我们使用两种方法调用接收器:
@ -958,7 +945,7 @@ curl -d '{"paths":[{"path":"unknown4456.jpg"}]}' http://127.0.0.1:8000/images/po
为了简洁,我不打算为 NSQ 和其它组件增加批量图片处理的能力。这些组件仍然是一次处理一个图片。这部分修改将留给你作为扩展内容。 :)
#### 新镜像
### 新镜像
为实现滚动更新,我首先需要为接收器服务创建一个新的镜像。新镜像使用新标签,告诉大家版本号为 v1.1。
@ -969,11 +956,11 @@ docker build -t skarlso/kube-receiver-alpine:v1.1 .
新镜像创建后,我们可以开始滚动更新了。
#### 滚动更新
### 滚动更新
在 Kubernetes 中,可以使用多种方式完成滚动更新。
##### 手动更新
#### 手动更新
不妨假设在我配置文件中使用的容器版本为 `v1.0`,那么实现滚动更新只需运行如下命令:
@ -991,7 +978,7 @@ kubectl rolling-update receiver --rollback
容器将回滚到使用上一个版本镜像,操作简捷无烦恼。
##### 应用新的配置文件
#### 应用新的配置文件
手动更新的不足在于无法版本管理。
@ -1051,7 +1038,7 @@ kubectl delete services -all
```
# 写在最后的话
## 写在最后的话
各位看官,本文就写到这里了。我们在 Kubernetes 上编写、部署、更新和扩展(老实说,并没有实现)了一个分布式应用。
@ -1065,9 +1052,9 @@ Gergely 感谢你阅读本文。
via: https://skarlso.github.io/2018/03/15/kubernetes-distributed-application/
作者:[hannibal ][a]
作者:[hannibal][a]
译者:[pinewall](https://github.com/pinewall)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,13 +1,15 @@
我们能否建立一个服务于用户而非广告商的社交网络?
=====
> 找出 Human Connection 是如何将透明度和社区放在首位的。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/people_team_community_group.png?itok=Nc_lTsUK)
如今,开源软件具有深远的意义,在推动数字经济创新方面发挥着关键作用。世界正在快速彻底地改变。世界各地的人们需要一个专门的,中立的,透明的在线平台来迎接我们这个时代的挑战。
如今,开源软件具有深远的意义,在推动数字经济创新方面发挥着关键作用。世界正在快速彻底地改变。世界各地的人们需要一个专门的、中立的、透明的在线平台来迎接我们这个时代的挑战。
开放的原则可能会成为让我们到达那里的方法to 校正者:这句上下文没有理解)。如果我们用开放的思维方式将数字创新与社会创新结合在一起,会发生什么?
开放的原则也许是让我们达成这一目标的方法。如果我们用开放的思维方式将数字创新与社会创新结合在一起,会发生什么?
这个问题是我们在 [Human Connection][1] 工作的核心,这是一个具有前瞻性的,以德国为基础的知识和行动网络,其使命是创建一个服务于全球的真正的社交网络。我们受到这样一种观念为指引,即人类天生慷慨而富有同情心,并且他们在慈善行为上茁壮成长。但我们还没有看到一个完全支持我们自然倾向,于乐于助人和合作以促进共同利益的社交网络。Human Connection 渴望成为让每个人都成为积极变革者的平台。
这个问题是我们在 [Human Connection][1] 工作的核心,这是一个具有前瞻性的,以德国为基础的知识和行动网络,其使命是创建一个服务于全球的真正的社交网络。我们受到这样一种观念为指引,即人类天生慷慨而富有同情心,并且他们在慈善行为上茁壮成长。但我们还没有看到一个完全支持我们的自然趋势,与乐于助人和合作以促进共同利益的社交网络。Human Connection 渴望成为让每个人都成为积极变革者的平台。
为了实现一个以解决方案为导向的平台的梦想让人们通过与慈善机构、社区团体和社会变革活动人士的接触围绕社会公益事业采取行动Human Connection 将开放的价值观作为社会创新的载体。
@ -15,31 +17,28 @@
### 首先是透明
透明是 Human Connection 的指导原则之一。Human Connection 邀请世界各地的程序员通过[在 Github 上提交他们的源代码][2]共同开发平台的源代码JavaScript, Vue, nuxt并通过贡献代码或编程附加功能来支持真正的社交网络。
透明是 Human Connection 的指导原则之一。Human Connection 邀请世界各地的程序员通过[在 Github 上提交他们的源代码][2]共同开发平台的源代码JavaScript、Vue、nuxt并通过贡献代码或编程附加功能来支持真正的社交网络。
但我们对透明的承诺超出了我们的发展实践。事实上,当涉及到建立一种新的社交网络,促进那些让世界变得更好的人之间的真正联系和互动,分享源代码只是迈向透明的一步。
但我们对透明的承诺超出了我们的发展实践。事实上,当涉及到建立一种新的社交网络,促进那些让世界变得更好的人之间的真正联系和互动,分享源代码只是迈向透明的一步。
为促进公开对话Human Connection 团队举行[定期在线公开会议][3]。我们在这里回答问题,鼓励建议并对潜在的问题作出回应。我们的 Meet The Team to 校正者:这里如果可以,请翻译得稍微优雅,我想不出来一个词)活动也会记录下来,并在事后向公众开放。通过对我们的流程,源代码和财务状况完全透明,我们可以保护自己免受批评或其他潜在的不利影响。
为促进公开对话Human Connection 团队举行[定期在线公开会议][3]。我们在这里回答问题,鼓励建议并对潜在的问题作出回应。我们的 Meet The Team 活动也会记录下来,并在事后向公众开放。通过对我们的流程,源代码和财务状况完全透明,我们可以保护自己免受批评或其他潜在的不利影响。
对透明的承诺意味着,所有在 Human Connection 上公开分享的用户贡献者将在 Creative Commons 许可下发布,最终作为数据包下载。通过让大众知识变得可用,特别是以一种分散的方式,我们创造了一个多元化社会的机会。
一个问题指导我们所有的组织决策:“它是否服务于人民和更大的利益?”我们用[联合国宪章(UN Charter)][4]和“世界人权宣言(Universal Declaration of Human Rights)”作为我们价值体系的基础。随着我们的规模越来越大,尤其是即将推出的公测版,我们必须对此任务负责。我甚至愿意邀请 Chaos Computer Club (译注:这是欧洲最大的黑客联盟)或其他黑客俱乐部通过随机检查我们的平台来验证我们的代码和行为的完整性。
一个问题指导我们所有的组织决策:“它是否服务于人民和更大的利益?”我们用<ruby>[联合国宪章][4]<rt>UN Charter</rt></ruby>和“<ruby>世界人权宣言<rt>Universal Declaration of Human Rights</rt></ruby>”作为我们价值体系的基础。随着我们的规模越来越大,尤其是即将推出的公测版,我们必须对此任务负责。我甚至愿意邀请 Chaos Computer Club LCTT 译注:这是欧洲最大的黑客联盟)或其他黑客俱乐部通过随机检查我们的平台来验证我们的代码和行为的完整性。
### 一个合作的社会
以一种[以社区为中心的协作方法][5]来编写 Human Connection 平台是超越社交网络实际应用理念的基础。我们的团队是通过找到问题的答案来驱动:“是什么让一个社交网络真正地社会化?”
一个抛弃了以利润为导向的算法,为广告商而不是最终用户服务的网络,只能通过转向对等生产和协作的过程而繁荣起来。例如,像 [Code Alliance][6] 和 [Code for America][7] 这样的组织已经证明了如何在一个开源环境中创造技术,造福人类并破坏to 校正:这里译为改变较好)现状。社区驱动的项目,如基于地图的报告平台 [FixMyStreet][8],或者为 Humanitarian OpenStreetMap 而建立的 [Tasking Manager][9],已经将众包作为推动其使用的一种方式。
一个抛弃了以利润为导向的算法、为最终用户而不是广告商服务的网络,只能通过转向对等生产和协作的过程而繁荣起来。例如,像 [Code Alliance][6] 和 [Code for America][7] 这样的组织已经证明了如何在一个开源环境中创造技术,造福人类并变革现状。社区驱动的项目,如基于地图的报告平台 [FixMyStreet][8],或者为 Humanitarian OpenStreetMap 而建立的 [Tasking Manager][9],已经将众包作为推动其使用的一种方式。
我们建立 Human Connection 的方法从一开始就是合作。为了收集关于必要功能和真正社交网络的目的的初步数据我们与巴黎索邦大学University Sorbonne的国家东方语言与文明研究所National Institute for Oriental Languages and Civilizations (INALCO) 和德国斯图加特媒体大学Stuttgart Media University )合作。这两个项目的研究结果都被纳入了 Human Connection 的早期开发。多亏了这项研究,[用户将拥有一套全新的功能][10],让他们可以控制自己看到的内容以及他们如何与他人的互动。由于早期的支持者[被邀请到网络的 alpha 版本][10],他们可以体验到第一个可用的值得注意的功能。这里有一些:
* 将信息与行动联系起来是我们研究会议的一个重要主题。当前的社交网络让用户处于信息阶段。这两所大学的学生团体都认为,需要一个以行动为导向的组件,以满足人类共同解决问题的本能。所以我们在平台上构建了一个[“Can Do”功能][11]。这是一个人在阅读了某个话题后可以采取行动的一种方式。“Can Do” 是用户建议的活动在“采取行动Take Action”领域每个人都可以实现。
* “Versus” 功能是另一个定义结果的方式to 校正者这句话稍微注意一下。在传统社交网络仅限于评论功能的地方我们的学生团体认为需要采用更加结构化且有用的方式进行讨论和争论。“Versus” 是对公共帖子的反驳,它是单独显示的,并提供了一个机会来突出围绕某个问题的不同意见。
我们建立 Human Connection 的方法从一开始就是合作。为了收集关于必要功能和真正社交网络的目的的初步数据,我们与巴黎<ruby>索邦大学<rt>University Sorbonne</rt></ruby><ruby>国家东方语言与文明研究所<rt>National Institute for Oriental Languages and Civilizations</rt></ruby>INALCO和德国<ruby>斯图加特媒体大学<rt>Stuttgart Media University</rt></ruby>合作。这两个项目的研究结果都被纳入了 Human Connection 的早期开发。多亏了这项研究,[用户将拥有一套全新的功能][10],让他们可以控制自己看到的内容以及他们如何与他人的互动。由于早期的支持者[被邀请到网络的 alpha 版本][10],他们可以体验到第一个可用的值得注意的功能。这里有一些:
* 将信息与行动联系起来是我们研究会议的一个重要主题。当前的社交网络让用户处于信息阶段。这两所大学的学生团体都认为,需要一个以行动为导向的组件,以满足人类共同解决问题的本能。所以我们在平台上构建了一个[“Can Do”功能][11]。这是一个人在阅读了某个话题后可以采取行动的一种方式。“Can Do” 是用户建议的活动,在“<ruby>采取行动<rt>Take Action</rt></ruby>”领域,每个人都可以实现。
* “Versus” 功能是另一个成果。在传统社交网络仅限于评论功能的地方我们的学生团体认为需要采用更加结构化且有用的方式进行讨论和争论。“Versus” 是对公共帖子的反驳,它是单独显示的,并提供了一个机会来突出围绕某个问题的不同意见。
* 今天的社交网络并没有提供很多过滤内容的选项。研究表明,情绪过滤选项可以帮助我们根据日常情绪驾驭社交空间,并可能通过在我们希望仅看到令人振奋的内容的那一天时,不显示悲伤或难过的帖子来潜在地保护我们的情绪健康。
Human Connection 邀请改革者合作开发一个网络,有可能动员世界各地的个人和团体将负面新闻变成 “Can Do”并与慈善机构和非营利组织一起参与社会创新项目。
[订阅我们的每周时事通讯][12]以了解有关开放组织的更多信息。
@ -51,7 +50,7 @@ via: https://opensource.com/open-organization/18/3/open-social-human-connection
作者:[Dennis Hack][a]
译者:[MjSeven](https://github.com/MjSeven)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,88 @@
迁移到 Linux安装软件
======
> 所有的 Linux 打包系统和工具都会让人迷惑,但是这篇面向初学者的教程可以帮助你搞明白。
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/birds-1835510_1920.jpg?itok=8i6mBStG)
如你所见,众所瞩目的 Linux 已经用在互联网,以及 Arduino、Beagle 和树莓派主板等设备上,或许你正在考虑是时候尝试一下 Linux 了。本系列将帮助你成功过渡到 Linux。如果你错过了本系列的早期文章可以在这里找到它们
- [第1部分 - 入门介绍][1]
- [第2部分 - 磁盘、文件和文件系统][2]
- [第3部分 - 图形操作环境][3]
- [第4部分 - 命令行][4]
- [第5部分 - 使用 sudo][5]
### 安装软件
要在你的计算机上获得新软件,通常的方法是从供应商处获得软件产品,然后运行一个安装程序。过去,软件产品会出现在像 CD-ROM 或 DVD 一样的物理媒介上,而现在我们经常从互联网上下载软件产品。
使用 Linux安装软件就像在你的智能手机上安装一样。如同你的手机应用商店一样在 Linux 上有个提供开源软件工具和程序的<ruby>中央仓库<rt>central repository</rt></ruby>,几乎任何你想要的程序都会出现在可用软件包列表中以供你安装。
每个程序并不需要运行单独的安装程序,而是你可以使用 Linux 发行版附带的软件包管理工具。(这里说的 Linux 发行版就是你安装的 Linux例如 Ubuntu、Fedora、Debian 等)每个发行版在互联网上都有它自己的集中存储库(称为仓库),它们存储了数千个预先构建好的应用程序。
你可能会注意到,在 Linux 上安装软件有几种例外情况。有时候,你仍然需要去供应商那里获取他们的软件,因为该程序不存在于你的发行版的中央仓库中。当软件不是开源和/或自由软件的时候,通常就是这种情况。
另外请记住,如果你想要安装一个不在发行版仓库中的程序时,事情就不是那么简单了,即使你正在安装自由及开源程序。这篇文章没有涉及到这些更复杂的情况,请遵循在线的指引。
有了所有的 Linux 包管理系统和工具,接下来干什么可能仍然令人困惑。本文应该有助于澄清一些事情。
### 包管理
目前在 Linux 发行版中有几个相互竞争的用于管理、安装和删除软件的包管理系统。每个发行版都选择使用了一个<ruby>包管理工具<rt>package management tools<rt></ruby>。Red Hat、Fedora、CentOS、Scientific Linux、SUSE 等使用 Red Hat 包管理RPM。Debian、Ubuntu、Linux Mint 等等都使用 Debian 包管理系统,简称 DPKG。还有一些其它包管理系统但 RPM 和 DPKG 是最常见的。
![](https://www.linux.com/sites/lcom/files/styles/floated_images/public/package-installer.png?itok=V9OU1Q0u)
*图 1: Package installers*
无论你使用的软件包管理是什么,它们通常都是一组构建于另外一种工具之上的工具(图 1。最底层是一个命令行工具它可以让你做任何与安装软件相关的一切工作。你可以列出已安装的程序、删除程序、安装软件包文件等等。
这个底层工具并不总是最方便使用的,所以通常会有一个命令行工具,它可以使用单个命令在发行版的中央仓库中找到软件包,并下载和安装它以及任何依赖项。最后,通常会有一个<ruby>图形应用程序<rt>graphical application<rt></ruby>,可以让你使用鼠标选择任何想要的内容,然后单击 “install” 按钮即可。
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/package-kit.png?itok=YimOq2Je)
*图 2: PackageKit*
对于基于 Red Hat 的发行版,包括 Fedora、CentOS、Scientific Linux 等,它们的底层工具是 rpm高级工具叫做 dnf在旧系统上是 yum。图形安装程序称为 PackageKit图 2它可能在系统管理菜单下显示名字为 “Add/Remove Software添加/删除软件)”。
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/ubuntu-software.png?itok=5QSctLEW)
*图 3: Ubuntu Software*
对于基于 Debian 的发行版,包括 Debian、Ubuntu、Linux Mint、Elementary OS 等,它们的底层命令行工具是 dpkg高级工具称为 apt。在 Ubuntu 上管理已安装软件的图形工具是 Ubuntu Software图 3。对于 Debian 和 Linux Mint图形工具称为<ruby>新立得<rt>Synaptic</rt></ruby>,它也可以安装在 Ubuntu 上。
你也可以在 Debian 相关发行版上安装一个基于文本的图形化工具 aptitude。它比新立得更强大并且即使你只能访问命令行也能工作。如果你想通过各种选项进行各种操作你可以试试这个但它使用起来比新立得更复杂。其它发行版也可能有自己独特的工具。
### 命令行工具
在 Linux 上安装软件的在线说明通常描述了在命令行中键入的命令。这些说明通常更容易理解,并且将命令复制粘贴到命令行窗口中,可以在不出错的情况下一步步进行。这与下面的说明相反:“打开这个菜单,选择这个程序,输入这个搜索模式,点击这个标签,选择这个程序,然后点击这个按钮”,这经常让你在各种操作中迷失。
有时你正在使用的 Linux 没有图形环境,因此熟悉从命令行安装软件包是件好事。表 1 和表 2 列出了基于 RPM 和 DPKG 系统的一下常见操作及其相关命令。
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/table_1_0.png?itok=hQ_o5Oh2)
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/table_2.png?itok=yl3UPQDw)
请注意 SUSE它像 RedHat 和 Fedora 一样使用 RPM却没有 dnf 或 yum。相反它使用一个名为 zypper 的程序作为高级命令行工具。其他发行版也可能有不同的工具,例如 Arch Linux 上的 pacman 或 Gentoo 上的 emerge。有很多包管理工具所以你可能需要查找哪个适用于你的发行版。
这些技巧应该能让你更好地了解如何在新的 Linux 中安装程序,以及更好地了解 Linux 中各种软件包管理方式如何相互关联。
通过 Linux 基金会和 edX 的免费 [“Linux 入门”][6]课程了解有关 Linux 的更多信息。
---
via: https://www.linux.com/blog/learn/2018/3/migrating-linux-installing-software
作者:[JOHN BONESIO][a]
译者:[MjSeven](https://github.com/MjSeven)
校对:[pityonline](https://github.com/pityonline), [wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linux.com/users/johnbonesio
[1]:https://linux.cn/article-9212-1.html
[2]:https://linux.cn/article-9213-1.html
[3]:https://linux.cn/article-9293-1.html
[4]:https://linux.cn/article-9565-1.html
[5]:https://linux.cn/article-9819-1.html
[6]:https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux

View File

@ -1,7 +1,11 @@
Python 字节码介绍
======
> 了解 Python 字节码是什么Python 如何使用它来执行你的代码,以及知道它是如何帮到你的。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_computer_development_programming.png?itok=4OM29-82)
如果你从没有写过 Python或者甚至只是使用过 Python你或许已经习惯于看 Python 源代码文件;它们的名字以 `.py` 结尾。你可能还看到过其它类型的文件,比如使用 `.pyc` 结尾的文件,或许你可能听说过,它们就是 Python 的 "字节码" 文件。(在 Python 3 上这些可能不容易看到 — 因为它们与你的 `.py` 文件不在同一个目录下,它们在一个叫 `__pycache__` 的子目录中)或者你也听说过,这是节省时间的一种方法,它可以避免每次运行 Python 时去重新解析源代码。
如果你曾经编写过 Python或者只是使用过 Python你或许经常会看到 Python 源代码文件——它们的名字以 `.py` 结尾。你可能还看到过其它类型的文件,比如以 `.pyc` 结尾的文件,或许你可能听说过它们就是 Python 的 “<ruby>字节码<rt>bytecode</rt></ruby>” 文件。(在 Python 3 上这些可能不容易看到 —— 因为它们与你的 `.py` 文件不在同一个目录下,它们在一个叫 `__pycache__` 的子目录中)或者你也听说过,这是节省时间的一种方法,它可以避免每次运行 Python 时去重新解析源代码。
但是,除了 “噢,原来这就是 Python 字节码” 之外,你还知道这些文件能做什么吗?以及 Python 是如何使用它们的?
@ -9,29 +13,26 @@ Python 字节码介绍
### Python 如何工作
Python 经常被介绍为它是一个解释型语言 — 其中一个原因是程序运行时,你的源代码被转换成 CPU 的原生指令 — 但这样认为只是部分正确。Python 与大多数解释型语言一样,确实是将源代码编译为一组虚拟机指令,并且 Python 解释器是针对相应的虚拟机实现的。这种中间格式被称为 “字节码”。
Python 经常被介绍为它是一个解释型语言 — 其中一个原因是程序运行时,你的源代码被转换成 CPU 的原生指令 —— 但这样的看法只是部分正确。Python 与大多数解释型语言一样,确实是将源代码编译为一组虚拟机指令,并且 Python 解释器是针对相应的虚拟机实现的。这种中间格式被称为 “字节码”。
因此,这些 `.pyc` 文件是 Python 悄悄留下的,是为了让它们运行的 “更快”,或者是针对你的源代码的 “优化” 版本;它们是你的程序在 Python 虚拟机上运行的字节码指令。
我们来看一个示例。这里是用 Python 写的经典程序 "Hello, World!"
我们来看一个示例。这里是用 Python 写的经典程序 “Hello, World!”:
```
def hello()
    print("Hello, World!")
```
下面是转换后的字节码(转换为人类可读的格式):
```
2           0 LOAD_GLOBAL              0 (print)
            2 LOAD_CONST               1 ('Hello, World!')
            4 CALL_FUNCTION            1
```
2 0 LOAD_GLOBAL 0 (print)
2 LOAD_CONST 1 ('Hello, World!')
4 CALL_FUNCTION 1
```
如果你输入那个 `hello()` 函数,然后使用 [CPython][1] 解释器去运行它,上面的 Python 程序将会运行。它看起来可能有点奇怪,因此,我们来深入了解一下它都做了些什么。
如果你输入那个 `hello()` 函数,然后使用 [CPython][1] 解释器去运行它,那么上述列出的内容就是 Python 所运行的。它看起来可能有点奇怪,因此,我们来深入了解一下它都做了些什么。
### Python 虚拟机内幕
@ -39,84 +40,68 @@ CPython 使用一个基于栈的虚拟机。也就是说,它完全面向栈数
CPython 使用三种类型的栈:
1. **调用栈**。这是运行 Python 程序的主要结构。它为每个当前活动的函数调用使用了一个东西 — "帧“,栈底是程序的入口点。每个函数调用推送一个新帧到调用栈,每当函数调用返回后,这个帧被销毁。
2. 在每个帧中,有一个 **计算栈** (也称为 **数据栈**)。这个栈就是 Python 函数运行的地方,运行的 Python 代码大多数是由推入到这个栈中的东西组成的,操作它们,然后在返回后销毁它们。
3. 在每个帧中,还有一个 **块栈**。它被 Python 用于去跟踪某些类型的控制结构loops、`try`/`except` 块、以及 `with` 块,全部推入到块栈中,当你退出这些控制结构时,块栈被销毁。这将帮助 Python 了解任意给定时刻哪个块是活动的,比如,一个 `continue` 或者 `break` 语句可能影响正确的块。
1. <ruby>调用栈<rt>call stack</rt></ruby>。这是运行 Python 程序的主要结构。它为每个当前活动的函数调用使用了一个东西 —— “<ruby><rt>frame</rt></ruby>”,栈底是程序的入口点。每个函数调用推送一个新的帧到调用栈,每当函数调用返回后,这个帧被销毁。
2. 在每个帧中,有一个<ruby>计算栈<rt>evaluation stack</rt></ruby> (也称为<ruby>数据栈<rt>data stack</rt></ruby>)。这个栈就是 Python 函数运行的地方,运行的 Python 代码大多数是由推入到这个栈中的东西组成的,操作它们,然后在返回后销毁它们。
3. 在每个帧中,还有一个<ruby>块栈<rt>block stack</rt></ruby>。它被 Python 用于去跟踪某些类型的控制结构:循环、`try` / `except` 块、以及 `with` 块,全部推入到块栈中,当你退出这些控制结构时,块栈被销毁。这将帮助 Python 了解任意给定时刻哪个块是活动的,比如,一个 `continue` 或者 `break` 语句可能影响正确的块。
大多数 Python 字节码指令操作的是当前调用栈帧的计算栈,虽然,还有一些指令可以做其它的事情(比如跳转到指定指令,或者操作块栈)。
为了更好地理解,假设我们有一些调用函数的代码,比如这个:`my_function(my_variable, 2)`。Python 将转换为一系列字节码指令:
1. 一个 `LOAD_NAME` 指令去查找函数对象 `my_function`,然后将它推入到计算栈的顶部
2. 另一个 `LOAD_NAME` 指令去查找变量 `my_variable`,然后将它推入到计算栈的顶部
3. 一个 `LOAD_CONST` 指令去推入一个实整数值 `2` 到计算栈的顶部
4. 一个 `CALL_FUNCTION` 指令
1. 一个 `LOAD_NAME` 指令去查找函数对象 `my_function`,然后将它推入到计算栈的顶部
2. 另一个 `LOAD_NAME` 指令去查找变量 `my_variable`,然后将它推入到计算栈的顶部
3. 一个 `LOAD_CONST` 指令去推入一个实整数值 `2` 到计算栈的顶部
4. 一个 `CALL_FUNCTION` 指令
这个 `CALL_FUNCTION` 指令将有 2 个参数,它表示那个 Python 需要从栈顶弹出两个位置参数;然后函数将在它上面进行调用,并且它也同时被弹出(对于函数涉及的关键字参数,它使用另一个不同的指令 — `CALL_FUNCTION_KW`,但使用的操作原则类似,以及第三个指令 — `CALL_FUNCTION_EX`,它适用于函数调用涉及到使用 `*``**` 操作符的情况)。一旦 Python 拥有了这些之后,它将在调用栈上分配一个新帧,填充到函数调用的本地变量上,然后,运行那个帧内的 `my_function` 字节码。运行完成后,这个帧将被调用栈销毁,最初的帧内返回的 `my_function` 将被推入到计算栈的顶部。
这个 `CALL_FUNCTION` 指令将有 2 个参数,它表示那个 Python 需要从栈顶弹出两个位置参数;然后函数将在它上面进行调用,并且它也同时被弹出(对于函数涉及的关键字参数,它使用另一个不同的指令 —— `CALL_FUNCTION_KW`,但使用的操作原则类似,以及第三个指令 —— `CALL_FUNCTION_EX`,它适用于函数调用涉及到参数使用 `*``**` 操作符的情况)。一旦 Python 拥有了这些之后,它将在调用栈上分配一个新帧,填充到函数调用的本地变量上,然后,运行那个帧内的 `my_function` 字节码。运行完成后,这个帧将被调用栈销毁,而在最初的帧内,`my_function` 的返回值将被推入到计算栈的顶部。
### 访问和理解 Python 字节码
如果你想玩转字节码那么Python 标准库中的 `dis` 模块将对你有非常大的帮助;`dis` 模块为 Python 字节码提供了一个 "反汇编",它可以让你更容易地得到一个人类可读的版本,以及查找各种字节码指令。[`dis` 模块的文档][2] 可以让你遍历它的内容,并且提供一个字节码指令能够做什么和有什么样的参数的完整清单。
如果你想玩转字节码那么Python 标准库中的 `dis` 模块将对你有非常大的帮助;`dis` 模块为 Python 字节码提供了一个 “反汇编”,它可以让你更容易地得到一个人类可读的版本,以及查找各种字节码指令。[`dis` 模块的文档][2] 可以让你遍历它的内容,并且提供一个字节码指令能够做什么和有什么样的参数的完整清单。
例如,获取上面的 `hello()` 函数的列表,可以在一个 Python 解析器中输入如下内容,然后运行它:
```
import dis
dis.dis(hello)
```
函数 `dis.dis()` 将反汇编一个函数、方法、类、模块、编译过的 Python 代码对象、或者字符串包含的源代码,以及显示出一个人类可读的版本。`dis` 模块中另一个方便的功能是 `distb()`。你可以给它传递一个 Python 追溯对象,或者发生预期外情况时调用它,然后它将反汇编发生预期外情况时在调用栈上最顶端的函数,并显示它的字节码,以及插入一个指向到引发意外情况的指令的指针。
函数 `dis.dis()` 将反汇编一个函数、方法、类、模块、编译过的 Python 代码对象、或者字符串包含的源代码,以及显示出一个人类可读的版本。`dis` 模块中另一个方便的功能是 `distb()`。你可以给它传递一个 Python 追溯对象,或者在发生预期外情况时调用它,然后它将在发生预期外情况时反汇编调用栈上最顶端的函数,并显示它的字节码,以及插入一个指向到引发意外情况的指令的指针。
它也可以用于查看 Python 为每个函数构建的编译后的代码对象,因为运行一个函数将会用到这些代码对象的属性。这里有一个查看 `hello()` 函数的示例:
```
>>> hello.__code__
<code object hello at 0x104e46930, file "<stdin>", line 1>
>>> hello.__code__.co_consts
(None, 'Hello, World!')
>>> hello.__code__.co_varnames
()
>>> hello.__code__.co_names
('print',)
```
代码对象在函数中可以作为属性 `__code__` 来访问,并且携带了一些重要的属性:
代码对象在函数中可以属性 `__code__` 来访问,并且携带了一些重要的属性:
* `co_consts` 是存在于函数体内的任意实数的元组
* `co_varnames` 是函数体内使用的包含任意本地变量名字的元组
* `co_names` 是在函数体内引用的任意非本地名字的元组
许多字节码指令 — 尤其是那些推入到栈中的加载值,或者在变量和属性中的存储值 — 在这些用作它们参数的元组中使用索引。
许多字节码指令 —— 尤其是那些推入到栈中的加载值,或者在变量和属性中的存储值 —— 在这些元组中的索引作为它们参数。
因此,现在我们能够理解 `hello()` 函数中所列出的字节码:
1. `LOAD_GLOBAL 0`:告诉 Python 通过 `co_names` (它是 `print` 函数)的索引 0 上的名字去查找它指向的全局对象,然后将它推入到计算栈
2. `LOAD_CONST 1`:带入 `co_consts` 在索引 1 上的实数值,并将它推入(索引 0 上的实数值是 `None`,它表示在 `co_consts` 中,因为 Python 函数调用有一个隐式的返回值 `None`,如果没有显式的返回表达式,就返回这个隐式的值 )。
3. `CALL_FUNCTION 1`:告诉 Python 去调用一个函数;它需要从栈中弹出一个位置参数,然后,新的栈顶将被函数调用。
1. `LOAD_GLOBAL 0`:告诉 Python 通过 `co_names` (它是 `print` 函数)的索引 0 上的名字去查找它指向的全局对象,然后将它推入到计算栈
2. `LOAD_CONST 1`:带入 `co_consts` 在索引 1 上的字面值,并将它推入(索引 0 上的字面值是 `None`,它表示在 `co_consts` 中,因为 Python 函数调用有一个隐式的返回值 `None`,如果没有显式的返回表达式,就返回这个隐式的值 )。
3. `CALL_FUNCTION 1`:告诉 Python 去调用一个函数;它需要从栈中弹出一个位置参数,然后,新的栈顶将被函数调用。
"原始的" 字节码 — 是非人类可读格式的字节 — 也可以在代码对象上作为 `co_code` 属性可用。如果你有兴趣尝试手工反汇编一个函数时,你可以从它们的十进制字节值中,使用列出 `dis.opname` 的方式去查看字节码指令的名字。
“原始的” 字节码 —— 是非人类可读格式的字节 —— 也可以在代码对象上作为 `co_code` 属性可用。如果你有兴趣尝试手工反汇编一个函数时,你可以从它们的十进制字节值中,使用列出 `dis.opname` 的方式去查看字节码指令的名字。
### 字节码的用处
现在,你已经了解的足够多了,你可能会想 ” OK我认为它很酷但是知道这些有什么实际价值呢由于对它很好奇我们去了解它但是除了好奇之外Python 字节码在几个方面还是非常有用的。
现在,你已经了解的足够多了,你可能会想 “OK我认为它很酷但是知道这些有什么实际价值呢由于对它很好奇我们去了解它但是除了好奇之外Python 字节码在几个方面还是非常有用的。
首先,理解 Python 的运行模型可以帮你更好地理解你的代码。人们都开玩笑说C 将成为一个 ”便携式汇编器“,在那里你可以很好地猜测出一段 C 代码转换成什么样的机器指令。理解 Python 字节码之后,你在使用 Python 时也具备同样的能力 — 如果你能预料到你的 Python 源代码将被转换成什么样的字节码,那么你可以知道如何更好地写和优化 Python 源代码。
首先,理解 Python 的运行模型可以帮你更好地理解你的代码。人们都开玩笑说C 是一种 “可移植汇编器”,你可以很好地猜测出一段 C 代码转换成什么样的机器指令。理解 Python 字节码之后,你在使用 Python 时也具备同样的能力 — 如果你能预料到你的 Python 源代码将被转换成什么样的字节码,那么你可以知道如何更好地写和优化 Python 源代码。
第二,理解字节码可以帮你更好地回答有关 Python 的问题。比如,我经常看到一些 Python 新手困惑为什么某些结构比其它结构运行的更快(比如,为什么 `{}``dict()` 快)。知道如何去访问和阅读 Python 字节码将让你很容易回答这样的问题(尝试对比一下: `dis.dis("{}")``dis.dis("dict()")` 就会明白)。
@ -131,7 +116,6 @@ dis.dis(hello)
* 最后CPython 解析器是一个开源软件,你可以在 [GitHub][1] 上阅读它。它在文件 `Python/ceval.c` 中实现了字节码解析器。[这是 Python 3.6.4 发行版中那个文件的链接][5];字节码指令是由第 1266 行开始的 `switch` 语句来处理的。
学习更多内容,参与到 James Bennett 的演讲,[有关字节的知识:理解 Python 字节码][6],将在 [PyCon Cleveland 2018][7] 召开。
--------------------------------------------------------------------------------
@ -141,7 +125,7 @@ via: https://opensource.com/article/18/4/introduction-python-bytecode
作者:[James Bennett][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,215 @@
JavaScript 路由器
======
构建单页面应用SPA有许多的框架/库,但是我希望它们能少一些。我有一个解决方案,我想共享给大家。
```
class Router {
constructor() {
this.routes = []
}
handle(pattern, handler) {
this.routes.push({ pattern, handler })
}
exec(pathname) {
for (const route of this.routes) {
if (typeof route.pattern === 'string') {
if (route.pattern === pathname) {
return route.handler()
}
} else if (route.pattern instanceof RegExp) {
const result = pathname.match(route.pattern)
if (result !== null) {
const params = result.slice(1).map(decodeURIComponent)
return route.handler(...params)
}
}
}
}
}
const router = new Router()
router.handle('/', homePage)
router.handle(/^\/users\/([^\/]+)$/, userPage)
router.handle(/^\//, notFoundPage)
function homePage() {
return 'home page'
}
function userPage(username) {
return `${username}'s page`
}
function notFoundPage() {
return 'not found page'
}
console.log(router.exec('/')) // home page
console.log(router.exec('/users/john')) // john's page
console.log(router.exec('/foo')) // not found page
```
使用它你可以为一个 URL 模式添加处理程序。这个模式可能是一个简单的字符串或一个正则表达式。使用一个字符串将精确匹配它,但是如果使用一个正则表达式将允许你做一些更复杂的事情,比如,从用户页面上看到的 URL 中获取其中的一部分,或者匹配任何没有找到页面的 URL。
我将详细解释这个 `exec` 方法 … 正如我前面说的URL 模式既有可能是一个字符串,也有可能是一个正则表达式,因此,我首先来检查它是否是一个字符串。如果模式与给定的路径名相同,它返回运行处理程序。如果是一个正则表达式,我们与给定的路径名进行匹配。如果匹配成功,它将获取的参数传递给处理程序,并返回运行这个处理程序。
### 工作示例
那个例子正好记录到了控制台。我们尝试将它整合到一个页面,看看它是什么样的。
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Router Demo</title>
<link rel="shortcut icon" href="data:,">
<script src="/main.js" type="module"></script>
</head>
<body>
<header>
<a href="/">Home</a>
<a href="/users/john_doe">Profile</a>
</header>
<main></main>
</body>
</html>
```
这是 `index.html`。对于单页面应用程序来说,你必须在服务器侧做一个特别的工作,因为所有未知的路径都将返回这个 `index.html`。在开发时,我们使用了一个 npm 工具调用了 [serve][1]。这个工具去提供静态内容。使用标志 `-s`/`--single`,你可以提供单页面应用程序。
使用 [Node.js][2] 和安装的 npm它与 Node 一起安装),运行:
```
npm i -g serve
serve -s
```
那个 HTML 文件将脚本 `main.js` 加载为一个模块。在我们渲染的相关页面中,它有一个简单的 `<header>` 和一个 `<main>` 元素。
`main.js` 文件中:
```
const main = document.querySelector('main')
const result = router.exec(location.pathname)
main.innerHTML = result
```
我们调用传递了当前路径名为参数的 `router.exec()`,然后将 `result` 设置为 `main` 元素的 HTML。
如果你访问 `localhost` 并运行它,你将看到它能够正常工作,但不是预期中的来自一个单页面应用程序。当你点击链接时,单页面应用程序将不会被刷新。
我们将在每个点击的链接的锚点上附加事件监听器,防止出现缺省行为,并做出正确的渲染。因为一个单页面应用程序是一个动态的东西,你预期要创建的锚点链接是动态的,因此要添加事件监听器,我使用的是一个叫 [事件委托][3] 的方法。
我给整个文档附加一个点击事件监听器,然后去检查在锚点上(或内部)是否有点击事件。
`Router` 类中,我有一个注册回调的方法,在我们每次点击一个链接或者一个 `popstate` 事件发生时,这个方法将被运行。每次你使用浏览器的返回或者前进按钮时,`popstate` 事件将被发送。
为了方便其见,我们给回调传递与 `router.exec(location.pathname)` 相同的参数。
```
class Router {
// ...
install(callback) {
const execCallback = () => {
callback(this.exec(location.pathname))
}
document.addEventListener('click', ev => {
if (ev.defaultPrevented
|| ev.button !== 0
|| ev.ctrlKey
|| ev.shiftKey
|| ev.altKey
|| ev.metaKey) {
return
}
const a = ev.target.closest('a')
if (a === null
|| (a.target !== '' && a.target !== '_self')
|| a.hostname !== location.hostname) {
return
}
ev.preventDefault()
if (a.href !== location.href) {
history.pushState(history.state, document.title, a.href)
execCallback()
}
})
addEventListener('popstate', execCallback)
execCallback()
}
}
```
对于链接的点击事件,除调用了回调之外,我们还使用 `history.pushState()` 去更新 URL。
我们将前面的 `main` 元素中的渲染移动到 `install` 回调中。
```
router.install(result => {
main.innerHTML = result
})
```
#### DOM
你传递给路由器的这些处理程序并不需要返回一个字符串。如果你需要更多的东西,你可以返回实际的 DOM。如
```
const homeTmpl = document.createElement('template')
homeTmpl.innerHTML = `
<div class="container">
<h1>Home Page</h1>
</div>
`
function homePage() {
const page = homeTmpl.content.cloneNode(true)
// You can do `page.querySelector()` here...
return page
}
```
现在,在 `install` 回调中,你可以去检查 `result` 是一个 `string` 还是一个 `Node`
```
router.install(result => {
if (typeof result === 'string') {
main.innerHTML = result
} else if (result instanceof Node) {
main.innerHTML = ''
main.appendChild(result)
}
})
```
这些就是基本的功能。我希望将它共享出来,因为我将在下篇文章中使用到这个路由器。
我已经以一个 [npm 包][4] 的形式将它发布了。
--------------------------------------------------------------------------------
via: https://nicolasparada.netlify.com/posts/js-router/
作者:[Nicolás Parada][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[qhwdw](https://github.com/qhwdw)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://nicolasparada.netlify.com/
[1]:https://npm.im/serve
[2]:https://nodejs.org/
[3]:https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation
[4]:https://www.npmjs.com/package/@nicolasparada/router

View File

@ -0,0 +1,178 @@
在 Linux 上如何得到一个段错误的核心转储
============================================================
本周工作中,我花了整整一周的时间来尝试调试一个段错误。我以前从来没有这样做过,我花了很长时间才弄清楚其中涉及的一些基本事情(获得核心转储、找到导致段错误的行号)。于是便有了这篇博客来解释如何做那些事情!
在看完这篇博客后,你应该知道如何从“哦,我的程序出现段错误,但我不知道正在发生什么”到“我知道它出现段错误时的堆栈、行号了! “。
### 什么是段错误?
<ruby>段错误<rt>segmentation fault</rt></ruby>”是指你的程序尝试访问不允许访问的内存地址的情况。这可能是由于:
* 试图解引用空指针(你不被允许访问内存地址 `0`
* 试图解引用其他一些不在你内存LCTT 译注:指不在合法的内存地址区间内)中的指针;
* 一个已被破坏并且指向错误的地方的 <ruby>C++ 虚表指针<rt>C++ vtable pointer</rt></ruby>,这导致程序尝试执行没有执行权限的内存中的指令;
* 其他一些我不明白的事情比如我认为访问未对齐的内存地址也可能会导致段错误LCTT 译注:在要求自然边界对齐的体系结构,如 MIPS、ARM 中更容易因非对齐访问产生段错误)。
这个“C++ 虚表指针”是我的程序发生段错误的情况。我可能会在未来的博客中解释这个,因为我最初并不知道任何关于 C++ 的知识,并且这种虚表查找导致程序段错误的情况也是我所不了解的。
但是!这篇博客后不是关于 C++ 问题的。让我们谈论的基本的东西,比如,我们如何得到一个核心转储?
### 步骤1运行 valgrind
我发现找出为什么我的程序出现段错误的最简单的方式是使用 `valgrind`:我运行
```
valgrind -v your-program
```
这给了我一个故障时的堆栈调用序列。 简洁!
但我想也希望做一个更深入调查,并找出些 `valgrind` 没告诉我的信息! 所以我想获得一个核心转储并探索它。
### 如何获得一个核心转储
<ruby>核心转储<rt>core dump</rt></ruby>是您的程序内存的一个副本,并且当您试图调试您的有问题的程序哪里出错的时候它非常有用。
当您的程序出现段错误Linux 的内核有时会把一个核心转储写到磁盘。 当我最初试图获得一个核心转储时,我很长一段时间非常沮丧,因为 - Linux 没有生成核心转储!我的核心转储在哪里?
这就是我最终做的事情:
1. 在启动我的程序之前运行 `ulimit -c unlimited`
2. 运行 `sudo sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t`
### ulimit设置核心转储的最大尺寸
`ulimit -c` 设置核心转储的最大尺寸。 它往往设置为 0这意味着内核根本不会写核心转储。 它以千字节为单位。 `ulimit` 是按每个进程分别设置的 —— 你可以通过运行 `cat /proc/PID/limit` 看到一个进程的各种资源限制。
例如这些是我的系统上一个随便一个 Firefox 进程的资源限制:
```
$ cat /proc/6309/limits
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size 0 unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 30571 30571 processes
Max open files 1024 1048576 files
Max locked memory 65536 65536 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 30571 30571 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us
```
内核在决定写入多大的核心转储文件时使用<ruby>软限制<rt>soft limit</rt></ruby>(在这种情况下,`max core file size = 0`)。 您可以使用 shell 内置命令 `ulimit``ulimit -c unlimited` 将软限制增加到<ruby>硬限制<rt>hard limit</rt></ruby>
### kernel.core_pattern核心转储保存在哪里
`kernel.core_pattern` 是一个内核参数,或者叫 “sysctl 设置”,它控制 Linux 内核将核心转储文件写到磁盘的哪里。
内核参数是一种设定您的系统全局设置的方法。您可以通过运行 `sysctl -a` 得到一个包含每个内核参数的列表,或使用 `sysctl kernel.core_pattern` 来专门查看 `kernel.core_pattern` 设置。
所以 `sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t` 将核心转储保存到目录 `/tmp` 下,并以 `core` 加上一系列能够标识(出故障的)进程的参数构成的后缀为文件名。
如果你想知道这些形如 `%e`、`%p` 的参数都表示什么,请参考 [man core][1]。
有一点很重要,`kernel.core_pattern` 是一个全局设置 —— 修改它的时候最好小心一点,因为有可能其它系统功能依赖于把它被设置为一个特定的方式(才能正常工作)。
### kernel.core_pattern 和 Ubuntu
默认情况下在 ubuntu 系统中,`kernel.core_pattern` 被设置为下面的值:
```
$ sysctl kernel.core_pattern
kernel.core_pattern = |/usr/share/apport/apport %p %s %c %d %P
```
这引起了我的迷惑(这 apport 是干什么的,它对我的核心转储做了什么?)。以下关于这个我了解到的:
* Ubuntu 使用一种叫做 apport 的系统来报告 apt 包有关的崩溃信息。
* 设定 `kernel.core_pattern=|/usr/share/apport/apport %p %s %c %d %P` 意味着核心转储将被通过管道送给 `apport` 程序。
* apport 的日志保存在文件 `/var/log/apport.log` 中。
* apport 默认会忽略来自不属于 Ubuntu 软件包一部分的二进制文件的崩溃信息
我最终只是跳过了 apport并把 `kernel.core_pattern` 重新设置为 `sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t`,因为我在一台开发机上,我不在乎 apport 是否工作,我也不想尝试让 apport 把我的核心转储留在磁盘上。
### 现在你有了核心转储,接下来干什么?
好的,现在我们了解了 `ulimit``kernel.core_pattern` ,并且实际上在磁盘的 `/tmp` 目录中有了一个核心转储文件。太好了!接下来干什么?我们仍然不知道该程序为什么会出现段错误!
下一步将使用 `gdb` 打开核心转储文件并获取堆栈调用序列。
### 从 gdb 中得到堆栈调用序列
你可以像这样用 `gdb` 打开一个核心转储文件:
```
$ gdb -c my_core_file
```
接下来,我们想知道程序崩溃时的堆栈是什么样的。在 `gdb` 提示符下运行 `bt` 会给你一个<ruby>调用序列<rt>backtrace</rt></ruby>。在我的例子里,`gdb` 没有为二进制文件加载符号信息,所以这些函数名就像 “??????”。幸运的是,(我们通过)加载符号修复了它。
下面是如何加载调试符号。
```
symbol-file /path/to/my/binary
sharedlibrary
```
这从二进制文件及其引用的任何共享库中加载符号。一旦我这样做了,当我执行 `bt`gdb 给了我一个带有行号的漂亮的堆栈跟踪!
如果你想它能工作,二进制文件应该以带有调试符号信息的方式被编译。在试图找出程序崩溃的原因时,堆栈跟踪中的行号非常有帮助。:)
### 查看每个线程的堆栈
通过以下方式在 `gdb` 中获取每个线程的调用栈!
```
thread apply all bt full
```
### gdb + 核心转储 = 惊喜
如果你有一个带调试符号的核心转储以及 `gdb`那太棒了您可以上下查看调用堆栈LCTT 译注:指跳进调用序列不同的函数中以便于查看局部变量),打印变量,并查看内存来得知发生了什么。这是最好的。
如果您仍然正在基于 gdb 向导来工作上只打印出栈跟踪与bt也可以。 :)
### ASAN
另一种搞清楚您的段错误的方法是使用 AddressSanitizer 选项编译程序“ASAN”`$CC -fsanitize=address`)然后运行它。 本文中我不准备讨论那个,因为本文已经相当长了,并且在我的例子中打开 ASAN 后段错误消失了,可能是因为 ASAN 使用了一个不同的内存分配器(系统内存分配器,而不是 tcmalloc
在未来如果我能让 ASAN 工作我可能会多写点有关它的东西。LCTT 译注:这里指使用 ASAN 也能复现段错误)
### 从一个核心转储得到一个堆栈跟踪真的很亲切!
这个博客听起来很多,当我做这些的时候很困惑,但说真的,从一个段错误的程序中获得一个堆栈调用序列不需要那么多步骤:
1. 试试用 `valgrind`
如果那没用,或者你想要拿到一个核心转储来调查:
1. 确保二进制文件编译时带有调试符号信息;
2. 正确的设置 `ulimit``kernel.core_pattern`
3. 运行程序;
4. 一旦你用 `gdb` 调试核心转储了,加载符号并运行 `bt`
5. 尝试找出发生了什么!
我可以使用 `gdb` 弄清楚有个 C++ 的虚表条目指向一些被破坏的内存,这有点帮助,并且使我感觉好像更懂了 C++ 一点。也许有一天我们会更多地讨论如何使用 `gdb` 来查找问题!
--------------------------------------------------------------------------------
via: https://jvns.ca/blog/2018/04/28/debugging-a-segfault-on-linux/
作者:[Julia Evans][a]
译者:[stephenxs](https://github.com/stephenxs)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://jvns.ca/about/
[1]:http://man7.org/linux/man-pages/man5/core.5.html

View File

@ -0,0 +1,359 @@
无密码验证:客户端
======
我们继续 [无密码验证][1] 的文章。上一篇文章中,我们用 Go 写了一个 HTTP 服务,用这个服务来做无密码验证 API。今天我们为它再写一个 JavaScript 客户端。
我们将使用 [这里的][2] 这个单页面应用程序SPA来展示使用的技术。如果你还没有读过它请先读它。
记住流程:
- 用户输入其 email。
- 用户收到一个带有魔法链接的邮件。
- 用户点击该链接、
- 用户验证成功。
对于根 URL`/`),我们将根据验证的状态分别使用两个不同的页面:一个是带有访问表单的页面,或者是已验证通过的用户的欢迎页面。另一个页面是验证回调的重定向页面。
### 伺服
我们将使用相同的 Go 服务器来为客户端提供服务,因此,在我们前面的 `main.go` 中添加一些路由:
```
router.Handle("GET", "/...", http.FileServer(SPAFileSystem{http.Dir("static")}))
```
```
type SPAFileSystem struct {
fs http.FileSystem
}
func (spa SPAFileSystem) Open(name string) (http.File, error) {
f, err := spa.fs.Open(name)
if err != nil {
return spa.fs.Open("index.html")
}
return f, nil
}
```
这个伺服文件放在 `static` 下,配合 `static/index.html` 作为回调。
你可以使用你自己的服务器,但是你得在服务器上启用 [CORS][3]。
### HTML
我们来看一下那个 `static/index.html` 文件。
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Passwordless Demo</title>
<link rel="shortcut icon" href="data:,">
<script src="/js/main.js" type="module"></script>
</head>
<body></body>
</html>
```
单页面应用程序的所有渲染由 JavaScript 来完成,因此,我们使用了一个空的 body 部分和一个 `main.js` 文件。
我们将使用 [上篇文章][2] 中的 Router。
### 渲染
现在,我们使用下面的内容来创建一个 `static/js/main.js` 文件:
```
import Router from 'https://unpkg.com/@nicolasparada/router'
import { isAuthenticated } from './auth.js'
const router = new Router()
router.handle('/', guard(view('home')))
router.handle('/callback', view('callback'))
router.handle(/^\//, view('not-found'))
router.install(async resultPromise => {
document.body.innerHTML = ''
document.body.appendChild(await resultPromise)
})
function view(name) {
return (...args) => import(`/js/pages/${name}-page.js`)
.then(m => m.default(...args))
}
function guard(fn1, fn2 = view('welcome')) {
return (...args) => isAuthenticated()
? fn1(...args)
: fn2(...args)
}
```
与上篇文章不同的是,我们实现了一个 `isAuthenticated()` 函数和一个 `guard()` 函数,使用它去渲染两种验证状态的页面。因此,当用户访问 `/` 时,它将根据用户是否通过了验证来展示主页或者是欢迎页面。
### 验证
现在,我们来编写 `isAuthenticated()` 函数。使用下面的内容来创建一个 `static/js/auth.js` 文件:
```
export function getAuthUser() {
const authUserItem = localStorage.getItem('auth_user')
const expiresAtItem = localStorage.getItem('expires_at')
if (authUserItem !== null && expiresAtItem !== null) {
const expiresAt = new Date(expiresAtItem)
if (!isNaN(expiresAt.valueOf()) && expiresAt > new Date()) {
try {
return JSON.parse(authUserItem)
} catch (_) { }
}
}
return null
}
export function isAuthenticated() {
return localStorage.getItem('jwt') !== null && getAuthUser() !== null
}
```
当有人登入时,我们将保存 JSON 格式的 web 令牌、它的过期日期,以及在 `localStorage` 上的当前已验证用户。这个模块就是这个用处。
* `getAuthUser()` 用于从 `localStorage` 获取已认证的用户,以确认 JSON 格式的 Web 令牌没有过期。
* `isAuthenticated()` 在前面的函数中用于去检查它是否没有返回 `null`
### 获取
在继续这个页面之前,我将写一些与服务器 API 一起使用的 HTTP 工具。
我们使用以下的内容去创建一个 `static/js/http.js` 文件:
```
import { isAuthenticated } from './auth.js'
function get(url, headers) {
return fetch(url, {
headers: Object.assign(getAuthHeader(), headers),
}).then(handleResponse)
}
function post(url, body, headers) {
return fetch(url, {
method: 'POST',
headers: Object.assign(getAuthHeader(), { 'content-type': 'application/json' }, headers),
body: JSON.stringify(body),
}).then(handleResponse)
}
function getAuthHeader() {
return isAuthenticated()
? { authorization: `Bearer ${localStorage.getItem('jwt')}` }
: {}
}
export async function handleResponse(res) {
const body = await res.clone().json().catch(() => res.text())
const response = {
statusCode: res.status,
statusText: res.statusText,
headers: res.headers,
body,
}
if (!res.ok) {
const message = typeof body === 'object' && body !== null && 'message' in body
? body.message
: typeof body === 'string' && body !== ''
? body
: res.statusText
const err = new Error(message)
throw Object.assign(err, response)
}
return response
}
export default {
get,
post,
}
```
这个模块导出了 `get()``post()` 函数。它们是 `fetch` API 的封装。当用户是已验证的,这二个函数注入一个 `Authorization: Bearer <token_here>` 头到请求中;这样服务器就能对我们进行身份验证。
### 欢迎页
我们现在来到欢迎页面。用如下的内容创建一个 `static/js/pages/welcome-page.js` 文件:
```
const template = document.createElement('template')
template.innerHTML = `
<h1>Passwordless Demo</h1>
<h2>Access</h2>
<form id="access-form">
<input type="email" placeholder="Email" autofocus required>
<button type="submit">Send Magic Link</button>
</form>
`
export default function welcomePage() {
const page = template.content.cloneNode(true)
page.getElementById('access-form')
.addEventListener('submit', onAccessFormSubmit)
return page
}
```
这个页面使用一个 `HTMLTemplateElement` 作为视图。这只是一个输入用户 email 的简单表单。
为了避免干扰,我将跳过错误处理部分,只是将它们输出到控制台上。
现在,我们来写 `onAccessFormSubmit()` 函数。
```
import http from '../http.js'
function onAccessFormSubmit(ev) {
ev.preventDefault()
const form = ev.currentTarget
const input = form.querySelector('input')
const email = input.value
sendMagicLink(email).catch(err => {
console.error(err)
if (err.statusCode === 404 && wantToCreateAccount()) {
runCreateUserProgram(email)
}
})
}
function sendMagicLink(email) {
return http.post('/api/passwordless/start', {
email,
redirectUri: location.origin + '/callback',
}).then(() => {
alert('Magic link sent. Go check your email inbox.')
})
}
function wantToCreateAccount() {
return prompt('No user found. Do you want to create an account?')
}
```
它对 `/api/passwordless/start` 发起了 POST 请求,请求体中包含 `email``redirectUri`。在本例中它返回 `404 Not Found` 状态码时,我们将创建一个用户。
```
function runCreateUserProgram(email) {
const username = prompt("Enter username")
if (username === null) return
http.post('/api/users', { email, username })
.then(res => res.body)
.then(user => sendMagicLink(user.email))
.catch(console.error)
}
```
这个用户创建程序,首先询问用户名,然后使用 email 和用户名做一个 `POST` 请求到 `/api/users`。成功之后,给创建的用户发送一个魔法链接。
### 回调页
这是访问表单的全部功能,现在我们来做回调页面。使用如下的内容来创建一个 `static/js/pages/callback-page.js` 文件:
```
import http from '../http.js'
const template = document.createElement('template')
template.innerHTML = `
<h1>Authenticating you</h1>
`
export default function callbackPage() {
const page = template.content.cloneNode(true)
const hash = location.hash.substr(1)
const fragment = new URLSearchParams(hash)
for (const [k, v] of fragment.entries()) {
fragment.set(decodeURIComponent(k), decodeURIComponent(v))
}
const jwt = fragment.get('jwt')
const expiresAt = fragment.get('expires_at')
http.get('/api/auth_user', { authorization: `Bearer ${jwt}` })
.then(res => res.body)
.then(authUser => {
localStorage.setItem('jwt', jwt)
localStorage.setItem('auth_user', JSON.stringify(authUser))
localStorage.setItem('expires_at', expiresAt)
location.replace('/')
})
.catch(console.error)
return page
}
```
请记住……当点击魔法链接时,我们会来到 `/api/passwordless/verify_redirect`,它将把我们重定向到重定向 URI我们将放在哈希中的 JWT 和过期日期传递给 `/callback`
回调页面解码 URL 中的哈希,提取这些参数去做一个 `GET` 请求到 `/api/auth_user`,用 JWT 保存所有数据到 `localStorage` 中。最后,重定向到主页面。
### 主页
创建如下内容的 `static/pages/home-page.js` 文件:
```
import { getAuthUser } from '../auth.js'
export default function homePage() {
const authUser = getAuthUser()
const template = document.createElement('template')
template.innerHTML = `
<h1>Passwordless Demo</h1>
<p>Welcome back, ${authUser.username} 👋</p>
<button id="logout-button">Logout</button>
`
const page = template.content
page.getElementById('logout-button')
.addEventListener('click', logout)
return page
}
function logout() {
localStorage.clear()
location.reload()
}
```
这个页面用于欢迎已验证用户,同时也有一个登出按钮。`logout()` 函数的功能只是清理掉 `localStorage` 并重载这个页面。
这就是全部内容了。我猜你在此之前已经看过这个 [demo][4] 了。当然,这些源代码也在同一个 [仓库][5] 中。
--------------------------------------------------------------------------------
via: https://nicolasparada.netlify.com/posts/passwordless-auth-client/
作者:[Nicolás Parada][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[qhwdw](https://github.com/qhwdw)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://nicolasparada.netlify.com/
[1]:https://linux.cn/article-9748-1.html
[2]:https://linux.cn/article-9815-1.html
[3]:https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
[4]:https://go-passwordless-demo.herokuapp.com/
[5]:https://github.com/nicolasparada/go-passwordless-demo

View File

@ -0,0 +1,406 @@
日常 Python 编程优雅之道
======
> 3 个可以使你的 Python 代码更优雅、可读、直观和易于维护的工具。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/serving-bowl-forks-dinner.png?itok=a3YqPwr5)
Python 提供了一组独特的工具和语言特性来使你的代码更加优雅、可读和直观。为正确的问题选择合适的工具,你的代码将更易于维护。在本文中,我们将研究其中的三个工具:魔术方法、迭代器和生成器,以及方法魔术。
### 魔术方法
魔术方法可以看作是 Python 的管道。它们被称为“底层”方法,用于某些内置的方法、符号和操作。你可能熟悉的常见魔术方法是 `__init__()`,当我们想要初始化一个类的新实例时,它会被调用。
你可能已经看过其他常见的魔术方法,如 `__str__``__repr__`。Python 中有一整套魔术方法,通过实现其中的一些方法,我们可以修改一个对象的行为,甚至使其行为类似于内置数据类型,例如数字、列表或字典。
让我们创建一个 `Money` 类来示例:
```
class Money:
currency_rates = {
'$': 1,
'€': 0.88,
}
def __init__(self, symbol, amount):
self.symbol = symbol
self.amount = amount
def __repr__(self):
return '%s%.2f' % (self.symbol, self.amount)
def convert(self, other):
""" Convert other amount to our currency """
new_amount = (
other.amount / self.currency_rates[other.symbol]
* self.currency_rates[self.symbol])
return Money(self.symbol, new_amount)
```
该类定义为给定的货币符号和汇率定义了一个货币汇率,指定了一个初始化器(也称为构造函数),并实现 `__repr__`,因此当我们打印这个类时,我们会看到一个友好的表示,例如 `$2.00` ,这是一个带有货币符号和金额的 `Money('$', 2.00)` 实例。最重要的是,它定义了一种方法,允许你使用不同的汇率在不同的货币之间进行转换。
打开 Python shell假设我们已经定义了使用两种不同货币的食品的成本如下所示
```
>>> soda_cost = Money('$', 5.25)
>>> soda_cost
$5.25
>>> pizza_cost = Money('€', 7.99)
>>> pizza_cost
€7.99
```
我们可以使用魔术方法使得这个类的实例之间可以相互交互。假设我们希望能够将这个类的两个实例一起加在一起,即使它们是不同的货币。为了实现这一点,我们可以在 `Money` 类上实现 `__add__` 这个魔术方法:
```
class Money:
# ... previously defined methods ...
def __add__(self, other):
""" Add 2 Money instances using '+' """
new_amount = self.amount + self.convert(other).amount
return Money(self.symbol, new_amount)
```
现在我们可以以非常直观的方式使用这个类:
```
>>> soda_cost = Money('$', 5.25)
>>> pizza_cost = Money('€', 7.99)
>>> soda_cost + pizza_cost
$14.33
>>> pizza_cost + soda_cost
€12.61
```
当我们将两个实例加在一起时,我们得到以第一个定义的货币符号所表示的结果。所有的转换都是在底层无缝完成的。如果我们想的话,我们也可以为减法实现 `__sub__`,为乘法实现 `__mul__` 等等。阅读[模拟数字类型][1]或[魔术方法指南][2]来获得更多信息。
我们学习到 `__add__` 映射到内置运算符 `+`。其他魔术方法可以映射到像 `[]` 这样的符号。例如,在字典中通过索引或键来获得一项,其实是使用了 `__getitem__` 方法:
```
>>> d = {'one': 1, 'two': 2}
>>> d['two']
2
>>> d.__getitem__('two')
2
```
一些魔术方法甚至映射到内置函数,例如 `__len__()` 映射到 `len()`
```
class Alphabet:
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def __len__(self):
return len(self.letters)
>>> my_alphabet = Alphabet()
>>> len(my_alphabet)
26
```
### 自定义迭代器
对于新的和经验丰富的 Python 开发者来说,自定义迭代器是一个非常强大的但令人迷惑的主题。
许多内置类型,例如列表、集合和字典,已经实现了允许它们在底层迭代的协议。这使我们可以轻松地遍历它们。
```
>>> for food in ['Pizza', 'Fries']:
         print(food + '. Yum!')
Pizza. Yum!
Fries. Yum!
```
我们如何迭代我们自己的自定义类?首先,让我们来澄清一些术语。
* 要成为一个可迭代对象,一个类需要实现 `__iter__()`
* `__iter__()` 方法需要返回一个迭代器
* 要成为一个迭代器,一个类需要实现 `__next__()`(或[在 Python 2][3]中是 `next()`),当没有更多的项要迭代时,必须抛出一个 `StopIteration` 异常。
呼!这听起来很复杂,但是一旦你记住了这些基本概念,你就可以在任何时候进行迭代。
我们什么时候想使用自定义迭代器?让我们想象一个场景,我们有一个 `Server` 实例在不同的端口上运行不同的服务,如 `http``ssh`。其中一些服务处于 `active` 状态,而其他服务则处于 `inactive` 状态。
```
class Server:
services = [
{'active': False, 'protocol': 'ftp', 'port': 21},
{'active': True, 'protocol': 'ssh', 'port': 22},
{'active': True, 'protocol': 'http', 'port': 80},
]
```
当我们遍历 `Server` 实例时,我们只想遍历那些处于 `active` 的服务。让我们创建一个 `IterableServer` 类:
```
class IterableServer:
    def __init__(self):
        self.current_pos = 0
    def __next__(self):
        pass  # TODO: 实现并记得抛出 StopIteration
```
首先,我们将当前位置初始化为 `0`。然后,我们定义一个 `__next__()` 方法来返回下一项。我们还将确保在没有更多项返回时抛出 `StopIteration`。到目前为止都很好!现在,让我们实现这个 `__next__()` 方法。
```
class IterableServer:
    def __init__(self):
        self.current_pos = 0.  # 我们初始化当前位置为 0
    def __iter__(self):  # 我们可以在这里返回 self因为实现了 __next__
        return self
    def __next__(self):
        while self.current_pos < len(self.services):
            service = self.services[self.current_pos]
            self.current_pos += 1
            if service['active']:
                return service['protocol'], service['port']
        raise StopIteration
    next = __next__  # 可选的 Python2 兼容性
```
我们对列表中的服务进行遍历,而当前的位置小于服务的个数,但只有在服务处于活动状态时才返回。一旦我们遍历完服务,就会抛出一个 `StopIteration` 异常。
因为我们实现了 `__next__()` 方法,当它耗尽时,它会抛出 `StopIteration`。我们可以从 `__iter__()` 返回 `self`,因为 `IterableServer` 类遵循 `iterable` 协议。
现在我们可以遍历一个 `IterableServer` 实例,这将允许我们查看每个处于活动的服务,如下所示:
```
>>> for protocol, port in IterableServer():
        print('service %s is running on port %d' % (protocol, port))
service ssh is running on port 22
service http is running on port 21
```
太棒了,但我们可以做得更好!在这样类似的实例中,我们的迭代器不需要维护大量的状态,我们可以简化代码并使用 [generator生成器][4] 来代替。
```
class Server:
    services = [
        {'active': False, 'protocol': 'ftp', 'port': 21},
        {'active': True, 'protocol': 'ssh', 'port': 22},
        {'active': True, 'protocol': 'http', 'port': 21},
    ]
    def __iter__(self):
        for service in self.services:
            if service['active']:
                yield service['protocol'], service['port']
```
`yield` 关键字到底是什么?在定义生成器函数时使用 yield。这有点像 `return`,虽然 `return` 在返回值后退出函数,但 `yield` 会暂停执行直到下次调用它。这允许你的生成器的功能在它恢复之前保持状态。查看 [yield 的文档][5]以了解更多信息。使用生成器,我们不必通过记住我们的位置来手动维护状态。生成器只知道两件事:它现在需要做什么以及计算下一个项目需要做什么。一旦我们到达执行点,即 `yield` 不再被调用,我们就知道停止迭代。
这是因为一些内置的 Python 魔法。在 [Python 关于 `__iter__()` 的文档][6]中我们可以看到,如果 `__iter__()` 是作为一个生成器实现的,它将自动返回一个迭代器对象,该对象提供 `__iter__()``__next__()` 方法。阅读这篇很棒的文章,深入了解[迭代器,可迭代对象和生成器][7]。
### 方法魔法
由于其独特的方面Python 提供了一些有趣的方法魔法作为语言的一部分。
其中一个例子是别名功能。因为函数只是对象,所以我们可以将它们赋值给多个变量。例如:
```
>>> def foo():
       return 'foo'
>>> foo()
'foo'
>>> bar = foo
>>> bar()
'foo'
```
我们稍后会看到它的作用。
Python 提供了一个方便的内置函数[称为 `getattr()`][8],它接受 `object, name, default` 参数并在 `object` 上返回属性 `name`。这种编程方式允许我们访问实例变量和方法。例如:
```
>>> class Dog:
sound = 'Bark'
def speak(self):
print(self.sound + '!', self.sound + '!')
>>> fido = Dog()
>>> fido.sound
'Bark'
>>> getattr(fido, 'sound')
'Bark'
>>> fido.speak
<bound method Dog.speak of <__main__.Dog object at 0x102db8828>>
>>> getattr(fido, 'speak')
<bound method Dog.speak of <__main__.Dog object at 0x102db8828>>
>>> fido.speak()
Bark! Bark!
>>> speak_method = getattr(fido, 'speak')
>>> speak_method()
Bark! Bark!
```
这是一个很酷的技巧,但是我们如何在实际中使用 `getattr` 呢?让我们看一个例子,我们编写一个小型命令行工具来动态处理命令。
```
class Operations:
    def say_hi(self, name):
        print('Hello,', name)
    def say_bye(self, name):
        print ('Goodbye,', name)
    def default(self, arg):
        print ('This operation is not supported.')
if __name__ == '__main__':
    operations = Operations()
    # 假设我们做了错误处理
    command, argument = input('> ').split()
    func_to_call = getattr(operations, command, operations.default)
    func_to_call(argument)
```
脚本的输出是:
```
$ python getattr.py
> say_hi Nina
Hello, Nina
> blah blah
This operation is not supported.
```
接下来,我们来看看 `partial`。例如,`functool.partial(func, *args, **kwargs)` 允许你返回一个新的 [partial 对象][9],它的行为类似 `func`,参数是 `args``kwargs`。如果传入更多的 `args`,它们会被附加到 `args`。如果传入更多的 `kwargs`,它们会扩展并覆盖 `kwargs`。让我们通过一个简短的例子来看看:
```
>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo
<functools.partial object at 0x1085a09f0>
>>> basetwo('10010')
18
# 这等同于
>>> int('10010', base=2)
```
让我们看看在我喜欢的一个[名为 `agithub`][10] 的库中的一些示例代码中,这个方法魔术是如何结合在一起的,这是一个(名字起得很 low 的) REST API 客户端,它具有透明的语法,允许你以最小的配置快速构建任何 REST API 原型(不仅仅是 GitHub。我发现这个项目很有趣因为它非常强大但只有大约 400 行 Python 代码。你可以在大约 30 行配置代码中添加对任何 REST API 的支持。`agithub` 知道协议所需的一切(`REST`、`HTTP`、`TCP`),但它不考虑上游 API。让我们深入到它的实现中。
以下是我们如何为 GitHub API 和任何其他相关连接属性定义端点 URL 的简化版本。在这里查看[完整代码][11]。
```
class GitHub(API):
    def __init__(self, token=None, *args, **kwargs):
        props = ConnectionProperties(api_url = kwargs.pop('api_url', 'api.github.com'))
        self.setClient(Client(*args, **kwargs))
        self.setConnectionProperties(props)
```
然后,一旦配置了[访问令牌][12],就可以开始使用 [GitHub API][13]。
```
>>> gh = GitHub('token')
>>> status, data = gh.user.repos.get(visibility='public', sort='created')
>>> # ^ 映射到 GET /user/repos
>>> data
... ['tweeter', 'snipey', '...']
```
请注意,你要确保 URL 拼写正确,因为我们没有验证 URL。如果 URL 不存在或出现了其他任何错误,将返回 API 抛出的错误。那么,这一切是如何运作的呢?让我们找出答案。首先,我们将查看一个 [`API` 类][14]的简化示例:
```
class API:
    # ... other methods ...
    def __getattr__(self, key):
        return IncompleteRequest(self.client).__getattr__(key)
    __getitem__ = __getattr__
```
`API` 类上的每次调用都会调用 [`IncompleteRequest` 类][15]作为指定的 `key`
```
class IncompleteRequest:
    # ... other methods ...
    def __getattr__(self, key):
        if key in self.client.http_methods:
            htmlMethod = getattr(self.client, key)
            return partial(htmlMethod, url=self.url)
        else:
            self.url += '/' + str(key)
            return self
    __getitem__ = __getattr__
class Client:
    http_methods = ('get')  # 还有 post, put, patch 等等。
    def get(self, url, headers={}, **params):
        return self.request('GET', url, None, headers)
```
如果最后一次调用不是 HTTP 方法(如 `get`、`post` 等),则返回带有附加路径的 `IncompleteRequest`。否则,它从[`Client` 类][16]获取 HTTP 方法对应的正确函数,并返回 `partial`
如果我们给出一个不存在的路径会发生什么?
```
>>> status, data = this.path.doesnt.exist.get()
>>> status
... 404
```
因为 `__getattr__` 别名为 `__getitem__`
```
>>> owner, repo = 'nnja', 'tweeter'
>>> status, data = gh.repos[owner][repo].pulls.get()
>>> # ^ Maps to GET /repos/nnja/tweeter/pulls
>>> data
.... # {....}
```
这真心是一些方法魔术!
### 了解更多
Python 提供了大量工具,使你的代码更优雅,更易于阅读和理解。挑战在于找到合适的工具来完成工作,但我希望本文为你的工具箱添加了一些新工具。而且,如果你想更进一步,你可以在我的博客 [nnja.io][17] 上阅读有关装饰器、上下文管理器、上下文生成器和命名元组的内容。随着你成为一名更好的 Python 开发人员,我鼓励你到那里阅读一些设计良好的项目的源代码。[Requests][18] 和 [Flask][19] 是两个很好的起步的代码库。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/4/elegant-solutions-everyday-python-problems
作者:[Nina Zakharenko][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[MjSeven](https://github.com/MjSeven)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/nnja
[1]:https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types
[2]:https://rszalski.github.io/magicmethods/
[3]:https://docs.python.org/2/library/stdtypes.html#iterator.next
[4]:https://docs.python.org/3/library/stdtypes.html#generator-types
[5]:https://docs.python.org/3/reference/expressions.html#yieldexpr
[6]:https://docs.python.org/3/reference/datamodel.html#object.__iter__
[7]:http://nvie.com/posts/iterators-vs-generators/
[8]:https://docs.python.org/3/library/functions.html#getattr
[9]:https://docs.python.org/3/library/functools.html#functools.partial
[10]:https://github.com/mozilla/agithub
[11]:https://github.com/mozilla/agithub/blob/master/agithub/GitHub.py
[12]:https://github.com/settings/tokens
[13]:https://developer.github.com/v3/repos/#list-your-repositories
[14]:https://github.com/mozilla/agithub/blob/dbf7014e2504333c58a39153aa11bbbdd080f6ac/agithub/base.py#L30-L58
[15]:https://github.com/mozilla/agithub/blob/dbf7014e2504333c58a39153aa11bbbdd080f6ac/agithub/base.py#L60-L100
[16]:https://github.com/mozilla/agithub/blob/dbf7014e2504333c58a39153aa11bbbdd080f6ac/agithub/base.py#L102-L231
[17]:http://nnja.io
[18]:https://github.com/requests/requests
[19]:https://github.com/pallets/flask
[20]:https://us.pycon.org/2018/schedule/presentation/164/
[21]:https://us.pycon.org/2018/

View File

@ -0,0 +1,165 @@
在 Linux 命令行中自定义文本颜色
======
> 在 Linux 命令行当中使用不同颜色以期提供一种根据文件类型来识别文件的简单方式。你可以修改这些颜色,但是在做之前应该对你做的事情有充分的理由。
![](https://images.idgesg.net/images/article/2018/05/numbers-100756457-large.jpg)
如果你在 Linux 命令行上花费了大量的时间(如果没有,那么你可能不会读这篇文章),你无疑注意到了 `ls` 以多种不同的颜色显示文件。你可能也注意到了一些区别 —— 目录是一种颜色,可执行文件是另一种颜色等等。
这一切是如何发生的呢?以及,你可以选择哪些选项来改变颜色分配可能就不是很多人都知道的。
一种方法是运行 `dircolors` 命令得到一大堆展示了如何指定这些颜色的数据。它会显示以下这些东西:
```
$ dircolors
LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do
=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg
=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01
;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01
;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=0
1;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31
:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.
xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.t
bz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.j
ar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.a
lz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.r
z=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.
mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:
*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:
*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;3
5:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;
35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01
;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01
;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01
;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;3
5:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;3
5:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;3
6:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;
36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;
36:*.spx=00;36:*.xspf=00;36:';
export LS_COLORS
```
如果你擅长解析文件,那么你可能会注意到这个列表有一种<ruby>模式<rt>patten</rt></ruby>。用冒号分隔开,你会看到这样的东西:
```
$ dircolors | tr ":" "\n" | head -10
LS_COLORS='rs=0
di=01;34
ln=01;36
mh=00
pi=40;33
so=01;35
do=01;35
bd=40;33;01
cd=40;33;01
or=40;31;01
```
OK这里有一个模式 —— 一系列定义,有一到三个数字组件。我们来看看其中的一个定义。
```
pi=40;33
```
有些人可能会问的第一个问题是“pi 是什么?”在这里,我们研究的是颜色和文件类型,所以这显然不是以 3.14 开头的那个有趣的数字。当然不是,这个 “pi” 代表 “pipe管道” —— Linux 系统上的一种特殊类型的文件,它可以将数据从一个程序传递给另一个程序。所以,让我们建立一个管道。
```
$ mknod /tmp/mypipe p
$ ls -l /tmp/mypipe
prw-rw-r-- 1 shs shs 0 May 1 14:00 /tmp/mypipe
```
当我们在终端窗口中查看我们的管道和其他几个文件时,颜色差异非常明显。
![font colors][1]
`pi` 的定义中如上所示“40” 使文件在终端(或 PuTTY窗口中使用黑色背景显示31 使字体颜色变红。管道是特殊的文件,这种特殊的处理使它们在目录列表中突出显示。
`bd``cd` 定义是相同的 —— `40;33;01`,它有一个额外的设置。这个设置会导致 <ruby>块设备<rt>block device</rt></ruby>bd<ruby>字符设备<rt>character device</rt></ruby>cd以黑色背景橙色字体和另一种效果显示 —— 字符将以粗体显示。
以下列表显示由<ruby>文件类型<rt>file type</rt></ruby>所指定的颜色和字体分配:
```
setting file type
======= =========
rs=0 reset to no color
di=01;34 directory
ln=01;36 link
mh=00 multi-hard link
pi=40;33 pipe
so=01;35 socket
do=01;35 door
bd=40;33;01 block device
cd=40;33;01 character device
or=40;31;01 orphan
mi=00 missing?
su=37;41 setuid
sg=30;43 setgid
ca=30;41 file with capability
tw=30;42 directory with sticky bit and world writable
ow=34;42 directory that is world writable
st=37;44 directory with sticky bit
ex=01;93 executable
```
你可能已经注意到,在 `dircolors` 命令输出中,我们的大多数定义都以星号开头(例如,`*.wav=00;36`)。这些按<ruby>文件扩展名<rt>file extension</rt></ruby>而不是文件类型定义显示属性。这有一个示例:
```
$ dircolors | tr ":" "\n" | tail -10
*.mpc=00;36
*.ogg=00;36
*.ra=00;36
*.wav=00;36
*.oga=00;36
*.opus=00;36
*.spx=00;36
*.xspf=00;36
';
export LS_COLORS
```
这些设置(上面列表中所有的 `00;36`)将使这些文件名以青色显示。可用的颜色如下所示。
![all colors][2]
### 如何改变设置
你要使用 `ls` 的别名来打开颜色显示功能。这通常是 Linux 系统上的默认设置,看起来是这样的:
```
alias ls='ls --color=auto'
```
如果要关闭字体颜色,可以运行 `unalias ls` 命令,然后文件列表将仅以默认字体颜色显示。
你可以通过修改 `$LS_COLORS` 设置和导出修改后的设置来更改文本颜色。
```
$ export LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;...
```
注意:上面的命令由于太长被截断了。
如果希望文本颜色的修改是永久性的,则需要将修改后的 `$LS_COLORS` 定义添加到一个启动文件中,例如 `.bashrc`
### 更多关于命令行文本
你可以在 NetworkWorld 的 [2016 年 11 月][3]的帖子中找到有关文本颜色的其他信息。
---
via: https://www.networkworld.com/article/3269587/linux/customizing-your-text-colors-on-the-linux-command-line.html
作者:[Sandra Henry-Stocker][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[MjSeven](https://github.com/MjSeven)
校对:[pityonline](https://github.com/pityonline)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
[1]: https://images.idgesg.net/images/article/2018/05/font-colors-100756483-large.jpg
[2]: https://images.techhive.com/images/article/2016/11/all-colors-100691990-large.jpg
[3]: https://www.networkworld.com/article/3138909/linux/coloring-your-world-with-ls-colors.html

View File

@ -0,0 +1,134 @@
如何轻松地检查 Ubuntu 版本以及其它系统信息
======
> 摘要:想知道你正在使用的 Ubuntu 具体是什么版本吗?这篇文档将告诉你如何检查你的 Ubuntu 版本、桌面环境以及其他相关的系统信息。
通常,你能非常容易的通过命令行或者图形界面获取你正在使用的 Ubuntu 的版本。当你正在尝试学习一篇互联网上的入门教材或者正在从各种各样的论坛里获取帮助的时候,知道当前正在使用的 Ubuntu 确切的版本号、桌面环境以及其他的系统信息将是尤为重要的。
在这篇简短的文章中,作者将展示各种检查 [Ubuntu][1] 版本以及其他常用的系统信息的方法。
### 如何在命令行检查 Ubuntu 版本
这个是获得 Ubuntu 版本的最好的办法。我本想先展示如何用图形界面做到这一点,但是我决定还是先从命令行方法说起,因为这种方法不依赖于你使用的任何[桌面环境][2]。 你可以在 Ubuntu 的任何变种系统上使用这种方法。
打开你的命令行终端 (`Ctrl+Alt+T`) 键入下面的命令:
```
lsb_release -a
```
上面命令的输出应该如下:
```
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.4 LTS
Release: 16.04
Codename: xenial
```
![How to check Ubuntu version in command line][3]
正像你所看到的,当前我的系统安装的 Ubuntu 版本是 Ubuntu 16.04 版本代号: Xenial。
且慢!为什么版本描述中显示的是 Ubuntu 16.04.4 而发行版本是 16.04到底哪个才是正确的版本16.04 还是 16.04.4? 这两者之间有什么区别?
如果言简意赅的回答这个问题的话,那么答案应该是你正在使用 Ubuntu 16.04。这个是基准版本,而 16.04.4 进一步指明这是 16.04 的第四个补丁版本。你可以将补丁版本理解为 Windows 世界里的服务包。在这里16.04 和 16.04.4 都是正确的版本号。
那么输出的 Xenial 又是什么?那正是 Ubuntu 16.04 的版本代号。你可以阅读下面这篇文章获取更多信息:[了解 Ubuntu 的命名惯例][4]。
#### 其他一些获取 Ubuntu 版本的方法
你也可以使用下面任意的命令得到 Ubuntu 的版本:
```
cat /etc/lsb-release
```
输出如下信息:
```
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.4 LTS"
```
![How to check Ubuntu version in command line][5]
你还可以使用下面的命令来获得 Ubuntu 版本:
```
cat /etc/issue
```
命令行的输出将会如下:
```
Ubuntu 16.04.4 LTS \n \l
```
不要介意输出末尾的\n \l. 这里 Ubuntu 版本就是 16.04.4或者更加简单16.04。
### 如何在图形界面下得到 Ubuntu 版本
在图形界面下获取 Ubuntu 版本更是小事一桩。这里我使用了 Ubuntu 18.04 的图形界面系统 GNOME 的屏幕截图来展示如何做到这一点。如果你在使用 Unity 或者别的桌面环境的话,显示可能会有所不同。这也是为什么我推荐使用命令行方式来获得版本的原因:你不用依赖形形色色的图形界面。
下面我来展示如何在桌面环境获取 Ubuntu 版本。
进入‘系统设置’并点击下面的‘详细信息’栏。
![Finding Ubuntu version graphically][6]
你将会看到系统的 Ubuntu 版本和其他和桌面系统有关的系统信息 这里的截图来自 [GNOME][7] 。
![Finding Ubuntu version graphically][8]
### 如何知道桌面环境以及其他的系统信息
你刚才学习的是如何得到 Ubuntu 的版本信息,那么如何知道桌面环境呢? 更进一步, 如果你还想知道当前使用的 Linux 内核版本呢?
有各种各样的命令你可以用来得到这些信息,不过今天我想推荐一个命令行工具, 叫做 [Neofetch][9]。 这个工具能在命令行完美展示系统信息,包括 Ubuntu 或者其他 Linux 发行版的系统图标。
用下面的命令安装 Neofetch
```
sudo apt install neofetch
```
安装成功后,运行 `neofetch` 将会优雅的展示系统的信息如下。
![System information in Linux terminal][10]
如你所见,`neofetch` 完全展示了 Linux 内核版本、Ubuntu 的版本、桌面系统版本以及环境、主题和图标等等信息。
希望我如上展示方法能帮到你更快的找到你正在使用的 Ubuntu 版本和其他系统信息。如果你对这篇文章有其他的建议,欢迎在评论栏里留言。
再见。:)
--------------------------------------------------------------------------------
via: https://itsfoss.com/how-to-know-ubuntu-unity-version/
作者:[Abhishek Prakash][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[DavidChenLiang](https://github.com/davidchenliang)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/abhishek/
[1]:https://www.ubuntu.com/
[2]:https://en.wikipedia.org/wiki/Desktop_environment
[3]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2013/03/check-ubuntu-version-command-line-1-800x216.jpeg
[4]:https://itsfoss.com/linux-code-names/
[5]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2013/03/check-ubuntu-version-command-line-2-800x185.jpeg
[6]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2013/03/ubuntu-version-system-settings.jpeg
[7]:https://www.gnome.org/
[8]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2013/03/checking-ubuntu-version-gui.jpeg
[9]:https://itsfoss.com/display-linux-logo-in-ascii/
[10]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2013/03/ubuntu-system-information-terminal-800x400.jpeg

View File

@ -2,7 +2,8 @@ Android 工程师的一年
============================================================
![](https://cdn-images-1.medium.com/max/2000/1*tqshw1o4JZZlA1HW3Cki1Q.png)
>妙绝的绘画来自 [Miquel Beltran][0]
> 这幅妙绝的绘画来自 [Miquel Beltran][0]
我的技术生涯,从两年前算起。开始是 QA 测试员,一年后就转入开发人员角色。没怎么努力,也没有投入过多的个人时间。
@ -12,7 +13,7 @@ Android 工程师的一年
我的第一个职位角色, Android 开发者,开始于一年前。我工作的这家公司,可以花一半的时间去尝试其它角色的工作,这给我从 QA 职位转到 Android 开发者职位创造了机会。
这一转变归功于我在晚上和周末投入学习 Android 的时间。我通过了[ Android 基础纳米学位][3]、[Andriod 工程师纳米学位][4]课程,也获得了[ Google 开发者认证][5]。这部分的详细故事在[这儿][6]。
这一转变归功于我在晚上和周末投入学习 Android 的时间。我通过了 [Android 基础纳米学位][3]、[Andriod 工程师纳米学位][4]课程,也获得了 [Google 开发者认证][5]。这部分的详细故事在[这儿][6]。
两个月后,公司雇佣了另一位 QA我转向全职工作。挑战从此开始
@ -46,29 +47,27 @@ Android 工程师的一年
一个例子就是拉取代码进行公开展示和代码审查。有是我会请同事私下检查我的代码,并不想被公开拉取,向任何人展示。
其他时候,当我做代码审查时,会花好几分钟盯着"批准"按纽犹豫不决,在担心审查通过的会被其他同事找出毛病。
其他时候,当我做代码审查时,会花好几分钟盯着“批准”按纽犹豫不决,在担心审查通过的代码会被其他同事找出毛病。
当我在一些事上持反对意见时,由于缺乏相关知识,担心被坐冷板凳,从来没有大声说出来过。
> 某些时间我会请同事私下[...]检查我的代码,以避免被公开展示。
* * *
### 新的公司,新的挑战
后来,我手边有了个新的机会。感谢曾经和我共事的朋友,我被[ Babbel ][7]邀请去参加初级 Android 工程师职位的招聘流程。
后来,我手边有了个新的机会。感谢曾经和我共事的朋友,我被 [Babbel][7] 邀请去参加初级 Android 工程师职位的招聘流程。
我见到了他们的团队,同时自告奋勇的在他们办公室主持了一次本地会议。此事让我下定决心要申请这个职位。我喜欢公司的箴言:全民学习。其次,公司每个人都非常友善,在那儿工作看起来很愉快!但我没有马上申请,因为我认为自己不够好,所以为什么能申请呢?
还好我的朋友和搭档推动我这样做,他们给了我发送简历的力量和勇气。过后不久就进入了面试流程。这很简单:以很小的应该程序来进行编码挑战,随后是和团队一起的技术面试,之后是和招聘经理间关于团队合作的面试。
还好我的朋友和搭档推动我这样做,他们给了我发送简历的力量和勇气。过后不久就进入了面试流程。这很简单:以很小的程序的形式来进行编码挑战,随后是和团队一起的技术面试,之后是和招聘经理间关于团队合作的面试。
#### 招聘过程
我用周未的时间来完成编码挑战的项目,并在周一就立即发送过去。不久就受邀去当场面试。
技术面试是关于编程挑战本身,我们谈论了 Android 好的不好的、我为什么以这种方式实现这功能,以及如何改进等等。随后是招聘经理进行的一次简短的关于团队合作面试,也有涉及到编程挑战的事,我们谈到了我面临的挑战,我如何解决这些问题,等等。
技术面试是关于编程挑战本身,我们谈论了 Android 好的不好的地方、我为什么以这种方式实现这功能,以及如何改进等等。随后是招聘经理进行的一次简短的关于团队合作面试,也有涉及到编程挑战的事,我们谈到了我面临的挑战,我如何解决这些问题,等等。
最后,通过面试,得到 offer, 我授受了!
最后,通过面试,得到 offer我授受了!
我的 Android 工程师生涯的第一年,有九个月在一个公司,后面三个月在当前的公司。
@ -88,7 +87,7 @@ Android 工程师的一年
两次三次后,压力就堵到胸口。为什么我还不知道?为什么就那么难理解?这种状态让我焦虑万分。
我意识到我需要承认我确实不懂某个特定的主题,但第一步是要知道有这么个概念!有是,仅仅需要的就是更多的时间、更多的练习,最终会"在大脑中完全演绎" :-)
我意识到我需要承认我确实不懂某个特定的主题,但第一步是要知道有这么个概念!有时,仅仅需要的就是更多的时间、更多的练习,最终会“在大脑中完全演绎” :-)
例如,我常常为 Java 的接口类和抽象类所困扰,不管看了多少的例子,还是不能完全明白他们之间的区别。但一旦我使用后,即使还不能解释其工作原理,也知道了怎么使用以及什么时候使用。
@ -102,19 +101,13 @@ Android 工程师的一年
工程师的角色不仅仅是编码,而是广泛的技能。 我仍然处于旅程的起点,在掌握它的道路上,我想着重于以下几点:
* 交流:因为英文不是我的母语,所以有的时候我会努力传达我的想法,这在我工作中是至关重要的。我可以通过写作,阅读和交谈来解决这个问题。
* 提有建设性的反馈意见: 我想给同事有意义的反馈,这样我们一起共同发展。
* 为我的成就感到骄傲: 我需要创建一个列表来跟踪各种成就,无论大小,或整体进步,所以当我挣扎时我可以回顾并感觉良好。
* 不要着迷于不知道的事情: 当有很多新事物出现时很难做到都知道,所以只关注必须的,及手头项目需要的东西,这非常重要的。
* 多和同事分享知识。我是初级的并不意味着没有可以分享的!我需要持续分享我感兴趣的的文章及讨论话题。我知道同事们会感激我的。
* 耐心和持续学习: 和现在一样的保持不断学习,但对自己要有更多耐心。
* 自我保健: 随时注意休息,不要为难自己。 放松也富有成效。
* 交流:因为英文不是我的母语,所以有的时候我需要努力传达我的想法,这在我工作中是至关重要的。我可以通过写作,阅读和交谈来解决这个问题。
* 提有建设性的反馈意见:我想给同事有意义的反馈,这样我们一起共同发展。
* 为我的成就感到骄傲:我需要创建一个列表来跟踪各种成就,无论大小,或整体进步,所以当我挣扎时我可以回顾并感觉良好。
* 不要着迷于不知道的事情:当有很多新事物出现时很难做到都知道,所以只关注必须的,及手头项目需要的东西,这非常重要的。
* 多和同事分享知识:我是初级的并不意味着没有可以分享的!我需要持续分享我感兴趣的的文章及讨论话题。我知道同事们会感激我的。
* 耐心和持续学习:和现在一样的保持不断学习,但对自己要有更多耐心。
* 自我保健:随时注意休息,不要为难自己。 放松也富有成效。
--------------------------------------------------------------------------------
@ -122,7 +115,7 @@ via: https://proandroiddev.com/a-year-as-android-engineer-55e2a428dfc8
作者:[Lara Martín][a]
译者:[runningwater](https://github.com/runningwater)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,90 @@
使用 Xenlism 主题对你的 Linux 桌面进行令人惊叹的改造
============================================================
> 简介Xenlism 主题包提供了一个美观的 GTK 主题、彩色图标和简约的壁纸,将你的 Linux 桌面转变为引人注目的操作系统。
除非我找到一些非常棒的东西,否则我不会每天都把整篇文章献给一个主题。我曾经经常发布主题和图标。但最近,我更喜欢列出[最佳 GTK 主题][6]和图标主题。这对我和你来说都更方便,你可以在一个地方看到许多美丽的主题。
在 [Pop OS 主题][7]套件之后Xenlism 是另一个让我对它的外观感到震惊的主题。
![Xenlism GTK theme for Ubuntu and Other Linux](https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/05/xenlishm-minimalism-gtk-theme-800x450.jpeg)
Xenlism GTK 主题基于 Arc 主题其得益于许多主题的灵感。GTK 主题提供类似于 macOS 的 Windows 按钮我既不特别喜欢也没有特别不喜欢。GTK 主题采用扁平、简约的布局,我喜欢这样。
Xenlism 套件中有两个图标主题。Xenlism Wildfire 是以前的,已经进入我们的[最佳图标主题][8]列表。
![Beautiful Xenlism Wildfire theme for Ubuntu and Other Linux](https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/05/xenlism-wildfire-theme-800x450.jpeg)
*Xenlism Wildfire 图标*
Xenlsim Storm 是一个相对较新的图标主题,但同样美观。
![Beautiful Xenlism Storm theme for Ubuntu and Other Linux](https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/05/xenlism-storm-theme-1-800x450.jpeg)
*Xenlism Storm 图标*
Xenlism 主题在 GPL 许可下开源。
### 如何在 Ubuntu 18.04 上安装 Xenlism 主题包
Xenlism 开发提供了一种通过 PPA 安装主题包的更简单方法。尽管 PPA 可用于 Ubuntu 16.04,但我发现 GTK 主题不适用于 Unity。它适用于 Ubuntu 18.04 中的 GNOME 桌面。
打开终端(`Ctrl+Alt+T`)并逐个使用以下命令:
```
sudo add-apt-repository ppa:xenatt/xenlism
sudo apt update
```
该 PPA 提供四个包:
* xenlism-finewalls一组壁纸可直接在 Ubuntu 的壁纸中使用。截图中使用了其中一个壁纸。
* xenlism-minimalism-themeGTK 主题
* xenlism-storm一个图标主题见前面的截图
* xenlism-wildfire-icon-theme具有多种颜色变化的另一个图标主题文件夹颜色在变体中更改
你可以自己决定要安装的主题组件。就个人而言,我认为安装所有组件没有任何损害。
```
sudo apt install xenlism-minimalism-theme xenlism-storm-icon-theme xenlism-wildfire-icon-theme xenlism-finewalls
```
你可以使用 GNOME Tweaks 来更改主题和图标。如果你不熟悉该过程,我建议你阅读本教程以学习[如何在 Ubuntu 18.04 GNOME 中安装主题][9]。
### 在其他 Linux 发行版中获取 Xenlism 主题
你也可以在其他 Linux 发行版上安装 Xenlism 主题。各种 Linux 发行版的安装说明可在其网站上找到:
[安装 Xenlism 主题][10]
### 你怎么看?
我知道不是每个人都会同意我,但我喜欢这个主题。我想你将来会在 It's FOSS 的教程中会看到 Xenlism 主题的截图。
你喜欢 Xenlism 主题吗?如果不喜欢,你最喜欢什么主题?在下面的评论部分分享你的意见。
### 关于作者
我是一名专业软件开发人员,也是 It's FOSS 的创始人。我是一名狂热的 Linux 爱好者和开源爱好者。我使用 Ubuntu 并相信分享知识。除了Linux我喜欢经典侦探之谜。我是 Agatha Christie 作品的忠实粉丝。
--------------------------------------------------------------------------------
via: https://itsfoss.com/xenlism-theme/
作者:[Abhishek Prakash][a]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://itsfoss.com/author/abhishek/
[1]:https://itsfoss.com/author/abhishek/
[2]:https://itsfoss.com/xenlism-theme/#comments
[3]:https://itsfoss.com/category/desktop/
[4]:https://itsfoss.com/tag/themes/
[5]:https://itsfoss.com/tag/xenlism/
[6]:https://itsfoss.com/best-gtk-themes/
[7]:https://itsfoss.com/pop-icon-gtk-theme-ubuntu/
[8]:https://itsfoss.com/best-icon-themes-ubuntu-16-04/
[9]:https://itsfoss.com/install-themes-ubuntu/
[10]:http://xenlism.github.io/minimalism/#install

View File

@ -0,0 +1,246 @@
搭建属于你自己的 Git 服务器
======
![](https://www.linux.com/images/stories/41373/GitLab-3.png)
> 在本文中我们的目的是让你了解如何设置属于自己的Git服务器。
[Git][1] 是由 [Linux Torvalds 开发][2]的一个版本控制系统,现如今正在被全世界大量开发者使用。许多公司喜欢使用基于 Git 版本控制的 GitHub 代码托管。[根据报道GitHub 是现如今全世界最大的代码托管网站][3]。GitHub 宣称已经有 920 万用户和 2180 万个仓库。许多大型公司现如今也将代码迁移到 GitHub 上。[甚至于谷歌,一家搜索引擎公司,也正将代码迁移到 GitHub 上][4]。
### 运行你自己的 Git 服务器
GitHub 能提供极佳的服务,但却有一些限制,尤其是你是单人或是一名 coding 爱好者。GitHub 其中之一的限制就是其中免费的服务没有提供代码私有托管业务。[你不得不支付每月 7 美金购买 5 个私有仓库][5],并且想要更多的私有仓库则要交更多的钱。
万一你想要私有仓库或需要更多权限控制,最好的方法就是在你的服务器上运行 Git。不仅你能够省去一笔钱你还能够在你的服务器有更多的操作。在大多数情况下大多数高级 Linux 用户已经拥有自己的服务器,并且在这些服务器上方式 Git 就像“啤酒一样免费”LCTT 译注:指免费软件)。
在这篇教程中,我们主要讲在你的服务器上,使用两种代码管理的方法。一种是运行一个纯 Git 服务器,另一个是使用名为 [GitLab][6] 的 GUI 工具。在本教程中,我在 VPS 上运行的操作系统是 Ubuntu 14.04 LTS。
### 在你的服务器上安装 Git
在本篇教程中,我们考虑一个简单案例,我们有一个远程服务器和一台本地服务器,现在我们需要使用这两台机器来工作。为了简单起见,我们就分别叫它们为远程服务器和本地服务器。
首先,在两边的机器上安装 Git。你可以从依赖包中安装 Git在本文中我们将使用更简单的方法
```
sudo apt-get install git-core
```
为 Git 创建一个用户。
```
sudo useradd git
passwd git
```
为了容易的访问服务器,我们设置一个免密 ssh 登录。首先在你本地电脑上创建一个 ssh 密钥:
```
ssh-keygen -t rsa
```
这时会要求你输入保存密钥的路径,这时只需要点击回车保存在默认路径。第二个问题是输入访问远程服务器所需的密码。它生成两个密钥——公钥和私钥。记下您在下一步中需要使用的公钥的位置。
现在您必须将这些密钥复制到服务器上,以便两台机器可以相互通信。在本地机器上运行以下命令:
```
cat ~/.ssh/id_rsa.pub | ssh git@remote-server "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
```
现在,用 `ssh` 登录进服务器并为 Git 创建一个项目路径。你可以为你的仓库设置一个你想要的目录。
现在跳转到该目录中:
```
cd /home/swapnil/project-1.git
```
现在新建一个空仓库:
```
git init --bare
Initialized empty Git repository in /home/swapnil/project-1.git
```
现在我们需要在本地机器上新建一个基于 Git 版本控制仓库:
```
mkdir -p /home/swapnil/git/project
```
进入我们创建仓库的目录:
```
cd /home/swapnil/git/project
```
现在在该目录中创建项目所需的文件。留在这个目录并启动 `git`
```
git init
Initialized empty Git repository in /home/swapnil/git/project
```
把所有文件添加到仓库中:
```
git add .
```
现在,每次添加文件或进行更改时,都必须运行上面的 `add` 命令。 您还需要为每个文件更改都写入提交消息。提交消息基本上说明了我们所做的更改。
```
git commit -m "message" -a
[master (root-commit) 57331ee] message
2 files changed, 2 insertions(+)
create mode 100644 GoT.txt
create mode 100644 writing.txt
```
在这种情况下,我有一个名为 GoT《权力的游戏》的点评的文件并且我做了一些更改所以当我运行命令时它指定对文件进行更改。 在上面的命令中 `-a` 选项意味着提交仓库中的所有文件。 如果您只更改了一个,则可以指定该文件的名称而不是使用 `-a`
举一个例子:
```
git commit -m "message" GoT.txt
[master e517b10] message
1 file changed, 1 insertion(+)
```
到现在为止,我们一直在本地服务器上工作。现在我们必须将这些更改推送到远程服务器上,以便通过互联网访问,并且可以与其他团队成员进行协作。
```
git remote add origin ssh://git@remote-server/repo-<wbr< a="">>path-on-server..git
```
现在,您可以使用 `pull``push` 选项在服务器和本地计算机之间推送或拉取:
```
git push origin master
```
如果有其他团队成员想要使用该项目,则需要将远程服务器上的仓库克隆到其本地计算机上:
```
git clone git@remote-server:/home/swapnil/project.git
```
这里 `/home/swapnil/project.git` 是远程服务器上的项目路径,在你本机上则会改变。
然后进入本地计算机上的目录(使用服务器上的项目名称):
```
cd /project
```
现在他们可以编辑文件,写入提交更改信息,然后将它们推送到服务器:
```
git commit -m 'corrections in GoT.txt story' -a
```
然后推送改变:
```
git push origin master
```
我认为这足以让一个新用户开始在他们自己的服务器上使用 Git。 如果您正在寻找一些 GUI 工具来管理本地计算机上的更改,则可以使用 GUI 工具,例如 QGit 或 GitK for Linux。
![](https://www.linux.com/images/stories/41373/QGit.jpg)
### 使用 GitLab
这是项目所有者和协作者的纯命令行解决方案。这当然不像使用 GitHub 那么简单。不幸的是,尽管 GitHub 是全球最大的代码托管商,但是它自己的软件别人却无法使用。因为它不是开源的,所以你不能获取源代码并编译你自己的 GitHub。这与 WordPress 或 Drupal 不同,您无法下载 GitHub 并在您自己的服务器上运行它。
像往常一样在开源世界中是没有终结的尽头。GitLab 是一个非常优秀的项目。这是一个开源项目,允许用户在自己的服务器上运行类似于 GitHub 的项目管理系统。
您可以使用 GitLab 为团队成员或公司运行类似于 GitHub 的服务。您可以使用 GitLab 在公开发布之前开发私有项目。
GitLab 采用传统的开源商业模式。他们有两种产品:免费的开源软件,用户可以在自己的服务器上安装,以及类似于 GitHub 的托管服务。
可下载版本有两个版本,免费的社区版和付费企业版。企业版基于社区版,但附带针对企业客户的其他功能。它或多或少与 WordPress.org 或 Wordpress.com 提供的服务类似。
社区版具有高度可扩展性,可以在单个服务器或群集上支持 25000 个用户。GitLab 的一些功能包括Git 仓库管理,代码评论,问题跟踪,活动源和维基。它配备了 GitLab CI用于持续集成和交付。
Digital Ocean 等许多 VPS 提供商会为用户提供 GitLab 服务。 如果你想在你自己的服务器上运行它你可以手动安装它。GitLab 为不同的操作系统提供了软件包。 在我们安装 GitLab 之前,您可能需要配置 SMTP 电子邮件服务器,以便 GitLab 可以在需要时随时推送电子邮件。官方推荐使用 Postfix。所以先在你的服务器上安装 Postfix
```
sudo apt-get install postfix
```
在安装 Postfix 期间,它会问你一些问题,不要跳过它们。 如果你一不小心跳过,你可以使用这个命令来重新配置它:
```
sudo dpkg-reconfigure postfix
```
运行此命令时,请选择 “Internet Site”并为使用 Gitlab 的域名提供电子邮件 ID。
我是这样输入的:
```
xxx@x.com
```
用 Tab 键并为 postfix 创建一个用户名。接下来将会要求你输入一个目标邮箱。
在剩下的步骤中,都选择默认选项。当我们安装且配置完成后,我们继续安装 GitLab。
我们使用 `wget` 来下载软件包(用 [最新包][7] 替换下载链接)
```
wget https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.9.4-omnibus.1-1_amd64.deb
```
然后安装这个包:
```
sudo dpkg -i gitlab_7.9.4-omnibus.1-1_amd64.deb
```
现在是时候配置并启动 GitLab 了。
```
sudo gitlab-ctl reconfigure
```
您现在需要在配置文件中配置域名,以便您可以访问 GitLab。打开文件。
```
nano /etc/gitlab/gitlab.rb
```
在这个文件中编辑 `external_url` 并输入服务器域名。保存文件,然后从 Web 浏览器中打开新建的一个 GitLab 站点。
![](https://www.linux.com/images/stories/41373/GitLab-1.jpg)
默认情况下,它会以系统管理员的身份创建 `root`,并使用 `5iveL!fe` 作为密码。 登录到 GitLab 站点,然后更改密码。
![](https://www.linux.com/images/stories/41373/GitLab-2.png)
密码更改后,登录该网站并开始管理您的项目。
![](https://www.linux.com/images/stories/41373/GitLab-3.png)
GitLab 有很多选项和功能。最后,我借用电影“黑客帝国”中的经典台词:“不幸的是,没有人知道 GitLab 可以做什么。你必须亲自尝试一下。”
--------------------------------------------------------------------------------
via: https://www.linux.com/learn/how-run-your-own-git-server
作者:[Swapnil Bhartiya][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[wyxplus](https://github.com/wyxplus)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linux.com/users/arnieswap
[1]:https://github.com/git/git
[2]:https://www.linuxfoundation.org/blog/10-years-of-git-an-interview-with-git-creator-linus-torvalds/
[3]:https://github.com/about/press
[4]:http://google-opensource.blogspot.com/2015/03/farewell-to-google-code.html
[5]:https://github.com/pricing
[6]:https://about.gitlab.com/
[7]:https://about.gitlab.com/downloads/

View File

@ -1,49 +1,50 @@
五个最热门的开源机器学习 JavaScript 框架
======
> 如果是你一位想要深入机器学习的 JavaScript 程序员或想成为一位使用 JavaScript 的机器学习专家,那么这些开源框架也许会吸引你。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/web-spider-frame-framework-2.png?itok=ng6O0fd4)
开源工具的可用性使得开发者能够更加轻松地开发应用这一点使机器学习领域本身获得了巨大的极高。例如AndreyBu他来自德国在机器学习领域拥有五年以上的经验他一直在使用各种各样的开源框架来创造富有魅力的机器学习项目。
开源工具的涌现使得开发者能够更加轻松地开发应用,这一点使机器学习领域本身获得了极大增长例如AndreyBu他来自德国在机器学习领域拥有五年以上的经验他一直在使用各种各样的开源框架来创造富有魅力的机器学习项目。
虽然 python 支持绝大多数的机器学习框架,但是 JavaScript 也并没有被抛弃。JavaScript 开发者可以在浏览器中使用各种框架来训练和部署机器学习模型。
虽然 Python 是绝大多数的机器学习框架所采用的语言,但是 JavaScript 也并没有被抛下。JavaScript 开发者可以在浏览器中使用各种框架来训练和部署机器学习模型。
下面是 JavaScript 中最热门五个机器学习框架
### 1\. TensorFlow.js
### 1 TensorFlow.js
[TensorFlow.js][2] 是一个开源库,它使你能在浏览器中完整地运行机器学习程序,它是 Deeplearn.js 的继承者Deeplearn.js 不再被提供更新。TensorFlow.js 在 Deeplearn.js 功能的基础上进行了改善,使你能够充分利用浏览器,得到更加深入的机器学习经验。
[TensorFlow.js][2] 是一个开源库,它使你能在浏览器中完整地运行机器学习程序,它是 Deeplearn.js 的继承者Deeplearn.js 不再更新。TensorFlow.js 在 Deeplearn.js 功能的基础上进行了改善,使你能够充分利用浏览器,得到更加深入的机器学习经验。
通过这个开源库,你可以在浏览器中使用有各种功能的、直观的 API 来定义、训练和部署模型。除此之外,它能够自动为 WebGL 和 Node.js 提供支持。
通过这个开源库,你可以在浏览器中使用有各种功能的、直观的 API 来定义、训练和部署模型。除此之外,它自动提供 WebGL 和 Node.js 的支持。
如果您有了一个已经训练过的模型你想要导入到浏览器中。TensorFlow.js 可以让你做到这一点,你也可以在不离开浏览器的情况下重新训练已有的模型。
现在有很多在浏览器中提供广泛的机器学习功能的资源型开源工具这个机器学习工具库就是这些开源工具的集合。这个工具库为好几种机器学习算法提供支持包括非监督式学习、监督式学习、数据处理、人工神经网络ANN、数学和回归。
### 2、 机器学习工具库
如果你以前使用 python现在想找类似于 Scikit-learn 的,能在浏览器中使用 JavaScript 进行机器学习的工具,这套工具会满足你的要求
现在有很多在浏览器中提供广泛的机器学习功能的资源型开源工具,这个[机器学习工具库][3]就是这些开源工具的集合。这个工具库为好几种机器学习算法提供支持包括非监督式学习、监督式学习、数据处理、人工神经网络ANN、数学和回归
### 3\. Keras.js
如果你以前使用 Python现在想找类似于 Scikit-learn 的,能在浏览器中使用 JavaScript 进行机器学习的工具,这套工具会满足你的要求。
### 3、 Keras.js
[Keras.js][4] 是另外一个热门的开源框架,它使你能够在浏览器中运行机器学习模型,它使用 WebGL 来提供 GPU 模式的支持。如果你有使用 Node.js 的模型,你就只能在 GPU 模式下运行它。Keras.js 还为使用任意后端框架的模型训练提供支持,例如 Microsoft Cognitive Toolkit (CNTK) 。
一些 Keras 模型可以部署在客户端浏览器上,包括 Inception v3 (训练在 ImageNet 上)50 层冗余网络(训练在 ImageNet 上),和卷积变化自动编码器(训练在 MNIST 上)。
### 4\. Brain.js
### 4 Brain.js
机器学习里的概念非常重要,它可能会使刚开始进入这个领域的人们气馁,这个领域里的学术用语和专业词汇可能会使初学者感到崩溃,而解决以上问题的能力就是 Brain.js 的优势所在。它是开源的,基于 JavaScript 的框架,简化了定义、训练和运行神经网络的流程。
机器学习里的概念非常重要,它可能会使刚开始进入这个领域的人们气馁,这个领域里的学术用语和专业词汇可能会使初学者感到崩溃,而解决以上问题的能力就是 [Brain.js][5] 的优势所在。它是开源的,基于 JavaScript 的框架,简化了定义、训练和运行神经网络的流程。
如果你是一个 JavaScript 开发者并且在机器学习领域是完全的新手Brain.js 能减低你学习的难度曲线。它可以和 Node.js 一起使用或者运行在客户端浏览器里来训练机器学习模型。Brain.js 支持部分类型的神经网络包括前馈式网络、Ellman 网络,和门循环单元网络。
### 5\. STDLib
### 5 STDLib
[STDLib][6] 是一个基于 JavaScript 和 Node.js 应用的开源库,如果您正在寻找一种在浏览器中运行,支持科学和数字化的基于 web 的机器学习应用STDLib 能满足你的需要。
这个库能提供全面而先进的数学和统计学上的功能,来帮助你构建高性能的机器学习模型。你同样也可以使用它扩展的公用程序来构建应用程序和其他的库。除此之外,如果你想要一个数据可视化和探索性数据分析的框架。
STDLib值得拥有。
这个库能提供全面而先进的数学和统计学上的功能,来帮助你构建高性能的机器学习模型。你同样也可以使用它丰富的功能来构建应用程序和其他的库。除此之外,如果你想要一个数据可视化和探索性数据分析的框架 —— STDLib值得拥有。
### Conclusion
### 总结
如果你是一个 JavaScript 开发者,并且打算深入研究令人兴奋的机器学习世界,或者说,你是一个机器学习方面的专家,打算开始尝试使用 JavaScript ,那么上述的开源框架会激起您的兴趣。
@ -56,7 +57,7 @@ via: https://opensource.com/article/18/5/machine-learning-javascript-frameworks
作者:[Dr.Michael J.Garbade][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[hopefully2333](https://github.com/hopefully2333)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,13 +1,13 @@
3个 Python 命令行工具
3 个 Python 命令行工具
======
> 用 Click、Docopt 和 Fire 库写你自己的命令行应用。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/osdc-lead-tool-box.png?itok=NrJYb417)
这篇文章是与 [Lacey Williams Hensche][1] 共同撰写的
有时对于某项工作来说一个命令行工具就足以胜任。命令行工具是一种从你的 shell 或者终端之类的地方交互或运行的程序。[Git][2] 和 [Curl][3] 就是两个你也许已经很熟悉的命令行工具
有时对于某项工作来说一个命令行工具就足以胜任。命令行工具是一个交互程序,类似你的 shell 或者终端。[Git][2] 和 [Curl][3] 就是两个你也许已经很熟悉的命令行工具。
当你有一小段代码需要在一行中执行多次或者经常性地被执行命令行工具会很实用。Django 开发者执行 `./manage.py runserver` 命令来启动他们的网络服务器Docker 开发者执行 `docker-compose up` 来启动他们的容器。你想要写一个命令行工具的原因可能和你一开始想写代码的原因有很大不同。
当你有一小段代码需要在一行中执行多次或者经常性地被执行命令行工具就会很有用。Django 开发者执行 `./manage.py runserver` 命令来启动他们的网络服务器Docker 开发者执行 `docker-compose up` 来启动他们的容器。你想要写一个命令行工具的原因可能和你一开始想写代码的原因有很大不同。
对于这个月的 Python 专栏,我们有 3 个库想介绍给希望为自己编写命令行工具的 Python 使用者。
@ -19,24 +19,24 @@
* 包含说明如何将命令行工具打包成一个更加易于执行的 Python 应用程序
* 自动生成实用的帮助文本
* 使你能够叠加使用可选和必要参数,甚至是 [多个命令][5]
* 有一个 Django 版本( [`django-click`][6] )来编写管理命令
* 有一个 Django 版本( [`django-click`][6] 来编写管理命令
Click 使用 `@click.command()` 去声明一个函数作为命令,同时可以指定必要和可选参数。
```
# hello.py
import click
import click
@click.command()
@click.option('--name', default='', help='Your name')
def say_hello(name):
    click.echo("Hello {}!".format(name))
click.echo("Hello {}!".format(name))
if __name__ == '__main__':
    hello()
say_hello()
```
`@click.option()` 修饰器声明了一个 [可选参数][7] 并且 `@click.argument()` 修饰器声明了一个 [必要参数][8]。你可以通过叠加修饰器来组合可选和必要参数。`echo()` 方法将结果打印到控制台。
`@click.option()` 修饰器声明了一个 [可选参数][7] ,而 `@click.argument()` 修饰器声明了一个 [必要参数][8]。你可以通过叠加修饰器来组合可选和必要参数。`echo()` 方法将结果打印到控制台。
```
$ python hello.py --name='Lacey'
@ -45,42 +45,42 @@ Hello Lacey!
### Docopt
[Docopt][9] 是一个命令行工具解析器,类似于命令行工具的 Markdown。如果你喜欢流畅地编写应用文档在本文推荐的库中 Docopt 有着最好的格式化帮助文本。它不是我们最爱的命令行工具开发包的原因是它的文档犹如把人扔进深渊,使你开始使用时会有一些小困难。然而,它仍是一个轻量级广受欢迎的库,特别是当一个漂亮的说明文档对你来说很重要的时候。
[Docopt][9] 是一个命令行工具解析器,类似于命令行工具的 Markdown。如果你喜欢流畅地编写应用文档在本文推荐的库中 Docopt 有着最好的格式化帮助文本。它不是我们最爱的命令行工具开发包的原因是它的文档犹如把人扔进深渊,使你开始使用时会有一些小困难。然而,它仍是一个轻量级的、广受欢迎的库,特别是当一个漂亮的说明文档对你来说很重要的时候。
Docopt 对于如何格式化文章开头的 docstring 是很特别的。在工具名称后面的 docsring 中,顶部元素必须是“Usage:”并且需要列出你希望命令被调用的方式(比如:自身调用,使用参数等等)。Usage 需要包含 **help****version** 标记
Docopt 对于如何格式化文章开头的 docstring 是很特别的。在工具名称后面的 docsring 中,顶部元素必须是 `Usage:` 并且需要列出你希望命令被调用的方式(比如:自身调用,使用参数等等)。`Usage:` 需要包含 `help``version` 参数
docstring 中的第二个元素是“Options:”对于在“Usages:”中提及的可选项和参数,它应当提供更多的信息。你的 docstring 的内容变成了你帮助文本的内容。
docstring 中的第二个元素是 `Options:`,对于在 `Usages:` 中提及的可选项和参数,它应当提供更多的信息。你的 docstring 的内容变成了你帮助文本的内容。
```
"""HELLO CLI
Usage:
    hello.py
    hello.py <name>
    hello.py -h|--help
    hello.py -v|--version
hello.py
hello.py <name>
hello.py -h|--help
hello.py -v|--version
Options:
    <name>  Optional name argument.
    -h --help  Show this screen.
    -v --version  Show version.
<name> Optional name argument.
-h --help Show this screen.
-v --version Show version.
"""
from docopt import docopt
def say_hello(name):
    return("Hello {}!".format(name))
return("Hello {}!".format(name))
if __name__ == '__main__':
    arguments = docopt(__doc__, version='DEMO 1.0')
    if arguments['<name>']:
        print(say_hello(arguments['<name>']))
    else:
        print(arguments)
arguments = docopt(__doc__, version='DEMO 1.0')
if arguments['<name>']:
print(say_hello(arguments['<name>']))
else:
print(arguments)
```
在最基本的层面Docopt 被设计用来返回你的参数键值对。如果我不指定名字调用上面的命令,我会得到一个字典的返回:
在最基本的层面Docopt 被设计用来返回你的参数键值对。如果我不指定上述的 `name` 调用上面的命令,我会得到一个字典的返回
```
$ python hello.py
@ -91,20 +91,20 @@ $ python hello.py
这里可看到我没有输入 `help``version` 标记并且 `name` 参数是 `None`
但是如果我带着一个 name 参数调用,`say_hello` 函数就会执行了。
但是如果我带着一个 `name` 参数调用,`say_hello` 函数就会执行了。
```
$ python hello.py Jeff
Hello Jeff!
```
Docopt 允许同时定必要和可选参数,且各自有着不同的语法约定。必要参数需要在 `ALLCAPS``<carets>` 中展示,而可选参数需要单双横杠显示,就像--like。更多内容可以阅读 Docopt 有关 [patterns][10] 的文档。
Docopt 允许同时定必要和可选参数,且各自有着不同的语法约定。必要参数需要在 `ALLCAPS``<carets>` 中展示,而可选参数需要单双横杠显示,就像 `--like`。更多内容可以阅读 Docopt 有关 [patterns][10] 的文档。
### Fire
[Fire][11] 是谷歌的一个命令行工具开发库。尤其令人喜欢的是当你的命令需要更多复杂参数或者处理 Python 对象时,它会聪明地尝试解析你的参数类型。
Fire 的 [文档][12] 包括了海量的样例但是我希望这些文档能被更好地组织。Fire 能够处理 [同一个文件中的多条命令][13]、使用 [对象][14] 的方法作为命令和 [组][15] 命令。
Fire 的 [文档][12] 包括了海量的样例但是我希望这些文档能被更好地组织。Fire 能够处理 [同一个文件中的多条命令][13]、使用 [对象][14] 的方法作为命令和 [组][15] 命令。
它的弱点在于输出到控制台的文档。命令行中的 docstring 不会出现在帮助文本中,并且帮助文本也不一定标识出参数。
@ -113,11 +113,11 @@ import fire
def say_hello(name=''):
    return 'Hello {}!'.format(name)
return 'Hello {}!'.format(name)
if __name__ == '__main__':
  fire.Fire()
fire.Fire()
```
参数是必要还是可选取决于你是否在函数或者方法定义中为其指定了一个默认值。要调用命令,你必须指定文件名和函数名,比较类似 Click 的语法:
@ -129,7 +129,7 @@ Hello Rikki!
你还可以像标记一样传参,比如 `--name=Rikki`
### 额外奖赏:打包!
### 额外赠送:打包!
Click 包含了使用 `setuptools` [打包][16] 命令行工具的使用说明(强烈推荐按照说明操作)。
@ -139,20 +139,20 @@ Click 包含了使用 `setuptools` [打包][16] 命令行工具的使用说明
from setuptools import setup
setup(
    name='hello',
    version='0.1',
    py_modules=['hello'],
    install_requires=[
        'Click',
    ],
    entry_points='''
        [console_scripts]
        hello=hello:say_hello
    ''',
name='hello',
version='0.1',
py_modules=['hello'],
install_requires=[
'Click',
],
entry_points='''
[console_scripts]
hello=hello:say_hello
''',
)
```
任何你看见 `hello` 的地方,使用你自己的模块名称替换掉,但是要记得忽略`.py` 后缀名。将 `say_hello` 替换成你的函数名称。
任何你看见 `hello` 的地方,使用你自己的模块名称替换掉,但是要记得忽略 `.py` 后缀名。将 `say_hello` 替换成你的函数名称。
然后,执行 `pip install --editable` 来使你的命令在命令行中可用。
@ -169,10 +169,10 @@ Hello Jeff!
via: https://opensource.com/article/18/5/3-python-command-line-tools
作者:[Jeff Triplett][a]
作者:[Jeff Triplett][a][Lacey Williams Hensche][1]
选题:[lujun9972](https://github.com/lujun9972)
译者:[hoppipolla-](https://github.com/hoppipolla-)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,228 @@
你所不了解的 Bash关于 Bash 数组的介绍
======
> 进入这个古怪而神奇的 Bash 数组的世界。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/programming-code-keyboard-laptop.png?itok=pGfEfu2S)
尽管软件工程师常常使用命令行来进行各种开发,但命令行中的数组似乎总是一个模糊的东西(虽然不像正则操作符 `=~` 那么复杂隐晦)。除开隐晦和有疑问的语法,[Bash][1] 数组其实是非常有用的。
### 稍等,这是为什么?
写 Bash 相关的东西很难,但如果是写一篇像手册那样注重怪异语法的文章,就会非常简单。不过请放心,这篇文章的目的就是让你不用去读该死的使用手册。
#### 真实(通常是有用的)示例
为了这个目的,想象一下真实世界的场景以及 Bash 是怎么帮忙的:你正在公司里面主导一个新工作,评估并优化内部数据管线的运行时间。首先,你要做个参数扫描分析来评估管线使用线程的状况。简单起见,我们把这个管道当作一个编译好的 C++ 黑盒子,这里面我们能够调整的唯一的参数是用于处理数据的线程数量:`./pipeline --threads 4`。
### 基础
我们首先要做的事是定义一个数组,用来容纳我们想要测试的 `--threads` 参数:
```
allThreads=(1 2 4 8 16 32 64 128)
```
本例中所有元素都是数字但参数并不一定是数字Bash 中的数组可以容纳数字和字符串,比如 `myArray=(1 2 "three" 4 "five")` 就是个有效的表达式。就像 Bash 中其它的变量一样,确保赋值符号两边没有空格。否则 Bash 将会把变量名当作程序来执行,把 `=` 当作程序的第一个参数。
现在我们初始化了数组,让我们解析它其中的一些元素。仅仅输入 `echo $allThreads` ,你能发现,它只会输出第一个元素。
要理解这个产生的原因,需要回到上一步,回顾我们一般是怎么在 Bash 中输出变量。考虑以下场景:
```
type="article"
echo "Found 42 $type"
```
假如我们得到的变量 `$type` 是一个单词,我们想要添加在句子结尾一个 `s`。我们无法直接把 `s` 加到 `$type` 里面,因为这会把它变成另一个变量,`$types`。尽管我们可以利用像 `echo "Found 42 "$type"s"` 这样的代码形变,但解决这个问题的最好方法是用一个花括号:`echo "Found 42 ${type}s"`,这让我们能够告诉 Bash 变量名的起止位置有趣的是JavaScript/ES6 在 [template literals][2] 中注入变量和表达式的语法和这里是一样的)
事实上,尽管 Bash 变量一般不用花括号,但在数组中需要用到花括号。这反而允许我们指定要访问的索引,例如 `echo ${allThreads[1]}` 返回的是数组中的第二个元素。如果不写花括号,比如 `echo $allThreads[1]`,会导致 Bash 把 `[1]` 当作字符串然后输出。
是的Bash 数组的语法很怪,但是至少他们是从 0 开始索引的,不像有些语言(说的就是你,`R` 语言)。
### 遍历数组
上面的例子中我们直接用整数作为数组的索引,我们现在考虑两种其他情况:第一,如果想要数组中的第 `$i` 个元素,这里 `$i` 是一个代表索引的变量,我们可以这样 `echo ${allThreads[$i]}` 解析这个元素。第二,要输出一个数组的所有元素,我们把数字索引换成 `@` 符号(你可以把 `@` 当作表示 `all` 的符号):`echo ${allThreads[@]}`。
#### 遍历数组元素
记住上面讲过的,我们遍历 `$allThreads` 数组,把每个值当作 `--threads` 参数启动管线:
```
for t in ${allThreads[@]}; do
  ./pipeline --threads $t
done
```
#### 遍历数组索引
接下来,考虑一个稍稍不同的方法。不遍历所有的数组元素,我们可以遍历所有的索引:
```
for i in ${!allThreads[@]}; do
  ./pipeline --threads ${allThreads[$i]}
done
```
一步一步看:如之前所见,`${allThreads[@]}` 表示数组中的所有元素。前面加了个感叹号,变成 `${!allThreads[@]}`,这会返回数组索引列表(这里是 0 到 7。换句话说。`for` 循环就遍历所有的索引 `$i` 并从 `$allThreads` 中读取第 `$i` 个元素,当作 `--threads` 选项的参数。
这看上去很辣眼睛,你可能奇怪为什么我要一开始就讲这个。这是因为有时候在循环中需要同时获得索引和对应的值,例如,如果你想要忽视数组中的第一个元素,使用索引可以避免额外创建在循环中累加的变量。
### 填充数组
到目前为止,我们已经能够用给定的 `--threads` 选项启动管线了。现在假设按秒计时的运行时间输出到管线。我们想要捕捉每个迭代的输出,然后把它保存在另一个数组中,因此我们最终可以随心所欲的操作它。
#### 一些有用的语法
在深入代码前,我们要多介绍一些语法。首先,我们要能解析 Bash 命令的输出。用这个语法可以做到:`output=$( ./my_script.sh )`,这会把命令的输出存储到变量 `$output` 中。
我们需要的第二个语法是如何把我们刚刚解析的值添加到数组中。完成这个任务的语法看起来很熟悉:
```
myArray+=( "newElement1" "newElement2" )
```
#### 参数扫描
万事具备,执行参数扫描的脚步如下:
```
allThreads=(1 2 4 8 16 32 64 128)
allRuntimes=()
for t in ${allThreads[@]}; do
runtime=$(./pipeline --threads $t)
allRuntimes+=( $runtime )
done
```
就是这个了!
### 还有什么能做的?
这篇文章中,我们讲过使用数组进行参数扫描的场景。我敢保证有很多理由要使用 Bash 数组,这里就有两个例子:
#### 日志警告
本场景中,把应用分成几个模块,每一个都有它自己的日志文件。我们可以编写一个 cron 任务脚本,当某个模块中出现问题标志时向特定的人发送邮件:
```
# 日志列表,发生问题时应该通知的人
logPaths=("api.log" "auth.log" "jenkins.log" "data.log")
logEmails=("jay@email" "emma@email" "jon@email" "sophia@email")
# 在每个日志中查找问题标志
for i in ${!logPaths[@]};
do
  log=${logPaths[$i]}
  stakeholder=${logEmails[$i]}
  numErrors=$( tail -n 100 "$log" | grep "ERROR" | wc -l )
# 如果近期发现超过 5 个错误,就警告负责人
  if [[ "$numErrors" -gt 5 ]];
  then
    emailRecipient="$stakeholder"
    emailSubject="WARNING: ${log} showing unusual levels of errors"
    emailBody="${numErrors} errors found in log ${log}"
    echo "$emailBody" | mailx -s "$emailSubject" "$emailRecipient"
  fi
done
```
#### API 查询
如果你想要生成一些分析数据,分析你的 Medium 帖子中用户评论最多的。由于我们无法直接访问数据库SQL 不在我们考虑范围,但我们可以用 API
为了避免陷入关于 API 授权和令牌的冗长讨论,我们将会使用 [JSONPlaceholder][3],这是一个面向公众的测试服务 API。一旦我们查询每个帖子解析出每个评论者的邮箱我们就可以把这些邮箱添加到我们的结果数组里
```
endpoint="https://jsonplaceholder.typicode.com/comments"
allEmails=()
# 查询前 10 个帖子
for postId in {1..10};
do
# 执行 API 调用,获取该帖子评论者的邮箱
  response=$(curl "${endpoint}?postId=${postId}")
 
# 使用 jq 把 JSON 响应解析成数组
  allEmails+=( $( jq '.[].email' <<< "$response" ) )
done
```
注意这里我是用 [jq 工具][4] 从命令行里解析 JSON 数据。关于 `jq` 的语法超出了本文的范围,但我强烈建议你了解它。
你可能已经想到,使用 Bash 数组在数不胜数的场景中很有帮助,我希望这篇文章中的示例可以给你思维的启发。如果你从自己的工作中找到其它的例子想要分享出来,请在帖子下方评论。
### 请等等,还有很多东西!
由于我们在本文讲了很多数组语法,这里是关于我们讲到内容的总结,包含一些还没讲到的高级技巧:
| 语法 | 效果 |
|:--|:--|
| `arr=()` | 创建一个空数组 |
| `arr=(1 2 3)` | 初始化数组 |
| `${arr[2]}` | 取得第三个元素 |
| `${arr[@]}` | 取得所有元素 |
| `${!arr[@]}` | 取得数组索引 |
| `${#arr[@]}` | 计算数组长度 |
| `arr[0]=3` | 覆盖第 1 个元素 |
| `arr+=(4)` | 添加值 |
| `str=$(ls)` | 把 `ls` 输出保存到字符串 |
| `arr=( $(ls) )` | 把 `ls` 输出的文件保存到数组里 |
| `${arr[@]:s:n}` | 取得从索引 `s` 开始的 `n` 个元素 |
### 最后一点思考
正如我们所见Bash 数组的语法很奇怪,但我希望这篇文章让你相信它们很有用。只要你理解了这些语法,你会发现以后会经常使用 Bash 数组。
#### Bash 还是 Python
问题来了:什么时候该用 Bash 数组而不是其他的脚本语法,比如 Python
对我而言,完全取决于需求——如果你可以只需要调用命令行工具就能立马解决问题,你也可以用 Bash。但有些时候当你的脚本属于一个更大的 Python 项目时,你也可以用 Python。
比如,我们可以用 Python 来实现参数扫描,但我们只用编写一个 Bash 的包装:
```
import subprocess
all_threads = [1, 2, 4, 8, 16, 32, 64, 128]
all_runtimes = []
# 用不同的线程数字启动管线
for t in all_threads:
  cmd = './pipeline --threads {}'.format(t)
# 使用子线程模块获得返回的输出
  p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
  output = p.communicate()[0]
  all_runtimes.append(output)
```
由于本例中没法避免使用命令行,所以可以优先使用 Bash。
#### 羞耻的宣传时间
如果你喜欢这篇文章,这里还有很多类似的文章! [在此注册,加入 OSCON][5]2018 年 7 月 17 号我会在这做一个主题为 [你所不了解的 Bash][6] 的在线编码研讨会。没有幻灯片,不需要门票,只有你和我在命令行里面敲代码,探索 Bash 中的奇妙世界。
本文章由 [Medium] 首发,再发布时已获得授权。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/5/you-dont-know-bash-intro-bash-arrays
作者:[Robert Aboukhalil][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[BriFuture](https://github.com/BriFuture)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/robertaboukhalil
[1]:https://opensource.com/article/17/7/bash-prompt-tips-and-tricks
[2]:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
[3]:https://github.com/typicode/jsonplaceholder
[4]:https://stedolan.github.io/jq/
[5]:https://conferences.oreilly.com/oscon/oscon-or
[6]:https://conferences.oreilly.com/oscon/oscon-or/public/schedule/detail/67166
[7]:https://medium.com/@robaboukhalil/the-weird-wondrous-world-of-bash-arrays-a86e5adf2c69

View File

@ -0,0 +1,86 @@
2018 年 6 月 COPR 中值得尝试的 4 个很酷的新项目
======
![](https://fedoramagazine.org/wp-content/uploads/2017/08/4-copr-1024x433.jpg)
COPR 是个人软件仓库[集合][1],它不在 Fedora 中。这是因为某些软件不符合轻松打包的标准。或者它可能不符合其他 Fedora 标准尽管它是免费和开源的。COPR 可以在 Fedora 套件之外提供这些项目。COPR 中的软件不被 Fedora 基础设施不支持或没有被该项目所签名。但是,这是一种尝试新的或实验性的软件的一种巧妙的方式。
这是 COPR 中一组新的有趣项目。
### Ghostwriter
[Ghostwriter][2] 是 [Markdown][3] 格式的文本编辑器,它有一个最小的界面。它以 HTML 格式提供文档预览,并为 Markdown 提供语法高亮显示。它提供了仅高亮显示当前正在编写的段落或句子的选项。此外Ghostwriter 可以将文档导出为多种格式,包括 PDF 和 HTML。最后它有所谓的“海明威”模式其中删除被禁用迫使用户现在智能编写而在稍后编辑。
![][4]
#### 安装说明
仓库目前为 Fedora 26、27、28 和 Rawhide 以及 EPEL 7 提供 Ghostwriter。要安装 Ghostwriter请使用以下命令
```
sudo dnf copr enable scx/ghostwriter
sudo dnf install ghostwriter
```
### Lector
[Lector][5] 是一个简单的电子书阅读器程序。Lector 支持最常见的电子书格式,如 EPUB、MOBI 和 AZW以及漫画书格式 CBZ 和 CBR。它很容易设置 —— 只需指定包含电子书的目录即可。你可以使用表格或书籍封面浏览 Lector 库内的书籍。Lector 的功能包括书签、用户自定义标签和内置字典。![][6]
#### 安装说明
该仓库目前为 Fedora 26、27、28 和 Rawhide 提供Lector。要安装 Lector请使用以下命令
```
sudo dnf copr enable bugzy/lector
sudo dnf install lector
```
### Ranger
Ranerger 是一个基于文本的文件管理器,它带有 Vim 键绑定。它以三列显示目录结构。左边显示父目录中间显示当前目录的内容右边显示所选文件或目录的预览。对于文本文件Ranger 将文件的实际内容作为预览。![][7]
#### 安装说明
该仓库目前为 Fedora 27、28 和 Rawhide 提供 Ranger。要安装 Ranger请使用以下命令
```
sudo dnf copr enable fszymanski/ranger
sudo dnf install ranger
```
### PrestoPalette
PrestoPeralette 是一款帮助创建平衡调色板的工具。PrestoPalette 的一个很好的功能是能够使用光照来影响调色板的亮度和饱和度。你可以将创建的调色板导出为 PNG 或 JSON。
![][8]
#### 安装说明
仓库目前为 Fedora 26、27、28 和 Rawhide 以及 EPEL 7 提供 PrestoPalette。要安装 PrestoPalette请使用以下命令
```
sudo dnf copr enable dagostinelli/prestopalette
sudo dnf install prestopalette
```
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/4-try-copr-june-2018/
作者:[Dominik Turecek][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://fedoramagazine.org
[1]:https://copr.fedorainfracloud.org/
[2]:http://wereturtle.github.io/ghostwriter/
[3]:https://daringfireball.net/
[4]:https://fedoramagazine.org/wp-content/uploads/2018/05/ghostwriter.png
[5]:https://github.com/BasioMeusPuga/Lector
[6]:https://fedoramagazine.org/wp-content/uploads/2018/05/lector.png
[7]:https://fedoramagazine.org/wp-content/uploads/2018/05/ranger.png
[8]:https://fedoramagazine.org/wp-content/uploads/2018/05/prestopalette.png

View File

@ -0,0 +1,71 @@
你应该了解的 6 个开源 AI 工具
======
> 让我们来看看几个任何人都能用的自由开源的 AI 工具。
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/artificial-intelligence-3382507_1920.jpg?itok=HarDnwVX)
在开源领域,不管你的想法是多少的新颖独到,先去看一下别人是否已经做成了这个概念,总是一个很明智的做法。对于有兴趣借助不断成长的<ruby>人工智能<rt>Artificial Intelligence</rt></ruby>AI的力量的组织和个人来说许多优秀的工具不仅是自由开源的而且在很多的情况下它们都已经过测试和久经考验的。
在领先的公司和非盈利组织中AI 的优先级都非常高,并且这些公司和组织都开源了很有价值的工具。下面的举例是任何人都可以使用的自由开源的 AI 工具。
### Acumos
[Acumos AI][1] 是一个平台和开源框架,使用它可以很容易地去构建、共享和分发 AI 应用。它规范了运行一个“开箱即用的”通用 AI 环境所需要的<ruby>基础设施栈<rt>infrastructure stack</rt></ruby>和组件。这使得数据科学家和模型训练者可以专注于它们的核心竞争力,而不用在无止境的定制、建模,以及训练一个 AI 实现上浪费时间。
Acumos 是 [LF 深度学习基金会][2] 的一部分,它是 Linux 基金会中的一个组织,它支持在人工智能、<ruby>机器学习<rt>machine learning</rt><ruby>、以及<ruby>深度学习<rt>deep learning</rt></ruby>方面的开源创新。它的目标是让这些重大的新技术可用于开发者和数据科学家,包括那些在深度学习和 AI 上经验有限的人。LF 深度学习基金会 [最近批准了一个项目生命周期和贡献流程][3],并且它现在正接受项目贡献的建议。
### Facebook 的框架
Facebook [开源了][4] 其中心机器学习系统,它设计用于做一些大规模的人工智能任务,以及一系列其它的 AI 技术。这个工具是经过他们公司验证使用的平台的一部分。Facebook 也开源了一个叫 [Caffe2][5] 的深度学习和人工智能的框架。
### CaffeOnSpark
**说到 Caffe**。 Yahoo 也在开源许可证下发布了它自己的关键的 AI 软件。[CaffeOnSpark 工具][6] 是基于深度学习的它是人工智能的一个分支在帮助机器识别人类语言或者照片、视频的内容方面非常有用。同样地IBM 的机器学习程序 [SystemML][7] 可以通过 Apache 软件基金会自由地共享和修改。
### Google 的工具
Google 花费了几年的时间开发了它自己的 [TensorFlow][8] 软件框架,用于去支持它的 AI 软件和其它预测和分析程序。TensorFlow 是你可能都已经在使用的一些 Google 工具背后的引擎,包括 Google Photos 和在 Google app 中使用的语言识别。
Google 开源了两个 [AIY 套件][9],它可以让个人很容易地使用人工智能,它们专注于计算机视觉和语音助理。这两个套件将用到的所有组件封装到一个盒子中。该套件目前在美国的 Target 中有售,并且它是基于开源的树莓派平台的 —— 有越来越多的证据表明,在开源和 AI 交集中将发生非常多的事情。
### H2O.ai
我 [以前介绍过][10] H2O.ai它在机器学习和人工智能领域中占有一席之地因为它的主要工具是自由开源的。你可以获取主要的 H2O 平台和 Sparkling Water它与 Apache Spark 一起工作,只需要去 [下载][11] 它们即可。这些工具遵循 Apache 2.0 许可证,它是一个非常灵活的开源许可证,你甚至可以在 Amazon Web 服务AWS和其它的集群上运行它们而这仅需要几百美元而已。
### Microsoft 入局
“我们的目标是让 AI 大众化,让每个人和组织获得更大的成就,“ Microsoft CEO 萨提亚·纳德拉 [说][12]。因此,微软持续迭代它的 [Microsoft Cognitive Toolkit][13]CNTK。它是一个能够与 TensorFlow 和 Caffe 去竞争的一个开源软件框架。Cognitive Toolkit 可以工作在 64 位的 Windows 和 Linux 平台上。
Cognitive Toolkit 团队的报告称“Cognitive Toolkit 通过允许用户去创建、训练,以及评估他们自己的神经网络,以使企业级的、生产系统级的 AI 成为可能,这些神经网络可能跨多个 GPU 以及多个机器在大量的数据集中高效伸缩。”
---
从来自 Linux 基金会的新电子书中学习更多的有关 AI 知识。Ibrahim Haddad 的 [开源 AI项目、洞察和趋势][14] 调查了 16 个流行的开源 AI 项目—— 深入研究了他们的历史、代码库、以及 GitHub 的贡献。 [现在可以免费下载这个电子书][14]。
--------------------------------------------------------------------------------
via: https://www.linux.com/blog/2018/6/6-open-source-ai-tools-know
作者:[Sam Dean][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[qhwdw](https://github.com/qhwdw)
校对:[pityonline](https://github.com/pityonline), [wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linux.com/users/sam-dean
[1]:https://www.acumos.org/
[2]:https://www.linuxfoundation.org/projects/deep-learning/
[3]:https://www.linuxfoundation.org/blog/lf-deep-learning-foundation-announces-project-contribution-process/
[4]:https://code.facebook.com/posts/1687861518126048/facebook-to-open-source-ai-hardware-design/
[5]:https://venturebeat.com/2017/04/18/facebook-open-sources-caffe2-a-new-deep-learning-framework/
[6]:http://yahoohadoop.tumblr.com/post/139916563586/caffeonspark-open-sourced-for-distributed-deep
[7]:https://systemml.apache.org/
[8]:https://www.tensorflow.org/
[9]:https://www.techradar.com/news/google-assistant-sweetens-raspberry-pi-with-ai-voice-control
[10]:https://www.linux.com/news/sparkling-water-bridging-open-source-machine-learning-and-apache-spark
[11]:http://www.h2o.ai/download
[12]:https://blogs.msdn.microsoft.com/uk_faculty_connection/2017/02/10/microsoft-cognitive-toolkit-cntk/
[13]:https://www.microsoft.com/en-us/cognitive-toolkit/
[14]:https://www.linuxfoundation.org/publications/open-source-ai-projects-insights-and-trends/

View File

@ -0,0 +1,226 @@
Buildah 入门
======
> Buildah 提供一种灵活、可脚本编程的方式,来使用你熟悉的工具创建精简、高效的容器镜像。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/blocks_building.png?itok=eMOT-ire)
[Buildah][1] 是一个命令行工具,可以方便、快捷的构建与<ruby>[开放容器标准][2]<rt>Open Container Initiative</rt></ruby>OCI兼容的容器镜像这意味着其构建的镜像与 Docker 和 Kubernetes 兼容。该工具可作为 Docker 守护进程 `docker build` 命令(即使用传统的 Dockerfile 构建镜像)的一种<ruby>简单<rt>drop-in</rt></ruby>替换而且更加灵活允许构建镜像时使用你擅长的工具。Buildah 可以轻松与脚本集成并生成<ruby>流水线<rt>pipeline</rt></ruby>最好之处在于构建镜像不再需要运行容器守护进程LCTT 译注:这里主要是指 Docker 守护进程)。
### docker build 的简单替换
目前你可能使用 Dockerfile 和 `docker build` 命令构建镜像,那么你可以马上使用 Buildah 进行替代。Buildah 的 `build-using-dockerfile` (或 `bud`)子命令与 `docker build` 基本等价,因此可以轻松的与已有脚本结合或构建流水线。
类似我的上一篇关于 Buildah 的[文章][3],我也将以使用源码安装 “GNU Hello” 为例进行说明,对应的 Dockerfile 文件如下:
```
FROM fedora:28
LABEL maintainer Chris Collins <collins.christopher@gmail.com>
RUN dnf install -y tar gzip gcc make \
        && dnf clean all
ADD http://ftpmirror.gnu.org/hello/hello-2.10.tar.gz /tmp/hello-2.10.tar.gz
RUN tar xvzf /tmp/hello-2.10.tar.gz -C /opt
WORKDIR /opt/hello-2.10
RUN ./configure
RUN make
RUN make install
RUN hello -v
ENTRYPOINT "/usr/local/bin/hello"
```
使用 Buildah 从 Dockerfile 构建镜像也很简单,使用 `buildah bud -t hello .` 替换 `docker build -t hello .` 即可:
```
[chris@krang] $ sudo buildah bud -t hello .
STEP 1: FROM fedora:28
Getting image source signatures
Copying blob sha256:e06fd16225608e5b92ebe226185edb7422c3f581755deadf1312c6b14041fe73
 81.48 MiB / 81.48 MiB [====================================================] 8s
Copying config sha256:30190780b56e33521971b0213810005a69051d720b73154c6e473c1a07ebd609
 2.29 KiB / 2.29 KiB [======================================================] 0s
Writing manifest to image destination
Storing signatures
STEP 2: LABEL maintainer Chris Collins <collins.christopher@gmail.com>
STEP 3: RUN dnf install -y tar gzip gcc make    && dnf clean all
<考虑篇幅略去后续输出>
```
镜像构建完毕后,可以使用 `buildah images` 命令查看这个新镜像:
```
[chris@krang] $ sudo buildah images
IMAGE ID        IMAGE NAME                              CREATED AT              SIZE
30190780b56e    docker.io/library/fedora:28             Mar 7, 2018 16:53       247 MB
6d54bef73e63    docker.io/library/hello:latest    May 3, 2018 15:24     391.8 MB
```
新镜像的标签为 `hello:latest`,我们可以将其推送至远程镜像仓库,可以使用 [CRI-O][4] 或其它 Kubernetes CRI 兼容的运行时来运行该镜像,也可以推送到远程仓库。如果你要测试对 Docker build 命令的替代性,你可以将镜像拷贝至 docker 守护进程的本地镜像存储中,这样 Docker 也可以使用该镜像。使用 `buildah push` 可以很容易的完成推送操作:
```
[chris@krang] $ sudo buildah push hello:latest docker-daemon:hello:latest
Getting image source signatures
Copying blob sha256:72fcdba8cff9f105a61370d930d7f184702eeea634ac986da0105d8422a17028
 247.02 MiB / 247.02 MiB [==================================================] 2s
Copying blob sha256:e567905cf805891b514af250400cc75db3cb47d61219750e0db047c5308bd916
 144.75 MiB / 144.75 MiB [==================================================] 1s
Copying config sha256:6d54bef73e638f2e2dd8b7bf1c4dfa26e7ed1188f1113ee787893e23151ff3ff
 1.59 KiB / 1.59 KiB [======================================================] 0s
Writing manifest to image destination
Storing signatures
[chris@krang] $ sudo docker images | head -n2
REPOSITORY              TAG             IMAGE ID        CREATED                 SIZE
docker.io/hello      latest       6d54bef73e63  2 minutes ago   398 MB
[chris@krang] $ sudo docker run -t hello:latest
Hello, world!
```
### 若干差异
与 Docker build 不同Buildah 不会自动的将 Dockerfile 中的每条指令产生的变更提到新的<ruby>分层<rt>layer</rt></ruby>中,只是简单的每次从头到尾执行构建。类似于<ruby>自动化<rt>automation</rt></ruby><ruby>流水线构建<rt>build pipeline</rt></ruby>,这种<ruby>无缓存构建<rt>non-cached</rt></ruby>方式的好处是可以提高构建速度,在指令较多时尤为明显。从<ruby>自动部署<rt>automated deployment</rt></ruby><ruby>持续交付<rt>continuous delivery</rt></ruby>的视角来看,使用这种方式可以快速的将新变更落实到生产环境中。
但从实际角度出发,缓存机制的缺乏对镜像开发不利,毕竟缓存层可以避免一遍遍的执行构建,从而显著的节省时间。自动分层只在 `build-using-dockerfile` 命令中生效。但我们在下面会看到Buildah 原生命令允许我们选择将变更提交到硬盘的时间,提高了开发的灵活性。
### Buildah 原生命令
Buildah _真正_ 有趣之处在于它的原生命令,你可以在容器构建过程中使用这些命令进行交互。相比与使用 `build-using-dockerfile/bud` 命令执行每次构建Buildah 提供命令让你可以与构建过程中的临时容器进行交互。Docker 也使用临时或<ruby> _中间_ <rt>intermediate</rt></ruby>容器,但你无法在镜像构建过程中与其交互。)
还是使用 “GNU Hello” 为例,考虑使用如下 Buildah 命令构建的镜像:
```
#!/usr/bin/env bash
set -o errexit
# Create a container
container=$(buildah from fedora:28)
# Labels are part of the "buildah config" command
buildah config --label maintainer="Chris Collins <collins.christopher@gmail.com>" $container
# Grab the source code outside of the container
curl -sSL http://ftpmirror.gnu.org/hello/hello-2.10.tar.gz -o hello-2.10.tar.gz
buildah copy $container hello-2.10.tar.gz /tmp/hello-2.10.tar.gz
buildah run $container dnf install -y tar gzip gcc make
buildah run $container dnf clean all
buildah run $container tar xvzf /tmp/hello-2.10.tar.gz -C /opt
# Workingdir is also a "buildah config" command
buildah config --workingdir /opt/hello-2.10 $container
buildah run $container ./configure
buildah run $container make
buildah run $container make install
buildah run $container hello -v
# Entrypoint, too, is a “buildah config” command
buildah config --entrypoint /usr/local/bin/hello $container
# Finally saves the running container to an image
buildah commit --format docker $container hello:latest
```
我们可以一眼看出这是一个 Bash 脚本而不是 Dockerfile。基于 Buildah 的原生命令,可以轻易的使用任何脚本语言或你擅长的自动化工具编写脚本。形式可以是 makefile、Python 脚本或其它你擅长的类型。
这个脚本做了哪些工作呢首先Buildah 命令 `container=$(buildah from fedora:28)` 基于 fedora:28 镜像创建了一个正在运行的容器,将容器名(`buildah from` 命令的返回值)保存到变量中,便于后续使用。后续所有命令都是有 `$container` 变量指明需要操作的容器。这些命令的功能大多可以从名称看出:`buildah copy` 将文件拷贝至容器,`buildah run` 会在容器中执行命令。可以很容易的将上述命令与 Dockerfile 中的指令对应起来。
最后一条命令 `buildah commit` 将容器提交到硬盘上的镜像中。当不使用 Dockerfile 而是使用 Buildah 命令构建镜像时,你可以使用 `commit` 命令决定何时保存变更。在上例中,所有的变更是一起提交的;但也可以增加中间提交,让你可以选择作为起点的<ruby>缓存点<rt>cache point</rt></ruby>。(例如,执行完 `dnf install` 命令后将变更缓存到硬盘是特别有意义的,一方面因为该操作耗时较长,另一方面每次执行的结果也确实相同。)
### 挂载点,安装目录以及 chroot
另一个可以大大增加构建镜像灵活性的 Buildah 命令是 `buildah mount`,可以将容器的根目录挂载到你主机的一个挂载点上。例如:
```
[chris@krang] $ container=$(sudo buildah from fedora:28)
[chris@krang] $ mountpoint=$(sudo buildah mount ${container})
[chris@krang] $ echo $mountpoint
/var/lib/containers/storage/overlay2/463eda71ec74713d8cebbe41ee07da5f6df41c636f65139a7bd17b24a0e845e3/merged
[chris@krang] $ cat ${mountpoint}/etc/redhat-release
Fedora release 28 (Twenty Eight)
[chris@krang] $ ls ${mountpoint}
bin   dev  home  lib64          media  opt   root  sbin  sys  usr
boot  etc  lib   lost+found  mnt        proc  run   srv   tmp  var
```
这太棒了,你可以通过与挂载点交互对容器镜像进行修改。这允许你使用主机上的工具进行构建和安装软件,不用将这些构建工具打包到容器镜像本身中。例如,在我们上面的 Bash 脚本中,我们需要安装 tar、Gzip、GCC 和 make在容器内编译 “GNU Hello”。如果使用挂载点我仍使用同样的工具进行构建但下载的压缩包和 tar、Gzip 等 RPM 包都在主机而不是容器和生成的镜像内:
```
#!/usr/bin/env bash
set -o errexit
# Create a container
container=$(buildah from fedora:28)
mountpoint=$(buildah mount $container)
buildah config --label maintainer="Chris Collins <collins.christopher@gmail.com>" $container
curl -sSL http://ftpmirror.gnu.org/hello/hello-2.10.tar.gz \
     -o /tmp/hello-2.10.tar.gz
tar xvzf src/hello-2.10.tar.gz -C ${mountpoint}/opt
pushd ${mountpoint}/opt/hello-2.10
./configure
make
make install DESTDIR=${mountpoint}
popd
chroot $mountpoint bash -c "/usr/local/bin/hello -v"
buildah config --entrypoint "/usr/local/bin/hello" $container
buildah commit --format docker $container hello
buildah unmount $container
```
在上述脚本中,需要提到如下几点:
1. `curl` 命令将压缩包下载到主机中,而不是镜像中;
2. (主机中的) `tar` 命令将压缩包中的源代码解压到容器的 `/opt` 目录;
3. `configure``make` 和 `make install` 命令都在主机的挂载点目录中执行,而不是在容器内;
4. 这里的 `chroot` 命令用于将挂载点本身当作根路径并测试 "hello" 是否正常工作;类似于前面例子中用到的 `buildah run` 命令。
这个脚本更加短小,使用大多数 Linux 爱好者都很熟悉的工具,最后生成的镜像也更小(没有 tar 包,没有额外的软件包等)。你甚至可以使用主机系统上的包管理器为容器安装软件。例如,(出于某种原因)你希望安装 GNU Hello 的同时在容器中安装 [NGINX][5]
```
[chris@krang] $ mountpoint=$(sudo buildah mount ${container})
[chris@krang] $ sudo dnf install nginx --installroot $mountpoint
[chris@krang] $ sudo chroot $mountpoint nginx -v
nginx version: nginx/1.12.1
```
在上面的例子中DNF 使用 `--installroot` 参数将 NGINX 安装到容器中,可以通过 chroot 进行校验。
### 快来试试吧!
Buildah 是一种轻量级、灵活的容器镜像构建方法,不需要在主机上运行完整的 Docker 守护进程。除了提供基于 Dockerfile 构建容器的开箱即用支持Buildah 还可以很容易的与脚本或你喜欢的构建工具相结合特别是可以使用主机上已有的工具构建容器镜像。Buildah 生成的容器体积更小,更便于网络传输,占用更小的存储空间,而且潜在的受攻击面更小。快来试试吧!
**[阅读相关的故事,[使用 Buildah 创建小体积的容器][6]]**
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/6/getting-started-buildah
作者:[Chris Collins][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[pinewall](https://github.com/pinewall)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/clcollins
[1]:https://github.com/projectatomic/buildah
[2]:https://www.opencontainers.org/
[3]:http://chris.collins.is/2017/08/17/buildah-a-new-way-to-build-container-images/
[4]:http://cri-o.io/
[5]:https://www.nginx.com/
[6]:https://linux.cn/article-9719-1.html

View File

@ -1,10 +1,13 @@
3 款 Linux 桌面的日记程序
======
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/desk_clock_job_work.jpg?itok=Nj4fuhl6)
保持记日记,即使是不定期,也可以带来很多好处。这不仅是治疗和宣泄,而且还可以很好地记录你所处的位置以及你去过的地方。它可以帮助你展示你在生活中的进步,并提醒你自己做对了什么,做错了什么。
> 用轻量、灵活的数字日记工具来记录你的活动。
无论你记日记的原因是什么,都有多种方法可以做到这一点。你可以去读书,使用笔和纸。你可以使用基于 Web 的程序。或者你可以使用[简单的文本文件][1]。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/desk_clock_job_work.jpg?itok=Nj4fuhl6)
保持记日记的习惯,即使是不定期地记,也可以带来很多好处。这不仅是治疗和宣泄,而且还可以很好地记录你所在的位置以及你去过的地方。它可以帮助你展示你在生活中的进步,并提醒你自己做对了什么,做错了什么。
无论你记日记的原因是什么,都有多种方法可以做到这一点。你可以使用传统的笔和纸,也可以使用基于 Web 的程序,或者你可以使用[简单的文本文件][1]。
另一种选择是使用专门的日记程序。Linux 桌面有几种非常灵活且非常有用的日记工具。我们来看看其中的三个。
@ -12,11 +15,11 @@
![](https://opensource.com/sites/default/files/uploads/red-notebook.png)
在这里描述的三个日记程序中,[RedNotebook][2] 是最灵活的。大部分灵活性来自其模板。这些模板可让记录个人想法或会议记录、计划旅程或记录电话。你还可以编辑现有模板或创建自己的模板。
在这里描述的三个日记程序中,[RedNotebook][2] 是最灵活的。大部分灵活性来自其模板。这些模板可让记录个人想法或会议记录、计划旅程或记录电话。你还可以编辑现有模板或创建自己的模板。
你使用与 Markdown 非常相似的标记语言记录日记。你还可以在日记中添加标签,以便于查找。只需在程序的左窗格中单击或输入标记,右窗格中将显示相应日记的列表。
可以使用与 Markdown 非常相似的标记语言记录日记。你还可以在日记中添加标签,以便于查找。只需在程序的左窗格中单击或输入标记,右窗格中将显示相应日记的列表。
最重要的是,你可以将全部或部分或仅一个日记录导出为纯文本、HTML、LaTeX 或 PDF。在执行此操作之前你可以通过单击工具栏上的“预览”按钮了解日志在 PDF 或 HTML 中的显示情况。
最重要的是,你可以将全部、部分或仅一个日记导出为纯文本、HTML、LaTeX 或 PDF。在执行此操作之前你可以通过单击工具栏上的“预览”按钮了解日志在 PDF 或 HTML 中的显示情况。
总的来说RedNotebook 是一款易于使用且灵活的程序。它需要习惯,但一旦你这样做,它是一个有用的工具。
@ -24,9 +27,9 @@
![](https://opensource.com/sites/default/files/uploads/lifeograph.png)
[Lifeograph][3] 与 RedNotebook 有相似的外观和感觉。它没有那么多功能,但 Lifeograph 可以完成工作
[Lifeograph][3] 与 RedNotebook 有相似的外观和感觉。它没有那么多功能,但 Lifeograph 也够了
该程序通过保持简单和整洁来简化记日记。你有一个很大的区域可以记录,你可以为日记添加一些基本格式。这包括通常的粗体和斜体,以及箭头和高亮显示。你可以在日记中添加标签,以便更好地组织和查找它们。
该程序通过保持简单和整洁来简化记日记这件事。你有一个很大的区域可以记录,你可以为日记添加一些基本格式。这包括通常的粗体和斜体,以及箭头和高亮显示。你可以在日记中添加标签,以便更好地组织和查找它们。
Lifeograph 有一个我觉得特别有用的功能。首先,你可以创建多个日记 - 例如,工作日记和个人日记。其次是密码保护你的日记的能力。虽然该网站声称 Lifeograph 使用“真正的加密”,但没有关于它的详细信息。尽管如此,设置密码仍然会阻止大多数窥探者。
@ -34,15 +37,15 @@ Lifeograph 有一个我觉得特别有用的功能。首先,你可以创建多
![](https://opensource.com/sites/default/files/uploads/almanah.png)
[Almanah Diary][4] 是另一种非常简单的日记工具。但不要因为它缺乏功能就关闭它。这很简单,但完成了工作
[Almanah Diary][4] 是另一种非常简单的日记工具。但不要因为它缺乏功能就丢掉它。虽简单,但足够
有多简单?它差多是一个区域包含了日记输入和日历。你可以做更多的事情 - 比如添加一些基本格式粗体、斜体和下划线并将文本转换为超链接。Almanah 还允许你加密日记。
有多简单?它差不多只是一个包含了日记输入和日历的区域而已。你可以做更多的事情 —— 比如添加一些基本格式粗体、斜体和下划线并将文本转换为超链接。Almanah 还允许你加密日记。
虽然有一个功能可以将纯文本文件导入程序,但我无法使其正常工作。尽管如此,如果你喜欢一个简单,能够快速记日记的软件,那么 Almanah 日记值得一看。
虽然有一个可以将纯文本文件导入程序的功能,但我无法使其正常工作。尽管如此,如果你喜欢一个简单,能够快速记日记的软件,那么 Almanah 日记值得一看。
### 命令行怎么样?
如果你不想用 GUI 则可以不必去做。命令行是保存日记的绝佳选择。
如果你不想用 GUI 则可以不必。命令行是保存日记的绝佳选择。
我尝试过并且喜欢的是 [jrnl][5]。或者你可以使用[此方案][6],它使用命令行别名格式化并将日记保存到文本文件中。
@ -55,7 +58,7 @@ via: https://opensource.com/article/18/6/linux-journaling-applications
作者:[Scott Nesbitt][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,77 @@
GitLab 的付费套餐现在可以免费用于开源项目
======
最近在开源社区发生了很多事情。首先,[微软收购了 GitHub][1],然后人们开始寻找 [GitHub 替代套餐][2],甚至在 Linus Torvalds 发布 [Linux Kernel 4.17][3] 时没有花一点时间考虑它。好吧,如果你一直关注我们,我认为你知道这一切。
但是如今GitLab 做出了一个明智的举措,为教育机构和开源项目免费提供高级套餐。当许多开发人员有兴趣将他们的开源项目迁移到 GitLab 时,没有更好的时机来提供这些了。
### GitLab 的高级套餐现在对开源项目和教育机构免费
![GitLab Logo][4]
在今天2018/6/7[发布的博客][5]中GitLab 宣布其**旗舰**和黄金套餐现在对教育机构和开源项目免费。虽然我们已经知道为什么 GitLab 做出这个举动(一个完美的时机!),但他们还是解释了他们让它免费的动机:
> 我们让 GitLab 对教育机构免费,因为我们希望学生使用我们最先进的功能。许多大学已经运行了 GitLab。如果学生使用 GitLab 旗舰和黄金套餐的高级功能,他们将把这些高级功能的经验带到他们的工作场所。
>
> 我们希望有更多的开源项目使用 GitLab。GitLab.com 上的公共项目已经拥有 GitLab 旗舰套餐的所有功能。像 [Gnome][6] 和 [Debian][7] 这样的项目已经在自己的服务器运行开源版 GitLab 。随着今天的宣布,在专有软件上运行的开源项目可以使用 GitLab 提供的所有功能,同时我们通过向非开源组织收费来建立可持续的业务模式。
### GitLab 提供的这些“免费”套餐是什么?
![GitLab Pricing][8]
GitLab 有两类产品。一个是你可以在自己的云托管服务如 [Digital Ocean][9] 上运行的软件。另一个是 Gitlab 软件既服务,其中托管由 GitLab 本身管理,你在 GitLab.com 上获得一个帐户。
![GitLab Pricing for hosted service][10]
黄金套餐是托管类别中最高的产品,而旗舰套餐是自托管类别中的最高产品。
你可以在 GitLab 定价页面上获得有关其功能的更多详细信息。请注意,支持服务不包括在套餐中。你必须单独购买。
### 你必须符合某些条件才能使用此优惠
GitLab 还提到 —— 该优惠对谁有效。以下是他们在博客文章中写的内容:
> 1. **教育机构:**任何为了学习、教育的机构,并且/或者由合格的教育机构、教职人员、学生训练。教育目的不包括商业,专业或任何其他营利目的。
>
> 2. **开源项目:**任何使用[标准开源许可证][11]且非商业性的项目。它不应该有付费支持或付费贡献者。
>
虽然免费套餐不包括支持,但是当你迫切需要专家帮助解决问题时,你仍然可以支付每用户每月 4.95 美元的额外费用 —— 当你特别需要一个专家来解决问题时,这是一个非常合理的价格。
GitLab 还为学生们添加了一条说明:
> 为减轻 GitLab 的管理负担,只有教育机构才能代表学生申请。如果你是学生并且你的教育机构不申请,你可以在 GitLab.com 上使用公共项目的所有功能,使用私人项目的免费功能,或者自己付费。
### 总结
现在 GitLab 正在加快脚步,你如何看待它?
你有 [GitHub][12] 上的项目吗?你会切换么?或者,幸运的是,你从一开始就碰巧使用 GitLab
请在下面的评论栏告诉我们你的想法。
--------------------------------------------------------------------------------
via: https://itsfoss.com/gitlab-free-open-source/
作者:[Ankush Das][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://itsfoss.com/author/ankush/
[1]:https://itsfoss.com/microsoft-github/
[2]:https://itsfoss.com/github-alternatives/
[3]:https://itsfoss.com/linux-kernel-4-17/
[4]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/06/GitLab-logo-800x450.png
[5]:https://about.gitlab.com/2018/06/05/gitlab-ultimate-and-gold-free-for-education-and-open-source/
[6]:https://www.gnome.org/news/2018/05/gnome-moves-to-gitlab-2/
[7]:https://salsa.debian.org/public
[8]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/06/gitlab-pricing.jpeg
[9]:https://m.do.co/c/d58840562553
[10]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/06/gitlab-hosted-service-800x273.jpeg
[11]:https://itsfoss.com/open-source-licenses-explained/
[12]:https://github.com/

View File

@ -0,0 +1,68 @@
Mesos 和 Kubernetes不是竞争者
======
> 人们经常用 x 相对于 y 这样的术语来考虑问题但是它并不是一个技术对另一个技术的问题。Ben Hindman 在这里解释了 Mesos 是如何对另外一种技术进行补充的。
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/architecture-barge-bay-161764_0.jpg?itok=vNChG5fb)
Mesos 的起源可以追溯到 2009 年当时Ben Hindman 还是加州大学伯克利分校研究并行编程的博士生。他们在 128 核的芯片上做大规模的并行计算,以尝试去解决多个问题,比如怎么让软件和库在这些芯片上运行更高效。他与同学们讨论能否借鉴并行处理和多线程的思想,并将它们应用到集群管理上。
Hindman 说 “最初,我们专注于大数据” 。那时,大数据非常热门,而 Hadoop 就是其中的一个热门技术。“我们发现,人们在集群上运行像 Hadoop 这样的程序与运行多线程应用及并行应用很相似。”Hindman 说。
但是,它们的效率并不高,因此,他们开始去思考,如何通过集群管理和资源管理让它们运行的更好。“我们查看了那个时期很多的各种技术” Hindman 回忆道。
然后Hindman 和他的同事们决定去采用一种全新的方法。“我们决定对资源管理创建一个低级的抽象,然后在此之上运行调度服务和做其它的事情。” Hindman 说,“基本上,这就是 Mesos 的本质 —— 将资源管理部分从调度部分中分离出来。”
他成功了,并且 Mesos 从那时开始强大了起来。
### 将项目呈献给 Apache
这个项目发起于 2009 年。在 2010 年时,团队决定将这个项目捐献给 Apache 软件基金会ASF。它在 Apache 孵化,并于 2013 年成为顶级项目TLP
为什么 Mesos 社区选择 Apache 软件基金会有很多的原因比如Apache 许可证,以及基金会已经拥有了一个充满活力的其它此类项目的社区。
与影响力也有关系。许多在 Mesos 上工作的人也参与了 Apache并且许多人也致力于像 Hadoop 这样的项目。同时,来自 Mesos 社区的许多人也致力于其它大数据项目,比如 Spark。这种交叉工作使得这三个项目 —— Hadoop、Mesos以及 Spark —— 成为 ASF 的项目。
与商业也有关系。许多公司对 Mesos 很感兴趣,并且开发者希望它能由一个中立的机构来维护它,而不是让它成为一个私有项目。
### 谁在用 Mesos
更好的问题应该是,谁不在用 Mesos从 Apple 到 Netflix 每个都在用 Mesos。但是Mesos 也面临任何技术在早期所面对的挑战。“最初,我要说服人们,这是一个很有趣的新技术。它叫做‘容器’,因为它不需要使用虚拟机” Hindman 说。
从那以后,这个行业发生了许多变化,现在,只要与别人聊到基础设施,必然是从”容器“开始的 —— 感谢 Docker 所做出的工作。今天再也不需要做说服工作了,而在 Mesos 出现的早期,前面提到的像 Apple、Netflix以及 PayPal 这样的公司。他们已经知道了容器替代虚拟机给他们带来的技术优势。“这些公司在容器成为一种现象之前,已经明白了容器的价值所在”, Hindman 说。
可以在这些公司中看到,他们有大量的容器而不是虚拟机。他们所做的全部工作只是去管理和运行这些容器,并且他们欣然接受了 Mesos。在 Mesos 早期就使用它的公司有 Apple、Netflix、PayPal、Yelp、OpenTable 和 Groupon。
“大多数组织使用 Mesos 来运行各种服务” Hindman 说,“但也有些公司用它做一些非常有趣的事情,比如,数据处理、数据流、分析任务和应用程序。“
这些公司采用 Mesos 的其中一个原因是资源管理层之间有一个明晰的界线。当公司运营容器的时候Mesos 为他们提供了很好的灵活性。
“我们尝试使用 Mesos 去做的一件事情是去创建一个层,以让使用者享受到我们的层带来的好处,当然也可以在它之上创建任何他们想要的东西,” Hindman 说。 “我认为这对一些像 Netflix 和 Apple 这样的大公司非常有用。”
但是并不是每个公司都是技术型的公司不是每个公司都有或者应该有这种专长。为帮助这样的组织Hindman 联合创建了 Mesosphere 去围绕 Mesos 提供服务和解决方案。“我们最终决定,为这样的组织去构建 DC/OS它不需要技术专长或者不想把时间花费在像构建这样的事情上。”
### Mesos vs. Kubernetes?
人们经常用 x 相对于 y 这样的术语来考虑问题,但是它并不是一个技术对另一个技术的问题。大多数的技术在一些领域总是重叠的,并且它们可以是互补的。“我不喜欢将所有的这些东西都看做是竞争者。我认为它们中的一些与另一个在工作中是互补的,” Hindman 说。
“事实上,名字 Mesos 表示它处于 ‘中间’;它是一种中间的操作系统”, Hindman 说,“我们有一个容器调度器的概念,它能够运行在像 Mesos 这样的东西之上。当 Kubernetes 刚出现的时候,我们实际上在 Mesos 的生态系统中接受了它,并将它看做是在 Mesos 上的 DC/OS 中运行容器的另一种方式。”
Mesos 也复活了一个名为 [Marathon][1](一个用于 Mesos 和 DC/OS 的容器编排器)的项目,它成为了 Mesos 生态系统中最重要的成员。但是Marathon 确实无法与 Kubernetes 相比较。“Kubernetes 比 Marathon 做的更多,因此,你不能将它们简单地相互交换,” Hindman 说,“与此同时,我们在 Mesos 中做了许多 Kubernetes 中没有的东西。因此,这些技术之间是互补的。”
不要将这些技术视为相互之间是敌对的关系,它们应该被看做是对行业有益的技术。它们不是技术上的重复;它们是多样化的。据 Hindman 说,“对于开源领域的终端用户来说,这可能会让他们很困惑,因为他们很难去知道哪个技术适用于哪种任务,但这是这个被称之为开源的本质所在。“
这只是意味着有更多的选择,并且每个都是赢家。
--------------------------------------------------------------------------------
via: https://www.linux.com/blog/2018/6/mesos-and-kubernetes-its-not-competition
作者:[Swapnil Bhartiya][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[qhwdw](https://github.com/qhwdw)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linux.com/users/arnieswap
[1]:https://mesosphere.github.io/marathon/

View File

@ -1,9 +1,11 @@
将你的树莓派打造成一个 Tor 中继节点
======
> 在此教程中学习如何将你的旧树莓派打造成一个完美的 Tor 中继节点。
![](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/tor-onion-router.jpg?itok=6WUl0ElH)
你是否和我一样,在第一代或者第二代树莓派发布时买了一个,玩了一段时间就把它搁置“吃灰”了。毕竟,除非你是机器人爱好者,否则一般不太可能去长时间使用一个处理器很慢的并且内存只有 256 MB 的计算机。这并不是说你不能用它去做一件很酷的东西,但是在工作和其它任务之间,我还没有看到用一些旧的物件发挥新作用的机会。
你是否和我一样,在第一代或者第二代树莓派发布时买了一个,玩了一段时间就把它搁置“吃灰”了。毕竟,除非你是机器人爱好者,否则一般不太可能去长时间使用一个处理器很慢的并且内存只有 256 MB 的计算机。这并不是说你不能用它去做一件很酷的东西,但是在工作和其它任务之间,我还没有看到用一些旧的物件发挥新作用的机会。
然而,如果你想去好好利用它并且不想花费你太多的时间和资源的话,可以将你的旧树莓派打造成一个完美的 Tor 中继节点。
@ -11,18 +13,13 @@
在此之前你或许听说过 [Tor 项目][1]如果恰好你没有听说过我简单给你介绍一下“Tor” 是 “The Onion Router洋葱路由器” 的缩写,它是用来对付在线追踪和其它违反隐私行为的技术。
不论你在因特网上做什么事情,都会在你的 IP 包通过的设备上留下一些数字“脚印”:所有的交换机、路由器、负载均衡,以及目标网络记录的来自你的原始会话的 IP 地址,以及你访问的因特网资源(经常是主机名、[甚至是在使用 HTTPS 时][2])的 IP 地址。如何你是在家中上因特网,那么你的 IP 地址可以直接映射到你的家庭所在地。如果你使用了 VPN 服务([你应该使用][3]),那么你的 IP 地址是映射到你的 VPN 提供商那里,而 VPN 提供商是可以映射到你的家庭所在地的。无论如何,有可能在某个地方的某个人正在根据你访问的网络和在网站上呆了多长时间来为你建立一个个人的在线资料。然后将这个资料进行出售,并与从其它服务上收集的资料进行聚合,然后利用广告网络进行赚钱。至少,这是乐观主义者对如何利用这些数据的一些看法 —— 我相信你还可以找到更多的更恶意地使用这些数据的例子。
Tor 项目尝试去提供一个解决这种问题的方案,使它们不可能(或者至少是更加困难)追踪到你的终端 IP 地址。Tor 是通过让你的连接在一个由匿名的入口节点、中继节点、和出口节点组成的匿名中继链上反复跳转的方式来实现防止追踪的目的:
1. **入口节点** 只知道你的 IP 地址和中继节点的 IP 地址,但是不知道你最终要访问的目标 IP 地址
2. **中继节点** 只知道入口节点和出口节点的 IP 地址,以及即不是源也不是最终目标的 IP 地址
3. **出口节点** 仅知道中继节点和最终目标地址,它是在到达最终目标地址之前解密流量的节点
不论你在互联网上做什么事情,都会在你的 IP 包通过的设备上留下一些数字“脚印”:所有的交换机、路由器、负载均衡,以及目标网络记录的来自你的原始会话的 IP 地址,以及你访问的互联网资源(通常是它的主机名,[即使是在使用 HTTPS 时][2])的 IP 地址。如过你是在家中上互联网,那么你的 IP 地址可以直接映射到你的家庭所在地。如果你使用了 VPN 服务([你应该使用][3]),那么你的 IP 地址映射到你的 VPN 提供商那里,而 VPN 提供商是可以映射到你的家庭所在地的。无论如何,有可能在某个地方的某个人正在根据你访问的网络和在网站上呆了多长时间来为你建立一个个人的在线资料。然后将这个资料进行出售,并与从其它服务上收集的资料进行聚合,然后利用广告网络进行赚钱。至少,这是乐观主义者对如何利用这些数据的一些看法 —— 我相信你还可以找到更多的更恶意地使用这些数据的例子。
Tor 项目尝试去提供一个解决这种问题的方案,使它们不可能(或者至少是更加困难)追踪到你的终端 IP 地址。Tor 是通过让你的连接在一个由匿名的入口节点、中继节点和出口节点组成的匿名中继链上反复跳转的方式来实现防止追踪的目的:
1. **入口节点** 只知道你的 IP 地址和中继节点的 IP 地址,但是不知道你最终要访问的目标 IP 地址
2. **中继节点** 只知道入口节点和出口节点的 IP 地址,以及既不是源也不是最终目标的 IP 地址
3. **出口节点** 仅知道中继节点和最终目标地址,它是在到达最终目标地址之前解密流量的节点
中继节点在这个交换过程中扮演一个关键的角色,因为它在源请求和目标地址之间创建了一个加密的障碍。甚至在意图偷窥你数据的对手控制了出口节点的情况下,在他们没有完全控制整个 Tor 中继链的情况下仍然无法知道请求源在哪里。
@ -30,81 +27,68 @@ Tor 项目尝试去提供一个解决这种问题的方案,使它们不可能
#### 考虑去做 Tor 中继时要记住的一些事情
一个 Tor 中继节点仅发送和接收加密流量 —— 它从不访问任何其它站点或者在线资源,因此你不用担心有人会利用你的家庭 IP 地址去直接浏览一些令人担心的站点。话虽如此,但是如果你居住在一个提供匿名增强服务anonymity-enhancing services是违法行为的司法管辖区的话,那么你还是不要运营你的 Tor 中继节点了。你还需要去查看你的因特网服务提供商的服务条款是否允许你去运营一个 Tor 中继。
一个 Tor 中继节点仅发送和接收加密流量 —— 它从不访问任何其它站点或者在线资源,因此你不用担心有人会利用你的家庭 IP 地址去直接浏览一些令人担心的站点。话虽如此,但是如果你居住在一个提供<ruby>匿名增强服务<rt>anonymity-enhancing services</rt></ruby>是违法行为的司法管辖区的话,那么你还是不要运营你的 Tor 中继节点了。你还需要去查看你的互联网服务提供商的服务条款是否允许你去运营一个 Tor 中继。
### 需要哪些东西
* 一个带完整外围附件的树莓派(任何型号/代次都行)
* 一张有 [Raspbian Stretch Lite][4] 的 SD 卡
* 一根以太网线缆
* 一根用于供电的 micro-USB 线缆
* 一个键盘和带 HDMI 接口的显示器(在配置期间使用)
本指南假设你已经配置好了你的家庭网络连接的线缆或者 ADSL 路由器,它用于运行 NAT 转换(它几乎是必需的)。大多数型号的树莓派都有一个可用于为树莓派供电的 USB 端口,如果你只是使用路由器的 WiFi 功能,那么路由器应该有空闲的以太网口。但是在我们将树莓派设置为一个“配置完不管”的 Tor 中继之前,我们还需要一个键盘和显示器。
### 引导脚本
我改编了一个很流行的 Tor 中继节点引导脚本以适配树莓派上使用 —— 你可以在我的 GitHub 仓库 <https://github.com/mricon/tor-relay-bootstrap-rpi> 上找到它。你用它引导树莓派并使用缺省的用户 “pi” 登入之后,做如下的工作:
我改编了一个很流行的 Tor 中继节点引导脚本以适配树莓派上使用 —— 你可以在我的 GitHub 仓库 <https://github.com/mricon/tor-relay-bootstrap-rpi> 上找到它。你用它引导树莓派并使用缺省的用户 `pi` 登入之后,做如下的工作:
```
sudo apt-get install -y git
git clone https://github.com/mricon/tor-relay-bootstrap-rpi
cd tor-relay-bootstrap-rpi
sudo ./bootstrap.sh
```
这个脚本将做如下的工作:
1. 安装最新版本的操作系统更新以确保树莓派打了所有的补丁
2. 将系统配置为无人值守自动更新,以确保有可用更新时会自动接收并安装
3. 安装 Tor 软件
4. 告诉你的 NAT 路由器去转发所需要的端口(端口一般是 443 和 8080因为这两个端口最不可能被互联网提供商过滤掉上的数据包到你的中继节点
4. 告诉你的 NAT 路由器去转发所需要的端口(端口一般是 443 和 8080因为这两个端口最不可能被因特网提供商过滤掉上的数据包到你的中继节点
脚本运行完成后,你需要去配置 torrc 文件 —— 但是首先,你需要决定打算贡献给 Tor 流量多大带宽。首先,在 Google 中输入 “[Speed Test][5]”,然后点击 “Run Speed Test” 按钮。你可以不用管 “Download speed” 的结果,因为你的 Tor 中继能处理的速度不会超过最大的上行带宽。
脚本运行完成后,你需要去配置 `torrc` 文件 —— 但是首先,你需要决定打算贡献给 Tor 流量多大带宽。首先,在 Google 中输入 “[Speed Test][5]”,然后点击 “Run Speed Test” 按钮。你可以不用管 “Download speed” 的结果,因为你的 Tor 中继能处理的速度不会超过最大的上行带宽。
所以,将 “Mbps upload” 的数字除以 8然后再乘以 1024结果就是每秒多少 KB 的宽带速度。比如,如果你得到的上行带宽是 21.5 Mbps那么这个数字应该是
```
21.5 Mbps / 8 * 1024 = 2752 KBytes per second
```
你可以限制你的中继带宽为那个数字的一半,并允许突发带宽为那个数字的四分之三。确定好之后,使用喜欢的文本编辑器打开 /etc/tor/torrc 文件,调整好带宽设置。
你可以限制你的中继带宽为那个数字的一半,并允许突发带宽为那个数字的四分之三。确定好之后,使用喜欢的文本编辑器打开 `/etc/tor/torrc` 文件,调整好带宽设置。
```
RelayBandwidthRate 1300 KBytes
RelayBandwidthBurst 2400 KBytes
```
当然,如果你想更慷慨,你可以将那几个设置的数字调的更大,但是尽量不要设置为最大的出口带宽 —— 如果设置的太高,它会影响你的日常使用。
你打开那个文件之后,你应该去设置更多的东西。首先是昵称 —— 只是为了你自己保存记录,第二个是联系信息,只需要一个电子邮件地址。由于你的中继是运行在无人值守模式下的,你应该使用一个定期检查的电子邮件地址 —— 如果你的中继节点离线超过 48 个小时,你将收到 “Tor Weather” 服务的告警信息。
```
Nickname myrpirelay
ContactInfo you@example.com
```
保存文件并重引导系统去启动 Tor 中继。
### 测试它确认有 Tor 流量通过
如果你想去确认中继节点的功能,你可以运行 “arm” 工具:
如果你想去确认中继节点的功能,你可以运行 `arm` 工具:
```
sudo -u debian-tor arm
```
它需要一点时间才显示,尤其是在老板子上。它通常会给你显示一个表示入站和出站流量(或者是错误信息,它将有助于你去排错)的柱状图。
@ -120,7 +104,7 @@ via: https://www.linux.com/blog/intro-to-linux/2018/6/turn-your-raspberry-pi-tor
作者:[Konstantin Ryabitsev][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,184 @@
4 种用于构建嵌入式 Linux 系统的工具
======
> 了解 Yocto、Buildroot、 OpenWRT和改造过的桌面发行版以确定哪种方式最适合你的项目。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/desk_clock_job_work.jpg?itok=Nj4fuhl6)
Linux 被部署到比 Linus Torvalds 在他的宿舍里开发时所预期的更广泛的设备。令人震惊的支持了各种芯片使得Linux 可以应用于大大小小的设备上:从 [IBM 的巨型机][1]到不如其连接的端口大的[微型设备][2],以及各种大小的设备。它被用于大型企业数据中心、互联网基础设施设备和个人的开发系统。它还为消费类电子产品、移动电话和许多物联网设备提供了动力。
在为桌面和企业级设备构建 Linux 软件时,开发者通常在他们的构建机器上使用桌面发行版,如 [Ubuntu][3] 以便尽可能与被部署的机器相似。如 [VirtualBox][4] 和 [Docker][5] 这样的工具使得开发、测试和生产环境更好的保持了一致。
### 什么是嵌入式系统?
维基百科将[嵌入式系统][6]定义为:“在更大的机械或电气系统中具有专用功能的计算机系统,往往伴随着实时计算限制。”
我觉得可以很简单地说,嵌入式系统是大多数人不认为是计算机的计算机。它的主要作用是作为某种设备,而不被视为通用计算平台。
嵌入式系统编程的开发环境通常与测试和生产环境大不相同。它们可能会使用不同的芯片架构、软件堆栈甚至操作系统。开发工作流程对于嵌入式开发人员与桌面和 Web 开发人员来说是非常不同的。通常,其构建后的输出将包含目标设备的整个软件映像,包括内核、设备驱动程序、库和应用程序软件(有时也包括引导加载程序)。
在本文中,我将对构建嵌入式 Linux 系统的四种常用方式进行纵览。我将介绍一下每种产品的工作原理,并提供足够的信息来帮助读者确定使用哪种工具进行设计。我不会教你如何使用它们中的任何一个;一旦缩小了选择范围,就有大量深入的在线学习资源。没有任何选择适用于所有情况,我希望提供足够的细节来指导您的决定。
### Yocto
[Yocto][7] 项目 [定义][8]为“一个开源协作项目,提供模板、工具和方法,帮助您为嵌入式产品创建定制的基于 Linux 的系统,而不管硬件架构如何。”它是用于创建定制的 Linux 运行时映像的配方、配置值和依赖关系的集合,可根据您的特定需求进行定制。
完全公开:我在嵌入式 Linux 中的大部分工作都集中在 Yocto 项目上,而且我对这个系统的认识和偏见可能很明显。
Yocto 使用 [Openembedded][9] 作为其构建系统。从技术上讲,这两个是独立的项目;然而,在实践中,用户不需要了解区别,项目名称经常可以互换使用。
Yocto 项目的输出大致由三部分组成:
  * **目标运行时二进制文件:**这些包括引导加载程序、内核、内核模块、根文件系统映像。以及将 Linux 部署到目标平台所需的任何其他辅助文件。
  * **包流:**这是可以安装在目标上的软件包集合。您可以根据需要选择软件包格式例如deb、rpm、ipk。其中一些可能预先安装在目标运行时二进制文件中但可以构建用于安装到已部署系统的软件包。
  * **目标 SDK**这些是安装在目标平台上的软件的库和头文件的集合。应用程序开发人员在构建代码时使用它们,以确保它们与适当的库链接
#### 优点
Yocto 项目在行业中得到广泛应用,并得到许多有影响力的公司的支持。此外,它还拥有一个庞大且充满活力的开发人员[社区][10]和[生态系统][11]。开源爱好者和企业赞助商的结合的方式有助于推动 Yocto 项目。
获得 Yocto 的支持有很多选择。如果您想自己动手,有书籍和其他培训材料。如果您想获得专业知识,有许多有 Yocto 经验的工程师。而且许多商业组织可以为您的设计提供基于 Yocto 的 Turnkey 产品或基于服务的实施和定制。
Yocto 项目很容易通过 [层][12] 进行扩展,层可以独立发布以添加额外的功能,或针对项目发布时尚不可用的平台,或用于保存系统特有定制功能。层可以添加到你的配置中,以添加未特别包含在市面上版本中的独特功能;例如,“[meta-browser] [13]” 层包含 Web 浏览器的清单,可以轻松为您的系统进行构建。因为它们是独立维护的,所以层可以按不同的时间发布(根据层的开发速度),而不是跟着标准的 Yocto 版本发布。
Yocto 可以说是本文讨论的任何方式中最广泛的设备支持。由于许多半导体和电路板制造商的支持Yocto 很可能能够支持您选择的任何目标平台。主版本 Yocto [分支][14]仅支持少数几块主板(以便达成合理的测试和发布周期),但是,标准工作模式是使用外部主板支持层。
最后Yocto 非常灵活和可定制。您的特定应用程序的自定义可以存储在一个层进行封装和隔离通常将要素层特有的自定义项存储为层本身的一部分这可以将相同的设置同时应用于多个系统配置。Yocto 还提供了一个定义良好的层优先和覆盖功能。这使您可以定义层应用和搜索元数据的顺序。它还使您可以覆盖具有更高优先级的层的设置;例如,现有清单的许多自定义功能都将保留。
#### 缺点
Yocto 项目最大的缺点是学习曲线陡峭。学习该系统并真正理解系统需要花费大量的时间和精力。 根据您的需求,这可能对您的应用程序不重要的技术和能力投入太大。 在这种情况下,与一家商业供应商合作可能是一个不错的选择。
Yocto 项目的开发时间和资源相当高。 需要构建的包(包括工具链,内核和所有目标运行时组件)的数量相当不少。 Yocto 开发人员的开发工作站往往是大型系统。 不建议使用小型笔记本电脑。 这可以通过使用许多提供商提供的基于云的构建服务器来缓解。 另外Yocto 有一个内置的缓存机制,当它确定用于构建特定包的参数没有改变时,它允许它重新使用先前构建的组件。
#### 建议
为您的下一个嵌入式 Linux 设计使用 Yocto 项目是一个强有力的选择。 在这里介绍的选项中,无论您的目标用例如何,它都是最广泛适用的。 广泛的行业支持,积极的社区和广泛的平台支持使其成为必须设计师的不错选择。
### Buildroot
[Buildroot][15] 项目定义为“通过交叉编译生成嵌入式 Linux 系统的简单、高效且易于使用的工具。”它与 Yocto 项目具有许多相同的目标但它注重简单性和简约性。一般来说Buildroot 会禁用所有软件包的所有可选编译时设置(有一些值得注意的例外),从而生成尽可能小的系统。系统设计人员需要启用适用于给定设备的设置。
Buildroot 从源代码构建所有组件,但不支持按目标包管理。因此,它有时称为固件生成器,因为镜像在构建时大部分是固定的。应用程序可以更新目标文件系统,但是没有机制将新软件包安装到正在运行的系统中。
Buildroot 输出主要由三部分组成:
  * 将 Linux 部署到目标平台所需的根文件系统映像和任何其他辅助文件
  * 适用于目标硬件的内核,引导加载程序和内核模块
  * 用于构建所有目标二进制文件的工具链。
#### 优点
Buildroot 对简单性的关注意味着,一般来说,它比 Yocto 更容易学习。核心构建系统用 Make 编写,并且足够短以便开发人员了解整个系统,同时可扩展到足以满足嵌入式 Linux 开发人员的需求。 Buildroot 核心通常只处理常见用例,但它可以通过脚本进行扩展。
Buildroot 系统使用普通的 Makefile 和 Kconfig 语言来进行配置。 Kconfig 由 Linux 内核社区开发,广泛用于开源项目,使得许多开发人员都熟悉它。
由于禁用所有可选的构建时设置的设计目标Buildroot 通常会使用开箱即用的配置生成尽可能最小的镜像。一般来说,构建时间和构建主机资源的规模将比 Yocto 项目的规模更小。
#### 缺点
关注简单性和最小化启用的构建方式意味着您可能需要执行大量的自定义来为应用程序配置 Buildroot 构建。此外,所有配置选项都存储在单个文件中,这意味着如果您有多个硬件平台,则需要为每个平台进行每个定制更改。
对系统配置文件的任何更改都需要全部重新构建所有软件包。与 Yocto 相比,这个问题通过最小的镜像大小和构建时间得到了一定的解决,但在你调整配置时可能会导致构建时间过长。
中间软件包状态缓存默认情况下未启用,并且不像 Yocto 实施那么彻底。这意味着,虽然第一次构建可能比等效的 Yocto 构建短,但后续构建可能需要重建许多组件。
#### 建议
对于大多数应用程序,使用 Buildroot 进行下一个嵌入式 Linux 设计是一个不错的选择。如果您的设计需要多种硬件类型或其他差异但由于同步多个配置的复杂性您可能需要重新考虑但对于由单一设置组成的系统Buildroot 可能适合您。
### OpenWRT/LEDE
[OpenWRT][16] 项目开始为消费类路由器开发定制固件。您当地零售商提供的许多低成本路由器都可以运行 Linux 系统,但可能无法开箱即用。这些路由器的制造商可能无法提供频繁的更新来解决新的威胁,即使他们这样做,安装更新镜像的机制也很困难且容易出错。 OpenWRT 项目为许多已被其制造商放弃的设备生成更新的固件镜像,让这些设备焕发新生。
OpenWRT 项目的主要交付物是可用于大量商业设备的二进制镜像。它有网络可访问的软件包存储库,允许设备最终用户将新软件添加到他们的系统中。 OpenWRT 构建系统是一个通用构建系统,它允许开发人员创建自定义版本以满足他们自己的需求并添加新软件包,但其主要重点是目标二进制文件。
#### 优点
如果您正在为商业设备寻找替代固件,则 OpenWRT 应位于您的选项列表中。它的维护良好,可以保护您免受制造商固件无法解决的问题。您也可以添加额外的功能,使您的设备更有用。
如果您的嵌入式设计专注于网络,则 OpenWRT 是一个不错的选择。网络应用程序是 OpenWRT 的主要用例,您可能会发现许多可用的软件包。
#### 缺点
OpenWRT 对您的设计限制很多(与 Yocto 和 Buildroot 相比)。如果这些决定不符合您的设计目标,则可能需要进行大量的修改。
在部署的设备中允许基于软件包的更新是很难管理的。按照其定义,这会导致与您的 QA 团队测试的软件负载不同。此外,很难保证大多数软件包管理器的原子安装,以及错误的电源循环可能会使您的设备处于不可预知的状态。
#### 建议
OpenWRT 是爱好者项目或商用硬件再利用的不错选择。它也是网络应用程序的不错选择。如果您需要从默认设置进行大量定制,您可能更喜欢 Buildroot 或 Yocto。
### 桌面发行版
设计嵌入式 Linux 系统的一种常见方法是从桌面发行版开始,例如 [Debian][17] 或 [Red Hat][18],并删除不需要的组件,直到安装的镜像符合目标设备的占用空间。这是 [Raspberry Pi][20] 平台流行的 [Raspbian][19]发行版的方法。
#### 优点
这种方法的主要优点是熟悉。通常,嵌入式 Linux 开发人员也是桌面 Linux 用户,并且精通他们的选择发行版。在目标上使用类似的环境可能会让开发人员更快地入门。根据所选的分布,可以使用 apt 和 yum 等标准封装工具安装许多其他工具。
可以将显示器和键盘连接到目标设备,并直接在那里进行所有的开发。对于不熟悉嵌入式空间的开发人员来说,这可能是一个更为熟悉的环境,无需配置和使用棘手的跨开发平台设置。
大多数桌面发行版可用的软件包数量通常大于前面讨论的嵌入式特定的构建器可用软件包数量。由于较大的用户群和更广泛的用例,您可能能够找到您的应用程序所需的所有运行时包,这些包已经构建并可供使用。
#### 缺点
将目标平台作为您的主要开发环境可能会很慢。运行编译器工具是一项资源密集型操作,根据您构建的代码的多少,这可能会严重妨碍您的性能。
除了一些例外情况,桌面发行版的设计并不适合低资源系统,并且可能难以充分裁剪目标映像。同样,桌面环境中的预设工作流程对于大多数嵌入式设计来说都不理想。以这种方式获得可再现的环境很困难。手动添加和删除软件包很容易出错。这可以使用特定于发行版的工具进行脚本化,例如基于 Debian 系统的 [debootstrap][21]。为了进一步提高[可再现性][21],您可以使用配置管理工具,如 [CFEngine][22](我的雇主 [Mender.io][23] 完整披露了
这一工具)。但是,您仍然受发行版提供商的支配,他们将更新软件包以满足他们的需求,而不是您的需求。
#### 建议
对于您打算推向市场的产品,请谨慎使用此方法。这对于爱好者应用程序来说是一个很好的模型;但是,对于需要支持的产品,这种方法很可能会遇到麻烦。虽然您可能能够获得更快的起步,但从长远来看,您可能会花费您的时间和精力。
### 其他考虑
这个讨论集中在构建系统的功能上但通常有非功能性需求可能会影响您的决定。如果您已经选择了片上系统SoC或电路板则您的选择很可能由供应商决定。如果您的供应商为特定系统提供板级支持包BSP使用它通常会节省相当多的时间但请研究 BSP 的质量以避免在开发周期后期发生问题。
如果您的预算允许,您可能需要考虑为目标操作系统使用商业供应商。有些公司会为这里讨论的许多选项提供经过验证和支持的配置,除非您拥有嵌入式 Linux 构建系统方面的专业知识,否则这是一个不错的选择,可以让您专注于核心能力。
作为替代,您可以考虑为您的开发人员进行商业培训。这可能比商业操作系统供应商便宜,并且可以让你更加自给自足。这是快速找到您选择的构建系统基础知识的学习曲线。
最后,您可能已经有一些开发人员拥有一个或多个系统的经验。如果你的工程师有倾向性,当你做出决定时,肯定值得考虑。
### 总结
构建嵌入式 Linux 系统有多种选择,每种都有优点和缺点。将这部分设计放在优先位置至关重要,因为在以后的过程中切换系统的成本非常高。除了这些选择之外,还有新的系统在开发中。希望这次讨论能够为评估新的系统(以及这里提到的系统)提供一些背景,并帮助您为下一个项目做出坚实的决定。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/6/embedded-linux-build-tools
作者:[Drew Moseley][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[LHRChina](https://github.com/LHRChina)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/drewmoseley
[1]:https://en.wikipedia.org/wiki/Linux_on_z_Systems
[2]:http://www.picotux.com/
[3]:https://www.ubuntu.com/
[4]:https://www.virtualbox.org/
[5]:https://www.docker.com/
[6]:https://en.wikipedia.org/wiki/Embedded_system
[7]:https://yoctoproject.org/
[8]:https://www.yoctoproject.org/about/
[9]:https://www.openembedded.org/
[10]:https://www.yoctoproject.org/community/
[11]:https://www.yoctoproject.org/ecosystem/participants/
[12]:https://layers.openembedded.org/layerindex/branch/master/layers/
[13]:https://layers.openembedded.org/layerindex/branch/master/layer/meta-browser/
[14]:https://yoctoproject.org/downloads
[15]:https://buildroot.org/
[16]:https://openwrt.org/
[17]:https://www.debian.org/
[18]:https://www.redhat.com/
[19]:https://www.raspbian.org/
[20]:https://www.raspberrypi.org/
[21]:https://wiki.debian.org/Debootstrap
[22]:https://cfengine.com/
[23]:http://Mender.io

View File

@ -0,0 +1,59 @@
BLUI创建游戏 UI 的简单方法
======
> 开源游戏开发插件运行虚幻引擎的用户使用基于 Web 的编程方式创建独特的用户界面元素。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/gaming_plugin_blui_screenshot.jpg?itok=91nnYCt_)
游戏开发引擎在过去几年中变得越来越易于​​使用。像 Unity 这样一直免费使用的引擎,以及最近从基于订阅的服务切换到免费服务的<ruby>虚幻引擎<rt>Unreal Engine</rt></ruby>,允许独立开发者使用 AAA 发行商相同达到行业标准的工具。虽然这些引擎都不是开源的,但每个引擎都能够促进其周围的开源生态系统的发展。
这些引擎中可以包含插件以允许开发人员通过添加特定程序来增强引擎的基本功能。这些程序的范围可以从简单的资源包到更复杂的事物,如人工智能 AI 集成。这些插件来自不同的创作者。有些是由引擎开发工作室和有些是个人提供的。后者中的很多是开源插件。
### 什么是 BLUI
作为独立游戏开发工作室的一员我体验到了在专有游戏引擎上使用开源插件的好处。Aaron Shea 开发的一个开源插件 [BLUI][1] 对我们团队的开发过程起到了重要作用。它允许我们使用基于 Web 的编程(如 HTML/CSS 和 JavaScript创建用户界面 UI 组件。尽管<ruby>虚幻引擎<rt>Unreal Engine</rt></ruby>(我们选择的引擎)有一个实现了类似目的的内置 UI 编辑器,我们也选择使用这个开源插件。我们选择使用开源替代品有三个主要原因:它们的可访问性、易于实现以及伴随的开源程序活跃的、支持性好的在线社区。
在虚幻引擎的最早版本中,我们在游戏中创建 UI 的唯一方法是通过引擎的原生 UI 集成,使用 Autodesk 的 Scaleform 程序,或通过在虚幻社区中传播的一些选定的基于订阅的虚幻引擎集成。在这些情况下,这些解决方案要么不能为独立开发者提供有竞争力的 UI 解决方案,对于小型团队来说太昂贵,要么只能为大型团队和 AAA 开发者提供。
在商业产品和虚幻引擎的原生整合失败后,我们向独立社区寻求解决方案。我们在那里发现了 BLUI。它不仅与虚幻引擎无缝集成而且还保持了一个强大且活跃的社区经常推出更新并确保独立开发人员可以轻松访问文档。BLUI 使开发人员能够将 HTML 文件导入虚幻引擎,并在程序内部对其进行编程。这使得通过 web 语言创建的 UI 能够集成到游戏的代码、资源和其他元素中,并拥有所有 HTML、CSS、Javascript 和其他网络语言的能力。它还为开源 [Chromium Embedded Framework][2] 提供全面支持。
### 安装和使用 BLUI
使用 BLUI 的基本过程包括首先通过 HTML 创建 UI。开发人员可以使用任何工具来实现此目的包括<ruby>自举<rt>bootstrapped</rt> JavaScript 代码、外部 API 或任何数据库代码。一旦这个 HTML 页面完成,你可以像安装任何虚幻引擎插件那样安装它,并加载或创建一个项目。项目加载后,你可以将 BLUI 函数放在虚幻引擎 UI 图纸中的任何位置,或者通过 C++ 进行硬编码。开发人员可以通过其 HTML 页面调用函数,或使用 BLUI 的内部函数轻松更改变量。
![Integrating BLUI into Unreal Engine 4 blueprints][4]
*将 BLUI 集成到虚幻 4 图纸中。*
在我们当前的项目中,我们使用 BLUI 将 UI 元素与游戏中的音轨同步,为游戏机制的节奏方面提供视觉反馈。将定制引擎编程与 BLUI 插件集成很容易。
![Using BLUI to sync UI elements with the soundtrack.][6]
*使用 BLUI 将 UI 元素与音轨同步。*
通过 BLUI GitHub 页面上的[文档][7],将 BLUI 集成到虚幻 4 中是一个轻松的过程。还有一个由支持虚幻引擎开发人员组成的[论坛][8],他们乐于询问和回答关于插件以及实现该工具时出现的任何问题。
### 开源优势
开源插件可以在专有游戏引擎的范围内扩展创意。他们继续降低进入游戏开发的障碍,并且可以产生前所未有的游戏内的机制和资源。随着对专有游戏开发引擎的访问持续增长,开源插件社区将变得更加重要。不断增长的创造力必将超过专有软件,开源代码将会填补这些空白,并促进开发真正独特的游戏。而这种新颖性正是让独立游戏如此美好的原因!
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/6/blui-game-development-plugin
作者:[Uwana lkaiddi][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/uwikaiddi
[1]:https://github.com/AaronShea/BLUI
[2]:https://bitbucket.org/chromiumembedded/cef
[3]:/file/400616
[4]:https://opensource.com/sites/default/files/uploads/blui_gaming_plugin-integratingblui.png (Integrating BLUI into Unreal Engine 4 blueprints)
[5]:/file/400621
[6]:https://opensource.com/sites/default/files/uploads/blui_gaming_plugin-syncui.png (Using BLUI to sync UI elements with the soundtrack.)
[7]:https://github.com/AaronShea/BLUI/wiki
[8]:https://forums.unrealengine.com/community/released-projects/29036-blui-open-source-html5-js-css-hud-ui

View File

@ -0,0 +1,122 @@
可代替 Dropbox 的 5 个开源软件
=====
> 寻找一个不会破坏你的安全、自由或银行资产的文件共享应用。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/dropbox.jpg?itok=qFwcqboT)
Dropbox 在文件共享应用中是个 800 磅的大猩猩。尽管它是个极度流行的工具,但你可能仍想使用一个软件去替代它。
也行你出于各种好的理由,包括安全和自由,这使你决定用[开源方式][1]。亦或是你已经被数据泄露吓坏了,或者定价计划不能满足你实际需要的存储量。
幸运的是,有各种各样的开源文件共享应用,可以提供给你更多的存储容量,更好的安全性,并且以低于 Dropbox 很多的价格来让你掌控你自己的数据。有多低呢?如果你有一定的技术和一台 Linux 服务器可供使用,那尝试一下免费的应用吧。
这里有 5 个最好的可以代替 Dropbox 的开源应用,以及其他一些,你可能想考虑使用。
### ownCloud
![](https://opensource.com/sites/default/files/uploads/owncloud.png)
[ownCloud][2] 发布于 2010 年,是本文所列应用中最老的,但是不要被这件事蒙蔽:它仍然十分流行(根据该公司统计,有超过 150 万用户),并且由由 1100 个参与者的社区积极维护,定期发布更新。
它的主要特点——文件共享和文档写作功能和 Dropbox 的功能相似。它们的主要区别(除了它的[开源协议][3])是你的文件可以托管在你的私人 Linux 服务器或云上,给予用户对自己数据完全的控制权。(自托管是本文所列应用的一个普遍的功能。)
使用 ownCloud你可以通过 Linux、MacOS 或 Windows 的客户端和安卓、iOS 的移动应用程序来同步和访问文件。你还可以通过带有密码保护的链接分享给其他人来协作或者上传和下载。数据传输通过端到端加密E2EE和 SSL 加密来保护安全。你还可以通过使用它的 [市场][4] 中的各种各样的第三方应用来扩展它的功能。当然,它也提供付费的、商业许可的企业版本。
ownCloud 提供了详尽的[文档][5],包括安装指南和针对用户、管理员、开发者的手册。你可以从 GitHub 仓库中获取它的[源码][6]。
### NextCloud
![](https://opensource.com/sites/default/files/uploads/nextcloud.png)
[NextCloud][7] 在 2016 年从 ownCloud 分裂出来,并且具有很多相同的功能。 NextCloud 以它的高安全性和法规遵从性作为它的一个独特的[推崇的卖点][8]。它具有 HIPAA (医疗) 和 GDPR (隐私)法规遵从功能,并提供广泛的数据策略约束、加密、用户管理和审核功能。它还在传输和存储期间对数据进行加密,并且集成了移动设备管理和身份验证机制 (包括 LDAP/AD、单点登录、双因素身份验证等
像本文列表里的其他应用一样, NextCloud 是自托管的,但是如果你不想在自己的 Linux 上安装 NextCloud 服务器,该公司与几个[提供商][9]达成了伙伴合作,提供安装和托管,并销售服务器、设备和服务支持。在[市场][10]中提供了大量的apps 来扩展它的功能。
NextCloud 的[文档][11]为用户、管理员和开发者提供了详细的信息并且它的论坛、IRC 频道和社交媒体提供了基于社区的支持。如果你想贡献或者获取它的源码、报告一个错误、查看它的 AGPLv3 许可,或者想了解更多,请访问它的[GitHub 项目主页][12]。
### Seafile
![](https://opensource.com/sites/default/files/uploads/seafile.png)
与 ownCloud 或 NextCloud 相比,[Seafile][13] 或许没有花里胡哨的卖点app 生态),但是它能完成任务。实质上, 它充当了 Linux 服务器上的虚拟驱动器,以扩展你的桌面存储,并允许你使用密码保护和各种级别的权限(即只读或读写) 有选择地共享文件。
它的协作功能包括文件夹权限控制,密码保护的下载链接和像 Git 一样的版本控制和记录。文件使用双因素身份验证、文件加密和 AD/LDAP 集成进行保护,并且可以从 Windows、MacOS、Linux、iOS 或 Android 设备进行访问。
更多详细信息, 请访问 Seafile 的 [GitHub 仓库][14]、[服务手册][15]、[wiki][16] 和[论坛][17]。请注意, Seafile 的社区版在 [GPLv2][18] 下获得许可,但其专业版不是开源的。
### OnionShare
![](https://opensource.com/sites/default/files/uploads/onionshare.png)
[OnionShare][19] 是一个很酷的应用:如果你想匿名,它允许你安全地共享单个文件或文件夹。不需要设置或维护服务器,所有你需要做的就是[下载和安装][20],无论是在 MacOS, Windows 还是 Linux 上。文件始终在你自己的计算机上; 当你共享文件时OnionShare 创建一个 web 服务器,使其可作为 Tor 洋葱服务访问,并生成一个不可猜测的 .onion URL这个 URL 允许收件人通过 [Tor 浏览器][21]获取文件。
你可以设置文件共享的限制,例如限制可以下载的次数或使用自动停止计时器,这会设置一个严格的过期日期/时间,超过这个期限便不可访问(即使尚未访问该文件)。
OnionShare 在 [GPLv3][22] 之下被许可;有关详细信息,请查阅其 [GitHub 仓库][22],其中还包括[文档][23],介绍了这个易用的文件共享软件的特点。
### Pydio Cells
![](https://opensource.com/sites/default/files/uploads/pydiochat.png)
[Pydio Cells][24] 在 2018 年 5 月推出了稳定版,是对 Pydio 共享应用程序的核心服务器代码的彻底大修。由于 Pydio 的基于 PHP 的后端的限制,开发人员决定用 Go 服务器语言和微服务体系结构重写后端。(前端仍然是基于 PHP 的)。
Pydio Cells 包括通常的共享和版本控制功能以及应用程序中的消息接受、移动应用程序Android 和 iOS以及一种社交网络风格的协作方法。安全性包括基于 OpenID 连接的身份验证、rest 加密、安全策略等。企业发行版中包含着高级功能,但在社区(家庭)版本中,对于大多数中小型企业和家庭用户来说,依然是足够的。
您可以 在 Linux 和 MacOS 里[下载][25] Pydio Cells。有关详细信息, 请查阅 [文档常见问题][26]、[源码库][27] 和 [AGPLv3 许可证][28]
### 其他
如果以上选择不能满足你的需求,你可能想考虑其他开源的文件共享型应用。
* 如果你的主要目的是在设备间同步文件而不是分享文件,考察一下 [Syncthing][29]。
* 如果你是一个 Git 的粉丝而不需要一个移动应用。你可能更喜欢 [SparkleShare][30]。
* 如果你主要想要一个地方聚合所有你的个人数据, 看看 [Cozy][31]。
* 如果你想找一个轻量级的或者专注于文件共享的工具,考察一下 [Scott Nesbitt's review][32]——一个罕为人知的工具。
哪个是你最喜欢的开源文件共享应用?在评论中让我们知悉。
--------------------------------------------------------------------------------
via: https://opensource.com/alternatives/dropbox
作者:[Opensource.com][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[distant1219](https://github.com/distant1219)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com
[1]:https://opensource.com/open-source-way
[2]:https://owncloud.org/
[3]:https://www.gnu.org/licenses/agpl-3.0.html
[4]:https://marketplace.owncloud.com/
[5]:https://doc.owncloud.com/
[6]:https://github.com/owncloud
[7]:https://nextcloud.com/
[8]:https://nextcloud.com/secure/
[9]:https://nextcloud.com/providers/
[10]:https://apps.nextcloud.com/
[11]:https://nextcloud.com/support/
[12]:https://github.com/nextcloud
[13]:https://www.seafile.com/en/home/
[14]:https://github.com/haiwen/seafile
[15]:https://manual.seafile.com/
[16]:https://seacloud.cc/group/3/wiki/
[17]:https://forum.seafile.com/
[18]:https://github.com/haiwen/seafile/blob/master/LICENSE.txt
[19]:https://onionshare.org/
[20]:https://onionshare.org/#downloads
[21]:https://www.torproject.org/
[22]:https://github.com/micahflee/onionshare/blob/develop/LICENSE
[23]:https://github.com/micahflee/onionshare/wiki
[24]:https://pydio.com/en
[25]:https://pydio.com/download/
[26]:https://pydio.com/en/docs/faq
[27]:https://github.com/pydio/cells
[28]:https://github.com/pydio/pydio-core/blob/develop/LICENSE
[29]:https://syncthing.net/
[30]:http://www.sparkleshare.org/
[31]:https://cozy.io/en/
[32]:https://opensource.com/article/17/3/file-sharing-tools

View File

@ -0,0 +1,91 @@
使用 Open edX 托管课程
======
> Open edX 为各种规模和类型的组织提供了一个强大而多功能的开源课程管理的解决方案。要不要了解一下。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003588_01_rd3os.combacktoschoolseriesgen_rh_032x_0.png?itok=cApG9aB4)
[Open edX 平台][2] 是一个自由开源的课程管理系统,它是 [全世界][3] 都在使用的大规模网络公开课MOOC以及小型课程和培训模块的托管平台。在 Open edX 的 [第七个主要发行版][1] 中,到现在为止,它已经提供了超过 8,000 个原创课程和 5000 万个课程注册数。你可以使用你自己的本地设备或者任何行业领先的云基础设施服务提供商来安装这个平台,而且,随着项目的[服务提供商][4]名单越来越长来自它们中的软件即服务SaaS的可用模型也越来越多了。
Open edX 平台被来自世界各地的顶尖教育机构、私人公司、公共机构、非政府组织、非营利机构,以及教育技术初创企业广泛地使用,并且该项目的服务提供商全球社区不断地让甚至更小的组织也可以访问这个平台。如果你打算向广大的读者设计和提供教育内容,你应该考虑去使用 Open edX 平台。
### 安装
安装这个软件有多种方式,这可能有点让你难以选择,至少刚开始是这样。但是不管你是以何种方式 [安装 Open edX][5]最终你都得到的是有相同功能的应用程序。默认安装包含一个为在线学习者提供的、全功能的学习管理系统LMS和一个全功能的课程管理工作室CMSCMS 可以让你的讲师团队用它来编写原创课程内容。你可以把 CMS 当做是课程内容设计和管理的 “[Wordpress][6]”,把 LMS 当做是课程销售、分发、和消费的 “[Magento][7]”。
Open edX 是设备无关的、完全响应式的应用软件,并且不用花费很多的努力就可发布一个原生的 iOS 和 Android 应用它可以无缝地集成到你的实例后端。Open edX 平台的代码库、原生移动应用、以及安装脚本都发布在 [GitHub][8] 上。
#### 有何期望
Open edX 平台的 [GitHub 仓库][9] 包含适用于各种类型的组织的、性能很好的、产品级的代码。来自数百个机构的数千名程序员经常为 edX 仓库做贡献,并且这个平台是一个名副其实的、研究如何去构建和管理一个复杂的企业级应用的好案例。因此,尽管你可能会遇到大量的类似“如何将平台迁移到生产环境中”的问题,但是你无需对 Open edX 平台代码库本身的质量和健状性担忧。
通过少量的培训你的讲师就可以去设计不错的在线课程。但是请记住Open edX 是通过它的 [XBlock][10] 组件架构进行扩展的,因此,通过他们和你的努力,你的讲师将有可能将不错的课程变成精品课程。
这个平台在单服务器环境下也运行的很好,并且它是高度模块化的,几乎可以进行无限地水平扩展。它也是主题化的和本地化的,平台的功能和外观可以根据你的需要进行几乎无限制地调整。平台在你的设备上可以按需安装并可靠地运行。
#### 需要一些封装
请记住,有大量的 edX 软件模块是不包含在默认安装中的,并且这些模块提供的经常都是各种组织所需要的功能。比如,分析模块、电商模块,以及课程的通知/公告模块都是不包含在默认安装中的,并且这些单独的模块都是值得安装的。另外,在数据备份/恢复和系统管理方面要完全依赖你自己去处理。幸运的是,有关这方面的内容,社区有越来越多的文档和如何去做的文章。你可以通过 Google 和 Bing 去搜索,以帮助你在生产环境中安装它们。
虽然有很多文档良好的程序,但是根据你的技能水平,配置 [oAuth][11] 和 [SSL/TLS][12],以及使用平台的 [REST API][13] 可能对你是一个挑战。另外,一些组织要求将 MySQL 和/或 MongoDB 数据库在中心化环境中管理如果你正好是这种情况你还需要将这些服务从默认平台安装中分离出来。edX 设计团队已经尽可能地为你做了简化,但是由于它是一个非常重大的更改,因此可能需要一些时间去实现。
如果你面临资源和/或技术上的困难 —— 不要气馁Open edX 社区 SaaS 提供商,像 [appsembler][14] 和 [eduNEXT][15],提供了引人入胜的替代方案去进行 DIY 安装,尤其是如果你只想简单购买就行。
### 技术栈
在 Open edX 平台的安装上探索是件令人兴奋的事情,从架构的角度来说,这个项目是一个典范。应用程序模块是 [Django][16] 应用,它利用了大量的开源社区的顶尖项目,包括 [Ubuntu][17]、[MySQL][18]、[MongoDB][19]、[RabbitMQ][20]、[Elasticsearch][21]、[Hadoop][22]、等等。
![edx-architecture.png][24]
*Open edX 技术栈CC BY来自 edX*
将这些组件安装并配置好本身就是一件非常不容易的事情,但是以这样的一种方式将所有的组件去打包,并适合于任意规模和复杂性的组织,并且能够按他们的需要进行任意调整搭配而无需在代码上做重大改动,看起来似乎是不可能的事情 —— 它就是这种情况,直到你看到主要的平台配置参数安排和命名是多少的巧妙和直观。请注意,平台的组织结构有一个学习曲线,但是,你所学习的一切都是值的去学习的,不仅是对这个项目,对一般意义上的大型 IT 项目都是如此。
提醒一点:这个平台的 UI 是在不断变动的,最终的目标是在 [React][25] 和 [Bootstrap][26] 上实现标准化。与此同时,你将会发现基本主题有多个实现的样式,这可能会让你感到困惑。
### 采用
edX 项目能够迅速得到世界范围内的采纳,很大程度上取决于该软件的运行情况。这一点也不奇怪,这个项目成功地吸引了大量才华卓越的人参与其中,他们作为程序员、项目顾问、翻译者、技术作者、以及博客作者参与了项目的贡献。一年一次的 [Open edX 会议][27]、[官方的 edX Google Group][28]、以及 [Open edX 服务提供商名单][4] 是了解这个多样化的、不断成长的生态系统的非常好的起点。我作为相对而言的新人,我发现参与和直接从事这个项目的各个方面是非常容易的。
祝你学习之旅一切顺利,并且当你构思你的项目时,你可以随时联系我。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/6/getting-started-open-edx
作者:[Lawrence Mc Daniel][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[qhwdw](https://github.com/qhwdw)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/mcdaniel0073
[1]:https://openedx.atlassian.net/wiki/spaces/DOC/pages/11108700/Open+edX+Releases
[2]:https://open.edx.org/about-open-edx
[3]:https://www.edx.org/schools-partners
[4]:https://openedx.atlassian.net/wiki/spaces/COMM/pages/65667081/Open+edX+Service+Providers
[5]:https://openedx.atlassian.net/wiki/spaces/OpenOPS/pages/60227779/Open+edX+Installation+Options
[6]:https://wordpress.com/
[7]:https://magento.com/
[8]:https://github.com/edx
[9]:https://github.com/edx/edx-platform
[10]:https://open.edx.org/xblocks
[11]:https://oauth.net/
[12]:https://en.wikipedia.org/wiki/Transport_Layer_Security
[13]:https://en.wikipedia.org/wiki/Representational_state_transfer
[14]:https://www.appsembler.com/
[15]:https://www.edunext.co/
[16]:https://www.djangoproject.com/
[17]:https://www.ubuntu.com/
[18]:https://www.mysql.com/
[19]:https://www.mongodb.com/
[20]:https://www.rabbitmq.com/
[21]:https://www.elastic.co/
[22]:http://hadoop.apache.org/
[23]:/file/400696
[24]:https://opensource.com/sites/default/files/uploads/edx-architecture_0.png "edx-architecture.png"
[25]:%E2%80%9Chttps://reactjs.org/%E2%80%9C
[26]:%E2%80%9Chttps://getbootstrap.com/%E2%80%9C
[27]:https://con.openedx.org/
[28]:https://groups.google.com/forum/#!forum/openedx-ops

View File

@ -0,0 +1,160 @@
如何在 Linux 上检查用户所属组
======
将用户添加到现有组是 Linux 管理员的常规活动之一。这是一些在大环境中工作的管理员的日常活动。
甚至我会因为业务需求而在我的环境中每天都在进行这样的活动。它是帮助你识别环境中现有组的重要命令之一。
此外,这些命令还可以帮助你识别用户所属的组。所有用户都列在 `/etc/passwd` 中,组列在 `/etc/group` 中。
无论我们使用什么命令,都将从这些文件中获取信息。此外,每个命令都有其独特的功能,可帮助用户单独获取所需的信息。
### 什么是 /etc/passwd
`/etc/passwd` 是一个文本文件,其中包含登录 Linux 系统所必需的每个用户信息。它维护有用的用户信息,如用户名、密码、用户 ID、组 ID、用户 ID 信息、家目录和 shell。passwd 每行包含了用户的详细信息,共有如上所述的 7 个字段。
```
$ grep "daygeek" /etc/passwd
daygeek:x:1000:1000:daygeek,,,:/home/daygeek:/bin/bash
```
### 什么是 /etc/group
`/etc/group` 是一个文本文件,用于定义用户所属的组。我们可以将多个用户添加到单个组中。它允许用户访问其他用户文件和文件夹,因为 Linux 权限分为三类:用户、组和其他。它维护有关组的有用信息,例如组名、组密码,组 IDGID和成员列表。每个都在一个单独的行。组文件每行包含了每个组的详细信息共有 4 个如上所述字段。
这可以通过使用以下方法来执行。
* `groups` 显示一个组的所有成员。
* `id` 打印指定用户名的用户和组信息。
* `lid` 显示用户的组或组的用户。
* `getent` 从 Name Service Switch 库中获取条目。
* `grep` 代表“<ruby>全局正则表达式打印<rt>global regular expression print</rt></ruby>”,它能打印匹配的模式。
### 什么是 groups 命令?
`groups` 命令打印每个给定用户名的主要组和任何补充组的名称。
```
$ groups daygeek
daygeek : daygeek adm cdrom sudo dip plugdev lpadmin sambashare
```
如果要检查与当前用户关联的组列表。只需运行 `groups` 命令,无需带任何用户名。
```
$ groups
daygeek adm cdrom sudo dip plugdev lpadmin sambashare
```
### 什么是 id 命令?
id 代表 “<ruby>身份<rt>identity</rt></ruby>”。它打印真实有效的用户和组 ID。打印指定用户或当前用户的用户和组信息。
```
$ id daygeek
uid=1000(daygeek) gid=1000(daygeek) groups=1000(daygeek),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),118(lpadmin),128(sambashare)
```
如果要检查与当前用户关联的组列表。只运行 `id` 命令,无需带任何用户名。
```
$ id
uid=1000(daygeek) gid=1000(daygeek) groups=1000(daygeek),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),118(lpadmin),128(sambashare)
```
### 什么是 lid 命令?
它显示用户的组或组的用户。显示有关包含用户名的组或组名称中包含的用户的信息。此命令需要管理员权限。
```
$ sudo lid daygeek
adm(gid=4)
cdrom(gid=24)
sudo(gid=27)
dip(gid=30)
plugdev(gid=46)
lpadmin(gid=108)
daygeek(gid=1000)
sambashare(gid=124)
```
### 什么是 getent 命令?
`getent` 命令显示 Name Service Switch 库支持的数据库中的条目,它们在 `/etc/nsswitch.conf` 中配置。
```
$ getent group | grep daygeek
adm:x:4:syslog,daygeek
cdrom:x:24:daygeek
sudo:x:27:daygeek
dip:x:30:daygeek
plugdev:x:46:daygeek
lpadmin:x:118:daygeek
daygeek:x:1000:
sambashare:x:128:daygeek
```
如果你只想打印关联的组名称,请在上面的命令中使用 `awk`
```
$ getent group | grep daygeek | awk -F: '{print $1}'
adm
cdrom
sudo
dip
plugdev
lpadmin
daygeek
sambashare
```
运行以下命令仅打印主群组信息。
```
$ getent group daygeek
daygeek:x:1000:
```
### 什么是 grep 命令?
`grep` 代表 “<ruby>全局正则表达式打印<rt>global regular expression print</rt></ruby>”,它能打印文件匹配的模式。
```
$ grep "daygeek" /etc/group
adm:x:4:syslog,daygeek
cdrom:x:24:daygeek
sudo:x:27:daygeek
dip:x:30:daygeek
plugdev:x:46:daygeek
lpadmin:x:118:daygeek
daygeek:x:1000:
sambashare:x:128:daygeek
```
如果你只想打印关联的组名称,请在上面的命令中使用 `awk`
```
$ grep "daygeek" /etc/group | awk -F: '{print $1}'
adm
cdrom
sudo
dip
plugdev
lpadmin
daygeek
sambashare
```
--------------------------------------------------------------------------------
via: https://www.2daygeek.com/how-to-check-which-groups-a-user-belongs-to-on-linux/
作者:[Prakash Subramanian][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.2daygeek.com/author/prakash/

View File

@ -0,0 +1,77 @@
使用 LSWC 在 Linux 中自动更改壁纸
======
> 简介:这是一个小脚本,可以在 Linux 桌面上定期自动更改壁纸。
顾名思义LittleSimpleWallpaperChanger LSWC是一个小脚本可以定期地随机更改壁纸。
我知道在“外观”或“更改桌面背景”设置中有一个随机壁纸选项。但那是随机更改预置的壁纸而不是你添加的壁纸。
因此,在本文中,我们将看到如何使用 LittleSimpleWallpaperChanger 设置包含照片的随机桌面壁纸。
### Little Simple Wallpaper Changer (LSWC)
[LittleSimpleWallpaperChanger][1] LSWC 是一个非常轻量级的脚本,它在后台运行,从用户指定的文件夹中更改壁纸。壁纸以 1 至 5 分钟的随机间隔变化。该软件设置起来相当简单,设置完后,用户就可以不用再操心了。
![Little Simple Wallpaper Changer to change wallpapers in Linux][2]
#### 安装 LSWC
[点此链接下载 LSWC][3]。压缩文件的大小约为 15KB。
* 进入下载位置。
* 右键单击下载的 .zip 文件,然后选择“在此处解压”。
* 打开解压后的文件夹,右键单击并选择“在终端中打开”。
* 在终端中复制粘贴命令 `bash ./README_and_install.sh` 并按回车键。
* 然后会弹出一个对话框,要求你选择包含壁纸的文件夹。单击它,然后选择你存放壁纸的文件夹。
* 就是这样。然后重启计算机。
![Little Simple Wallpaper Changer for Linux][4]
#### 使用 LSWC
安装时LSWC 会要求你选择包含壁纸的文件夹。因此,我建议你在安装 LSWC 之前创建一个文件夹并将你想要的壁纸全部移动到那。或者你可以使用图片文件夹中的“壁纸”文件夹。**所有壁纸都必须是 .jpg 格式。**
你可以添加更多壁纸或从所选文件夹中删除当前壁纸。要更改壁纸文件夹位置,你可以从以下文件中编辑壁纸的位置。
```
.config/lswc/homepath.conf
```
#### 删除 LSWC
打开终端并运行以下命令以停止 LSWC
```
pkill lswc
```
在文件管理器中打开家目录,然后按 `Ctrl+H` 显示隐藏文件,接着删除以下文件:
* `.local` 中的 `scripts` 文件夹
* `.config` 中的 `lswc` 文件夹
* `.config/autostart` 中的 `lswc.desktop` 文件
这就完成了。创建自己的桌面背景幻灯片。LSWC 非常轻巧,易于使用。安装它然后忘记它。
LSWC 功能不是很丰富,但这是有意的。它做了它打算做的事情,那就是更换壁纸。如果你想要一个自动下载壁纸的工具试试 [WallpaperDownloader][5]。
请在下面的评论栏分享你对这个漂亮的小软件的想法。别忘了分享这篇文章。干杯。
--------------------------------------------------------------------------------
via: https://itsfoss.com/little-simple-wallpaper-changer/
作者:[Aquil Roshan][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://itsfoss.com/author/aquil/
[1]:https://github.com/LittleSimpleWallpaperChanger/lswc
[2]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/05/Little-simple-wallpaper-changer-2-800x450.jpg
[3]:https://github.com/LittleSimpleWallpaperChanger/lswc/raw/master/Lswc.zip
[4]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/05/Little-simple-wallpaper-changer-1-800x450.jpg
[5]:https://itsfoss.com/wallpaperdownloader-linux/

View File

@ -0,0 +1,120 @@
如何在 Linux 中使用一个命令升级所有软件
======
![](https://www.ostechnix.com/wp-content/uploads/2018/06/topgrade-720x340.png)
众所周知,让我们的 Linux 系统保持最新状态会用到多种包管理器。比如说,在 Ubuntu 中,你无法使用 `sudo apt update``sudo apt upgrade` 命令升级所有软件。此命令仅升级使用 APT 包管理器安装的应用程序。你有可能使用 `cargo`、[pip][1]、`npm`、`snap` 、`flatpak` 或 [Linuxbrew][2] 包管理器安装了其他软件。你需要使用相应的包管理器才能使它们全部更新。
再也不用这样了!跟 `topgrade` 打个招呼,这是一个可以一次性升级系统中所有软件的工具。
你无需运行每个包管理器来更新包。这个 `topgrade` 工具通过检测已安装的软件包、工具、插件并运行相应的软件包管理器来更新 Linux 中的所有软件,用一条命令解决了这个问题。它是自由而开源的,使用 **rust 语言**编写。它支持 GNU/Linux 和 Mac OS X.
### 在 Linux 中使用一个命令升级所有软件
`topgrade` 存在于 AUR 中。因此,你可以在任何基于 Arch 的系统中使用 [Yay][3] 助手程序安装它。
```
$ yay -S topgrade
```
在其他 Linux 发行版上,你可以使用 `cargo` 包管理器安装 `topgrade`。要安装 cargo 包管理器,请参阅以下链接:
- [在 Linux 安装 rust 语言][12]
然后,运行以下命令来安装 `topgrade`
```
$ cargo install topgrade
```
安装完成后,运行 `topgrade` 以升级 Linux 系统中的所有软件。
```
$ topgrade
```
一旦调用了 `topgrade`,它将逐个执行以下任务。如有必要,系统会要求输入 root/sudo 用户密码。
1、 运行系统的包管理器:
* Arch运行 `yay` 或者回退到 [pacman][4]
* CentOS/RHEL运行 `yum upgrade`
* Fedora :运行 `dnf upgrade`
* Debian/Ubuntu运行 `apt update``apt dist-upgrade`
* Linux/macOS运行 `brew update``brew upgrade`
2、 检查 Git 是否跟踪了以下路径。如果有,则拉取它们:
* `~/.emacs.d` (无论你使用 Spacemacs 还是自定义配置都应该可用)
* `~/.zshrc`
* `~/.oh-my-zsh`
* `~/.tmux`
* `~/.config/fish/config.fish`
* 自定义路径
3、 Unix运行 `zplug` 更新
4、 Unix使用 TPM 升级 `tmux` 插件
5、 运行 `cargo install-update`
6、 升级 Emacs 包
7、 升级 Vim 包。对以下插件框架均可用:
* NeoBundle
* [Vundle][5]
* Plug
8、 升级 [npm][6] 全局安装的包
9、 升级 Atom 包
10、 升级 [Flatpak][7] 包
11、 升级 [snap][8] 包
12、 Linux运行 `fwupdmgr` 显示固件升级。 (仅查看​​。实际不会执行升级)
13、 运行自定义命令。
最后,`topgrade` 将运行 `needrestart` 以重新启动所有服务。在 Mac OS X 中,它会升级 App Store 程序。
我的 Ubuntu 18.04 LTS 测试环境的示例输出:
![][10]
好处是如果一个任务失败,它将自动运行下一个任务并完成所有其他后续任务。最后,它将显示摘要,其中包含运行的任务数量,成功的数量和失败的数量等详细信息。
![][11]
**建议阅读:**
就个人而言,我喜欢创建一个像 `topgrade` 程序的想法,并使用一个命令升级使用各种包管理器安装的所有软件。我希望你也觉得它有用。还有更多的好东西。敬请关注!
干杯!
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/how-to-upgrade-everything-using-a-single-command-in-linux/
作者:[SK][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.ostechnix.com/author/sk/
[1]:https://www.ostechnix.com/manage-python-packages-using-pip/
[2]:https://www.ostechnix.com/linuxbrew-common-package-manager-linux-mac-os-x/
[3]:https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/
[4]:https://www.ostechnix.com/getting-started-pacman/
[5]:https://www.ostechnix.com/manage-vim-plugins-using-vundle-linux/
[6]:https://www.ostechnix.com/manage-nodejs-packages-using-npm/
[7]:https://www.ostechnix.com/flatpak-new-framework-desktop-applications-linux/
[8]:https://www.ostechnix.com/install-snap-packages-arch-linux-fedora/
[9]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
[10]:http://www.ostechnix.com/wp-content/uploads/2018/06/topgrade-1.png
[11]:http://www.ostechnix.com/wp-content/uploads/2018/06/topgrade-2.png
[12]:https://www.ostechnix.com/install-rust-programming-language-in-linux/

View File

@ -0,0 +1,92 @@
如何在 Fedora 上安装 Pipenv
======
![](https://fedoramagazine.org/wp-content/uploads/2018/06/pipenv-install-816x345.jpg)
Pipenv 的目标是将打包界bundler、composer、npm、cargo、yarn 等)最好的东西带到 Python 世界来。它试图解决一些问题,并简化整个管理过程。
目前Python 程序依赖项的管理有时似乎是一个挑战。开发人员通常为每个新项目创建一个[虚拟环境][1],并使用 [pip][2] 将依赖项安装到其中。此外,他们必须将已安装的软件包的集合保存到 `requirements.txt` 文件中。我们看到过许多旨在自动化此工作流程的工具和包装程序。但是,仍然需要结合多个程序,并且 `requirements.txt` 格式本身并不适用于更复杂的场景。
### 一个统治它们的工具
Pipenv 可以正确地管理复杂的相互依赖关系,它还提供已安装包的手动记录。例如,开发、测试和生产环境通常需要一组不同的包。过去,每个项目需要维护多个 `requirements.txt`。Pipenv 使用 [TOML][4] 语法引入了新的 [Pipfile][3] 格式。多亏这种格式,你终于可以在单个文件中维护不同环境的多组需求。
在将第一行代码提交到项目中仅一年后Pipenv 已成为管理 Python 程序依赖关系的官方推荐工具。现在它终于在 Fedora 仓库中提供。
### 在 Fedora 上安装 Pipenv
在全新安装 Fedora 28 及更高版本后,你只需在终端上运行此命令即可安装 Pipenv
```
$ sudo dnf install pipenv
```
现在,你的系统已准备好在 Pipenv 的帮助下开始使用新的 Python 3 程序。
重要的是,虽然这个工具为程序提供了很好的解决方案,但它并不是为处理库需求而设计的。编写 Python 库时,不需要固定依赖项。你应该在 `setup.py` 文件中指定 `install_requires`
### 基本依赖管理
首先为项目创建一个目录:
```
$ mkdir new-project && cd new-project
```
接下来是为此项目创建虚拟环境:
```
$ pipenv --three
```
这里的 `-three` 选项将虚拟环境的 Python 版本设置为 Python 3。
安装依赖项:
```
$ pipenv install requests
Installing requests…
Adding requests to Pipfile's [packages]…
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
```
最后生成 lockfile
```
$ pipenv lock
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (b14837)
```
你还可以检查依赖关系图:
```
$ pipenv graph
- certifi [required: >=2017.4.17, installed: 2018.4.16]
- chardet [required: <3.1.0,>=3.0.2, installed: 3.0.4]
- idna [required: <2.8,>=2.5, installed: 2.7]
- urllib3 [required: >=1.21.1,<1.24, installed: 1.23]
```
有关 Pipenv 及其命令的更多详细信息,请参见[文档][5]。
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/install-pipenv-fedora/
作者:[Michal Cyprian][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://fedoramagazine.org/author/mcyprian/
[1]:https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments
[2]:https://developer.fedoraproject.org/tech/languages/python/pypi-installation.html
[3]:https://github.com/pypa/pipfile
[4]:https://github.com/toml-lang/toml
[5]:https://docs.pipenv.org/

View File

@ -1,67 +1,72 @@
Linux 上的五个开源益智游戏
======
> 用这些有趣好玩的游戏来测试你的战略能力。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/puzzle-pieces.jpg?itok=YHIN4_0L)
游戏一直是 Linux 的弱点之一。由于 Steam、GOG 和其他将商业游戏引入多种操作系统的努力,这种情况近年来有所改变,但这些游戏通常不是开源的。当然,这些游戏可以在开源操作系统上玩,但对于纯粹开源主义者来说还不够好。
那么,一个只使用开源软件的人,能否找到那些经过足够打磨的游戏,在不损害其开源理念的前提下,提供一种可靠的游戏体验呢?当然可以。虽然开源游戏历来不太可能与一些借由大量预算开发的 AAA 商业游戏相匹敌,但在多种类型的开源游戏中,有很多都很有趣,可以从大多数主要 Linux 发行版的仓库中安装。即使某个特定的游戏没有被打包成特定的发行版本,通常也很容易从项目的网站上下载该游戏以便安装和游戏。
那么,一个只使用开源软件的人,能否找到那些经过足够打磨的游戏,在不损害其开源理念的前提下,提供一种可靠的游戏体验呢当然可以。虽然开源游戏历来不太可能与一些借由大量预算开发的 AAA 商业游戏相匹敌,但在多种类型的开源游戏中,有很多都很有趣,可以从大多数主要 Linux 发行版的仓库中安装。即使某个特定的游戏没有被打包成特定的发行版本,通常也很容易从项目的网站上下载该游戏以便安装和游戏。
这篇文章着眼于益智游戏。我已经写过[街机风格游戏][1]和[棋牌游戏][2]. 在之后的文章中,我计划涉足赛车,角色扮演,战略和模拟经营游戏。
这篇文章着眼于益智游戏。我已经写过[街机风格游戏][1]和[棋牌游戏][2]。 在之后的文章中,我计划涉足赛车,角色扮演、战略和模拟经营游戏。
### Atomix
### Atomix
![](https://opensource.com/sites/default/files/uploads/atomix.png)
[Atomix][3] 是1990年在 Amiga、Commodore 64、MS-DOS 和其他平台发布的 [Atomix][4] 益智游戏的开源克隆。Atomix 的目标是通过连接原子来构建原子分子。单个原子可以向上、向下、向左或向右移动,并一直朝这个方向移动,直到原子撞上一个障碍物——水平墙或另一个原子。这意味着需要进行规划,以确定在水平上构建分子的位置,以及移动单个部件的顺序。第一关是一个简单的水分子,它由两个氢原子和一个氧原子组成,但后来的关卡是更复杂的分子。
[Atomix][3] 是 1990 年在 Amiga、Commodore 64、MS-DOS 和其他平台发布的 [Atomix][4] 益智游戏的开源克隆。Atomix 的目标是通过连接原子来构建原子分子。单个原子可以向上、向下、向左或向右移动,并一直朝这个方向移动,直到原子撞上一个障碍物——水平墙或另一个原子。这意味着需要进行规划,以确定在水平上构建分子的位置,以及移动单个部件的顺序。第一关是一个简单的水分子,它由两个氢原子和一个氧原子组成,但后来的关卡是更复杂的分子。
要安装 Atomix请运行以下命令:
* 在 Fedora: `dnf`` install ``atomix`
* 在 Debian/Ubuntu: `apt install`
* 在 Fedora `dnf install atomix`
* 在 Debian/Ubuntu `apt install atomix`
### Fish Fillets - Next Generation
### Fish Fillets - Next Generation
![](https://opensource.com/sites/default/files/uploads/fish_fillets.png)
[Fish Fillets - Next Generation][5] 是游戏Fish fillet的Linux移植版本它在1998年在Windows发布源代码在2004年GPL旗下发布。游戏中,两条鱼试图将物体移出道路来通过不同的关卡。这两条鱼有不同的属性,所以玩家需要为每个任务挑选合适的鱼。较大的鱼可以移动较重的物体,但它更大,这意味着它不适合较小的空隙。较小的鱼可以适应那些较小的间隙,但它不能移动较重的物体。如果一个物体从上面掉下来,两条鱼都会被压死,所以玩家在移动棋子时要小心。
[Fish Fillets - Next Generation][5] 是游戏 Fish fillet 的 Linux 移植版本,它于 1998 年在 Windows 发布,源代码在 2004 年以 GPL 许可证发布。游戏中,两条鱼试图将物体移出道路来通过不同的关卡。这两条鱼有不同的属性,所以玩家需要为每个任务挑选合适的鱼。较大的鱼可以移动较重的物体,但它更大,这意味着它不适合较小的空隙。较小的鱼可以适应那些较小的间隙,但它不能移动较重的物体。如果一个物体从上面掉下来,两条鱼都会被压死,所以玩家在移动棋子时要小心。
要安装 Fish fillet——Next Generation请运行以下命令:
* 在 Fedora: `dnf`` install fillets-ng`
* 在 Debian/Ubuntu: `apt install fillets-ng`
* 在 Fedora`dnf install fillets-ng`
* 在 Debian/Ubuntu `apt install fillets-ng`
### Frozen Bubble
### Frozen Bubble
![](https://opensource.com/sites/default/files/uploads/frozen-bubble.png)
[Frozen Bubble][6] 是一款街机风格的益智游戏从屏幕底部向屏幕顶部的一堆泡泡射击。如果三个相同颜色的气泡连接在一起它们就会被从屏幕上移除。任何连接在被移除的气泡下面但没有连接其他任何东西的气泡也会被移除。在拼图模式下关卡的设计是固定的玩家只需要在泡泡掉到屏幕底部的线以下前将泡泡从游戏区域中移除。该游戏街机模式和多人模式遵循相同的基本规则但也有不同这增加了多样性。Frozen Bubble是一个标志性的开源游戏所以如果你以前没有玩过它玩玩看。
[Frozen Bubble][6] 是一款街机风格的益智游戏从屏幕底部向屏幕顶部的一堆泡泡射击。如果三个相同颜色的气泡连接在一起它们就会被从屏幕上移除。任何连接在被移除的气泡下面但没有连接其他任何东西的气泡也会被移除。在拼图模式下关卡的设计是固定的玩家只需要在泡泡掉到屏幕底部的线以下前将泡泡从游戏区域中移除。该游戏街机模式和多人模式遵循相同的基本规则但也有不同这增加了多样性。Frozen Bubble 是一个标志性的开源游戏,所以如果你以前没有玩过它,玩玩看。
要安装 Frozen Bubble请运行以下命令
* 在 Fedora: `dnf`` install frozen-bubble`
* 在 Fedora: `dnf install frozen-bubble`
* 在 Debian/Ubuntu: `apt install frozen-bubble`
### Hex-a-hop
![](https://opensource.com/sites/default/files/uploads/hex-a-hop.png)
[Hex-a-hop][7] 是一款基于六角形瓦片的益智游戏,玩家需要将所有的绿色瓦片从水平面上移除。瓦片通过移动被移除。由于瓦片在移动后会消失,所以有必要规划出穿过水平面的最佳路径,以便在不被卡住的情况下移除所有的瓦片。但是,如果玩家使用的是次优路径,会有撤销功能。之后的关卡增加了额外的复杂性,包括需要跨越多个时间的瓦片和使玩家跳过一定数量的六角弹跳瓦片。
[Hex-a-hop][7] 是一款基于六角形瓦片的益智游戏,玩家需要将所有的绿色瓦片从水平面上移除。瓦片通过移动被移除。由于瓦片在移动后会消失,所以有必要规划出穿过水平面的最佳路径,以便在不被卡住的情况下移除所有的瓦片。但是,如果玩家使用的是次优路径,会有撤销功能。之后的关卡增加了额外的复杂性,包括需要跨越多的瓦片和使玩家跳过一定数量的六角弹跳瓦片。
要安装 Hex-a-hop请运行以下命令
* 在 Fedora: `dnf`` install hex-a-hop`
* 在 Fedora: `dnf install hex-a-hop`
* 在 Debian/Ubuntu: `apt install hex-a-hop`
### Pingus
![](https://opensource.com/sites/default/files/uploads/pingus.png)
[Pingus][8] 是 [Lemmings][9] 的开源克隆。这不是一个精确的克隆,但游戏非常相似。小动物( Lemmings 里的旅鼠Pingus 里的企鹅)通过关卡入口进入关卡开始沿着直线行走。玩家需要使用特殊技能使小动物能够到达关卡的出口而不会被困住或者掉下悬崖。这些技能包括挖掘或建桥。如果有足够数量的小动物进入出口这个关卡将成功完成玩家可以进入下一个关卡。Pingus 为标准的 Lemmings 添加了一些额外的特性,包括一个世界地图和一些在原版游戏中没有的技能,但经典 Lemmings 游戏的粉丝们在这个开源版本中仍会感到自在。
[Pingus][8] 是 [Lemmings][9] 的开源克隆。这不是一个精确的克隆,但游戏非常相似。小动物Lemmings 里是旅鼠Pingus 里是企鹅)通过关卡入口进入关卡开始沿着直线行走。玩家需要使用特殊技能使小动物能够到达关卡的出口而不会被困住或者掉下悬崖。这些技能包括挖掘或建桥。如果有足够数量的小动物进入出口这个关卡将成功完成玩家可以进入下一个关卡。Pingus 为标准的 Lemmings 添加了一些额外的特性,包括一个世界地图和一些在原版游戏中没有的技能,但经典 Lemmings 游戏的粉丝们在这个开源版本中仍会感到自在。
要安装 Pingus请运行以下命令
* 在 Fedora: `dnf`` install ``pingus`
* 在 Debian/Ubuntu: `apt install ``pingus`
* 在 Fedora: `dnf install pingus`
* 在 Debian/Ubuntu: `apt install pingus`
我漏掉你最喜欢的开源益智游戏了吗? 请在下面的评论中分享。
@ -73,7 +78,7 @@ via: https://opensource.com/article/18/6/puzzle-games-linux
作者:[Joshua Allen Holm][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[ZenMoore](https://github.com/ZenMoore)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,73 @@
TrueOS 不再想要成为“桌面 BSD”了
============================================================
[TrueOS][9] 很快会有一些非常重大的变化。今天,我们将了解桌面 BSD 领域将会发生什么。
### 通告
![TrueOS: Core Operating System BSD](https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/06/true-os-bsd-desktop.jpeg)
[TrueOS][10] 背后的团队[宣布][11]他们将改变项目的重点。到目前为止TrueOS 使用开箱即用的图形用户界面来轻松安装 BSD。然而它现在将成为“一个先进的操作系统保留你所知道和喜欢的 ZFS[OpenZFS][12])和 [FreeBSD][13]的所有稳定性,并添加额外的功能来创造一个全新的、创新的操作系统。我们的目标是创建一个核心操作系统,该系统具有模块化、实用性,非常适合自己动手和高级用户。“
从本质上讲TrueOs 将成为 FreeBSD 的下游分支。他们将集成更新一些的软件到系统中,例如 [OpenRC][14] 和 [LibreSSL][15]。他们希望能坚持 6 个月的发布周期。
其目标是使 TrueOS 成为可以作为其他项目构建的基础。缺少图形部分以使其更加地与发行版无关。
### 桌面用户如何?
如果你读过我的[TrueOS 评论][17]并且有兴趣尝试使用桌面 BSD 或已经使用 TrueOS请不要担心这对于生活来说也是一个很好的建议。TrueOS 的所有桌面元素都将剥离到 [Project Trident][18]。目前Project Trident 网站的细节不多。他们仿佛还在进行剥离的幕后工作。
如果你目前拥有 TrueOS则无需担心迁移。TrueOS 团队表示,“对于那些希望迁移到其他基于 FreeBSD 的发行版,如 Project Trident 或 [GhostBSD][19] 的人而言将会有迁移方式。”
### 想法
当我第一次阅读该公告时坦率地说有点担心。改变名字可能是一个坏主意。客户将习惯使用一个名称但如果产品名称发生变化他们可能很容易失去对项目的跟踪。TrueOS 经历过名称更改。该项目于 2006 年启动时,它被命名为 PC-BSD但在 2016 年,名称更改为 TrueOS。它让我想起了[ArchMerge 和 Arcolinux 传奇][21]。
话虽这么说,我认为这对 BSD 的桌面用户来说是一件好事。我常听见对 PC-BSD 和 TrueOS 的一个批评是它不是很精致。剥离项目的两个部分将有助于提高相关开发人员的关注度。TrueOS 团队将能够为缓慢进展的 FreeBSD 添加更新的功能Project Trident 团队将能够改善用户的桌面体验。
我希望两个团队都好。请记住,当有人为开源而努力时,即使是我们不会使用的部分,我们也都会受益。
你对 TrueOS 和 Project Trident 的未来有何看法?请在下面的评论中告诉我们。
------------------------------
关于作者:
我叫 John Paul Wohlscheid。我是一个有抱负的神秘作家喜欢玩技术尤其是 Linux。你可以在[我的个人网站][23]关注我。
--------------------------------------------------------------------------------
via: https://itsfoss.com/trueos-plan-change/
作者:[John Paul Wohlscheid][a]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://itsfoss.com/author/john/
[1]:https://itsfoss.com/author/john/
[2]:https://itsfoss.com/trueos-plan-change/#comments
[3]:https://itsfoss.com/category/bsd/
[4]:https://itsfoss.com/category/news/
[5]:https://itsfoss.com/tag/bsd/
[6]:https://itsfoss.com/tag/freebsd/
[7]:https://itsfoss.com/tag/project-trident/
[8]:https://itsfoss.com/tag/trueos/
[9]:https://www.trueos.org/
[10]:https://www.trueos.org/
[11]:https://www.trueos.org/blog/trueosdownstream/
[12]:http://open-zfs.org/wiki/Main_Page
[13]:https://www.freebsd.org/
[14]:https://en.wikipedia.org/wiki/OpenRC
[15]:http://www.libressl.org/
[16]:https://itsfoss.com/midnightbsd-founder-lucas-holt/
[17]:https://itsfoss.com/trueos-bsd-review/
[18]:http://www.project-trident.org/
[19]:https://www.ghostbsd.org/
[20]:https://itsfoss.com/interview-freedos-jim-hall/
[21]:https://itsfoss.com/archlabs-vs-archmerge/
[22]:http://reddit.com/r/linuxusersgroup
[23]:http://johnpaulwohlscheid.work/

View File

@ -0,0 +1,79 @@
命令行中的世界杯
======
![](https://i2.wp.com/www.linuxlinks.com/wp-content/uploads/2018/06/football-wc2018.jpg?resize=700%2C450&ssl=1)
足球始终在我们身边。即使我们国家的队伍已经出局LCTT 译注:显然这不是指我们国家,因为我们根本没有入局……),我还是想知道球赛比分。目前, 国际足联世界杯是世界上最大的足球锦标赛2018 届是由俄罗斯主办的。每届世界杯都有一些足球强国未能取得参赛资格LCTT 译注:我要吐槽么?)。意大利和荷兰就无缘本次世界杯。但是即使在未参加比赛的国家,追踪关注最新比分也成为了一种仪式。我希望能及时了解这个世界级的重大赛事最新比分的变化,而不用去搜索不同的网站。
如果你很喜欢命令行,那么有更好的方法用一个小型命令行程序追踪最新的世界杯比分和排名。让我们看一看最热门的可用的球赛趋势分析程序之一,它叫作 football-cli。
football-cli 不是一个开创性的应用程序。这几年,有许多命令行工具可以让你了解到最新的球赛比分和赛事排名。例如,我是 soccer-cli Python 写的)和 App-football Perl 写的)的重度用户。但我总是在寻找新的趋势分析应用,而 football-cli 在某些方面脱颖而出。
football-cli 是 JavaScript 开发的,由 Manraj Singh 编写,它是开源的软件。基于 MIT 许可证发布,用 npmJavaScript 包管理器)安装十分简单。那么,让我们直接行动吧!
该应用程序提供了命令以获取过去及现在的赛事得分、查看联赛和球队之前和将要进行的赛事。它也会显示某一特定联赛的排名。有一条指令可以列出程序所支持的不同赛事。我们不妨从最后一个条指令开始。
在 shell 提示符下:
```
luke@ganges:~$ football lists
```
![球赛列表][3]
世界杯被列在最下方,我错过了昨天的比赛,所以为了了解比分,我在 shell 提示下输入:
```
luke@ganges:~$ football scores
```
![football-wc-22][4]
现在,我想看看目前的世界杯小组排名。很简单:
```
luke@ganges:~$ football standings -l WC
```
下面是输出的一个片段:
![football-wc-biaoge][5]
你们当中眼尖的可能会注意到这里有一个错误。比如比利时看上去领先于 G 组,但这是不正确的,比利时和英格兰(截稿前)在得分上打平。在这种情况下,纪律好的队伍排名更高。英格兰收到两张黄牌,而比利时收到三张,因此,英格兰应当名列榜首。
假设我想知道利物浦 90 天前英超联赛的结果,那么:
```
luke@ganges:~$ football fixtures -l PL -d 90 -t "Liverpool"
```
![足球-利物浦][6]
我发现这个程序非常方便。它用一种清晰、整洁而有吸引力的方式显示分数和排名。当欧洲联赛再次开始时,它就更有用了。(事实上 2018-19 冠军联赛已经在进行中)!
这几个示例让大家对 football-cli 的实用性有了更深的体会。想要了解更多,请转至开发者的 [GitHub 页面][7]。足球 命令行 football-cli。
如同许多类似的工具一样,该软件从 football-data.org 获取相关数据。这项服务以机器可读的方式为所有欧洲主要联赛提供数据,包括比赛、球队、球员、结果等等。所有这些信息都是以 JOSN 形式通过一个易于使用的 RESTful API 提供的。
--------------------------------------------------------------------------------
via: https://www.linuxlinks.com/football-cli-world-cup-football-on-the-command-line/
作者:[Luke Baker][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[ZenMoore](https://github.com/ZenMoore)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linuxlinks.com/author/luke-baker/
[1]:https://www.linuxlinks.com/wp-content/plugins/jetpack/modules/lazy-images/images/1x1.trans.gif
[2]:https://i0.wp.com/www.linuxlinks.com/wp-content/uploads/2017/12/CLI.png?resize=195%2C171&ssl=1
[3]:https://i2.wp.com/www.linuxlinks.com/wp-content/uploads/2018/06/football-lists.png?resize=595%2C696&ssl=1
[4]:https://i2.wp.com/www.linuxlinks.com/wp-content/uploads/2018/06/football-wc-22.png?resize=634%2C75&ssl=1
[5]:https://i0.wp.com/www.linuxlinks.com/wp-content/uploads/2018/06/football-wc-table.png?resize=750%2C581&ssl=1
[6]:https://i1.wp.com/www.linuxlinks.com/wp-content/uploads/2018/06/football-Liverpool.png?resize=749%2C131&ssl=1
[7]:https://github.com/ManrajGrover/football-cli
[8]:https://www.linuxlinks.com/links/Software/
[9]:https://discord.gg/uN8Rqex

View File

@ -0,0 +1,100 @@
区块链进化简史:为什么开源是其核心所在
======
> 从比特币到下一代区块链。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/block-quilt-chain.png?itok=mECoDbrc)
当开源项目开发下一个新版本时,用后缀 “-ng” 表示 “下一代”的情况并不鲜见。幸运的是,到目前为止,快速演进的区块链成功地避开了这个命名陷阱。但是在这个开源生态系统的演进过程中,改变是不断发生的,而好的创意以典型的开源方式在许多不同的项目中被采用、交融和演进。
在本文中,我将审视不同代次的区块链,并且看一看在处理这个生态系统遇到的问题时出现什么创意。当然,任何对生态系统进行分类的尝试都有其局限性的 —— 和不同意见者的 —— 但是这也将为混乱的区块链项目提供了一个粗略的指南。
### 始作俑者:比特币
第一代的区块链起源于 <ruby>[比特币][1]<rt>Bitcoin</rt></ruby> 区块链,这是以去中心化、点对点加密货币为基础的<ruby>总帐<rt>ledger</rt></ruby>,它从 [Slashdot][2] 网站上的杂谈变成了一个主流话题。
这个区块链是一个分布式总帐,它对所有用户的<ruby>交易<rt>transaction</rt></ruby>保持跟踪,以避免他们<ruby>双重支付<rt>double-spending</rt></ruby>(双花)货币(在历史上,这个任务是委托给第三方—— 银行 ——来做的)。为防范攻击者在系统上捣乱,总帐被复制到每个参与到比特币网络的计算机上,并且每次只允许一台计算机去更新总帐。为决定哪台计算机能够获得更新总帐的权力,系统安排在比特币网络上的计算机之间每 10 分钟进行一场竞赛,这将消耗它们的(许多)能源才能参与竞赛。赢家将获得将前 10 分钟发生的交易写入到总帐(区块链中的“区块”)的权力,并且为赢家写入区块链的工作给予一些比特币奖励。这种方式被称为<ruby>工作量证明<rt>proof of work</rt></ruby>PoW共识机制。
这就是区块链最有趣的地方。比特币以[开源项目][3]的方式发布于 2009 年 1 月 。在 2010 年,由于意识到这些元素中的许多是可以调整的,围绕比特币聚集起了一个社区 —— [bitcointalk 论坛][4],来开始各种实验。
起初,看到的比特币区块链是一个分布式数据库的形式, [Namecoin][5] 项目出现后,建议去保存任意数据到它的事务数据库中。如果区块链能够记录金钱的转移,那么它也应该能够记录其它资产的转移,比如域名。这正是 Namecoin 的主要使用场景,它上线于 2011 年 4 月 —— 也就是比特币出现两年后。
Namecoin 调整的地方是区块链的内容,<ruby>[莱特币][6]<rt>Litecoin</rt></ruby> 调整的是两个技术部分:一是将两个区块的时间间隔从 10 分钟减少到 2.5 分钟,二是改变了竞赛方式(用 [scrypt][7] 来替换了 SHA-256 安全哈希算法)。这是能够做到的,因为比特币是以开源软件的方式来发布的,而莱特币本质上与比特币在其它部分是完全相同的。莱特币是修改了比特币共识机制的第一个分叉,这也为其它的更多“币”铺平了道路。
沿着这条道路,基于比特币代码库的各种变种越来越多。其中一些扩展了比特币的用途,比如 [Zerocash][8] 协议,它专注于提供交易的匿名性和可替换性,但它最终分拆为它自己的货币 —— [Zcash][9]。
虽然 Zcash 带来了它自己的创新,使用了最近被称为“<ruby>零知识证明<rt>zero-knowledge proof</rt></ruby>”的加密技术,但它维持着与大多数主要的比特币代码库的兼容性,这意味着它能够从上游的比特币创新中获益。
另外的项目 —— [CryptoNote][10],它萌芽于相同的社区,但是并没有使用相同的代码,它以比特币为背景来构建的,但又与之不同。它发布于 2012 年 12 月,由于它的出现,导致了几种加密货币的诞生,最著名的 <ruby>[门罗币][11]<rt>Monero</rt></ruby> 2014就是其中之一。门罗币与 Zcash 使用了不同的方法,但解决了相同的问题:隐私性和可替换性。
就像在开源世界中经常出现的案例一样,做同样的工作有不止一个的工具可用。
### 下一代“Blockchain-ng”
但是,到目前为止,所有的这些变体只是改进加密货币或者扩展它们去支持其它类型的事务。因此,这就引出了第二代区块链。
一旦社区开始去修改区块链的用法和调整技术部分时,对于一些想去扩展和重新思考它们未来的人来说,这种调整花费不了多长时间的。比特币的长期追随者 —— [Vitalik Buterin][12] 在 2013 年底建议,区域链的事务应该能够表示一个状态机的状态变化,将区域链视为能够运行应用程序(“<ruby>智能合约<rt>smart contract</rt></ruby>”)的分布式计算机。这个项目 —— <ruby>[以太坊][13]<rt>Ethereum</rt></ruby>,上线于 2015 年 4 月。它在运行分布式应用程序方面取得了巨大的成功,它的一些非常流行的分布式应用程序(<ruby>[加密猫][14]<rt>CryptoKitties</rt></ruby>)甚至导致以太坊区块链变慢。
这证明了目前的区块链存在一个很大的局限性:速度和容量。(速度通常用每秒事务数来测量,简称 TPS有几个提议都建议去解决这个速度问题<ruby>分片<rt>sharding</rt></ruby><ruby>侧链<rt>sidechain</rt></ruby>,以及一个被称为“<ruby>第二层<rt>second-layer</rt></ruby>”的解决方案。这里需要更多的创新。
随着“智能合约”这个词开始流行起来,并且用已经被证实仍然很慢的技术去运行它们,那么就需要实现其它的思路:<ruby>许可区块链<rt>Permissioned blockchain</rt></ruby>。到目前为止,我们所介绍的所有区块链网络有两个没有明说的特征:一是它们是公开的(任何人都可以看到它们的功能),二是它们不需要许可(任何人都可以加入它们)。这两个部分是运行一个分布式的、非基于第三方的货币应该具有的和必需具有的条件。
随着区块链被认为出现与加密货币越来越明显的分离趋势,开始去考虑一些隐私、许可场景是很有意义的。一个有业务关系但不需要彼此完全信任的财团类型的参与者,能够从这些区块链类型中获益 —— 比如,物流链上的参与者,定期进行双边结算或者使用一个清算中心的金融、保险、或医疗保健机构。
一旦你将设置从“任何人都可以加入”变为“仅邀请者方可加入”,进一步对区块链构建区块的方式进行改变和调整将变得可能,那么对一些人来说,结果将变得非常有趣。
首先设计用来保护网络不受恶意或者垃圾参与者的影响的工作量证明PoW可以被替换为更简单的和更少资源消耗的一些东西比如基于 [Raft][15] 的共识协议。在更高级别的安全性和更快的速度之间进行权衡,采用更简单的共识算法。对于更多群体来说这样更理想,因为他们可以用基于加密技术的担保来取代其它的基于法律关系的担保,例如为避免由于竞争而产生的大量能源消耗,而工作量证明就是这种情况。另外一个创新的地方是,使用 <ruby>[股权证明][16]<rt>Proof of Stake</rt></ruby>PoS它是公共网络共识机制的一个重量级的竞争者。它将可能像许可链网络一样找到它自己的实现方式。
有几个项目可以让创建许可区块链变得更简单,包括 [Quorum][17] (以太坊的一个分叉)和 [Hyperledger][18] 的 [Fabric][19] 和 [Sawtooth][20],这是基于新代码的两个开源项目。
许可区块链可以避免公共的、非许可方式的区块链中某些错综复杂的问题但是它自己也存在一些问题。正确地管理参与者是其中的一个问题谁可以加入如何辨别他们如何将他们从网络上移除网络上的一个实体是否去管理一个中央公共密钥基础设施PKI?
### 区块链的开放本质
到目前为止的所有案例中,有一件事情是很明确的:使用一个区块链的目标是去提升网络中的参与者和它产生的数据的信任水平,理想情况下,不需要做进一步的工作即可足以使用它。
只有为这个网络提供动力的软件是自由和开源的,才能达到这种信任水平。即便是一个正确的、专用的、分布式区块链,它的本质仍然是运行着相同的第三方代码的私有代理的集合。从本质上来说,区块链的源代码必须是开源的,但仅是开源还不够。随着生态系统持续成长,这既是最低限度的担保也是进一步创新的源头。
最后,值得一提的是,虽然区块链的开放本质被认为是创新和变化的源头,它也被认为是一种治理形式:代码治理,用户期望运行的任何一个特定版本,都应该包含他们认为的整个网络应该包含的功能和方法。在这方面,需要说明的一点是,一些区块链的开放本质正在“变味”。但是这一问题正在解决。
### 第三和第四代:治理
接下来,我正在考虑第三代和第四代区块链:区块链将内置治理工具,并且项目将去解决棘手的大量不同区块链之间互连互通的问题,以便于它们之间可以交换信息和价值。
---
关于作者
axel simon 长期的自由及开源软件爱好者,就职于 Red Hat ,关注安全和区块链技术,以及分布式系统和协议。致力于保护互联网及其成就(知识分享、信息访问、去中心化和网络中立)。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/6/blockchain-guide-next-generation
作者:[Axel Simon][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[qhwdw](https://github.com/qhwdw)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/axel
[1]:https://bitcoin.org
[2]:https://slashdot.org/
[3]:https://github.com/bitcoin/bitcoin
[4]:https://bitcointalk.org/
[5]:https://www.namecoin.org/
[6]:https://litecoin.org/
[7]:https://en.wikipedia.org/wiki/Scrypt
[8]:http://zerocash-project.org/index
[9]:https://z.cash
[10]:https://cryptonote.org/
[11]:https://en.wikipedia.org/wiki/Monero_(cryptocurrency)
[12]:https://en.wikipedia.org/wiki/Vitalik_Buterin
[13]:https://ethereum.org
[14]:http://cryptokitties.co/
[15]:https://en.wikipedia.org/wiki/Raft_(computer_science)
[16]:https://www.investopedia.com/terms/p/proof-stake-pos.asp
[17]:https://www.jpmorgan.com/global/Quorum
[18]:https://hyperledger.org/
[19]:https://www.hyperledger.org/projects/fabric
[20]:https://www.hyperledger.org/projects/sawtooth

View File

@ -0,0 +1,138 @@
Sosreport收集系统日志和诊断信息的工具
======
![](https://www.ostechnix.com/wp-content/uploads/2018/06/sos-720x340.png)
如果你是 RHEL 管理员,你可能肯定听说过 **Sosreport** :一个可扩展、可移植的支持数据收集工具。它是一个从类 Unix 操作系统中收集系统配置详细信息和诊断信息的工具。当用户提出支持服务单时,他/她必须运行此工具并将由 Sosreport 工具生成的结果报告发送给 Red Hat 支持人员。然后,执行人员将根据报告进行初步分析,并尝试找出系统中的问题。不仅在 RHEL 系统上,你可以在任何类 Unix 操作系统上使用它来收集系统日志和其他调试信息。
### 安装 Sosreport
Sosreport 在 Red Hat 官方系统仓库中,因此你可以使用 Yum 或 DNF 包管理器安装它,如下所示。
```
$ sudo yum install sos
```
要么,
```
$ sudo dnf install sos
```
在 Debian、Ubuntu 和 Linux Mint 上运行:
```
$ sudo apt install sosreport
```
### 用法
安装后,运行以下命令以收集系统配置详细信息和其他诊断信息。
```
$ sudo sosreport
```
系统将要求你输入系统的一些详细信息,例如系统名称、案例 ID 等。相应地输入详细信息,然后按回车键生成报告。如果你不想更改任何内容并使用默认值,只需按回车键即可。
我的 CentOS 7 服务器的示例输出:
```
sosreport (version 3.5)
This command will collect diagnostic and configuration information from
this CentOS Linux system and installed applications.
An archive containing the collected information will be generated in
/var/tmp/sos.DiJXi7 and may be provided to a CentOS support
representative.
Any information provided to CentOS will be treated in accordance with
the published support policies at:
https://wiki.centos.org/
The generated archive may contain data considered sensitive and its
content should be reviewed by the originating organization before being
passed to any third party.
No changes will be made to system configuration.
Press ENTER to continue, or CTRL-C to quit.
Please enter your first initial and last name [server.ostechnix.local]:
Please enter the case id that you are generating this report for []:
Setting up archive ...
Setting up plugins ...
Running plugins. Please wait ...
Running 73/73: yum...
Creating compressed archive...
Your sosreport has been generated and saved in:
/var/tmp/sosreport-server.ostechnix.local-20180628171844.tar.xz
The checksum is: 8f08f99a1702184ec13a497eff5ce334
Please send this file to your support representative.
```
如果你不希望系统提示你输入此类详细信息,请如下使用批处理模式。
```
$ sudo sosreport --batch
```
正如你在上面的输出中所看到的,生成了一个归档报告并保存在 `/var/tmp/sos.DiJXi7` 中。在 RHEL 6/CentOS 6 中,报告将在 `/tmp` 中生成。你现在可以将此报告发送给你的支持人员,以便他可以进行初步分析并找出问题所在。
你可能会担心或想知道报告中的内容。如果是这样,你可以通过运行以下命令来查看它:
```
$ sudo tar -tf /var/tmp/sosreport-server.ostechnix.local-20180628171844.tar.xz
```
要么,
```
$ sudo vim /var/tmp/sosreport-server.ostechnix.local-20180628171844.tar.xz
```
请注意,上述命令不会解压存档,而只显示存档中的文件和文件夹列表。如果要查看存档中文件的实际内容,请首先使用以下命令解压存档:
```
$ sudo tar -xf /var/tmp/sosreport-server.ostechnix.local-20180628171844.tar.xz
```
存档的所有内容都将解压当前工作目录中 `ssosreport-server.ostechnix.local-20180628171844/` 目录中。进入目录并使用 `cat` 命令或任何其他文本浏览器查看文件内容:
```
$ cd sosreport-server.ostechnix.local-20180628171844/
$ cat uptime
17:19:02 up 1:03, 2 users, load average: 0.50, 0.17, 0.10
```
有关 Sosreport 的更多详细信息,请参阅手册页。
```
$ man sosreport
```
就是这些了。希望这些有用。还有更多好东西。敬请关注!
干杯!
--------------------------------------------------------------------------------
via: https://www.ostechnix.com/sosreport-a-tool-to-collect-system-logs-and-diagnostic-information/
作者:[SK][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.ostechnix.com/author/sk/

View File

@ -0,0 +1,43 @@
我的第一个系统管理员错误
======
> 如何在崩溃的局面中集中精力寻找解决方案。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUSINESS_mistakes.png?itok=dN0OoIl5)
如果你在 IT 领域工作,你知道事情永远不会像你想象的那样完好。在某些时候,你会遇到错误或出现问题,你最终必须解决问题。这就是系统管理员的工作。
作为人类,我们都会犯错误。我们不是已经犯错,就是即将犯错。结果,我们最终还必须解决自己的错误。总是这样。我们都会失误、敲错字母或犯错。
作为一名年轻的系统管理员,我艰难地学到了这一课。我犯了一个大错。但是多亏了上级的指导,我学会了不去纠缠于我的错误,而是制定一个“错误策略”来做正确的事情。从错误中吸取教训。克服它,继续前进。
我的第一份工作是一家小公司的 Unix 系统管理员。真的,我是一名生嫩的系统管理员,但我大部分时间都独自工作。我们是一个小型 IT 团队,只有我们三个人。我是 20 或 30 台 Unix 工作站和服务器的唯一系统管理员。另外两个支持 Windows 服务器和桌面。
任何阅读这篇文章的系统管理员都不会对此感到意外,作为一个不成熟的初级系统管理员,我最终在错误的目录中运行了 `rm` 命令——作为 root 用户。我以为我正在为我们的某个程序删除一些陈旧的缓存文件。相反,我错误地清除了 `/etc` 目录中的所有文件。糟糕。
我意识到犯了错误是看到了一条错误消息,“`rm` 无法删除某些子目录”。但缓存目录应该只包含文件!我立即停止了 `rm` 命令,看看我做了什么。然后我惊慌失措。一下子,无数个想法涌入了我的脑中。我刚刚销毁了一台重要的服务器吗?系统会怎么样?我会被解雇吗?
幸运的是,我运行的是 `rm *` 而不是 `rm -rf *`,因此我只删除了文件。子目录仍在那里。但这并没有让我感觉更好。
我立刻去找我的主管告诉她我做了什么。她看到我对自己的错误感到愚蠢,但这是我犯的。尽管紧迫,她花了几分钟时间跟我做了一些指导。她说:“你不是第一个这样做的人,在你这种情况下,别人会怎么做?”这帮助我平静下来并专注。我开始更少考虑我刚刚做的愚蠢事情,而更多地考虑我接下来要做的事情。
我做了一个简单的策略:不要重启服务器。使用相同的系统作为模板,并重建 `/etc` 目录。
制定了行动计划后,剩下的就很容易了。只需运行正确的命令即可从另一台服务器复制 `/etc` 文件并编辑配置,使其与系统匹配。多亏了我对所有东西都做记录的习惯,我使用已有的文档进行最后的调整。我避免了完全恢复服务器,这意味着一个巨大的宕机事件。
可以肯定的是,我从这个错误中吸取了教训。在接下来作为系统管理员的日子中,我总是在运行任何命令之前确认我所在的目录。
我还学习了构建“错误策略”的价值。当事情出错时,恐慌并思考接下来可能发生的所有坏事是很自然的。这是人性。但是制定一个“错误策略”可以帮助我不再担心出了什么问题,而是专注于让事情变得更好。我仍然会想一下,但是知道我接下来的步骤可以让我“克服它”。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/7/my-first-sysadmin-mistake
作者:[Jim Hall][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/jim-hall

View File

@ -0,0 +1,147 @@
如何在绝大部分类型的机器上安装 NVIDIA 显卡驱动
======
![](https://fedoramagazine.org/wp-content/uploads/2018/06/nvidia-816x345.jpg)
无论是研究还是娱乐,安装一个最新的显卡驱动都能提升你的计算机性能,并且使你能全方位地实现新功能。本安装指南使用 Fedora 28 的新的第三方仓库来安装 NVIDIA 驱动。它将引导您完成硬件和软件两方面的安装,并且涵盖需要让你的 NVIDIA 显卡启动和运行起来的一切知识。这个流程适用于任何支持 UEFI 的计算机和任意新的 NVIDIA 显卡。
### 准备
本指南依赖于下面这些材料:
* 一台使用 [UEFI][1] 的计算机,如果你不确定你的电脑是否有这种固件,请运行 `sudo dmidecode -t 0`。如果输出中出现了 “UEFI is supported”你的安装过程就可以继续了。不然的话虽然可以在技术上更新某些电脑来支持 UEFI但是这个过程的要求很苛刻我们通常不建议你这么使用。
* 一个现代的、支持 UEFI 的 NVIDIA 的显卡
* 一个满足你的 NVIDIA 显卡的功率和接线要求的电源(有关详细信息,请参考“硬件和修改”的章节)
* 网络连接
* Fedora 28 系统
### 安装实例
这个安装示例使用的是:
* 一台 Optiplex 9010 的主机(一台相当老的机器)
* [NVIDIA GeForce GTX 1050 Ti XLR8 游戏超频版 4 GB GDDR5 PCI Express 3.0 显卡][2]
* 为了满足新显卡的电源要求,电源升级为 [EVGA 80 PLUS 600 W ATX 12V/EPS 12V][3]这个最新的电源PSU比推荐的最低要求高了 300 W但在大部分情况下满足推荐的最低要求就足够了。
* 然后当然的Fedora 28 也别忘了.
### 硬件和修改
#### 电源PSU
打开你的台式机的机箱,检查印刷在电源上的最大输出功率。然后,查看你的 NVIDIA 显卡的文档,确定推荐的最小电源功率要求(以瓦特为单位)。除此之外,检查你的显卡,看它是否需要额外的接线,例如 6 针连接器,大多数的入门级显卡只从主板获取电力,但是有一些显卡需要额外的电力,如果出现以下情况,你需要升级你的电源:
1. 你的电源的最大输出功率低于显卡建议的最小电源功率。注意:根据一些显卡厂家的说法,比起推荐的功率,预先构建的系统可能会需要更多或更少的功率,而这取决于系统的配置。如果你使用的是一个特别耗电或者特别节能的配置,请灵活决定你的电源需求。
2. 你的电源没有提供必须的接线口来为你的显卡供电。
电源的更换很容易,但是在你拆除你当前正在使用的电源之前,请务必注意你的接线布局。除此之外,请确保你选择的电源适合你的机箱。
#### CPU
虽然在大多数老机器上安装高性能的 NVIDIA 显卡是可能的,但是一个缓慢或受损的 CPU 会阻碍显卡性能的发挥,如果要计算在你的机器上瓶颈效果的影响,请点击[这里][4]。了解你的 CPU 性能来避免高性能的显卡和 CPU 无法保持匹配是很重要的。升级你的 CPU 是一个潜在的考虑因素。
#### 主板
在继续进行之前,请确认你的主板和你选择的显卡是兼容的。你的显卡应该插在最靠近散热器的 PCI-E x16 插槽中。确保你的设置为显卡预留了足够的空间。此外,请注意,现在大部分的显卡使用的都是 PCI-E 3.0 技术。虽然这些显卡如果插在 PCI-E 3.0 插槽上会运行地最好,但如果插在一个旧版的插槽上的话,性能也不会受到太大的影响。
### 安装
1、 首先,打开终端更新你的包管理器(如果没有更新的话):
```
sudo dnf update
```
2、 然后,使用这条简单的命令进行重启:
```
reboot
```
3、 在重启之后,安装 Fedora 28 的工作站的仓库:
```
sudo dnf install fedora-workstation-repositories
```
4、 接着,设置 NVIDIA 驱动的仓库:
```
sudo dnf config-manager --set-enabled rpmfusion-nonfree-nvidia-driver
```
5、 然后,再次重启。
6、 在这次重启之后,通过下面这条命令验证是否添加了仓库:
```
sudo dnf repository-packages rpmfusion-nonfree-nvidia-driver info
```
如果加载了多个 NVIDIA 工具和它们各自的 spec 文件,请继续进行下一步。如果没有,你可能在添加新仓库的时候遇到了一个错误。你应该再试一次。
7、 登录,连接到互联网,然后打开“软件”应用程序。点击“加载项>硬件驱动> NVIDIA Linux 图形驱动>安装”。
如果你使用更老的显卡或者想使用多个显卡,请进一步查看 [RPMFusion 指南][8]。最后,要确保启动成功,设置 `/etc/gdm/custom.conf` 中的 `WaylandEnable=false`,确认避免使用安全启动。
接着,再一次重启。
8、这个过程完成后关闭所有的应用并**关机**。拔下电源插头,然后按下电源按钮以释放余电,避免你被电击。如果你对电源有开关,关闭它。
9、 最后,安装显卡,拔掉老的显卡并将新的显卡插入到正确的 PCI-E x16 插槽中。成功安装新的显卡之后,关闭你的机箱,插入电源 ,然后打开计算机,它应该会成功启动。
**注意:** 要禁用此安装中使用的 NVIDIA 驱动仓库,或者要禁用所有的 Fedora 工作站仓库,请参考这个 [Fedora Wiki 页面][6]。
### 验证
1、 如果你新安装的 NVIDIA 显卡已连接到你的显示器并显示正确,则表明你的 NVIDIA 驱动程序已成功和显卡建立连接。
如果你想去查看你的设置,或者验证驱动是否在正常工作(这里,主板上安装了两块显卡),再次打开 “NVIDIA X 服务器设置应用程序”。这次,你应该不会得到错误信息提示,并且系统会给出有关 X 的设置文件和你的 NVIDIA 显卡的信息。(请参考下面的屏幕截图)
![NVIDIA X Server Settings][7]
通过这个应用程序,你可以根据你的需要需改 X 配置文件,并可以监控显卡的性能,时钟速度和温度信息。
2、 为确保新显卡以满功率运行显卡性能测试是非常必要的。GL Mark 2是一个提供后台处理、构建、照明、纹理等等有关信息的标准工具。它提供了一个优秀的解决方案。GL Mark 2 记录了各种各样的图形测试的帧速率,然后输出一个总体的性能评分(这被称为 glmark2 分数)。
**注意:** glxgears 只会测试你的屏幕或显示器的性能,不会测试显卡本身,请使用 GL Mark 2。
要运行 GLMark2
1. 打开终端并关闭其他所有的应用程序
2. 运行 `sudo dnf install glmark2` 命令
3. 运行 `glmark2` 命令
4. 允许运行完整的测试来得到最好的结果。检查帧速率是否符合你对这块显卡的预期。如果你想要额外的验证,你可以查阅网站来确认是否已有你这块显卡的 glmark2 测试评分被公布到网上,你可以比较这个分数来评估你这块显卡的性能。
5. 如果你的帧速率或者 glmark2 评分低于预期请思考潜在的因素。CPU 造成的瓶颈?其他问题导致?
如果诊断的结果很好,就开始享受你的新显卡吧。
### 参考链接
- [How to benchmark your GPU on Linux][9]
- [How to install a graphics card][10]
- [The Fedora Wiki Page][6]
- [The Bottlenecker][4]
- [What Is Unified Extensible Firmware Interface (UEFI)][1]
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/install-nvidia-gpu/
作者:[Justice del Castillo][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[hopefully2333](https://github.com/hopefully2333)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://fedoramagazine.org/author/justice/
[1]:https://whatis.techtarget.com/definition/Unified-Extensible-Firmware-Interface-UEFI
[2]:https://www.cnet.com/products/pny-geforce-gtx-xlr8-gaming-1050-ti-overclocked-edition-graphics-card-gf-gtx-1050-ti-4-gb/specs/
[3]:https://www.evga.com/products/product.aspx?pn=100-B1-0600-KR
[4]:http://thebottlenecker.com (Home: The Bottle Necker)
[5]:https://bytebucket.org/kenneym/fedora-28-nvidia-gpu-installation/raw/7bee7dc6effe191f1f54b0589fa818960a8fa18b/nvidia_xserver_error.jpg?token=c6a7effe35f1c592a155a4a46a068a19fd060a91 (NVIDIA X Sever Prompt)
[6]:https://fedoraproject.org/wiki/Workstation/Third_Party_Software_Repositories
[7]:https://bytebucket.org/kenneym/fedora-28-nvidia-gpu-installation/raw/7bee7dc6effe191f1f54b0589fa818960a8fa18b/NVIDIA_XCONFIG.png?token=64e1a7be21e5e9ba157f029b65e24e4eef54d88f (NVIDIA X Server Settings)
[8]:https://rpmfusion.org/Howto/NVIDIA?highlight=%28CategoryHowto%29
[9]: https://www.howtoforge.com/tutorial/linux-gpu-benchmark/
[10]: https://www.pcworld.com/article/2913370/components-graphics/how-to-install-a-graphics-card.html

View File

@ -0,0 +1,60 @@
macOS 和 Linux 的内核有什么区别
======
有些人可能会认为 macOS 和 Linux 内核之间存在相似之处,因为它们可以处理类似的命令和类似的软件。有些人甚至认为苹果公司的 macOS 是基于 Linux 的。事实上是,两个内核有着截然不同的历史和特征。今天,我们来看看 macOS 和 Linux 的内核之间的区别。
![macOS vs Linux][1]
### macOS 内核的历史
我们将从 macOS 内核的历史开始。1985 年,由于与首席执行官 John Sculley 和董事会不和,<ruby>史蒂夫·乔布斯<rt>Steve Jobs</rt></ruby>离开了苹果公司。然后,他成立了一家名为 [NeXT][2] 的新电脑公司。乔布斯希望将一款带有新操作系统的新计算机快速推向市场。为了节省时间NeXT 团队使用了卡耐基梅隆大学的 [Mach 内核][3] 和部分 BSD 代码库来创建 [NeXTSTEP 操作系统][4]。
NeXT 从来没有取得过财务上的成功,部分归因于乔布斯花钱的习惯,就像他还在苹果公司一样。与此同时,苹果公司曾多次试图更新其操作系统,甚至与 IBM 合作但从未成功。1997年苹果公司以 4.29 亿美元收购了 NeXT。作为交易的一部分史蒂夫·乔布斯回到了苹果公司同时 NeXTSTEP 成为了 macOS 和 iOS 的基础。
### Linux 内核的历史
与 macOS 内核不同Linux 的创建并非源于商业尝试。相反,它是由[芬兰计算机科学专业学生<ruby>林纳斯·托瓦兹<rt>Linus Torvalds</rt></ruby>于 1991 年创建的][5]。最初,内核是按照林纳斯自己的计算机的规格编写的,因为他想利用其新的 80386 处理器(的特性)。林纳斯[于 1991 年 8 月在 Usenet 上][6]发布了他的新内核代码。很快他就收到了来自世界各地的代码和功能建议。次年Orest Zborowski 将 X Window 系统移植到 Linux使其能够支持图形用户界面。
在过去的 27 年中Linux 已经慢慢成长并增加了不少功能。这不再是一个学生的小型项目。现在它运行在[世界上][7]大多数的[计算设备][8]和[超级计算机][9]上。不错!
### macOS 内核的特性
macOS 内核被官方称为 XNU。这个[首字母缩写词][10]代表“XNU is Not Unix”。根据 [苹果公司的 Github 页面][10]XNU 是“将卡耐基梅隆大学开发的 Mach 内核和 FreeBSD 组件整合而成的混合内核,加上用于编写驱动程序的 C++ API”。代码的 BSD 子系统部分[“在微内核系统中通常实现为用户空间的服务”][11]。Mach 部分负责底层工作,例如多任务、内存保护、虚拟内存管理、内核调试支持和控制台 I/O。
### Linux 内核的特性
虽然 macOS 内核结合了微内核([Mach][12])和宏内核([BSD][13])的特性,但 Linux 只是一个宏内核。[宏内核][14]负责管理 CPU、内存、进程间通信、设备驱动程序、文件系统和系统服务调用 LCTT 译注:原文为 system server calls但结合 Linux 内核的构成,译者认为这里翻译成系统服务调用更合适,即 system service calls
### 用一句话总结 Linux 和 Mac 的区别
macOS 内核XNU比 Linux 历史更悠久并且基于两个更古老一些的代码库的结合另一方面Linux 新一些,是从头开始编写的,并且在更多设备上使用。
如果您发现这篇文章很有趣,请花一点时间在社交媒体,黑客新闻或 [Reddit][15] 上分享。
--------------------------------------------------------------------------------
via: https://itsfoss.com/mac-linux-difference/
作者:[John Paul][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[stephenxs](https://github.com/stephenxs)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/john/
[1]:https://4bds6hergc-flywheel.netdna-ssl.com/wp-content/uploads/2018/07/macos-vs-linux-kernels.jpeg
[2]:https://en.wikipedia.org/wiki/NeXT
[3]:https://en.wikipedia.org/wiki/Mach_(kernel)
[4]:https://en.wikipedia.org/wiki/NeXTSTEP
[5]:https://www.cs.cmu.edu/%7Eawb/linux.history.html
[6]:https://groups.google.com/forum/#!original/comp.os.minix/dlNtH7RRrGA/SwRavCzVE7gJ
[7]:https://www.zdnet.com/article/sorry-windows-android-is-now-the-most-popular-end-user-operating-system/
[8]:https://www.linuxinsider.com/story/31855.html
[9]:https://itsfoss.com/linux-supercomputers-2017/
[10]:https://github.com/apple/darwin-xnu
[11]:http://osxbook.com/book/bonus/ancient/whatismacosx/arch_xnu.html
[12]:https://en.wikipedia.org/wiki/Mach_(kernel
[13]:https://en.wikipedia.org/wiki/FreeBSD
[14]:https://www.howtogeek.com/howto/31632/what-is-the-linux-kernel-and-what-does-it-do/
[15]:http://reddit.com/r/linuxusersgroup

View File

@ -0,0 +1,97 @@
如何在 Linux 系统中使用 dd 命令而不会损毁你的磁盘
===========
> 使用 Linux 中的 dd 工具安全、可靠地制作一个驱动器、分区和文件系统的完整镜像。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_happy_sad_developer_programming.png?itok=72nkfSQ_)
*这篇文章节选自 Manning 出版社出版的图书 [Linux in Action][1]的第 4 章。*
你是否正在从一个即将损坏的存储驱动器挽救数据,或者要把本地归档进行远程备份,或者要把一个别处的活动分区做个完整的副本,那么你需要懂得如何安全而可靠的复制驱动器和文件系统。幸运的是,`dd` 是一个可以使用的简单而又功能强大的镜像复制命令,从现在到未来很长的时间内,也许直到永远都不会出现比 `dd` 更好的工具了。
### 对驱动器和分区做个完整的副本
仔细研究后,你会发现你可以使用 `dd` 做各种任务,但是它最重要的功能是处理磁盘分区。当然,你可以使用 `tar` 命令或者 `scp` 命令从一台计算机复制整个文件系统的文件,然后把这些文件原样粘贴在另一台刚刚安装好 Linux 操作系统的计算机中。但是,因为那些文件系统归档不是完整的映像文件,所以在复制文件的过程中需要计算机操作系统的运行作为基础。
另一方面,使用 `dd` 可以对任何数字信息完美的进行逐个字节的镜像。但是不论何时何地,当你要对分区进行操作时,我要告诉你早期的 Unix 管理员曾开过这样的玩笑:“ dd 的意思是<ruby>磁盘毁灭者<rt>disk destroyer</rt></ruby>LCTT 译注:`dd` 原意是<ruby>磁盘复制<rt>disk dump</rt></ruby>)。 在使用 `dd` 命令的时候,如果你输入了哪怕是一个字母,也可能立即永久性的擦除掉整个磁盘驱动器里的所有重要的数据。因此,一定要注意命令的拼写格式规范。
**记住:** 在按下回车键执行 `dd` 命令之前,暂时停下来仔细的认真思考一下。
### dd 命令的基本操作
现在你已经得到了适当的提醒,我们将从简单的事情开始。假设你要对代号为 `/dev/sda` 的整个磁盘数据创建精确的映像,你已经插入了一块空的磁盘驱动器 (理想情况下具有与代号为 `/dev/sda` 的磁盘驱动器相同的容量)。语法很简单: `if=` 定义源驱动器,`of=` 定义你要将数据保存到的文件或位置:
```
# dd if=/dev/sda of=/dev/sdb
```
接下来的例子将要对 `/dev/sda` 驱动器创建一个 .img 的映像文件,然后把该文件保存的你的用户帐号家目录:
```
# dd if=/dev/sda of=/home/username/sdadisk.img
```
上面的命令针对整个驱动器创建映像文件,你也可以针对驱动器上的单个分区进行操作。下面的例子针对驱动器的单个分区进行操作,同时使用了一个 `bs` 参数用于设置单次拷贝的字节数量 (此例中是 4096。设定 `bs` 参数值可能会影响 `dd` 命令的整体操作速度,该参数的理想设置取决于你的硬件配置和其它考虑。
```
# dd if=/dev/sda2 of=/home/username/partition2.img bs=4096
```
数据的恢复非常简单:通过颠倒 `if``of` 参数可以有效的完成任务。在此例中,`if=` 使用你要恢复的映像,`of=` 使用你想要写入映像的目标驱动器:
```
# dd if=sdadisk.img of=/dev/sdb
```
你也可以在一条命令中同时完成创建和拷贝任务。下面的例子中将使用 SSH 从远程驱动器创建一个压缩的映像文件,并把该文件保存到你的本地计算机中:
```
# ssh username@54.98.132.10 "dd if=/dev/sda | gzip -1 -" | dd of=backup.gz
```
你应该经常测试你的归档,确保它们可正常使用。如果它是你创建的启动驱动器,将它粘贴到计算机中,看看它是否能够按预期启动。如果它是普通分区的数据,挂载该分区,确保文件都存在而且可以正常的访问。
### 使用 dd 擦除磁盘数据
多年以前,我的一个负责政府海外大使馆安全的朋友曾经告诉我,在他当时在任的时候, 政府会给每一个大使馆提供一个官方版的锤子。为什么呢? 一旦大使馆设施可能被不友善的人员侵占,就会使用这个锤子毁坏所有的硬盘.
为什么要那样做?为什么不是删除数据就好了?你在开玩笑,对吧?所有人都知道从存储设备中删除包含敏感信息的文件实际上并没有真正移除这些数据。除非使用锤子彻底的毁坏这些存储介质,否则,只要有足够的时间和动机, 几乎所有的内容都可以从几乎任何数字存储介质重新获取。
但是,你可以使用 `dd` 命令让坏人非常难以获得你的旧数据。这个命令需要花费一些时间在 `/dev/sda1` 分区的每个扇区写入数百万个 `0`LCTT 译注:是指 0x0 字节,意即 NUL ,而不是数字 0
```
# dd if=/dev/zero of=/dev/sda1
```
还有更好的方法。通过使用 `/dev/urandom` 作为源文件,你可以在磁盘上写入随机字符:
```
# dd if=/dev/urandom of=/dev/sda1
```
### 监控 dd 的操作
由于磁盘或磁盘分区的归档可能需要很长的时间,因此你可能需要在命令中添加进度查看器。安装管道查看器(在 Ubuntu 系统上安装命令为 `sudo apt install pv`),然后把 `pv` 命令和 `dd` 命令结合在一起。使用 `pv`,最终的命令是这样的:
```
# dd if=/dev/urandom | pv | dd of=/dev/sda1
4,14MB 0:00:05 [ 98kB/s] [ <=> ]
```
想要推迟备份和磁盘管理工作?有了 `dd` 工具,你不会有太多的借口。它真的非常简单,但是要小心。祝你好运!
----------------
viahttps://opensource.com/article/18/7/how-use-dd-linux
作者:[David Clinton][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[SunWave](https://github.com/SunWave)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/remyd
[1]: https://www.manning.com/books/linux-in-action?a_aid=bootstrap-it&a_bid=4ca15fc9&chan=opensource

View File

@ -0,0 +1,79 @@
6 个可以帮你理解互联网工作原理的 RFC
======
> 以及 3 个有趣的 RFC。
![](https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/LAW-Internet_construction_9401467_520x292_0512_dc.png?itok=RPkPPtDe)
阅读源码是开源软件的重要组成部分。这意味着用户可以查看代码并了解做了什么。
但“阅读源码”并不仅适用于代码。理解代码实现的标准同样重要。这些标准编写在由<ruby>[互联网工程任务组][1]<rt>Internet Engineering Task Force</rt></ruby>IETF发布的称为“<ruby>意见征集<rt>Requests for Comment</rt></ruby>RFC的文档中。多年来已经发布了数以千计的 RFC因此我们收集了一些我们的贡献者认为必读的内容。
### 6 个必读的 RFC
#### RFC 2119 - 在 RFC 中用于指示需求级别的关键字
这是一个快速阅读,但它对了解其它 RFC 非常重要。 [RFC 2119][2] 定义了后续 RFC 中使用的需求级别。 “MAY” 究竟意味着什么?如果标准说 “SHOULD”你*真的*必须这样做吗通过为需求提供明确定义的分类RFC 2119 有助于避免歧义。
#### RFC 3339 - 互联网上的日期和时间:时间戳
时间是全世界程序员的祸根。 [RFC 3339][3] 定义了如何格式化时间戳。基于 [ISO 8601][4] 标准3339 为我们提供了一种表达时间的常用方法。例如,像星期几这样的冗余信息不应该包含在存储的时间戳中,因为它很容易计算。
#### RFC 1918 - 私有互联网的地址分配
有属于每个人的互联网,也有只属于你的互联网。私有网络一直在使用,[RFC 1918][5] 定义了这些网络。当然,你可以在路由器上设置在内部使用公网地址,但这是一个坏主意。或者,你可以将未使用的公共 IP 地址视为内部网络。在任何一种情况下都表明你从未阅读过 RFC 1918。
#### RFC 1912 - 常见的 DNS 操作和配置错误
一切都是 #@%@ 的 DNS 问题,对吧? [RFC 1912][6] 列出了管理员在试图保持互联网运行时所犯的错误。虽然它是在 1996 年发布的,但 DNS以及人们犯的错误并没有真正改变这么多。为了理解我们为什么首先需要 DNS如今我们再来看看 [RFC 289 - 我们希望正式的主机列表是什么样子的][7] 就知道了。
#### RFC 2822 — 互联网邮件格式
想想你知道什么是有效的电子邮件地址么?如果你知道有多少个站点不接受我邮件地址中 “+” 的话,你就知道你知道不知道了。 [RFC 2822][8] 定义了有效的电子邮件地址。它还详细介绍了电子邮件的其余部分。
#### RFC 7231 - 超文本传输协议HTTP/1.1):语义和内容
想想看,几乎我们在网上做的一切都依赖于 HTTP。 [RFC 7231][9] 是该协议的最新更新。它有超过 100 页,定义了方法、请求头和状态代码。
### 3 个应该阅读的 RFC
好吧,并非每个 RFC 都是严肃的。
#### RFC 1149 - 在禽类载体上传输 IP 数据报的标准
网络以多种不同方式传递数据包。 [RFC 1149][10] 描述了鸽子载体的使用。当我距离州际高速公路一英里以外时,它们的可靠性不会低于我的移动提供商。
#### RFC 2324 — 超文本咖啡壶控制协议HTCPCP/1.0
咖啡对于完成工作非常重要,当然,我们需要一个用于管理咖啡壶的程序化界面。 [RFC 2324][11] 定义了一个用于与咖啡壶交互的协议,并添加了 HTTP 418“我是一个茶壶”
#### RFC 69 — M.I.T.的分发列表更改
[RFC 69][12] 是否是第一个误导取消订阅请求的发布示例?
你必须阅读的 RFC 是什么(无论它们是否严肃)?在评论中分享你的列表。
--------------------------------------------------------------------------------
via: https://opensource.com/article/18/7/requests-for-comments-to-know
作者:[Ben Cotton][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/bcotton
[1]:https://www.ietf.org
[2]:https://www.rfc-editor.org/rfc/rfc2119.txt
[3]:https://www.rfc-editor.org/rfc/rfc3339.txt
[4]:https://www.iso.org/iso-8601-date-and-time-format.html
[5]:https://www.rfc-editor.org/rfc/rfc1918.txt
[6]:https://www.rfc-editor.org/rfc/rfc1912.txt
[7]:https://www.rfc-editor.org/rfc/rfc289.txt
[8]:https://www.rfc-editor.org/rfc/rfc2822.txt
[9]:https://www.rfc-editor.org/rfc/rfc7231.txt
[10]:https://www.rfc-editor.org/rfc/rfc1149.txt
[11]:https://www.rfc-editor.org/rfc/rfc2324.txt
[12]:https://www.rfc-editor.org/rfc/rfc69.txt

View File

@ -0,0 +1,127 @@
如何在 Android 上借助 Wine 来运行 Windows Apps
======
![](https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-featured-image.jpg)
Wine一种 Linux 上的程序,不是你喝的葡萄酒)是在类 Unix 操作系统上运行 Windows 程序的一个自由开源的兼容层。创建于 1993 年,借助它你可以在 Linux 和 macOS 操作系统上运行很多 Windows 程序虽然有时可能还需要做一些小修改。现在Wine 项目已经发布了 3.0 版本,这个版本兼容 Android 设备。
在本文中,我们将向你展示,在你的 Android 设备上如何借助 Wine 来运行 Windows Apps。
**相关阅读** : [如何使用 Winepak 在 Linux 上轻松安装 Windows 游戏][1]
### 在 Wine 上你可以运行什么?
Wine 只是一个兼容层,而不是一个全功能的仿真器,因此,你需要一个 x86 的 Android 设备才能完全发挥出它的优势。但是,大多数消费者手中的 Android 设备都是基于 ARM 的。
因为大多数人使用的是基于 ARM 的 Android 设备,所以有一个限制,只有适配在 Windows RT 上运行的那些 App 才能够使用 Wine 在基于 ARM 的 Android 上运行。但是随着发展,能够在 ARM 设备上运行的 App 数量越来越多。你可以在 XDA 开发者论坛上的这个 [帖子][2] 中找到兼容的这些 App 的清单。
在 ARM 上能够运行的一些 App 的例子如下:
* [Keepass Portable][3] 一个密码钱包
* [Paint.NET][4] 一个图像处理程序
* [SumatraPDF][5] 一个 PDF 文档阅读器,也能够阅读一些其它的文档类型
* [Audacity][6] 一个数字录音和编辑程序
也有一些再度流行的开源游戏,比如,[Doom][7] 和 [Quake 2][8],以及它们的开源克隆,比如 [OpenTTD][9] 和《运输大亨》的一个版本。
随着 Wine 在 Android 上越来越普及,能够在基于 ARM 的 Android 设备上的 Wine 中运行的程序越来越多。Wine 项目致力于在 ARM 上使用 QEMU 去仿真 x86 的 CPU 指令,在该项目完成后,能够在 Android 上运行的 App 将会迅速增加。
### 安装 Wine
在安装 Wine 之前,你首先需要去确保你的设备的设置 “允许从 Play 商店之外的其它源下载和安装 APK”。对于本文的用途你需要去许可你的设备从未知源下载 App。
1、 打开你手机上的设置,然后选择安全选项。
![wine-android-security][10]
2、 向下拉并点击 “Unknown Sources” 的开关。
![wine-android-unknown-sources][11]
3、 接受风险警告。
![wine-android-unknown-sources-warning][12]
4、 打开 [Wine 安装站点][13],并点选列表中的第一个选择框。下载将自动开始。
![wine-android-download-button][14]
5、 下载完成后,从下载目录中打开它,或者下拉通知菜单并点击这里的已完成的下载。
6、 开始安装程序。它将提示你它需要访问和记录音频,并去修改、删除、和读取你的 SD 卡。你也可为程序中使用的一些 App 授予访问音频的权利。
![wine-android-app-access][15]
7、 安装完成后,点击程序图标去打开它。
![wine-android-icon-small][16]
当你打开 Wine 后,它模仿的是 Windows 7 的桌面。
![wine-android-desktop][17]
Wine 有一个缺点是,你得有一个外接键盘去进行输入。如果你在一个小屏幕上运行它,并且触摸非常小的按钮很困难,你也可以使用一个外接鼠标。
你可以通过触摸 “开始” 按钮去打开两个菜单 —— “控制面板”和“运行”。
![wine-android-start-button][18]
### 使用 Wine 来工作
当你触摸 “控制面板” 后你将看到三个选项 —— 添加/删除程序、游戏控制器、和 Internet 设定。
使用 “运行”,你可以打开一个对话框去运行命令。例如,通过输入 `iexplore` 来启动 “Internet Explorer”。
![wine-android-run][19]
### 在 Wine 中安装程序
1、 在你的 Android 设备上下载应用程序(或通过云来同步)。一定要记住下载的程序保存的位置。
2、 打开 Wine 命令提示符窗口。
3、 输入程序的位置路径。如果你把下载的文件保存在 SD 卡上,输入:
```
cd sdcard/Download/[filename.exe]
```
4、 在 Android 上运行 Wine 中的文件,只需要简单地输入 EXE 文件的名字即可。
如果这个支持 ARM 的文件是兼容的,它将会运行。如果不兼容,你将看到一大堆错误信息。在这种情况下,在 Android 上的 Wine 中安装的 Windows 软件可能会损坏或丢失。
这个在 Android 上使用的新版本的 Wine 仍然有许多问题。它并不能在所有的 Android 设备上正常工作。它可以在我的 Galaxy S6 Edge 上运行的很好,但是在我的 Galaxy Tab 4 上却不能运行。许多游戏也不能正常运行,因为图形驱动还不支持 Direct3D。因为触摸屏还不是全扩展的所以你需要一个外接的键盘和鼠标才能很轻松地操作它。
即便是在早期阶段的发布版本中存在这样那样的问题,但是这种技术还是值得深思的。当然了,你要想在你的 Android 智能手机上运行 Windows 程序而不出问题,可能还需要等待一些时日。
--------------------------------------------------------------------------------
via: https://www.maketecheasier.com/run-windows-apps-android-with-wine/
作者:[Tracey Rosenberger][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[qhwdw](https://github.com/qhwdw)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.maketecheasier.com/author/traceyrosenberger/
[1]:https://www.maketecheasier.com/winepak-install-windows-games-linux/ "How to Easily Install Windows Games on Linux with Winepak"
[2]:https://forum.xda-developers.com/showthread.php?t=2092348
[3]:http://downloads.sourceforge.net/keepass/KeePass-2.20.1.zip
[4]:http://forum.xda-developers.com/showthread.php?t=2411497
[5]:http://forum.xda-developers.com/showthread.php?t=2098594
[6]:http://forum.xda-developers.com/showthread.php?t=2103779
[7]:http://forum.xda-developers.com/showthread.php?t=2175449
[8]:http://forum.xda-developers.com/attachment.php?attachmentid=1640830&amp;amp;d=1358070370
[9]:http://forum.xda-developers.com/showpost.php?p=36674868&amp;amp;postcount=151
[10]:https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-security.png "wine-android-security"
[11]:https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-unknown-sources.jpg "wine-android-unknown-sources"
[12]:https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-unknown-sources-warning.png "wine-android-unknown-sources-warning"
[13]:https://dl.winehq.org/wine-builds/android/
[14]:https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-download-button.png "wine-android-download-button"
[15]:https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-app-access.jpg "wine-android-app-access"
[16]:https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-icon-small.jpg "wine-android-icon-small"
[17]:https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-desktop.png "wine-android-desktop"
[18]:https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-start-button.png "wine-android-start-button"
[19]:https://www.maketecheasier.com/assets/uploads/2018/07/Wine-Android-Run.png "wine-android-run"

View File

@ -0,0 +1,215 @@
Debian 打包入门
======
> 创建 CardBook 软件包、本地 Debian 仓库,并修复错误。
![](http://minkush.me/img/posts/12.jpg)
我在 GSoCLCTT 译注Google Summer Of Code一项针对学生进行的开源项目训练营一般在夏季进行。)的任务中有一项是为用户构建 Thunderbird <ruby>扩展<rt>add-ons</rt></ruby>。一些非常流行的扩展,比如 [Lightning][1] (日历行事历)已经拥有了 deb 包。
另外一个重要的用于管理基于 CardDav 和 vCard 标准的联系人的扩展 [Cardbook][2] ,还没有一个 deb 包。
我的导师, [Daniel][3] 鼓励我去为它制作一个包,并上传到 [mentors.debian.net][4]。因为这样就可以使用 `apt-get` 来安装,简化了安装流程。这篇博客描述了我是如何从头开始学习为 CardBook 创建一个 Debian 包的。
首先,我是第一次接触打包,我在从源码构建包的基础上进行了大量研究,并检查它的协议是是否与 [DFSG][5] 兼容。
我从多个 Debian Wiki 中的指南中进行学习,比如 [打包介绍][6]、 [构建一个包][7],以及一些博客。
我还研究了包含在 [Lightning 扩展包][8]的 amd64 文件。
我创建的包可以在[这里][9]找到。
![Debian Package!][10]
*Debian 包*
### 创建一个空的包
我从使用 `dh_make` 来创建一个 `debian` 目录开始。
```
# Empty project folder
$ mkdir -p Debian/cardbook
```
```
# create files
$ dh_make\
> --native \
> --single \
> --packagename cardbook_1.0.0 \
> --email minkush@example.com
```
一些重要的文件,比如 `control`、`rules`、`changelog`、`copyright` 等文件被初始化其中。
所创建的文件的完整列表如下:
```
$ find /debian
debian/
debian/rules
debian/preinst.ex
debian/cardbook-docs.docs
debian/manpage.1.ex
debian/install
debian/source
debian/source/format
debian/cardbook.debhelper.lo
debian/manpage.xml.ex
debian/README.Debian
debian/postrm.ex
debian/prerm.ex
debian/copyright
debian/changelog
debian/manpage.sgml.ex
debian/cardbook.default.ex
debian/README
debian/cardbook.doc-base.EX
debian/README.source
debian/compat
debian/control
debian/debhelper-build-stamp
debian/menu.ex
debian/postinst.ex
debian/cardbook.substvars
debian/files
```
我了解了 Debian 系统中 [Dpkg][11] 包管理器及如何用它安装、删除和管理包。
我使用 `dpkg` 命令创建了一个空的包。这个命令创建一个空的包文件以及四个名为 `.changes`、`.deb`、 `.dsc``.tar.gz` 的文件。
- `.dsc` 文件包含了所发生的修改和签名
- `.deb` 文件是用于安装的主要包文件。
- `.tar.gz` tarball包含了源代码
这个过程也在 `/usr/share` 目录下创建了 `README``changelog` 文件。它们包含了关于这个包的基本信息比如描述、作者、版本。
我安装这个包,并检查这个包安装的内容。我的新包中包含了版本、架构和描述。
```
$ dpkg -L cardbook
/usr
/usr/share
/usr/share/doc
/usr/share/doc/cardbook
/usr/share/doc/cardbook/README.Debian
/usr/share/doc/cardbook/changelog.gz
/usr/share/doc/cardbook/copyright
```
### 包含 CardBook 源代码
在成功的创建了一个空包以后,我在包中添加了实际的 CardBook 扩展文件。 CardBook 的源代码托管在 [Gitlab][12] 上。我将所有的源码文件包含在另外一个目录,并告诉打包命令哪些文件需要包含在这个包中。
我使用 `vi` 编辑器创建一个 `debian/install` 文件并列举了需要被安装的文件。在这个过程中,我花费了一些时间去学习基于 Linux 终端的文本编辑器,比如 `vi` 。这让我熟悉如何在 `vi` 中编辑、创建文件和快捷方式。
当这些完成后,我在变更日志中更新了包的版本并记录了我所做的改变。
```
$ dpkg -l | grep cardbook
ii cardbook 1.1.0 amd64 Thunderbird add-on for address book
```
![Changelog][13]
*更新完包的变更日志*
在重新构建完成后,重要的依赖和描述信息可以被加入到包中。 Debian 的 `control` 文件可以用来添加额外的必须项目和依赖。
### 本地 Debian 仓库
在不创建本地存储库的情况下CardBook 可以使用如下的命令来安装:
```
$ sudo dpkg -i cardbook_1.1.0.deb
```
为了实际测试包的安装,我决定构建一个本地 Debian 存储库。没有它,`apt-get` 命令将无法定位包,因为它没有在 Debian 的包软件列表中。
为了配置本地 Debian 存储库,我复制我的包 .deb为放在 `/tmp` 目录中的 `Packages.gz` 文件。
![Packages-gz][14]
*本地 Debian 仓库*
为了使它工作,我了解了 `apt` 的配置和它查找文件的路径。
我研究了一种在 `apt-config` 中添加文件位置的方法。最后,我通过在 APT 中添加 `*.list` 文件来添加包的路径,并使用 `apt-cache` 更新APT缓存来完成我的任务。
因此,最新的 CardBook 版本可以成功的通过 `apt-get install cardbook` 来安装了。
![Package installation!][15]
*使用 apt-get 安装 CardBook*
### 修复打包错误和 Bugs
我的导师 Daniel 在这个过程中帮了我很多忙,并指导我如何进一步进行打包。他告诉我使用 [Lintian][16] 来修复打包过程中出现的常见错误和最终使用 [dput][17] 来上传 CardBook 包。
> Lintian 是一个用于发现策略问题和 Bug 的包检查器。它是 Debian 维护者们在上传包之前广泛使用的自动化检查 Debian 策略的工具。
我上传了该软件包的第二个更新版本到 Debian 目录中的 [Salsa 仓库][18] 的一个独立分支中。
我从 Debian backports 上安装 Lintian 并学习在一个包上用它来修复错误。我研究了它用在其错误信息中的缩写,和如何查看 Lintian 命令返回的详细内容。
```
$ lintian -i -I --show-overrides cardbook_1.2.0.changes
```
最初,在 `.changes` 文件上运行命令时,我惊讶地看到显示出来了大量错误、警告和注释!
![Package Error Brief!][19]
*在包上运行 Lintian 时看到的大量报错*
![Lintian error1!][20]
*详细的 Lintian 报错*
![Lintian error2!][23]
*详细的 Lintian 报错 (2) 以及更多*
我花了几天时间修复与 Debian 包策略违例相关的一些错误。为了消除一个简单的错误,我必须仔细研究每一项策略和 Debian 的规则。为此,我参考了 [Debian 策略手册][21] 以及 [Debian 开发者参考][22]。
我仍然在努力使它变得完美无暇,并希望很快可以将它上传到 mentors.debian.net
如果 Debian 社区中使用 Thunderbird 的人可以帮助修复这些报错就太感谢了。
--------------------------------------------------------------------------------
via: http://minkush.me/cardbook-debian-package/
作者:[Minkush Jain][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[Bestony](https://github.com/bestony)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:http://minkush.me/cardbook-debian-package/#
[1]:https://addons.mozilla.org/en-US/thunderbird/addon/lightning/
[2]:https://addons.mozilla.org/nn-NO/thunderbird/addon/cardbook/?src=hp-dl-featured
[3]:https://danielpocock.com/
[4]:https://mentors.debian.net/
[5]:https://wiki.debian.org/DFSGLicenses
[6]:https://wiki.debian.org/Packaging/Intro
[7]:https://wiki.debian.org/BuildingAPackage
[8]:https://packages.debian.org/stretch/amd64/lightning/filelist
[9]:https://salsa.debian.org/minkush-guest/CardBook/tree/debian-package/Debian
[10]:http://minkush.me/img/posts/13.png
[11]:https://packages.debian.org/stretch/dpkg
[12]:https://gitlab.com/CardBook/CardBook
[13]:http://minkush.me/img/posts/15.png
[14]:http://minkush.me/img/posts/14.png
[15]:http://minkush.me/img/posts/11.png
[16]:https://packages.debian.org/stretch/lintian
[17]:https://packages.debian.org/stretch/dput
[18]:https://salsa.debian.org/minkush-guest/CardBook/tree/debian-package
[19]:http://minkush.me/img/posts/16.png (Running Lintian on package)
[20]:http://minkush.me/img/posts/10.png
[21]:https://www.debian.org/doc/debian-policy/
[22]:https://www.debian.org/doc/manuals/developers-reference/
[23]:http://minkush.me/img/posts/17.png

View File

@ -0,0 +1,67 @@
在 Fedora 28 Workstation 使用 emoji 加速输入
======
![](https://fedoramagazine.org/wp-content/uploads/2018/07/emoji-typing-816x345.jpg)
Fedora 28 Workstation 添加了一个功能允许你使用键盘快速搜索、选择和输入 emoji。emoji这种可爱的表意文字是 Unicode 的一部分,在消息传递中使用得相当广泛,特别是在移动设备上。你可能听过这样的成语:“一图胜千言”。这正是 emoji 所提供的简单的图像供你在交流中使用。Unicode 的每个版本都增加了更多 emoji在最近的 Unicode 版本中添加了 200 多个 emoji。本文向你展示如何使它们在你的 Fedora 系统中易于使用。
很高兴看到 emoji 的数量在增长。但与此同时,它带来了如何在计算设备中输入它们的挑战。许多人已经将这些符号用于移动设备或社交网站中的输入。
[**编者注:**本文是对此主题以前发表过的文章的更新]。
### 在 Fedora 28 Workstation 上启用 emoji 输入
新的 emoji 输入法默认出现在 Fedora 28 Workstation 中。要使用它,必须使用“区域和语言设置”对话框启用它。从 Fedora Workstation 设置打开“区域和语言”对话框,或在“概要”中搜索它。
[![Region & Language settings tool][1]][2]
选择 `+` 控件添加输入源。出现以下对话框:
[![Adding an input source][3]][4]
选择最后选项三个点来完全展开选择。然后在列表底部找到“Other”并选择它
[![Selecting other input sources][5]][6]
在下面的对话框中,找到 “Typing Booster” 选项并选择它:
[![][7]][8]
这个高级输入法由 iBus 在背后支持。该高级输入法可通过列表右侧的齿轮图标在列表中识别。
输入法下拉菜单自动出现在 GNOME Shell 顶部栏中。确认你的默认输入法 —— 在此示例中为英语(美国) - 被选为当前输入法,你就可以输入了。
[![Input method dropdown in Shell top bar][9]][10]
### 使用新的表情符号输入法
现在 emoji 输入法启用了,按键盘快捷键 `Ctrl+Shift+E` 搜索 emoji。将出现一个弹出对话框你可以在其中输入搜索词例如 “smile” 来查找匹配的符号。
[![Searching for smile emoji][11]][12]
使用箭头键翻页列表。然后按回车进行选择,字形将替换输入内容。
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/boost-typing-emoji-fedora-28-workstation/
作者:[Paul W. Frields][a]
选题:[lujun9972](https://github.com/lujun9972)
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://fedoramagazine.org/author/pfrields/
[1]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-15-02-41-1024x718.png
[2]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-15-02-41.png
[3]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-14-33-46-1024x839.png
[4]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-14-33-46.png
[5]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-14-34-15-1024x839.png
[6]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-14-34-15.png
[7]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-14-34-41-1024x839.png
[8]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-14-34-41.png
[9]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-15-05-24-300x244.png
[10]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-15-05-24.png
[11]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-14-36-31-290x300.png
[12]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-08-14-36-31.png

Some files were not shown because too many files have changed in this diff Show More