mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-03-27 02:30:10 +08:00
commit
7b9c42b188
.gitmodules.travis.ymlLCTT翻译规范.mdMakefileREADME.mdcomiclctt2018.md
published
201309
20180529 Manage your workstation with Ansible- Configure desktop settings.md20180620 How To Find The Port Number Of A Service In Linux.md20180629 100 Best Ubuntu Apps.md201808
20160325 Network automation with Ansible.md20170713 A Collection Of Useful BASH Scripts For Heavy Commandline Users.md20170721 Arch Linux Applications Automatic Installation Script.md20170805 How to use Fio (Flexible I-O Tester) to Measure Disk Performance in Linux.md20171009 Considering Pythons Target Audience.md20171101 Linux command line tools for working with non-Linux users.md20171102 Using User Namespaces on Docker.md20171130 Google launches TensorFlow-based vision recognition kit for RPi Zero W.md20180107 7 leadership rules for the DevOps age.md20180118 How to Play Sound Through Two or More Output Devices in Linux.md20180306 How To Check All Running Services In Linux.md20180306 How to apply Machine Learning to IoT using Android Things and TensorFlow.md20180306 Try, learn, modify- The new IT leader-s code.md20180426 How To Check System Hardware Manufacturer, Model And Serial Number In Linux.md20180429 Asynchronous Processing with Go using Kafka and MongoDB.md20180508 Everything old is new again- Microservices - DXC Blogs.md20180508 UKTools - Easy Way To Install Latest Linux Kernel.md20180510 Splicing the Cloud Native Stack, One Floor at a Time.md20180516 How to Read Outlook Emails by Python.md20180523 A Set Of Useful Utilities For Debian And Ubuntu Users.md20180524 How CERN Is Using Linux and Open Source.md20180607 Find If A Package Is Available For Your Linux Distribution.md20180607 Using MQTT to send and receive data for your next project.md20180609 Anatomy of a Linux DNS Lookup - Part I.md20180615 5 Commands for Checking Memory Usage in Linux.md20180618 Anatomy of a Linux DNS Lookup - Part II.md20180619 How to reset, revert, and return to previous states in Git.md20180621 Bitcoin is a Cult - Adam Caudill.md20180622 How to Check Disk Space on Linux from the Command line.md20180623 Don-t Install Yaourt- Use These Alternatives for AUR in Arch Linux.md20180623 Intercepting and Emulating Linux System Calls with Ptrace - null program.md20180627 CIP- Keeping the Lights On with Linux.md20180702 How to edit Adobe InDesign files with Scribus and Gedit.md20180703 How to make a career move from proprietary to open source technology.md20180703 Why is Arch Linux So Challenging and What are Its Pros - Cons.md20180705 Testing Node.js in 2018.md20180706 Revisiting wallabag, an open source alternative to Instapaper.md20180709 A sysadmin-s guide to network management.md20180710 4 Essential and Practical Usage of Cut Command in Linux.md20180710 How I Fully Quit Google And You Can Too.md20180711 Javascript Framework Comparison with Examples React Vue Hyperapp.md20180711 netdev-day-1--ipsec.md20180712 A sysadmin-s guide to SELinux- 42 answers to the big questions.md20180712 Slices from the ground up.md20180712 netdev day 2 moving away from as fast as possible in networking code.md20180716 3 cool productivity apps for Fedora 28.md20180719 Incomplete Path Expansion (Completion) For Bash.md20180720 3 Methods to List All The Users in Linux System.md20180720 4 cool new projects to try in COPR for July 2018.md20180720 Convert video using Handbrake.md20180723 4 open source media conversion tools for the Linux desktop.md20180724 Textricator- Data extraction made simple.md20180726 4 cool apps for your terminal.md20180726 The evolution of package managers.md20180727 Three Graphical Clients for Git on Linux.md20180730 Open Source Networking Jobs- A Hotbed of Innovation and Opportunities.md20180731 A sysadmin-s guide to Bash.md20180731 How To Use Pbcopy And Pbpaste Commands On Linux.md20180801 Cross-Site Request Forgery.md20180802 6 Easy Ways to Check User Name And Other Information in Linux.md20180802 Getting started with Mu, a Python editor for beginners.md20180803 UNIX curiosities.md20180803 What data is too risky for the cloud.md20180803 Why I still love Alpine for email at the Linux terminal.md20180806 A gawk script to convert smart quotes.md20180806 Learn Python programming the easy way with EduBlocks.md20180806 What is CI-CD.md20180809 How To Switch Between Multiple PHP Versions In Ubuntu.md20180810 Image creation applications for Fedora.md20180812 Ubuntu 18.04 Vs. Fedora 28.md20180813 Convert file systems with Fstransform.md20180813 How To Switch Between Different Versions Of Commands In Linux.md20180813 How to display data in a human-friendly way on Linux.md20180813 Tips for using the top command in Linux.md20180814 How To Record Terminal Sessions As SVG Animations In Linux.md20180815 How the L1 Terminal Fault vulnerability affects Linux systems.md20180819 How to define and use functions in Linux Shell Script.md20180821 A Collection Of More Useful Unix Utilities.md
201809
20140805 How to Install Cinnamon Desktop on Ubuntu.md20160503 Cloud Commander - A Web File Manager With Console And Editor.md20170706 Docker Guide Dockerizing Python Django Application.md20170709 The Extensive Guide to Creating Streams in RxJS.md20170829 How To Set Up PF Firewall on FreeBSD to Protect a Web Server.md20171003 Trash-Cli - A Command Line Interface For Trashcan On Linux.md20171010 Operating a Kubernetes network.md20171124 How do groups work on Linux.md20171202 Scrot Linux command-line screen grabs made simple.md20180102 Top 7 open source project management tools for agile teams.md20180131 What I Learned from Programming Interviews.md
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "comic"]
|
||||
path = comic
|
||||
url = https://wxy@github.com/LCTT/comic.git
|
29
.travis.yml
29
.travis.yml
@ -1,2 +1,27 @@
|
||||
language: c
|
||||
script: make -s check
|
||||
language: minimal
|
||||
install:
|
||||
- sudo apt-get install jq
|
||||
- git clone --depth=1 -b gh-pages https://github.com/LCTT/TranslateProject/ build && rm -rf build/.git
|
||||
script:
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then sh ./scripts/check.sh; fi'
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then sh ./scripts/badge.sh; fi'
|
||||
- 'if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then sh ./scripts/status.sh; fi'
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
# - status
|
||||
except:
|
||||
- gh-pages
|
||||
git:
|
||||
submodules: false
|
||||
depth: false
|
||||
deploy:
|
||||
provider: pages
|
||||
skip_cleanup: true
|
||||
github_token: $GITHUB_TOKEN
|
||||
local_dir: build
|
||||
on:
|
||||
branch:
|
||||
- master
|
||||
# - status
|
||||
|
@ -1,4 +0,0 @@
|
||||
# Linux中国翻译规范
|
||||
1. 翻译中出现的专有名词,可参见Dict.md中的翻译。
|
||||
2. 英文人名,如无中文对应译名,一般不译。
|
||||
2. 缩写词,一般不须翻译,可考虑旁注中文全名。
|
51
Makefile
51
Makefile
@ -1,51 +0,0 @@
|
||||
DIR_PATTERN := (news|talk|tech)
|
||||
NAME_PATTERN := [0-9]{8} [a-zA-Z0-9_.,() -]*\.md
|
||||
|
||||
RULES := rule-source-added \
|
||||
rule-translation-requested \
|
||||
rule-translation-completed \
|
||||
rule-translation-revised \
|
||||
rule-translation-published
|
||||
.PHONY: check match $(RULES)
|
||||
|
||||
CHANGE_FILE := /tmp/changes
|
||||
|
||||
check: $(CHANGE_FILE)
|
||||
echo 'PR #$(TRAVIS_PULL_REQUEST) Changes:'
|
||||
cat $(CHANGE_FILE)
|
||||
echo
|
||||
echo 'Check for rules...'
|
||||
make -k $(RULES) 2>/dev/null | grep '^Rule Matched: '
|
||||
|
||||
$(CHANGE_FILE):
|
||||
git --no-pager diff $(TRAVIS_BRANCH) FETCH_HEAD --no-renames --name-status > $@
|
||||
|
||||
rule-source-added:
|
||||
echo 'Unmatched Files:'
|
||||
egrep -v '^A\s*"?sources/$(DIR_PATTERN)/$(NAME_PATTERN)"?' $(CHANGE_FILE) || true
|
||||
echo '[End of Unmatched Files]'
|
||||
[ $(shell egrep '^A\s*"?sources/$(DIR_PATTERN)/$(NAME_PATTERN)"?' $(CHANGE_FILE) | wc -l) -ge 1 ]
|
||||
[ $(shell egrep -v '^A\s*"?sources/$(DIR_PATTERN)/$(NAME_PATTERN)"?' $(CHANGE_FILE) | wc -l) = 0 ]
|
||||
echo 'Rule Matched: $(@)'
|
||||
|
||||
rule-translation-requested:
|
||||
[ $(shell egrep '^M\s*"?sources/$(DIR_PATTERN)/$(NAME_PATTERN)"?' $(CHANGE_FILE) | wc -l) = 1 ]
|
||||
[ $(shell cat $(CHANGE_FILE) | wc -l) = 1 ]
|
||||
echo 'Rule Matched: $(@)'
|
||||
|
||||
rule-translation-completed:
|
||||
[ $(shell egrep '^D\s*"?sources/$(DIR_PATTERN)/$(NAME_PATTERN)"?' $(CHANGE_FILE) | wc -l) = 1 ]
|
||||
[ $(shell egrep '^A\s*"?translated/$(DIR_PATTERN)/$(NAME_PATTERN)"?' $(CHANGE_FILE) | wc -l) = 1 ]
|
||||
[ $(shell cat $(CHANGE_FILE) | wc -l) = 2 ]
|
||||
echo 'Rule Matched: $(@)'
|
||||
|
||||
rule-translation-revised:
|
||||
[ $(shell egrep '^M\s*"?translated/$(DIR_PATTERN)/$(NAME_PATTERN)"?' $(CHANGE_FILE) | wc -l) = 1 ]
|
||||
[ $(shell cat $(CHANGE_FILE) | wc -l) = 1 ]
|
||||
echo 'Rule Matched: $(@)'
|
||||
|
||||
rule-translation-published:
|
||||
[ $(shell egrep '^D\s*"?translated/$(DIR_PATTERN)/$(NAME_PATTERN)"?' $(CHANGE_FILE) | wc -l) = 1 ]
|
||||
[ $(shell egrep '^A\s*"?published/$(NAME_PATTERN)' $(CHANGE_FILE) | wc -l) = 1 ]
|
||||
[ $(shell cat $(CHANGE_FILE) | wc -l) = 2 ]
|
||||
echo 'Rule Matched: $(@)'
|
117
README.md
117
README.md
@ -1,34 +1,40 @@
|
||||
|
||||
[](https://lctt.github.io/new)
|
||||
[](https://lctt.github.io/translating)
|
||||
[](https://github.com/LCTT/TranslateProject/tree/master/translated)
|
||||
[](https://github.com/LCTT/TranslateProject/tree/master/published)
|
||||
|
||||
[](https://travis-ci.com/LCTT/TranslateProject)
|
||||
[](https://github.com/LCTT/TranslateProject/graphs/contributors)
|
||||
[](https://github.com/LCTT/TranslateProject/pulls?q=is%3Apr+is%3Aclosed)
|
||||
|
||||
简介
|
||||
-------------------------------
|
||||
|
||||
LCTT 是“Linux中国”([https://linux.cn/](https://linux.cn/))的翻译组,负责从国外优秀媒体翻译 Linux 相关的技术、资讯、杂文等内容。
|
||||
[LCTT](https://linux.cn/lctt/) 是“Linux 中国”([https://linux.cn/](https://linux.cn/))的翻译组,负责从国外优秀媒体翻译 Linux 相关的技术、资讯、杂文等内容。
|
||||
|
||||
LCTT 已经拥有几百名活跃成员,并欢迎更多的Linux志愿者加入我们的团队。
|
||||
LCTT 已经拥有几百名活跃成员,并欢迎更多的 Linux 志愿者加入我们的团队。
|
||||
|
||||

|
||||

|
||||
|
||||
LCTT 的组成
|
||||
-------------------------------
|
||||
|
||||
**选题**,负责选择合适的内容,并将原文转换为 markdown 格式,提交到 LCTT 的 [TranslateProject](https://github.com/LCTT/TranslateProject) 库中。
|
||||
|
||||
**译者**,负责从选题中选择内容进行翻译。
|
||||
|
||||
**校对**,负责将初译的文章进行文字润色、技术校对等工作。
|
||||
|
||||
**发布**,负责将校对后的文章,排版进行发布。
|
||||
- LCTT 官网: [https://linux.cn/lctt/](https://linux.cn/lctt/)
|
||||
- LCTT 状态: [https://lctt.github.io/](https://lctt.github.io/)
|
||||
|
||||
加入我们
|
||||
-------------------------------
|
||||
|
||||
请首先加入翻译组的 QQ 群,群号是:198889102,加群时请说明是“志愿者”。加入后记得修改您的群名片为您的 GitHub 的 ID。
|
||||
请首先加入翻译组的 QQ 群,群号是:**198889102**,加群时请说明是“*志愿者*”。
|
||||
|
||||
加入的成员,请先阅读 [WIKI 如何开始](https://github.com/LCTT/TranslateProject/wiki/01-如何开始)。
|
||||
加入的成员,请:
|
||||
|
||||
1. 修改你的 QQ 群名片为“译者-您的_GitHub_ID”。
|
||||
2. 阅读 [WIKI](https://lctt.github.io/wiki) 了解如何开始。
|
||||
3. 遇到不解之处,请在群内发问。
|
||||
|
||||
如何开始
|
||||
-------------------------------
|
||||
|
||||
请阅读 [WIKI](https://github.com/LCTT/TranslateProject/wiki)。
|
||||
请阅读 [WIKI](https://lctt.github.io/wiki)。如需要协助,请在群内发问。
|
||||
|
||||
历史
|
||||
-------------------------------
|
||||
@ -65,43 +71,56 @@ LCTT 的组成
|
||||
* 2018/01/11 提升 lujun9972 成为核心成员,并加入选题组。
|
||||
* 2018/02/20 遭遇 DMCA 仓库被封。
|
||||
* 2018/05/15 提升 MjSeven 为核心成员。
|
||||
* 2018/08/01 [发布 Linux 中国通证:LCCN](https://linux.cn/article-9886-1.html)。
|
||||
* 2018/08/17 提升 pityonline 为核心成员,担任校对,并接受他的建议采用 PR 审核模式。
|
||||
* 2018/09/10 [LCTT 五周年](https://linux.cn/article-9999-1.html)。
|
||||
* 2018/10/25 重构了 CI,感谢 vizv、lujun9972、bestony。
|
||||
* 2018/11/13 [成立了项目管理委员会(PMC)](https://linux.cn/article-10279-1.html),初始成员为:@wxy (主席)、@oska874、@lujun9972、@bestony、@pityonline、@geekpi、@qhwdw。
|
||||
|
||||
核心成员
|
||||
|
||||
项目管理委员及核心成员
|
||||
-------------------------------
|
||||
|
||||
目前 LCTT 核心成员有:
|
||||
LCTT 现由项目管理委员会(PMC)进行管理,成员如下:
|
||||
|
||||
- 组长 @wxy,
|
||||
- 选题 @oska874,
|
||||
- 校对 @jasminepeng,
|
||||
- 钻石译者 @geekpi,
|
||||
- 钻石译者 @GOLinux,
|
||||
- 钻石译者 @ictlyh,
|
||||
- 技术组长 @bestony,
|
||||
- 漫画组长 @GHLandy,
|
||||
- LFS 组长 @martin2011qi,
|
||||
- 核心成员 @strugglingyouth,
|
||||
- 核心成员 @FSSlc,
|
||||
- 核心成员 @zpl1025,
|
||||
- 核心成员 @runningwater,
|
||||
- 核心成员 @bazz2,
|
||||
- 核心成员 @Vic020,
|
||||
- 核心成员 @alim0x,
|
||||
- 核心成员 @tinyeyeser,
|
||||
- 核心成员 @Locez,
|
||||
- 核心成员 @ucasFL,
|
||||
- 核心成员 @rusking,
|
||||
- 核心成员 @qhwdw,
|
||||
- 核心成员 @lujun9972
|
||||
- 核心成员 @MjSeven
|
||||
- 前任选题 @DeadFire,
|
||||
- 前任校对 @reinoir222,
|
||||
- 前任校对 @PurlingNayuki,
|
||||
- 前任校对 @carolinewuyan,
|
||||
- 功勋成员 @vito-L,
|
||||
- 功勋成员 @willqian,
|
||||
- 功勋成员 @vizv,
|
||||
- 功勋成员 @dongfengweixiao,
|
||||
- 🎩 主席 @wxy
|
||||
- 🎩 选题 @oska874
|
||||
- 🎩 选题 @lujun9972
|
||||
- 🎩 技术 @bestony
|
||||
- 🎩 校对 @pityonline
|
||||
- 🎩 译者 @geekpi
|
||||
- 🎩 译者 @qhwdw
|
||||
|
||||
目前 LCTT 核心成员有:
|
||||
|
||||
- ❤️ 核心成员 @vizv
|
||||
- ❤️ 核心成员 @zpl1025
|
||||
- ❤️ 核心成员 @runningwater
|
||||
- ❤️ 核心成员 @FSSlc
|
||||
- ❤️ 核心成员 @Vic020
|
||||
- ❤️ 核心成员 @alim0x
|
||||
- ❤️ 核心成员 @martin2011qi
|
||||
- ❤️ 核心成员 @Locez
|
||||
- ❤️ 核心成员 @ucasFL
|
||||
- ❤️ 核心成员 @MjSeven
|
||||
|
||||
曾经做出了巨大贡献的核心成员,被列入荣誉榜:
|
||||
|
||||
- 🏆 前任选题 @DeadFire
|
||||
- 🏆 前任校对 @reinoir222
|
||||
- 🏆 前任校对 @PurlingNayuki
|
||||
- 🏆 前任校对 @carolinewuyan
|
||||
- 🏆 前任校对 @jasminepeng
|
||||
- 🏆 功勋成员 @tinyeyeser
|
||||
- 🏆 功勋成员 @vito-L
|
||||
- 🏆 功勋成员 @willqian
|
||||
- 🏆 功勋成员 @GOLinux
|
||||
- 🏆 功勋成员 @bazz2
|
||||
- 🏆 功勋成员 @ictlyh
|
||||
- 🏆 功勋成员 @dongfengweixiao
|
||||
- 🏆 功勋成员 @strugglingyouth
|
||||
- 🏆 功勋成员 @GHLandy
|
||||
- 🏆 功勋成员 @rusking
|
||||
|
||||
全部成员列表请参见: https://linux.cn/lctt-list/ 。
|
||||
|
||||
|
1
comic
1
comic
@ -1 +0,0 @@
|
||||
Subproject commit e5db5b880dac1302ee0571ecaaa1f8ea7cf61901
|
75
lctt2018.md
Normal file
75
lctt2018.md
Normal 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 夜
|
77
published/201309/20190204 7 Best VPN Services For 2019.md
Normal file
77
published/201309/20190204 7 Best VPN Services For 2019.md
Normal file
@ -0,0 +1,77 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Modrisco)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10691-1.html)
|
||||
[#]: subject: (7 Best VPN Services For 2019)
|
||||
[#]: via: (https://www.ostechnix.com/7-best-opensource-vpn-services-for-2019/)
|
||||
[#]: author: (Editor https://www.ostechnix.com/author/editor/)
|
||||
|
||||
2019 年最好的 7 款虚拟私人网络服务
|
||||
======
|
||||
|
||||
在过去三年中,全球至少有 67% 的企业面临着数据泄露,亿万用户受到影响。研究表明,如果事先对数据安全采取最基本的保护措施,那么预计有 93% 的安全问题是可以避免的。
|
||||
|
||||
糟糕的数据安全会带来极大的代价,特别是对企业而言。它会大致大规模的破坏并影响你的品牌声誉。尽管有些企业可以艰难地收拾残局,但仍有一些企业无法从事故中完全恢复。不过现在,你很幸运地可以得到数据及网络安全软件。
|
||||
|
||||

|
||||
|
||||
到了 2019 年,你可以通过**虚拟私人网络**,也就是我们熟知的 **VPN** 来保护你免受网络攻击。当涉及到在线隐私和安全时,常常存在许多不确定因素。有数百个不同的 VPN 提供商,选择合适的供应商也同时意味着在定价、服务和易用性之间谋取恰当的平衡。
|
||||
|
||||
如果你正在寻找一个可靠的 100% 经过测试和安全的 VPN,你可能需要进行详尽的调查并作出最佳选择。这里为你提供在 2019 年 7 款最好用并经过测试的 VPN 服务。
|
||||
|
||||
### 1、Vpnunlimitedapp
|
||||
|
||||
通过 VPN Unlimited,你的数据安全将得到全面的保障。此 VPN 允许你连接任何 WiFi ,而无需担心你的个人数据可能被泄露。你的数据通过 AES-256 算法加密,保护你不受第三方和黑客的窥探。无论你身处何处,这款 VPN 都可确保你在所有网站上保持匿名且不受跟踪。它提供 7 天的免费试用和多种协议支持:openvpn、IKEv2 和 KeepSolidWise。有特殊需求的用户会获得特殊的额外服务,如个人服务器、终身 VPN 订阅和个人 IP 选项。
|
||||
|
||||
### 2、VPN Lite
|
||||
|
||||
VPN Lite 是一款易于使用而且**免费**的用于上网的 VPN 服务。你可以通过它在网络上保持匿名并保护你的个人隐私。它会模糊你的 IP 并加密你的数据,这意味着第三方无法跟踪你的所有线上活动。你还可以访问网络上的全部内容。使用 VPN Lite,你可以访问在被拦截的网站。你还放心地可以访问公共 WiFi 而不必担心敏感信息被间谍软件窃取和来自黑客的跟踪和攻击。
|
||||
|
||||
### 3、HotSpot Shield
|
||||
|
||||
这是一款在 2005 年推出的大受欢迎的 VPN。这套 VPN 协议至少被全球 70% 的数据安全公司所集成,并在全球有数千台服务器。它提供两种免费模式:一种为完全免费,但会有线上广告;另一种则为七天试用。它提供军事级的数据加密和恶意软件防护。HotSpot Shield 保证网络安全并保证高速网络。
|
||||
|
||||
### 4、TunnelBear
|
||||
|
||||
如果你是一名 VPN 新手,那么 TunnelBear 将是你的最佳选择。它带有一个用户友好的界面,并配有动画熊引导。你可以在 TunnelBear 的帮助下以极快的速度连接至少 22 个国家的服务器。它使用 **AES 256-bit** 加密算法,保证无日志记录,这意味着你的数据将得到保护。你还可以在最多五台设备上获得无限流量。
|
||||
|
||||
### 5、ProtonVPN
|
||||
|
||||
这款 VPN 为你提供强大的优质服务。你的连接速度可能会受到影响,但你也可以享受到无限流量。它具有易于使用的用户界面,提供多平台兼容。 ProtonVPN 的服务据说是因为为种子下载提供了优化因而无法访问 Netflix。你可以获得如协议和加密等安全功能来保证你的网络安全。
|
||||
|
||||
### 6、ExpressVPN
|
||||
|
||||
ExpressVPN 被认为是最好的用于接触封锁和保护隐私的离岸 VPN。凭借强大的客户支持和快速的速度,它已成为全球顶尖的 VPN 服务。它提供带有浏览器扩展和自定义固件的路由。 ExpressVPN 拥有一系列令人赞叹高质量应用程序,配有大量的服务器,并且最多只能支持三台设备。
|
||||
|
||||
ExpressVPN 并不是完全免费的,恰恰相反,正是由于它所提供的高质量服务而使之成为了市场上最贵的 VPN 之一。ExpressVPN 有 30 天内退款保证,因此你可以免费试用一个月。好消息是,这是完全没有风险的。例如,如果你在短时间内需要 VPN 来绕过在线审查,这可能是你的首选解决方案。用过它之后,你就不会随意想给一个会发送垃圾邮件、缓慢的免费的程序当成试验品。
|
||||
|
||||
ExpressVPN 也是享受在线流媒体和户外安全的最佳方式之一。如果你需要继续使用它,你只需要续订或取消你的免费试用。ExpressVPN 在 90 多个国家架设有 2000 多台服务器,可以解锁 Netflix,提供快速连接,并为用户提供完全隐私。
|
||||
|
||||
### 7、PureVPN
|
||||
|
||||
虽然 PureVPN 可能不是完全免费的,但它却是此列表中最实惠的一个。用户可以注册获得 7 天的免费试用,并在之后选择任一付费计划。通过这款 VPN,你可以访问到至少 140 个国家中的 750 余台服务器。它还可以在几乎所有设备上轻松安装。它的所有付费特性仍然可以在免费试用期间使用。包括无限数据流量、IP 泄漏保护和 ISP 不可见性。它支持的系统有 iOS、Android、Windows、Linux 和 macOS。
|
||||
|
||||
### 总结
|
||||
|
||||
如今,可用的免费 VPN 服务越来越多,为什么不抓住这个机会来保护你自己和你的客户呢?在了解到有那么多优秀的 VPN 服务后,我们知道即使是最安全的免费服务也不一定就完全没有风险。你可能需要付费升级到高级版以增强保护。高级版的 VPN 为你提供了免费试用,提供无风险退款保证。无论你打算花钱购买 VPN 还是准备使用免费 VPN,我们都强烈建议你使用一个。
|
||||
|
||||
**关于作者:**
|
||||
|
||||
**Renetta K. Molina** 是一个技术爱好者和健身爱好者。她撰写有关技术、应用程序、 WordPress 和其他任何领域的文章。她喜欢在空余时间打高尔夫球和读书。她喜欢学习和尝试新事物。
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/7-best-opensource-vpn-services-for-2019/
|
||||
|
||||
作者:[Editor][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Modrisco](https://github.com/Modrisco)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/editor/
|
||||
[b]: https://github.com/lujun9972
|
@ -0,0 +1,158 @@
|
||||
使用 Ansible 管理你的工作站:配置桌面设置
|
||||
======
|
||||
|
||||
> 在本系列第三篇(也是最后一篇)文章中,我们将使用 Ansible 自动化配置 GNOME 桌面设置。
|
||||
|
||||

|
||||
|
||||
在本系列关于使用 Ansible 配置工作站的[第一篇文章][1]中,我们设置了一个仓库并配置了一些基本的东西。在[第二篇文章][2]中,我们配置了 Ansible 以使其在对仓库进行更改时自动应用设置。在第三篇(也是最后一篇)文章中,我们将使用 Ansible 配置 GNOME 桌面设置。
|
||||
|
||||
此配置只适用于较新的发行版(例如我将在示例中使用的 Ubuntu 18.04)。较旧版本的 Ubuntu 将无法运行,因为它们附带了一个老版本的 `python-psutils`,对于 Ansible 的 `dconf` 模块无法正常工作。如果你使用的是较新版本的 Linux 发行版,则应该没有问题。
|
||||
|
||||
在开始之前,确保你已经完成了本系列的第一部分和第二部分,因为第三部分建立在此基础之上的。如果还没有,下载前两篇文章中一直使用的 GitHub [仓库][3],我们将为其添加更多功能。
|
||||
|
||||
### 设置壁纸和锁屏
|
||||
|
||||
首先,我们将创建一个任务手册来保存我们的 GNOME 设置。在仓库的根目录中,应该有一个名为 `local.yml` 的文件,添加以下行:
|
||||
|
||||
```
|
||||
- include: tasks/gnome.yml
|
||||
```
|
||||
|
||||
整个文件应如下所示:
|
||||
|
||||
```
|
||||
- hosts: localhost
|
||||
become: true
|
||||
pre_tasks:
|
||||
- name: update repositories
|
||||
apt: update_cache=yes
|
||||
changed_when: False
|
||||
|
||||
tasks:
|
||||
- include: tasks/users.yml
|
||||
- include: tasks/cron.yml
|
||||
- include: tasks/packages.yml
|
||||
- include: tasks/gnome.yml
|
||||
```
|
||||
|
||||
基本上,这添加了对名为 `gnome.yml` 文件的引用,它将存储在仓库内的 `tasks` 目录中。我们还没有创建这个文件,现在就来创建它。在 `tasks` 目录中创建 `gnome.yml` 文件,并将以下内容放入:
|
||||
|
||||
```
|
||||
- name: Install python-psutil package
|
||||
apt: name=python-psutil
|
||||
|
||||
- name: Copy wallpaper file
|
||||
copy: src=files/wallpaper.jpg dest=/home/jay/.wallpaper.jpg owner=jay group=jay mode=600
|
||||
|
||||
- name: Set GNOME Wallpaper
|
||||
become_user: jay
|
||||
dconf: key="/org/gnome/desktop/background/picture-uri" value="'file:///home/jay/.wallpaper.jpg'"
|
||||
```
|
||||
|
||||
注意,此代码多次引用我的用户名(`jay`),因此确保使用你机器上的用户名替换每次出现的 `jay`。另外,如果你没有像我一样使用 Ubuntu 18.04,你将必须更改 `apt` 一行来匹配你所选择的发行版的包管理器,并确认 `python-psutil` 包的名称,因为它可能有所不同。
|
||||
|
||||
在示例任务中,我引用了 `file` 目录下的 `wallpaper.jpg` 文件,此文件必须存在,否则 Ansible 配置将失败。在 `tasks` 目录中,创建一个名为 `files` 的子目录。找到你喜欢的壁纸图片,将其命名为 `wallpaper.jpg`,然后把它放在 `files` 目录中。如果文件是 PNG 图像而不是 JPG,在代码和仓库中更改文件扩展名。如果你觉得没有创意,我在 [GitHub 仓库][3] 中有一个示例壁纸文件,你可以使用它。
|
||||
|
||||
完成所有这些更改后,将内容提交到 GitHub 仓库,并推送这些更改。总结一下,你应该完成以下工作:
|
||||
|
||||
* 修改 `local.yml` 文件以引用 `tasks/gnome.yml`
|
||||
* 使用上面提到的内容创建 `tasks/gnome.yml`
|
||||
* 在 `tasks` 目录中创建一个 `files` 目录,其中有一个名为 `wallpaper.jpg` 的图像文件(或者你选择的任何名称)。
|
||||
|
||||
完成这些步骤并将更改推送到仓库后,配置应该在下次计划运行期间自动应用。(你可能还记得我们在上一篇文章中对此进行了自动化。)如果你想节省时间,可以使用以下命令立即应用配置:
|
||||
|
||||
```
|
||||
sudo ansible-pull -U https://github.com/<github_user>/ansible.git
|
||||
```
|
||||
|
||||
如果一切正常,你应该可以看到你的新壁纸。
|
||||
|
||||
让我们花一点时间来了解新的 GNOME 任务手册的功能。首先,我们添加了一个计划来安装 `python-psutil` 包。如果不添加它,我们就不能使用 `dconf` 模块,因为它需要在修改 GNOME 设置之前安装这个包。接下来,我们使用 `copy` 模块将壁纸文件复制到我们的 `home` 目录,并将生成的文件命名为以点开头的隐藏文件。如果你不希望此文件放在 `home` 目录的根目录中,你可以随时指示此部分将其复制到其它位置 —— 只要你在正确的位置引用它,它仍然可以工作。在下一个计划中,我们使用 `dconf` 模块来更改 GNOME 设置。在这种情况下,我们调整了 `/org/gnome/desktop/background/picture-uri` 键并将其设置为 `file:///home/jay/.wallpaper.jpg`。注意本节中的引号 —— 你必须在 `dconf` 值中使用两个单引号,如果值是一个字符串,还必须包含在双引号内。
|
||||
|
||||
现在,让我们进一步进行配置,并将背景应用于锁屏。这是现在的 GNOME 任务手册,但增加了两个额外的计划:
|
||||
|
||||
```
|
||||
- name: Install python-psutil package
|
||||
apt: name=python-psutil
|
||||
|
||||
- name: Copy wallpaper file
|
||||
copy: src=files/wallpaper.jpg dest=/home/jay/.wallpaper.jpg owner=jay group=jay mode=600
|
||||
|
||||
- name: Set GNOME wallpaper
|
||||
dconf: key="/org/gnome/desktop/background/picture-uri" value="'file:///home/jay/.wallpaper.jpg'"
|
||||
|
||||
- name: Copy lockscreenfile
|
||||
copy: src=files/lockscreen.jpg dest=/home/jay/.lockscreen.jpg owner=jay group=jay mode=600
|
||||
|
||||
- name: Set lock screen background
|
||||
become_user: jay
|
||||
dconf: key="/org/gnome/desktop/screensaver/picture-uri" value="'file:///home/jay/.lockscreen.jpg'"
|
||||
```
|
||||
|
||||
正如你所看到的,我们做的事情和设置壁纸时差不多。我们添加了两个额外的任务,一个是复制锁屏图像并将其放在我们的 `home` 目录中,另一个是将设置应用于 GNOME 以便使用它。同样,确保将 `jay` 更改为你的用户名,并命名你想要的锁屏图片 `lockscreen.jpg`,并将其复制到 `files` 目录。将这些更改提交到仓库后,在下一次计划的 Ansible 运行期间就会应用新的锁屏。
|
||||
|
||||
### 应用新的桌面主题
|
||||
|
||||
设置壁纸和锁屏背景很酷,但是让我们更进一步来应用桌面主题。首先,让我们在我们的任务手册中添加一条指令来安装 `arc` 主题的包。将以下代码添加到 GNOME 任务手册的开头:
|
||||
|
||||
```
|
||||
- name: Install arc theme
|
||||
apt: name=arc-theme
|
||||
```
|
||||
|
||||
然后,在底部,添加以下动作:
|
||||
|
||||
```
|
||||
- name: Set GTK theme
|
||||
become_user: jay
|
||||
dconf: key="/org/gnome/desktop/interface/gtk-theme" value="'Arc'"
|
||||
```
|
||||
|
||||
你看到 GNOME 的 GTK 主题在你眼前变化了吗?我们添加了一个动作来通过 `apt` 模块安装 `arc-theme` 包,另一个动作将这个主题应用到 GNOME。
|
||||
|
||||
### 进行其它定制
|
||||
|
||||
既然你已经更改了一些 GNOME 设置,你可以随意添加其它定制。你在 GNOME 中调整的任何设置都可以通过这种方式自动完成,设置壁纸和主题只是几个例子。你可能想知道如何找到要更改的设置,以下是一个我用的技巧。
|
||||
|
||||
首先,通过在你管理的计算机上运行以下命令,获取所有当前 `dconf` 设置的快照:
|
||||
|
||||
```
|
||||
dconf dump / > before.txt
|
||||
```
|
||||
|
||||
此命令将所有当前更改导出到名为 `before.txt` 的文件中。接下来,手动更改要自动化的设置,并再次获取 `dconf` 设置:
|
||||
|
||||
```
|
||||
dconf dump / > after.txt
|
||||
```
|
||||
|
||||
现在,你可以使用 `diff` 命令查看两个文件之间的不同之处:
|
||||
|
||||
```
|
||||
diff before.txt after.txt
|
||||
```
|
||||
|
||||
这应该会给你一个已更改键值的列表。虽然手动更改设置确实违背了自动化的目的,但你实际上正在做的是获取更新首选设置时更改的键,这允许你创建 Ansible 任务以修改这些设置,这样你就再也不需要碰这些设置了。如果你需要还原机器,Ansible 仓库会处理好你的每个定制。如果你有多台计算机,甚至是一组工作站,则只需手动进行一次更改,所有其他工作站都将应用新设置并完全同步。
|
||||
|
||||
### 最后
|
||||
|
||||
如果你已经阅读完本系列文章,你应该知道如何设置 Ansible 来自动化工作站。这些示例提供了一个有用的基础,你可以使用这些语法和示例进行其他定制。随着你的进展,你可以继续添加新的修改,这将使你的 Ansible 配置一直增长。
|
||||
|
||||
我已经用 Ansible 以这种方式自动化了一切,包括我的用户帐户和密码、Vim、tmux 等配置文件、桌面包、SSH 设置、SSH 密钥,基本上我想要自定义的一切都使用了。以本系列文章作为起点,将为你实现工作站的完全自动化铺平道路。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/5/manage-your-workstation-ansible-part-3
|
||||
|
||||
作者:[Jay LaCroix][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/jlacroix
|
||||
[1]:https://linux.cn/article-10434-1.html
|
||||
[2]:https://linux.cn/article-10449-1.html
|
||||
[3]:https://github.com/jlacroix82/ansible_article.git
|
@ -0,0 +1,191 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11066-1.html)
|
||||
[#]: subject: (How To Find The Port Number Of A Service In Linux)
|
||||
[#]: via: (https://www.ostechnix.com/how-to-find-the-port-number-of-a-service-in-linux/)
|
||||
[#]: author: (sk https://www.ostechnix.com/author/sk/)
|
||||
|
||||
如何在 Linux 中查找服务的端口号
|
||||
======
|
||||
|
||||
![Find The Port Number Of A Service In Linux OS][1]
|
||||
|
||||
由于某些原因,你可能经常需要查找端口名称和端口号。如果是这样,你很幸运。今天,在这个简短的教程中,我们将看到在 Linux 系统中最简单、最快捷的查找服务端口号的方法。可能有很多方法可以做到,但我目前只知道以下三种方法。请继续阅读。
|
||||
|
||||
### 在 Linux 中查找服务的端口号
|
||||
|
||||
#### 方法1:使用 grep 命令
|
||||
|
||||
要使用 `grep` 命令在 Linux 中查找指定服务的默认端口号,只需运行:
|
||||
|
||||
```
|
||||
$ grep <port> /etc/services
|
||||
```
|
||||
|
||||
例如,要查找 SSH 服务的默认端口,只需运行:
|
||||
|
||||
```
|
||||
$ grep ssh /etc/services
|
||||
```
|
||||
|
||||
就这么简单。此命令应该适用于大多数 Linux 发行版。以下是我的 Arch Linux 测试机中的示例输出:
|
||||
|
||||
```
|
||||
ssh 22/tcp
|
||||
ssh 22/udp
|
||||
ssh 22/sctp
|
||||
sshell 614/tcp
|
||||
sshell 614/udp
|
||||
netconf-ssh 830/tcp
|
||||
netconf-ssh 830/udp
|
||||
sdo-ssh 3897/tcp
|
||||
sdo-ssh 3897/udp
|
||||
netconf-ch-ssh 4334/tcp
|
||||
snmpssh 5161/tcp
|
||||
snmpssh-trap 5162/tcp
|
||||
tl1-ssh 6252/tcp
|
||||
tl1-ssh 6252/udp
|
||||
ssh-mgmt 17235/tcp
|
||||
ssh-mgmt 17235/udp
|
||||
```
|
||||
|
||||
正如你在上面的输出中所看到的,SSH 服务的默认端口号是 22。
|
||||
|
||||
让我们找到 Apache Web 服务器的端口号。为此,命令是:
|
||||
|
||||
```
|
||||
$ grep http /etc/services
|
||||
# http://www.iana.org/assignments/port-numbers
|
||||
http 80/tcp www www-http # WorldWideWeb HTTP
|
||||
http 80/udp www www-http # HyperText Transfer Protocol
|
||||
http 80/sctp # HyperText Transfer Protocol
|
||||
https 443/tcp # http protocol over TLS/SSL
|
||||
https 443/udp # http protocol over TLS/SSL
|
||||
https 443/sctp # http protocol over TLS/SSL
|
||||
gss-http 488/tcp
|
||||
gss-http 488/udp
|
||||
webcache 8080/tcp http-alt # WWW caching service
|
||||
webcache 8080/udp http-alt # WWW caching service
|
||||
[...]
|
||||
```
|
||||
|
||||
FTP 端口号是什么?这很简单!
|
||||
|
||||
```
|
||||
$ grep ftp /etc/services
|
||||
ftp-data 20/tcp
|
||||
ftp-data 20/udp
|
||||
# 21 is registered to ftp, but also used by fsp
|
||||
ftp 21/tcp
|
||||
ftp 21/udp fsp fspd
|
||||
tftp 69/tcp
|
||||
[...]
|
||||
```
|
||||
|
||||
#### 方法 2:使用 getent 命令
|
||||
|
||||
如你所见,上面的命令显示指定搜索词 “ssh”、“http” 和 “ftp” 的所有端口名称和数字。这意味着,你将获得与给定搜索词匹配的所有端口名称的相当长的输出。
|
||||
|
||||
但是,你可以使用 `getent` 命令精确输出结果,如下所示:
|
||||
|
||||
```
|
||||
$ getent services ssh
|
||||
ssh 22/tcp
|
||||
|
||||
$ getent services http
|
||||
http 80/tcp www www-http
|
||||
|
||||
$ getent services ftp
|
||||
ftp 21/tcp
|
||||
```
|
||||
|
||||
如果你不知道端口名称,但是知道端口号,那么你只需将端口名称替换为数字:
|
||||
|
||||
```
|
||||
$ getent services 80
|
||||
http 80/tcp
|
||||
```
|
||||
|
||||
要显示所有端口名称和端口号,只需运行:
|
||||
|
||||
```
|
||||
$ getent services
|
||||
```
|
||||
|
||||
#### 方法 3:使用 Whatportis 程序
|
||||
|
||||
Whatportis 是一个简单的 Python 脚本,来用于查找端口名称和端口号。与上述命令不同,此程序以漂亮的表格形式输出。
|
||||
|
||||
确保已安装 pip 包管理器。如果没有,请参考以下链接。
|
||||
|
||||
- [如何使用 pip 管理 Python 包][6]
|
||||
|
||||
安装 pip 后,运行以下命令安装 Whatportis 程序。
|
||||
|
||||
```
|
||||
$ pip install whatportis
|
||||
```
|
||||
|
||||
现在,你可以找到与服务关联的端口,如下所示。
|
||||
|
||||
```
|
||||
$ whatportis ssh
|
||||
|
||||
$ whatportis ftp
|
||||
|
||||
$ whatportis http
|
||||
```
|
||||
|
||||
我的 CentOS 7 服务器的示例输出:
|
||||
|
||||
![][7]
|
||||
|
||||
*在 Linux 中查找服务的端口号*
|
||||
|
||||
如果你不知道服务的确切名称,请使用 `–like` 标志来显示相关结果。
|
||||
|
||||
```
|
||||
$ whatportis mysql --like
|
||||
```
|
||||
|
||||
上述命令帮助你查找与服务关联的端口。你还可以找到与端口号相关联的服务,如下所示。
|
||||
|
||||
```
|
||||
$ whatportis 993
|
||||
```
|
||||
|
||||
你甚至可以以 JSON 格式显示结果。
|
||||
|
||||
```
|
||||
$ whatportis 993 --json
|
||||
```
|
||||
|
||||
![][8]
|
||||
|
||||
有关更多详细信息,请参阅 GitHub 仓库。
|
||||
|
||||
* [Whatportis GitHub 仓库][9]
|
||||
|
||||
就是这些了。你现在知道了如何使用三种简单方法在 Linux 中查找端口名称和端口号。如果你知道任何其他方法/命令,请在下面的评论栏告诉我。我会查看并更相应地更新本指南。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-find-the-port-number-of-a-service-in-linux/
|
||||
|
||||
作者:[sk][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[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/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.ostechnix.com/wp-content/uploads/2018/06/Find-The-Port-Number-720x340.png
|
||||
[2]: https://www.ostechnix.com/the-grep-command-tutorial-with-examples-for-beginners/
|
||||
[6]: https://www.ostechnix.com/manage-python-packages-using-pip/
|
||||
[7]: https://www.ostechnix.com/wp-content/uploads/2018/06/whatportis.png
|
||||
[8]: https://www.ostechnix.com/wp-content/uploads/2018/06/whatportis-1.png
|
||||
[9]: https://github.com/ncrocfer/whatportis
|
1208
published/20180629 100 Best Ubuntu Apps.md
Normal file
1208
published/20180629 100 Best Ubuntu Apps.md
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,47 +5,47 @@
|
||||
|
||||
### 网络自动化
|
||||
|
||||
随着 IT 行业的技术变化,从服务器虚拟化到公有云和私有云,以及自服务能力、容器化应用、平台即服务(PaaS)交付,有一直以来落后的一个领域就是网络。
|
||||
随着 IT 行业的技术变化,从服务器虚拟化到公有云和私有云,以及自服务能力、容器化应用、平台即服务(PaaS)交付,而一直以来落后的一个领域就是网络。
|
||||
|
||||
在过去的五年多,网络行业似乎有很多新的趋势出现,它们中的很多被归入到软件定义网络(SDN)。
|
||||
在过去的五年多,网络行业似乎有很多新的趋势出现,它们中的很多被归入到<ruby>软件定义网络<rt>software-defined networking</rt></ruby>(SDN)。
|
||||
|
||||
>注意
|
||||
>注意:
|
||||
|
||||
> SDN 是新出现的一种构建、管理、操作和部署网络的方法。SDN 最初的定义是出于将控制层和数据层(包转发)物理分离的需要,并且,解耦合的控制层必须管理好各自的设备。
|
||||
|
||||
> 如今,在 SDN 旗下已经有许多技术,包括<ruby>基于控制器的网络<rt>controller-based networks</rt></ruby>、网络设备上的 API、网络自动化、白盒交换机、策略网络化、网络功能虚拟化(NFV)等等。
|
||||
> 如今,在 SDN 旗下已经有许多技术,包括<ruby>基于控制器的网络<rt>controller-based networks</rt></ruby>、网络设备 API、网络自动化、<ruby>白盒交换机<rt>whitebox switche</rt></ruby>、策略网络化、<ruby>网络功能虚拟化<rt>Network Functions Virtualization</rt></ruby>(NFV)等等。
|
||||
|
||||
> 由于这篇报告的目的,我们参考 SDN 的解决方案作为我们的解决方案,其中包括一个网络控制器作为解决方案的一部分,并且提升了该网络的可管理性,但并不需要从数据层解耦控制层。
|
||||
> 出于这篇报告的目的,我们参考 SDN 的解决方案作为我们的解决方案,其中包括一个网络控制器作为解决方案的一部分,并且提升了该网络的可管理性,但并不需要从数据层解耦控制层。
|
||||
|
||||
这些趋势的之一是,网络设备的 API 作为管理和操作这些设备的一种方法而出现,真正地提供了机器对机器的通讯。当需要自动化和构建网络应用时 API 简化了开发过程,在数据如何建模时提供了更多结构。例如,当启用 API 的设备以 JSON/XML 返回数据时,它是结构化的,并且比返回原生文本信息、需要手工去解析的仅支持命令行的设备更易于使用。
|
||||
这些趋势的之一是,网络设备的 API 作为管理和操作这些设备的一种方法而出现,真正地提供了机器对机器的通讯。当需要自动化和构建网络应用时 API 简化了开发过程,在数据如何建模时提供了更多结构。例如,当启用 API 的设备以 JSON/XML 返回数据时,它是结构化的,并且比返回原生文本信息 —— 需要手工去解析的仅支持命令行的设备更易于使用。
|
||||
|
||||
在 API 之前,用于配置和管理网络设备的两个主要机制是命令行接口(CLI)和简单网络管理协议(SNMP)。让我们来了解一下它们,CLI 是一个设备的人机界面,而 SNMP 并不是为设备提供的实时编程接口。
|
||||
|
||||
幸运的是,因为很多供应商争相为设备增加 API,有时候 _只是因为_ 它被放到需求建议书(RFP)中,这就带来了一个非常好的副作用 —— 支持网络自动化。当真正的 API 发布时,访问设备内数据的过程,以及管理配置,就会被极大简化,因此,我们将在本报告中对此进行评估。虽然使用许多传统方法也可以实现自动化,比如,CLI/SNMP。
|
||||
|
||||
> 注意
|
||||
> 注意:
|
||||
|
||||
> 随着未来几个月或几年的网络设备更新,供应商的 API 无疑应该被做为采购网络设备(虚拟和物理)的关键决策标准而测试和使用。如果供应商提供一些库或集成到自动化工具中,或者如果被用于一个开放的标准或协议,用户应该知道数据是如何通过设备建模的,API 使用的传输类型是什么。
|
||||
> 随着未来几个月或几年(LCTT 译注:本文发表于 2016 年)的网络设备更新,供应商的 API 无疑应该被做为采购网络设备(虚拟和物理)的关键决策标准而测试和使用。如果供应商提供一些库或集成到自动化工具中,或者如果被用于一个开放的标准或协议,用户应该知道数据是如何通过设备建模的,API 使用的传输类型是什么。
|
||||
|
||||
总而言之,网络自动化,像大多数类型的自动化一样,是为了更快地工作。工作的更快是好事,降低部署和配置改变的时间并不总是许多 IT 组织需要去解决的问题。
|
||||
总而言之,网络自动化,像大多数类型的自动化一样,是为了更快地工作。工作的更快是好事,减少部署和配置改变的时间并不总是许多 IT 组织需要去解决的问题。
|
||||
|
||||
包括速度在内,我们现在看看这些各种类型的 IT 组织逐渐采用网络自动化的几种原因。你应该注意到,同样的原则也适用于其它类型的自动化。
|
||||
|
||||
### 简化架构
|
||||
#### 简化架构
|
||||
|
||||
今天,每个网络都是一片独特的“雪花”,并且,网络工程师们为能够通过一次性的改变来解决传输和网络应用问题而感到自豪,而这最终导致网络不仅难以维护和管理,而且也很难去实现自动化。
|
||||
今天,每个网络都是一片独特的“雪花”,并且,网络工程师们为能够通过一次性的网络改变来解决传输和应用问题而感到自豪,而这最终导致网络不仅难以维护和管理,而且也很难去实现自动化。
|
||||
|
||||
网络自动化和管理需要从一开始就包含到新的架构和设计中去部署,而不是作为一个二级或三级项目。哪个特性可以跨不同的供应商工作?哪个扩展可以跨不同的平台工作?当使用特别的网络设备平台时,API 类型或者自动化工程是什么?当这些问题在设计过程之前得到答案,最终的架构将变成简单的、可重复的、并且易于维护 _和_ 自动化的,在整个网络中将很少启用供应商专用的扩展。
|
||||
网络自动化和管理需要从一开始就包含到新的架构和设计中去部署,而不是作为一个二级或三级项目。哪个特性可以跨不同的供应商工作?哪个扩展可以跨不同的平台工作?当使用具体的网络设备平台时,API 类型或者自动化工程是什么?当这些问题在设计过程之前得到答案,最终的架构将变成简单的、可重复的、并且易于维护 _和_ 自动化的,在整个网络中将很少启用供应商专用的扩展。
|
||||
|
||||
### 确定的结果
|
||||
#### 确定的结果
|
||||
|
||||
在一个企业组织中,<ruby>改变审查会议<rt>change review meeting</rt></ruby>会评估面临的网络变化、它们对外部系统的影响、以及回滚计划。在人们通过 CLI 来执行这些 _面临的变化_ 的世界上,输入错误的命令造成的影响是灾难性的。想像一下,一个有 3 位、4 位、5位,或者 50 位工程师的团队。每位工程师应对 _面临的变化_ 都有他们自己的独特的方法。并且,在管理这些变化的期间,一个人使用 CLI 或者 GUI 的能力并不会消除和减少出现错误的机率。
|
||||
|
||||
使用经过验证和测试过的网络自动化可以帮助实现更多的可预测行为,并且使执行团队更有可能实现确实性结果,在保证任务没有人为错误的情况下首次正确完成的道路上更进一步。
|
||||
使用经过验证的和测试过的网络自动化可以帮助实现更多的可预测行为,并且使执行团队更有可能实现确实性的结果,首次在保证任务没有人为错误的情况下正确完成的道路上更进一步。
|
||||
|
||||
### 业务灵活性
|
||||
#### 业务灵活性
|
||||
|
||||
不用说,网络自动化不仅为部署变化提供速度和灵活性,而且使得根据业务需要去从网络设备中检索数据的速度变得更快。自从服务器虚拟化到来以后,服务器和虚拟化使得管理员有能力在瞬间去部署一个新的应用程序。而且,随着应用程序可以更快地部署,随之浮现的问题是为什么还需要花费如此长的时间配置一个 VLAN(虚拟局域网)、路由器、FW ACL(防火墙的访问控制列表)或者负载均衡策略呢?
|
||||
不用说,网络自动化不仅为部署变化提供了速度和灵活性,而且使得根据业务需要去从网络设备中检索数据的速度变得更快。自从服务器虚拟化到来以后,服务器和虚拟化使得管理员有能力在瞬间去部署一个新的应用程序。而且,随着应用程序可以更快地部署,随之浮现的问题是为什么还需要花费如此长的时间配置一个 VLAN(虚拟局域网)、路由器、FW ACL(防火墙的访问控制列表)或者负载均衡策略呢?
|
||||
|
||||
通过了解在一个组织内最常见的工作流和 _为什么_ 真正需要改变网络,部署如 Ansible 这样的现代的自动化工具将使这些变得非常简单。
|
||||
|
||||
@ -61,9 +61,9 @@ _Ansible 是一个无需代理和可扩展的超级简单的自动化平台。_
|
||||
|
||||
让我们更深入地了解它的细节,并且看一看那些使 Ansible 在行业内获得广泛认可的属性。
|
||||
|
||||
### 简单
|
||||
#### 简单
|
||||
|
||||
Ansible 的其中一个吸引人的属性是,使用它你 _不_ 需要特定的编程技能。所有的指令,或者任务都是自动化的,以一个标准的、任何人都可以理解的人类可读的数据格式的文档化。在 30 分钟之内完成安装和自动化任务的情况并不罕见!
|
||||
Ansible 的其中一个吸引人的属性是,使用它你 **不** 需要特定的编程技能。所有的指令,或者说任务都是自动化的,以一个标准的、任何人都可以理解的人类可读的数据格式的文档化。在 30 分钟之内完成安装和自动化任务的情况并不罕见!
|
||||
|
||||
例如,下列来自一个 Ansible <ruby>剧本<rt>playbook</rt></ruby>的任务用于去确保在一个 VLAN 存在于一个 Cisco Nexus 交换机中:
|
||||
|
||||
@ -73,90 +73,83 @@ Ansible 的其中一个吸引人的属性是,使用它你 _不_ 需要特定
|
||||
|
||||
你无需熟悉或写任何代码就可以明确地看出它将要做什么!
|
||||
|
||||
> 注意
|
||||
> 注意:
|
||||
|
||||
> 这个报告的下半部分涉到 Ansible 术语(<ruby>剧本<rt>playbook</rt></ruby>、<ruby>行动<rt>play</rt></ruby>、<ruby>任务<rt>task</rt></ruby>、<ruby>模块<rt>module</rt></ruby>等等)的细节。在我们使用 Ansible 进行网络自动化时,提及这些关键概念时我们会有一些简短的示例。
|
||||
> 这个报告的下半部分涉到 Ansible 术语(<ruby>剧本<rt>playbook</rt></ruby>、<ruby>剧集<rt>play</rt></ruby>、<ruby>任务<rt>task</rt></ruby>、<ruby>模块<rt>module</rt></ruby>等等)的细节。在我们使用 Ansible 进行网络自动化时,提及这些关键概念时我们会有一些简短的示例。
|
||||
|
||||
### 无代理
|
||||
#### 无代理
|
||||
|
||||
如果你看到市面上的其它工具,比如 Puppet 和 Chef,你学习它们会发现,一般情况下,它们要求每个实现自动化的设备必须安装特定的软件。这种情况在 Ansible 上 _并不_需要,这就是为什么 Ansible 是实现网络自动化的最佳选择的主要原因。
|
||||
如果你看过市面上的其它工具,比如 Puppet 和 Chef,你会发现,一般情况下,它们要求每个实现自动化的设备必须安装特定的软件。这种情况在 Ansible 上 _并不_需要,这就是为什么 Ansible 是实现网络自动化的最佳选择的主要原因。
|
||||
|
||||
它很好理解,那些 IT 自动化工具,包括 Puppet、Chef、CFEngine、SaltStack、和 Ansible,它们最初构建是为管理和自动化配置 Linux 主机,以跟得上部署的应用程序增长的步伐。因为 Linux 系统是被配置成自动化的,要安装代理并不是一个技术难题。如果有的话,它会担误安装过程,因为,现在有 _N_ 多个(你希望去实现自动化的)主机需要在它们上面部署软件。
|
||||
这很好理解,那些 IT 自动化工具,包括 Puppet、Chef、CFEngine、SaltStack、和 Ansible,它们最初构建是为管理和自动化配置 Linux 主机,以跟得上部署的应用程序增长的步伐。因为 Linux 系统是被配置成自动化的,要安装代理并不是一个技术难题。如果有的话,它也只会延误安装过程,因为,现在有 _N_ 多个(你希望去实现自动化的)主机需要在它们上面部署软件。
|
||||
|
||||
再加上,当使用代理时,它们需要的 DNS 和 NTP 配置更加复杂。这些都是大多数环境中已经配置好的服务,但是,当你希望快速地获取一些东西或者只是简单地想去测试一下它能做什么的时候,它将极大地担误整个设置和安装的过程。
|
||||
再加上,当使用代理时,它们需要的 DNS 和 NTP 配置更加复杂。这些都是大多数环境中已经配置好的服务,但是,当你希望快速地获取一些东西或者只是简单地想去测试一下它能做什么的时候,它将极大地耽误整个设置和安装的过程。
|
||||
|
||||
由于本报告只是为介绍利用 Ansible 实现网络自动化,它最有价值的是,Ansible 作为一个无代理平台,对于系统管理员来说,它更具有吸引力,这是为什么呢?
|
||||
由于本报告只是为介绍利用 Ansible 实现网络自动化,我们希望指出,Ansible 作为一个无代理平台,对于网络管理员来说,其比对系统管理员更具有吸引力。这是为什么呢?
|
||||
|
||||
正如前面所说的那样,对网络管理员来说,它是非常有吸引力的,Linux 操作系统是开源的,并且,任何东西都可以安装在它上面。对于网络来说,虽然它正在逐渐改变,但事实并非如此。如果我们更广泛地部署网络操作系统,如 Cisco IOS,它就是这样的一个例子,并且问一个问题, _“第三方软件能否部署在基于 IOS (译者注:此处的 IOS,指的是思科的网络操作系统 IOS)的平台上吗?”_它并不会给你惊喜,它的回答是 _NO_。
|
||||
正如前面所说的那样,对网络管理员来说,它是非常有吸引力的,Linux 操作系统是开源的,并且,任何东西都可以安装在它上面。对于网络来说,却并非如此,虽然它正在逐渐改变。如果我们更广泛地部署网络操作系统,如 Cisco IOS,它就是这样的一个例子,并且问一个问题, _“第三方软件能否部署在基于 IOS (LCTT 译注:此处的 IOS,指的是思科的网络操作系统 IOS)的平台上吗?”_毫无疑问,它的回答是 _NO_。
|
||||
|
||||
在过去的二十多年里,几乎所有的网络操作系统都是闭源的,并且,垂直整合到底层的网络硬件中。在一个网络设备中(路由器、交换机、负载均衡、防火墙、等等),不需要供应商的支持,有一个像 Ansible 这样的自动化平台,从头开始去构建一个无代理、可扩展的自动化平台,就像是它专门为网络行业订制的一样。我们最终将开始减少并消除与网络的人工交互。
|
||||
在过去的二十多年里,几乎所有的网络操作系统都是闭源的,并且,垂直整合到底层的网络硬件中。没有供应商的支持,在一个网络设备中(路由器、交换机、负载均衡、防火墙、等等)载入一个代理并不那么轻松。有一个像 Ansible 这样的自动化平台,从头开始去构建一个无代理、可扩展的自动化平台,就像是它专门为网络行业订制的一样。我们最终将开始减少并消除与网络的人工交互。
|
||||
|
||||
### 可扩展
|
||||
#### 可扩展
|
||||
|
||||
Ansible 的可扩展性也非常的好。作为一个开源的,并且从代码开始将在网络行业中发挥重要的作用,有一个可扩展的平台是必需的。这意味着如果供应商或社区不提供一个特定的特性或功能,开源社区,终端用户,消费者,顾问者,或者,任何可能去 _扩展_ Ansible 的人,去启用一个给定的功能集。过去,网络供应商或者工具供应商通过一个 hook 去提供插件和集成。想像一下,使用一个像 Ansible 这样的自动化平台,并且,你选择的网络供应商发布了你 _真正_ 需要的自动化的一个新特性。从理论上说,网络供应商或者 Ansible 可以发行一个新的插件去实现自动化这个独特的特性,这是一件非常好的事情,从你的内部工程师到你的增值分销商(VARs)或者你的顾问中的任何人,都可以去提供这种集成。
|
||||
|
||||
正如前面所说的那样,Ansible 实际上是极具扩展性的,Ansible 最初就是为自动化应用程序和系统构建的。这是因为,Ansible 的可扩展性是被网络供应商编写集成的,包括但不限于 Cisco、Arista、Juniper、F5、HP、A10、Cumulus、和 Palo Alto Networks。
|
||||
Ansible 的可扩展性也非常的好。从开源、代码开始在网络行业中发挥重要的作用时起,有一个可扩展的平台是必需的。这意味着如果供应商或社区不提供一个特定的特性或功能,开源社区、终端用户、消费者、顾问,或者任何的人能够 _扩展_ Ansible 来启用一个给定的功能集。过去,网络供应商或者工具供应商通过一个 hook 去提供新的插件和集成。想像一下,使用一个像 Ansible 这样的自动化平台,并且,你选择的网络供应商发布了你 _真正_ 需要的一个自动化的新特性。从理论上说,网络供应商或者 Ansible 可以发行一个新的插件去实现自动化这个独特的特性,这是一件非常好的事情,从你的内部工程师到你的增值分销商(VAR)或者你的顾问中的任何一个人,都可以去提供这种集成。
|
||||
|
||||
正如前面所说的那样,Ansible 实际上是极具扩展性的,Ansible 最初就是为自动化应用程序和系统构建的。这是因为,Ansible 的可扩展性来自于其集成性是为网络供应商编写的,包括但不限于 Cisco、Arista、Juniper、F5、HP、A10、Cumulus 和 Palo Alto Networks。
|
||||
|
||||
### 对于网络自动化,为什么要使用 Ansible?
|
||||
|
||||
我们已经简单了解除了 Ansible 是什么,以及一些网络自动化的好处,但是,对于网络自动化,我们为什么要使用 Ansible?
|
||||
|
||||
在一个完全透明的环境下,已经说的很多的理由是 Ansible 可以做什么,比如,作为一个很大的自动化应用程序部署平台,但是,我们现在要深入一些,更多地关注于网络,并且继续总结一些更需要注意的其它关键点。
|
||||
大家很清楚,使得 Ansible 成为如此伟大的一个自动化应用部署平台的许多原因已经被大家所提及了。但是,我们现在要深入一些,更多地关注于网络,并且继续总结一些更需要注意的其它关键点。
|
||||
|
||||
#### 无代理
|
||||
|
||||
### 无代理
|
||||
在实现网络自动化的时候,无代理架构的重要性并不是重点强调的,特别是当它适用于现有的自动化设备时。如果,我们看一下当前网络中已经安装的各种设备时,从 DMZ 和园区,到分支机构和数据中心,最大份额的设备 _并不_ 具有最新 API 的设备。从自动化的角度来看,API 可以使做一些事情变得很简单,像 Ansible 这样的无代理平台有可能去自动化和管理那些 _老旧(传统)_ 的设备。例如,_基于 CLI 的设备_,它的工具可以被用于任何网络环境中。
|
||||
|
||||
> 注意:
|
||||
|
||||
在实现网络自动化的时候,无代理架构的重要性并不是重点强调的,特别是当它适用于现有的自动化设备时。如果,我们看一下当前网络中已经安装的各种设备时,从 DMZ 和园区,到分支和数据中心,最大份额的设备 _并不_ 具有最新 API 的设备。从自动化的角度来看,API 可以使做一些事情变得很简单,像 Ansible 这样的无代理平台有可能去自动化和管理那些 _传统_ 的设备。例如,_基于CLI 的设备_,它的工具可以被用于任何网络环境中。
|
||||
> 如果仅支持 CLI 的设备已经集成进 Ansible,它的机制就像是,怎么在设备上通过协议如 telnet、SSH 和 SNMP 去进行只读访问和读写操作。
|
||||
|
||||
###### 注意
|
||||
作为一个独立的网络设备,像路由器、交换机、和防火墙正在持续去增加 API 的支持,SDN 解决方案也正在出现。SDN 解决方案的其中一个常见主题是,它们都提供一个单点集成和策略管理,通常是以一个 SDN 控制器的形式出现。这对于 Cisco ACI、VMware NSX、Big Switch Big Cloud Fabric 和 Juniper Contrail,以及其它的 SDN 提供者,比如 Nuage、Plexxi、Plumgrid、Midokura 和 Viptela,是一个真实的解决方案。这甚至包含开源的控制器,比如 OpenDaylight。
|
||||
|
||||
如果仅 CLI 的设备已经集成进 Ansible,它的机制就像是,怎么在设备上通过协议如 telnet、SSH、和 SNMP,去进行只读访问和读写操作。
|
||||
所有的这些解决方案都简化了网络管理,就像它们可以让一个管理员开始从“box-by-box”管理(LCTT 译者注:指的是单个设备挨个去操作的意思)迁移到网络范围的管理。这是在正确方向上迈出的很大的一步,这些解决方案并不能消除在变更期间中人类犯错的机率。例如,比起配置 _N_ 个交换机,你可能需要去配置一个单个的 GUI,它需要很长的时间才能实现所需要的配置改变 —— 它甚至可能更复杂,毕竟,相对于一个 CLI,他们更喜欢 GUI!另外,你可能有不同类型的 SDN 解决方案部署在每个应用程序、网络、区域或者数据中心。
|
||||
|
||||
作为一个独立的网络设备,像路由器、交换机、和防火墙持续去增加 APIs 的支持,SDN 解决方案也正在出现。SDN 解决方案的其中一个主题是,它们都提供一个单点集成和策略管理,通常是以一个 SDN 控制器的形式出现。这是真实的解决方案,比如,Cisco ACI、VMware NSX、Big Switch Big Cloud Fabric、和 Juniper Contrail,同时,其它的 SDN 提供者,比如 Nuage、Plexxi、Plumgrid、Midokura、和 Viptela。甚至包含开源的控制器,比如 OpenDaylight。
|
||||
在需要自动化的网络中,对于配置管理、监视和数据收集,当行业开始向基于控制器的网络架构中迁移时,这些需求并不会消失。
|
||||
|
||||
所有的这些解决方案都简化了网络管理,就像他们允许一个管理员去开始从“box-by-box”管理(译者注:指的是单个设备挨个去操作的意思)迁移到网络范围的管理。这是在正确方向上迈出的很大的一步,这些解决方案并不能消除在改变窗口中人类犯错的机率。例如,比起配置 _N_ 个交换机,你可能需要去配置一个单个的 GUI,它需要很长的时间才能实现所需要的配置改变 — 它甚至可能更复杂,毕竟,相对于一个 CLI,他们更喜欢 GUI!另外,你可能有不同类型的 SDN 解决方案部署在每个应用程序、网络、区域、或者数据中心。
|
||||
大量的软件定义网络中都部署有控制器,几乎所有的控制器都<ruby>提供<rt>expose</rt></ruby>一个最新的 REST API。并且,因为 Ansible 是一个无代理架构,它实现自动化是非常简单的,而不仅仅是对那些没有 API 的传统设备,但也有通过 REST API 的软件定义网络解决方案,在所有的终端上不需要有额外的软件(LCTT 译注:指的是代理)。最终的结果是,使用 Ansible,无论有或没有 API,可以使任何类型的设备都能够自动化。
|
||||
|
||||
在需要自动化的网络中,对于配置管理、监视、和数据收集,当行业开始向基于控制器的网络架构中迁移时,这些需求并不会消失。
|
||||
#### 自由开源软件(FOSS)
|
||||
|
||||
大量的软件定义网络中都部署有控制器,所有最新的控制器都提供(expose)一个最新的 REST API。并且,因为 Ansible 是一个无代理架构,它实现自动化是非常简单的,而不仅仅是没有 API 的传统设备,但也有通过 REST APIs 的软件定义网络解决方案,在所有的终端上不需要有额外的软件(译者注:指的是代理)。最终的结果是,使用 Ansible,无论有或没有 API,可以使任何类型的设备都能够自动化。
|
||||
Ansible 是一个开源软件,它的全部代码在 GitHub 上都是公开可访问的,使用 Ansible 是完全免费的。它可以在几分钟内完成安装并为网络工程师提供有用的价值。Ansible 这个开源项目,或者 Ansible 公司,在它们交付软件之前,你不会遇到任何一个销售代表。那是显而易见的事实,因为它是一个真正的开源项目,但是,作为开源的、社区驱动的软件项目在网络行业中的使用是非常少的,但是,也在逐渐增加,我们想明确指出这一点。
|
||||
|
||||
同样需要指出的一点是,Ansible, Inc. 也是一个公司,它也需要去赚钱,对吗?虽然 Ansible 是开源的,它也有一个叫 Ansible Tower 的企业产品,它增加了一些特性,比如,基于规则的访问控制(RBAC)、报告、 web UI、REST API、多租户等等,(相比 Ansible)它更适合于企业去部署。并且,更重要的是,Ansible Tower 甚至可以最多在 10 台设备上 _免费_ 使用,至少,你可以去体验一下,它是否会为你的组织带来好处,而无需花费一分钱,并且,也不需要与无数的销售代表去打交道。
|
||||
|
||||
### 免费和开源软件(FOSS)
|
||||
#### 可扩展性
|
||||
|
||||
Ansible 是一个开源软件,它的全部代码在 GitHub 上都是公开的、可访问的,使用 Ansible 是完全免费的。它可以在几分钟内完成安装并为网络工程师提供有用的价值。Ansible,这个开源项目,或者 Ansible 公司,在它们交付软件之前,你不会遇到任何一个销售代表。那是显而易见的事实,因为它是一个真正的开源项目,但是,开源项目的使用,在网络行业中社区驱动的软件是非常少的,但是,也在逐渐增加,我们想明确指出这一点。
|
||||
我们在前面说过,Ansible 主要是为部署 Linux 应用程序而构建的自动化平台,虽然从早期开始已经扩展到 Windows。需要指出的是,Ansible 开源项目并没有“自动化网络基础设施”的目标。事实上是,Ansible 社区更明白如何在底层的 Ansible 架构上更具灵活性和可扩展性,对于他们的自动化需要(包括网络)更容易成为一个 _扩展_ 的 Ansible。在过去的两年中,部署有许多的 Ansible 集成,许多是有行业独立人士进行的,比如,Matt Oswalt、Jason Edelman、Kirk Byers、Elisa Jasinska、David Barroso、Michael Ben-Ami、Patrick Ogenstad 和 Gabriele Gerbino,也有网络系统供应商的领导者,比如,Arista、Juniper、Cumulus、Cisco、F5、和 Palo Alto Networks。
|
||||
|
||||
同样需要指出的一点是,Ansible, Inc. 也是一个公司,它也需要去赚钱,对吗?虽然 Ansible 是开源的,它也有一个叫 Ansible Tower 的企业产品,它增加了一些特性,比如,基于规则的访问控制(RBAC)、报告、 web UI、REST APIs、多租户、等等,(相比 Ansible)它更适合于企业去部署。并且,更重要的是,Ansible Tower 甚至可以最多在 10 台设备上 _免费_ 使用,至少,你可以去体验一下,它是否会为你的组织带来好处,而无需花费一分钱,并且,也不需要与无数的销售代表去打交道。
|
||||
#### 集成到已存在的 DevOps 工作流中
|
||||
|
||||
Ansible 在 IT 组织中被用于应用程序部署。它被用于需要管理部署、监视和管理各种类型的应用程序的运维团队中。通过将 Ansible 集成到网络基础设施中,当新应用程序到来或迁移后,它扩展了可能的范围。而不是去等待一个新的顶架交换机(LCTT 译注:TOR,一种数据中心设备接入的方式)的到来、去添加一个 VLAN、或者去检查接口的速度/双工,所有的这些以网络为中心的任务都可以被自动化,并且可以集成到 IT 组织内已经存在的工作流中。
|
||||
|
||||
### 可扩展性
|
||||
#### 幂等性
|
||||
|
||||
我们在前面说过,Ansible 主要是为部署 Linux 应用程序而构建的自动化平台,虽然从早期开始已经扩展到 Windows。需要指出的是,Ansible 开源项目并没有自动化网络基础设施的目标。事实上是,Ansible 社区更多地理解了在底层的 Ansible 架构上怎么更具灵活性和可扩展性,对于他们的自动化需要,它变成了 _扩展_ 的 Ansible,它包含了网络。在过去的两年中,部署有许多的 Ansible 集成,许多行业独立人士(industry independents),比如,Matt Oswalt、Jason Edelman、Kirk Byers、Elisa Jasinska、David Barroso、Michael Ben-Ami、Patrick Ogenstad、和 Gabriele Gerbino,以及网络系统供应商的领导者,比如,Arista、Juniper、Cumulus、Cisco、F5、和 Palo Alto Networks。
|
||||
术语<ruby>幂等性<rt>idempotency</rt></ruby> (读作 item-potency)经常用于软件开发的领域中,尤其是当使用 REST API 工作的时候,以及在 _DevOps_ 自动化和配置管理框架的领域中,包括 Ansible。Ansible 的其中一个信念是,所有的 Ansible 模块(集成的)应该是幂等的。那么,对于一个模块来说,幂等是什么意思呢?毕竟,对大多数网络工程师来说,这是一个新的术语。
|
||||
|
||||
答案很简单。幂等性的本质是允许定义的任务,运行一次或者上千次都不会在目标系统上产生不利影响,仅仅是一种一次性的改变。换句话说,如果有一个要做的改变去使系统进入到它期望的状态,这种改变完成之后,并且,如果这个设备已经达到这种状态,就不会再发生改变。这不像大多数传统的定制脚本和拷贝、黏贴到那些终端窗口中的 CLI 命令。当相同的命令或者脚本在同一个系统上重复运行,(有时候)会出现错误。即使是粘贴一组命令到一个路由器中,也可能会遇到一些使你的其余的配置失效的错误。好玩吧?
|
||||
|
||||
### 集成到已存在的 DevOps 工作流中
|
||||
另外的例子是,如果你有一个配置 10 个 VLAN 的文件文件或者脚本,那么 _每次_ 运行这个脚本,相同的命令命令会被输入 10 次。如果使用一个幂等的 Ansible 模块,首先会从网络设备中采集已存在的配置,并且,每个新的 VLAN 被配置后会再次检查当前配置。仅仅当这个新的 VLAN 需要被添加(或者,比如说改变 VLAN 名字)是一个变更,命令才会真实地推送到设备。
|
||||
|
||||
Ansible 在 IT 组织中被用于应用程序部署。它被用于需要管理部署、监视、和管理各种类型的应用程序的操作团队中。通过将 Ansible 集成到网络基础设施中,当新应用程序到来或迁移后,它扩展了可能的范围。而不是去等待一个新的顶架交换机(TOR,译者注:一种数据中心设备接入的方式)的到来、去添加一个 VLAN、或者去检查接口的速度/双工,所有的这些以网络为中心的任务都可以被自动化,并且可以集成到 IT 组织内已经存在的工作流中。
|
||||
当一个技术越来越复杂,幂等性的价值就越高,在你修改的时候,你并不能注意到 _已存在_ 的网络设备的状态,而仅仅是从一个网络配置和策略角度去尝试达到 _期望的_ 状态。
|
||||
|
||||
#### 网络范围的和临时(Ad Hoc)的改变
|
||||
|
||||
### 幂等性
|
||||
用配置管理工具解决的其中一个问题是,配置“飘移”(当设备的期望配置逐渐漂移,或者改变,随着时间的推移,手动改变和/或在一个环境中使用了多个不同的工具),事实上,这也是像 Puppet 和 Chef 所使用的地方。代理商<ruby>电联<rt>phone home</rt></ruby>到前端服务器,验证它的配置,并且,如果需要变更,则改变它。这个方法是非常简单的。如果有故障了,需要去排除怎么办?你通常需要跳过管理系统,直接连到设备,找到并修复它,然后,马上离开,对不对?果然,在下次当代理电连回来,这个修复问题的改变被覆盖了(基于主/前端服务器是怎么配置的)。在高度自动化的环境中,一次性的改变应该被限制,但是,仍然允许使用它们(LCTT 译注:指的是一次性改变)的工具是非常有价值的。正如你想到的,其中一个这样的工具是 Ansible。
|
||||
|
||||
术语 _幂等性_ (明显能提升项目的效能) 经常用于软件开发的领域中,尤其是当使用 REST APIs工作的时候,以及在 _DevOps_ 自动化和配置管理框架的领域中,包括 Ansible。Ansible 的其中一个信念是,所有的 Ansible 模块(集成的)应该是幂等的。那么,对于一个模块来说,幂等是什么意思呢?毕竟,对大多数网络工程师来说,这是一个新的术语。
|
||||
因为 Ansible 是无代理的,这里并没有一个默认的推送或者拉取去防止配置漂移。自动化任务被定义在 Ansible <ruby剧本<rt>playbook</rt></ruby>中,当使用 Ansible 时,它让用户去运行剧本。如果剧本在一个给定的时间间隔内运行,并且你没有用 Ansible Tower,你肯定知道任务的执行频率;如果你只是在终端提示符下使用一个原生的 Ansible 命令行,那么该剧本就运行一次,并且仅运行一次。
|
||||
|
||||
答案很简单。幂等性的本质是允许定义的任务,运行一次或者上千次都不会在目标系统上产生不利影响,仅仅是一种一次性的改变。换句话说,如果一个请求的改变去使系统进入到它期望的状态,这种改变完成之后,并且,如果这个设备已经达到这种状态,它不会再发生改变。这不像大多数传统的定制脚本,和拷贝(copy),以及过去的那些终端窗口中的 CLI 命令。当相同的命令或者脚本在同一个系统上重复运行,会出现错误(有时候)。以前,粘贴一组命令到一个路由器中,然后得到一些使你的其余的配置失效的错误类型?好玩吧?
|
||||
|
||||
另外的例子是,如果你有一个配置 10 个 VLANs 的文件文件或者脚本,那么 _每次_ 运行这个脚本,相同的命令命令会被输入 10 次。如果使用一个幂等的 Ansible 模块,首先会从网络设备中采集已存在的配置,并且,每个新的 VLAN 被配置后会再次检查当前配置。仅仅是这个新的 VLAN 需要去被添加(或者,改变 VLAN 名字,作为一个示例)是一个改变,或者命令真实地推送到设备。
|
||||
|
||||
当一个技术越来越复杂,幂等性的价值就越高,在你修改的时候,你并不能注意到 _已存在_ 的网络设备的状态,仅仅是从一个网络配置和策略角度去尝试达到 _期望的_ 状态。
|
||||
|
||||
|
||||
### 网络范围的和临时(Ad Hoc)的改变
|
||||
|
||||
用配置管理工具解决的其中一个问题是,配置“飘移”(当设备的期望配置逐渐漂移,或者改变,随着时间的推移手动改变和/或在一个环境中使用了多个不同的工具),事实上,这也是像 Puppet 和 Chef 得到使用的地方。代理商 _phone home_ 到前端服务器,验证它的配置,并且,如果需要一个改变,则改变它。这个方法是非常简单的。如果有故障了,需要去排除怎么办?你通常需要通过管理系统,直接连到设备,找到并修复它,然后,马上离开,对不对?果然,在下次当代理的电话打到家里,修复问题的改变被覆盖了(基于主/前端服务器是怎么配置的)。在高度自动化的环境中,一次性的改变应该被限制,但是,仍然允许它们(译者注:指的是一次性改变)使用的工具是非常有价值的。正如你想到的,其中一个这样的工具是 Ansible。
|
||||
|
||||
因为 Ansible 是无代理的,这里并没有一个默认的推送或者拉取去防止配置漂移。自动化任务被定义在 Ansible playbook 中,当使用 Ansible 时,它推送到用户去运行 playbook。如果 playbook 在一个给定的时间间隔内运行,并且你没有用 Ansible Tower,你肯定知道任务的执行频率;如果你正好在终端提示符下使用一个原生的 Ansible 命令行,playbook 运行一次,并且仅运行一次。
|
||||
|
||||
缺省运行的 playbook 对网络工程师是很具有吸引力的,让人欣慰的是,在设备上手动进行的改变不会自动被覆盖。另外,当需要的时候,一个 playbook 运行的设备范围很容易被改变,即使是对一个单个设备进行自动化的单次改变,Ansible 仍然可以用,设备的 _范围_ 由一个被称为 Ansible 清单(inventory)的文件决定;这个清单可以是一台设备或者是一千台设备。
|
||||
缺省运行一次的剧本对网络工程师是很具有吸引力的,让人欣慰的是,在设备上手动进行的改变不会自动被覆盖。另外,当需要的时候,一个剧本所运行的设备范围很容易被改变,即使是对一个单个设备进行自动化的单次变更,Ansible 仍然可以用,设备的 _范围_ 由一个被称为 Ansible <ruby>清单<rt>inventory</rt></ruby>的文件决定;这个清单可以是一台设备或者是一千台设备。
|
||||
|
||||
下面展示的一个清单文件示例,它定义了两组共六台设备:
|
||||
|
||||
@ -172,13 +165,13 @@ leaf3
|
||||
leaf4
|
||||
```
|
||||
|
||||
为了自动化所有的主机,你的 play 定义的 playbook 的一个片段看起来应该是这样的:
|
||||
为了自动化所有的主机,你的剧本中的<ruby>剧集<rt>play</rt></ruby>定义的一个片段看起来应该是这样的:
|
||||
|
||||
```
|
||||
hosts: all
|
||||
```
|
||||
|
||||
并且,一个自动化的叶子节点交换机,它看起来应该像这样:
|
||||
并且,要只自动化一个叶子节点交换机,它看起来应该像这样:
|
||||
|
||||
```
|
||||
hosts: leaf1
|
||||
@ -190,27 +183,27 @@ hosts: leaf1
|
||||
hosts: core-switches
|
||||
```
|
||||
|
||||
###### 注意
|
||||
> 注意
|
||||
|
||||
正如前面所说的那样,这个报告的后面部分将详细介绍 playbooks、plays、和清单(inventories)。
|
||||
> 正如前面所说的那样,这个报告的后面部分将详细介绍剧本、剧集、和清单。
|
||||
|
||||
因为能够很容易地对一台设备或者 _N_ 台设备进行自动化,所以在需要对这些设备进行一次性改变时,Ansible 成为了最佳的选择。在网络范围内的改变它也做的很好:可以是关闭给定类型的所有接口、配置接口描述、或者是在一个跨企业园区布线的网络中添加 VLANs。
|
||||
因为能够很容易地对一台设备或者 _N_ 台设备进行自动化,所以在需要对这些设备进行一次性变更时,Ansible 成为了最佳的选择。在网络范围内的变更它也做的很好:可以是关闭给定类型的所有接口、配置接口描述、或者是在一个跨企业园区布线的网络中添加 VLAN。
|
||||
|
||||
### 使用 Ansible 实现网络任务自动化
|
||||
|
||||
这个报告从两个方面逐渐深入地讲解一些技术。第一个方面是围绕 Ansible 架构和它的细节,第二个方面是,从一个网络的角度,讲解使用 Ansible 可以完成什么类型的自动化。在这一章中我们将带你去详细了解第二方面的内容。
|
||||
|
||||
自动化一般被认为是速度快,但是,考虑到一些任务并不要求速度,这就是为什么一些 IT 团队没有认识到自动化的价值所在。VLAN 配置是一个非常好的例子,因为,你可能会想,“创建一个 VLAN 到底有多快?一般情况下每天添加多少个 VLANs?我真的需要自动化吗?”
|
||||
自动化一般被认为是速度快,但是,考虑到一些任务并不要求速度,这就是为什么一些 IT 团队没有认识到自动化的价值所在。VLAN 配置是一个非常好的例子,因为,你可能会想,“创建一个 VLAN 到底有多快?一般情况下每天添加多少个 VLAN?我真的需要自动化吗?”
|
||||
|
||||
在这一节中,我们专注于另外几种有意义的自动化任务,比如,设备准备、数据收集、报告、和遵从情况。但是,需要注意的是,正如我们前面所说的,自动化为你、你的团队、以及你的精确的更可预测的结果和更多的确定性,提供了更快的速度和敏捷性。
|
||||
在这一节中,我们专注于另外几种有意义的自动化任务,比如,设备准备、数据收集、报告和遵从情况。但是,需要注意的是,正如我们前面所说的,自动化为你、你的团队、以及你的精确的更可预测的结果和更多的确定性,提供了更快的速度和敏捷性。
|
||||
|
||||
### 设备准备
|
||||
#### 设备准备
|
||||
|
||||
为网络自动化开始使用 Ansible 的最容易也是最快的方法是,为设备最初投入使用创建设备配置文件,并且将配置文件推送到网络设备中。
|
||||
为网络自动化开始使用 Ansible 的最容易也是最快的方法是,为设备的最初投入使用创建设备配置文件,并且将配置文件推送到网络设备中。
|
||||
|
||||
如果我们去完成这个过程,它将分解为两步,第一步是创建一个配置文件,第二步是推送这个配置到设备中。
|
||||
|
||||
首先,我们需要去从供应商配置文件的底层专用语法(CLI)中解耦 _输入_。这意味着我们需要对配置参数中分离出文件和值,比如,VLANs、域信息、接口、路由、和其它的内容、等等,然后,当然是一个配置的模块文件。在这个示例中,这里有一个标准模板,它可以用于所有设备的初始部署。Ansible 将帮助提供配置模板中需要的输入和值之间的部分。几秒钟之内,Ansible 可以生成数百个可靠的和可预测的配置文件。
|
||||
首先,我们需要去从供应商配置文件的底层专用语法(CLI)中解耦 _输入_。这意味着我们需要对配置参数中分离出文件和值,比如,VLAN、域信息、接口、路由、和其它的内容等等,然后,当然是一个配置的模块文件。在这个示例中,这里有一个标准模板,它可以用于所有设备的初始部署。Ansible 将帮助提供配置模板中需要的输入和值之间的部分。几秒钟之内,Ansible 可以生成数百个可靠的和可预测的配置文件。
|
||||
|
||||
让我们快速的看一个示例,它使用当前的配置,并且分解它到一个模板和单独的一个(作为一个输入源的)变量文件中。
|
||||
|
||||
@ -238,13 +231,13 @@ vlan 50
|
||||
|
||||
如果我们提取输入值,这个文件将被转换成一个模板。
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
Ansible 使用基于 Python 的 Jinja2 模板化语言,因此,这个被命名为 _leaf.j2_ 的文件是一个 Jinja2 模板。
|
||||
> Ansible 使用基于 Python 的 Jinja2 模板化语言,因此,这个被命名为 _leaf.j2_ 的文件是一个 Jinja2 模板。
|
||||
|
||||
注意,下列的示例中,_双大括号({{)_ 代表一个变量。
|
||||
注意,下列的示例中,_双大括号(`{{}}`)_ 代表一个变量。
|
||||
|
||||
模板看起来像这些,并且给它命名为 _leaf.j2_:
|
||||
模板看起来像这些,并且给它命名为 `leaf.j2`:
|
||||
|
||||
```
|
||||
!
|
||||
@ -273,17 +266,17 @@ vlans:
|
||||
- { id: 50, name: misc }
|
||||
```
|
||||
|
||||
这意味着,如果管理 VLANs 的团队希望在网络设备中添加一个 VLAN,很简单,他们只需要在变量文件中改变它,然后,使用 Ansible 中一个叫 `template` 的模块,去重新生成一个新的配置文件。这整个过程也是幂等的;仅仅是在模板或者值发生改变时,它才会去生成一个新的配置文件。
|
||||
这意味着,如果管理 VLAN 的团队希望在网络设备中添加一个 VLAN,很简单,他们只需要在变量文件中改变它,然后,使用 Ansible 中一个叫 `template` 的模块,去重新生成一个新的配置文件。这整个过程也是幂等的;仅仅是在模板或者值发生改变时,它才会去生成一个新的配置文件。
|
||||
|
||||
一旦配置文件生成,它需要去 _推送_ 到网络设备。推送配置文件到网络设备使用一个叫做 `napalm_install_config`的开源的 Ansible 模块。
|
||||
|
||||
接下来的示例是一个简单的 playbook 去 _构建并推送_ 一个配置文件到网络设备。同样地,playbook 使用一个名叫 `template` 的模块去构建配置文件,然后使用一个名叫 `napalm_install_config` 的模块去推送它们,并且激活它作为设备上运行的新的配置文件。
|
||||
接下来的示例是一个 _构建并推送_ 一个配置文件到网络设备的简单剧本。同样地,该剧本使用一个名叫 `template` 的模块去构建配置文件,然后使用一个名叫 `napalm_install_config` 的模块去推送它们,并且激活它作为设备上运行的新的配置文件。
|
||||
|
||||
虽然没有详细解释示例中的每一行,但是,你仍然可以看明白它们实际上做了什么。
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
下面的 playbook 介绍了新的概念,比如,内置变量 `inventory_hostname`。这些概念包含在 [Ansible 术语和入门][1] 中。
|
||||
> 下面的剧本介绍了新的概念,比如,内置变量 `inventory_hostname`。这些概念包含在 [Ansible 术语和入门][1] 中。
|
||||
|
||||
```
|
||||
---
|
||||
@ -310,17 +303,17 @@ vlans:
|
||||
replace_config=0
|
||||
```
|
||||
|
||||
这个两步的过程是一个使用 Ansible 进行网络自动化入门的简单方法。通过模板简化了你的配置,构建配置文件,然后,推送它们到网络设备 — 因此,被称为 _BUILD 和 PUSH_ 方法。
|
||||
这个两步的过程是一个使用 Ansible 进行网络自动化入门的简单方法。通过模板简化了你的配置,构建配置文件,然后,推送它们到网络设备 — 因此,被称为 `BUILD` 和 `PUSH` 方法。
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
像这样的更详细的例子,请查看 [Ansible 网络集成][2]。
|
||||
> 像这样的更详细的例子,请查看 [Ansible 网络集成][2]。
|
||||
|
||||
### 数据收集和监视
|
||||
#### 数据收集和监视
|
||||
|
||||
监视工具一般使用 SNMP — 这些工具拉某些管理信息库(MIBs),然后给监视工具返回数据。基于返回的数据,它可能多于也可能少于你真正所需要的数据。如果接口基于返回的数据统计你正在拉的内容,你可能会返回在 _show interface_ 命令中显示的计数器。如果你仅需要 _interface resets_ 并且,希望去看到与重置相关的邻接 CDP/LLDP 的接口,那该怎么做呢?当然,这也可以使用当前的技术;可以运行多个显示命令去手动解析输出信息,或者,使用基于 SNMP 的工具,在 GUI 中切换不同的选项卡(Tab)找到真正你所需要的数据。Ansible 怎么能帮助我们去完成这些工作呢?
|
||||
监视工具一般使用 SNMP —— 这些工具拉取某些管理信息库(MIB),然后给监视工具返回数据。基于返回的数据,它可能多于也可能少于你真正所需要的数据。如果接口基于返回的数据统计你正在拉取的内容,你可能会返回在 `show interface` 命令中显示的计数器。如果你仅需要 `interface resets` 并且,希望去看到与重置相关的邻接 CDP/LLDP 的接口,那该怎么做呢?当然,这也可以使用当前的技术;可以运行多个显示命令去手动解析输出信息,或者,使用基于 SNMP 的工具,在 GUI 中切换不同的选项卡(Tab)找到真正你所需要的数据。Ansible 怎么能帮助我们去完成这些工作呢?
|
||||
|
||||
由于 Ansible 是完全开放并且是可扩展的,它可以精确地去收集和监视所需要的计数器或者值。这可能需要一些预先的定制工作,但是,最终这些工作是非常有价值的。因为采集的数据是你所需要的,而不是供应商提供给你的。Ansible 也提供直观的方法去执行某些条件任务,这意味着基于正在返回的数据,你可以执行子任务,它可以收集更多的数据或者产生一个配置改变。
|
||||
由于 Ansible 是完全开源并且是可扩展的,它可以精确地去收集和监视所需要的计数器或者值。这可能需要一些预先的定制工作,但是,最终这些工作是非常有价值的。因为采集的数据是你所需要的,而不是供应商提供给你的。Ansible 也提供了执行某些条件任务的直观方法,这意味着基于正在返回的数据,你可以执行子任务,它可以收集更多的数据或者产生一个配置改变。
|
||||
|
||||
网络设备有 _许多_ 统计和隐藏在里面的临时数据,而 Ansible 可以帮你提取它们。
|
||||
|
||||
@ -342,26 +335,23 @@ vlans:
|
||||
|
||||
你现在可以决定某些事情,而不需要事先知道是什么类型的设备。你所需要知道的仅仅是设备的只读通讯字符串。
|
||||
|
||||
#### 迁移
|
||||
|
||||
### 迁移
|
||||
从一个平台迁移到另外一个平台,可能是从同一个供应商或者是从不同的供应商,迁移从来都不是件容易的事。供应商可能提供一个脚本或者一个工具去帮助你迁移。Ansible 可以被用于去为所有类型的网络设备构建配置模板,然后,操作系统用这个方法去为所有的供应商生成一个配置文件,然后作为一个(通用数据模型的)输入设置。当然,如果有供应商专用的扩展,它也是会被用到的。这种灵活性不仅对迁移有帮助,而且也可以用于<ruby>灾难恢复<rt>disaster recovery</rt></ruby>(DR),它在生产系统中不同的交换机型号之间和灾备数据中心中是经常使用的,即使是在不同的供应商的设备上。
|
||||
|
||||
从一个平台迁移到另外一个平台,可能是从同一个供应商或者是从不同的供应商,迁移从来都不是件容易的事。供应商可能提供一个脚本或者一个工具去帮助你迁移。Ansible 可以被用于去为所有类型的网络设备构建配置模板,然后,操作系统用这个方法去为所有的供应商生成一个配置文件,然后作为一个(通用数据模型的)输入设置。当然,如果有供应商专用的扩展,它也是会被用到的。这种灵活性不仅对迁移有帮助,而且也可以用于灾难恢复(DR),它在生产系统中不同的交换机型号之间和灾备数据中心中是经常使用的,即使是在不同的供应商的设备上。
|
||||
#### 配置管理
|
||||
|
||||
正如前面所说的,配置管理是最常用的自动化类型。Ansible 可以很容易地做到创建<ruby>角色<rt>role</rt></ruby>去简化基于任务的自动化。从更高的层面来看,角色是指针对一个特定设备组的可重用的自动化任务的逻辑分组。关于角色的另一种说法是,认为角色就是相关的<ruby>工作流<rt>workflow</rt></ruby>。首先,在开始自动化添加值之前,需要理解工作流和过程。不论是开始一个小的自动化任务还是扩展它,理解工作流和过程都是非常重要的。
|
||||
|
||||
### 配置管理
|
||||
|
||||
正如前面所说的,配置管理是最常用的自动化类型。Ansible 可以很容易地做到创建 _角色(roles)_ 去简化基于任务的自动化。从更高的层面来看,角色是指针对一个特定设备组的可重用的自动化任务的逻辑分组。关于角色的另一种说法是,认为角色就是相关的工作流(workflows)。首先,在开始自动化添加值之前,需要理解工作流和过程。不论是开始一个小的自动化任务还是扩展它,理解工作流和过程都是非常重要的。
|
||||
|
||||
例如,一组自动化配置路由器和交换机的任务是非常常见的,并且它们也是一个很好的起点。但是,配置在哪台网络设备上?配置的 IP 地址是什么?或许需要一个 IP 地址管理方案?一旦用一个给定的功能分配了 IP 地址并且已经部署,DNS 也更新了吗?DHCP 的范围需要创建吗?
|
||||
例如,一组自动化地配置路由器和交换机的任务是非常常见的,并且它们也是一个很好的起点。但是,配置在哪台网络设备上?配置的 IP 地址是什么?或许需要一个 IP 地址管理方案?一旦用一个给定的功能分配了 IP 地址并且已经部署,DNS 也更新了吗?DHCP 的范围需要创建吗?
|
||||
|
||||
你可以看到工作流是怎么从一个小的任务开始,然后逐渐扩展到跨不同的 IT 系统?因为工作流持续扩展,所以,角色也一样(持续扩展)。
|
||||
|
||||
#### 遵从性
|
||||
|
||||
### 遵从性
|
||||
和其它形式的自动化工具一样,用任何形式的自动化工具产生配置改变都被视为风险。手工去产生改变可能看上去风险更大,正如你看到的和亲身经历过的那样,Ansible 有能力去做自动数据收集、监视、和配置构建,这些都是“只读的”和“低风险”的动作。其中一个 _低风险_ 使用案例是,使用收集的数据进行配置遵从性检查和配置验证。部署的配置是否满足安全要求?是否配置了所需的网络?协议 XYZ 禁用了吗?因为每个模块、或者用 Ansible 返回数据的整合,它只是非常简单地 _声明_ 那些事是 _TRUE_ 还是 _FALSE_。然后接着基于 _它_ 是 _TRUE_ 或者是 _FALSE_, 接着由你决定应该发生什么 —— 或许它只是被记录下来,或者,也可能执行一个复杂操作。
|
||||
|
||||
和其它形式的自动化工具一样,用任何形式的自动化工具产生配置改变都视为风险。手工去产生改变可能看上去风险更大,正如你看到的和亲身经历过的那样,Ansible 有能力去做自动数据收集、监视、和配置构建,这些都是“只读的”和“低风险”的动作。其中一个 _低风险_ 使用案例是,使用收集的数据进行配置遵从性检查和配置验证。部署的配置是否满足安全要求?是否配置了所需的网络?协议 XYZ 禁用了吗?因为每个模块、或者用 Ansible 返回数据的整合,它只是非常简单地 _声明_ 那些事是 _TRUE_ 还是 _FALSE_。然后接着基于 _它_ 是 _TRUE_ 或者是 _FALSE_, 接着由你决定应该发生什么 —— 或许它只是被记录下来,或者,也可能执行一个复杂操作。
|
||||
|
||||
### 报告
|
||||
#### 报告
|
||||
|
||||
我们现在知道,Ansible 也可以用于去收集数据和执行遵从性检查。Ansible 可以根据你想要做的事情去从设备中返回和收集数据。或许返回的数据成为其它的任务的输入,或者你想去用它创建一个报告。从模板中生成报告,并将真实的数据插入到模板中,创建和使用报告模板的过程与创建配置模板的过程是相同的。
|
||||
|
||||
@ -369,22 +359,21 @@ vlans:
|
||||
|
||||
创建报告的用处很多,不仅是为行政管理,也为了运营工程师,因为它们通常有双方都需要的不同指标。
|
||||
|
||||
|
||||
### Ansible 怎么工作
|
||||
|
||||
从一个网络自动化的角度理解了 Ansible 能做什么之后,我们现在看一下 Ansible 是怎么工作的。你将学习到从一个 Ansible 管理主机到一个被自动化的节点的全部通讯流。首先,我们回顾一下,Ansible 是怎么 _开箱即用的(out of the box)_,然后,我们看一下 Ansible 怎么去做到的,具体说就是,当网络设备自动化时,Ansible _模块_是怎么去工作的。
|
||||
从一个网络自动化的角度理解了 Ansible 能做什么之后,我们现在看一下 Ansible 是怎么工作的。你将学习到从一个 Ansible 管理主机到一个被自动化的节点的全部通讯流。首先,我们回顾一下,Ansible 是怎么<ruby>开箱即用<rt>out of the box</rt></ruby>的,然后,我们看一下 Ansible 怎么去做到的,具体说就是,当网络设备自动化时,Ansible _模块_是怎么去工作的。
|
||||
|
||||
### 开箱即用
|
||||
#### 开箱即用
|
||||
|
||||
到目前为止,你已经明白了,Ansible 是一个自动化平台。实际上,它是一个安装在一台单个服务器上或者企业中任何一位管理员的笔记本中的轻量级的自动化平台。当然,(安装在哪里?)这是由你来决定的。在基于 Linux 的机器上,使用一些实用程序(比如 pip、apt、和 yum)安装 Ansible 是非常容易的。
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
在本报告的其余部分,安装 Ansible 的机器被称为 _控制主机_。
|
||||
> 在本报告的其余部分,安装 Ansible 的机器被称为<ruby>控制主机<rt>control host</rt></ruby>。
|
||||
|
||||
控制主机将执行在 Ansible 的 playbook (不用担心,稍后我们将讲到 playbook 和其它的 Ansible 术语)中定义的所有自动化任务。现在,我们只需要知道,一个 playbook 是简单的一组自动化任务和在给定数量的主机上执行的指令。
|
||||
控制主机将执行定义在 Ansible 的<ruby>剧本<rt>playbook</rt></ruby> (不用担心,稍后我们将讲到剧本和其它的 Ansible 术语)中的所有自动化任务。现在,我们只需要知道,一个剧本是简单的一组自动化任务和在给定数量的主机上执行的指令。
|
||||
|
||||
当一个 playbook 创建之后,你还需要去定义它要自动化的主机。映射一个 playbook 和要自动化运行的主机,是通过一个被称为 Ansible 清单的文件。这是一个前面展示的示例,但是,这里是同一个清单文件的另外两个组:`cisco` 和 `arista`:
|
||||
当一个剧本创建之后,你还需要去定义它要自动化的主机。映射一个剧本和要自动化运行的主机,是通过一个被称为 Ansible <ruby>清单<rt>inventory</rt></ruby>的文件。这是一个前面展示的示例,但是,这里是同一个清单文件的另外两个组:`cisco` 和 `arista`:
|
||||
|
||||
```
|
||||
[cisco]
|
||||
@ -396,13 +385,13 @@ sfo1.acme.com
|
||||
sfo2.acme.com
|
||||
```
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
你也可以在清单文件中使用 IP 地址,而不是主机名。对于这样的示例,主机名将是通过 DNS 可解析的。
|
||||
> 你也可以在清单文件中使用 IP 地址,而不是主机名。对于这样的示例,主机名将是通过 DNS 可解析的。
|
||||
|
||||
正如你所看到的,Ansible 清单文件是一个文本文件,它列出了主机和主机组。然后,你可以在 playbook 中引用一个具体的主机或者组,以此去决定对给定的 play 和 playbook 在哪台主机上进行自动化。下面展示了两个示例。
|
||||
正如你所看到的,Ansible 清单文件是一个文本文件,它列出了主机和主机组。然后,你可以在剧本中引用一个具体的主机或者组,以此去决定对给定的<ruby>剧集<rt>play</rt></ruby>和剧本在哪台主机上进行自动化。下面展示了两个示例。
|
||||
|
||||
展示的第一个示例它看上去像是,你想去自动化 `cisco` 组中所有的主机,而展示的第二个示例只对 _nyc1.acme.com_ 主机进行自动化:
|
||||
展示的第一个示例它看上去像是,你想去自动化 `cisco` 组中所有的主机,而展示的第二个示例只对 `nyc1.acme.com` 主机进行自动化:
|
||||
|
||||
```
|
||||
---
|
||||
@ -424,7 +413,7 @@ sfo2.acme.com
|
||||
- TASKS YOU WANT TO AUTOMATE
|
||||
```
|
||||
|
||||
现在,我们已经理解了基本的清单文件,我们可以看一下(在控制主机上的)Ansible 是怎么与 _开箱即用_ 的设备通讯的,和在 Linux 终端上自动化的任务。这里需要明白一个重要的观点就是,需要去自动化的网络设备通常是不一样的。(译者注:指的是设备的类型、品牌、型号等等)
|
||||
现在,我们已经理解了基本的清单文件,我们可以看一下(在控制主机上的)Ansible 是怎么与 _开箱即用_ 的设备通讯的,和在 Linux 终端上自动化的任务。这里需要明白一个重要的观点就是,需要去自动化的网络设备通常是不一样的。(LCTT 译注:指的是设备的类型、品牌、型号等等)
|
||||
|
||||
Ansible 对基于 Linux 的系统去开箱即用自动化工作有两个要求。它们是 SSH 和 Python。
|
||||
|
||||
@ -434,31 +423,26 @@ Ansible 对基于 Linux 的系统去开箱即用自动化工作有两个要求
|
||||
|
||||
如果我们详细解释这个开箱即用工作流,它将分解成如下的步骤:
|
||||
|
||||
1. 当一个 Ansible play 被执行,控制主机使用 SSH 连接到基于 Linux 的目标节点。
|
||||
|
||||
2. 对于每个任务,也就是说,Ansible 模块将在这个 play 中被执行,通过 SSH 发送 Python 代码并直接在远程系统中执行。
|
||||
|
||||
1. 当执行一个 Ansible 剧集时,控制主机使用 SSH 连接到基于 Linux 的目标节点。
|
||||
2. 对于每个任务,也就是说,Ansible 模块将在这个剧集中被执行,通过 SSH 发送 Python 代码并直接在远程系统中执行。
|
||||
3. 在远程系统上运行的每个 Ansible 模块将返回 JSON 数据到控制主机。这些数据包含有信息,比如,配置改变、任务成功/失败、以及其它模块特定的数据。
|
||||
|
||||
4. JSON 数据返回给 Ansible,然后被用于去生成报告,或者被用作接下来模块的输入。
|
||||
5. 在剧集中为每个任务重复第 3 步。
|
||||
6. 在剧本中为每个剧集重复第 1 步。
|
||||
|
||||
5. 在 play 中为每个任务重复第 3 步。
|
||||
|
||||
6. 在 playbook 中为每个 play 重复第 1 步。
|
||||
|
||||
是不是意味着每个网络设备都可以被 Ansible 开箱即用?因为它们也都支持 SSH,确实,网络设备都支持 SSH,但是,它是第一个和第二要求的组合限制了网络设备可能的功能。
|
||||
是不是意味着每个网络设备都可以被 Ansible 开箱即用?因为它们也都支持 SSH,确实,网络设备都支持 SSH,但是,第一个和第二要求的组合限制了网络设备可能的功能。
|
||||
|
||||
刚开始时,大多数网络设备并不支持 Python,因此,使用默认的 Ansible 连接机制是无法进行的。换句话说,在过去的几年里,供应商在几个不同的设备平台上增加了 Python 支持。但是,这些平台中的大多数仍然缺乏必要的集成,以允许 Ansible 去直接通过 SSH 访问一个 Linux shell,并以适当的权限去拷贝所需的代码、创建临时目录和文件、以及在设备中执行代码。尽管 Ansible 中所有的这些部分都可以在基于 Linux 的网络设备上使用 SSH/Python 在本地运行,它仍然需要网络设备供应商去更进一步开放他们的系统。
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
值的注意的是,Arista 确实也提供了原生的集成,因为它可以放弃 SSH 用户,直接进入到一个 Linux shell 中访问 Python 引擎,它可以允许 Ansible 去使用默认连接机制。因为我们调用了 Arista,我们也需要着重强调与 Ansible 默认连接机制一起工作的 Cumulus。这是因为 Cumulus Linux 是原生 Linux,并且它并不需要为 Cumulus Linux 操作系统使用供应商 API。
|
||||
> 值的注意的是,Arista 确实也提供了原生的集成,因为它可以无需 SSH 用户,直接进入到一个 Linux shell 中访问 Python 引擎,它可以允许 Ansible 去使用其默认连接机制。因为我们调用了 Arista,我们也需要着重强调与 Ansible 默认连接机制一起工作的 Cumulus。这是因为 Cumulus Linux 是原生 Linux,并且它并不需要为 Cumulus Linux 操作系统使用供应商 API。
|
||||
|
||||
### Ansible 网络集成
|
||||
#### Ansible 网络集成
|
||||
|
||||
前面的节讲到过 Ansible 默认的工作方式。我们看一下,在开始一个 _play_ 之后,Ansible 是怎么去设置一个到设备的连接、通过执行拷贝 Python 代码到设备去运行任务、运行代码、和返回结果给 Ansible 控制主机。
|
||||
前面的节讲到过 Ansible 默认的工作方式。我们看一下,在开始一个 _剧集_ 之后,Ansible 是怎么去设置一个到设备的连接、通过拷贝 Python 代码到设备、运行代码、和返回结果给 Ansible 控制主机来执行任务。
|
||||
|
||||
在这一节中,我们将看一看,当使用 Ansible 进行自动化网络设备时都做了什么。正如前面讲过的,Ansible 是一个可拔插的连接架构。对于 _大多数_ 的网络集成, `connection` 参数设置为 `local`。在 playbook 中大多数的连接类型都设置为 `local`,如下面的示例所展示的:
|
||||
在这一节中,我们将看一看,当使用 Ansible 进行自动化网络设备时都做了什么。正如前面讲过的,Ansible 是一个可拔插的连接架构。对于 _大多数_ 的网络集成, `connection` 参数设置为 `local`。在剧本中大多数的连接类型都设置为 `local`,如下面的示例所展示的:
|
||||
|
||||
```
|
||||
---
|
||||
@ -471,15 +455,15 @@ Ansible 对基于 Linux 的系统去开箱即用自动化工作有两个要求
|
||||
- TASKS YOU WANT TO AUTOMATE
|
||||
```
|
||||
|
||||
注意在 play 中是怎么定义的,这个示例增加 `connection` 参数去和前面节中的示例进行比较。
|
||||
注意在剧集中是怎么定义的,这个示例增加 `connection` 参数去和前面节中的示例进行比较。
|
||||
|
||||
这告诉 Ansible 不要通过 SSH 去连接到目标设备,而是连接到本地机器运行这个 playbook。基本上,这是把连接职责委托给 playbook 中 _任务_ 节中使用的真实的 Ansible 模块。每个模块类型的委托权利允许这个模块在必要时以各种形式去连接到设备。这可能是 Juniper 和 HP Comware7 的 NETCONF、Arista 的 eAPI、Cisco Nexus 的 NX-API、或者甚至是基于传统系统的 SNMP,它们没有可编程的 API。
|
||||
这告诉 Ansible 不要通过 SSH 去连接到目标设备,而是连接到本地机器运行这个剧本。基本上,这是把连接职责委托给剧本中<ruby>任务<rt>task</rt></ruby> 节中使用的真实的 Ansible 模块。每个模块类型的委托权利允许这个模块在必要时以各种形式去连接到设备。这可能是 Juniper 和 HP Comware7 的 NETCONF、Arista 的 eAPI、Cisco Nexus 的 NX-API、或者甚至是基于传统系统的 SNMP,它们没有可编程的 API。
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
网络集成在 Ansible 中是以 Ansible 模块的形式带来的。尽管我们持续使用术语来吊你的胃口,比如,playbooks、plays、任务、和讲到的关键概念 `模块`,这些术语中的每一个都会在 [Ansible 术语和入门][3] 和 [动手实践使用 Ansible 去进行网络自动化][4] 中详细解释。
|
||||
> 网络集成在 Ansible 中是以 Ansible 模块的形式带来的。尽管我们持续使用术语来吊你的胃口,比如,剧本、剧集、任务、和讲到的关键概念模块,这些术语中的每一个都会在 [Ansible 术语和入门][3] 和 [动手实践使用 Ansible 去进行网络自动化][4] 中详细解释。
|
||||
|
||||
让我们看一看另外一个 playbook 的示例:
|
||||
让我们看一看另外一个剧本的示例:
|
||||
|
||||
```
|
||||
---
|
||||
@ -492,22 +476,21 @@ Ansible 对基于 Linux 的系统去开箱即用自动化工作有两个要求
|
||||
- nxos_vlan: vlan_id=10 name=WEB_VLAN
|
||||
```
|
||||
|
||||
你注意到了吗,这个 playbook 现在包含一个任务,并且这个任务使用了 `nxos_vlan` 模块。`nxos_vlan` 模块是一个 Python 文件,并且,在这个文件中它是使用 NX-API 连接到 Cisco 的 NX-OS 设备。可是,这个连接可能是使用其它设备 API 设置的,这就是为什么供应商和用户像我们这样能够去建立自己的集成的原因。集成(模块)通常是以每特性(per-feature)为基础完成的,虽然,你已经看到了像 `napalm_install_config` 这样的模块,它们也可以被用来 _推送_ 一个完整的配置文件。
|
||||
你注意到了吗,这个剧本现在包含一个任务,并且这个任务使用了 `nxos_vlan` 模块。`nxos_vlan` 模块是一个 Python 文件,并且,在这个文件中它是使用 NX-API 连接到 Cisco 的 NX-OS 设备。可是,这个连接可能是使用其它设备 API 设置的,这就是为什么供应商和用户像我们这样能够去建立自己的集成的原因。集成(模块)通常是以<ruby>每特性<rt>per-feature</rt></ruby>为基础完成的,虽然,你已经看到了像 `napalm_install_config` 这样的模块,它们也可以被用来 _推送_ 一个完整的配置文件。
|
||||
|
||||
主要区别之一是使用的默认连接机制,Ansible 启动一个持久的 SSH 连接到设备,并且这个连接为一个给定的 play 持续。当在一个模块中发生连接设置和拆除时,与许多使用 `connection=local` 的网络模块一样,对发生在 play 级别上的 _每个_ 任务,Ansible 将登入/登出设备。
|
||||
主要区别之一是使用的默认连接机制,Ansible 启动一个持久的 SSH 连接到设备,并且对于一个给定的剧集而已该连接将持续存在。当在一个模块中发生连接设置和拆除时,与许多使用 `connection=local` 的网络模块一样,对发生在剧集级别上的 _每个_ 任务,Ansible 将登入/登出设备。
|
||||
|
||||
而在传统的 Ansible 形式下,每个网络模块返回 JSON 数据。仅有的区别是相对于目标节点,数据的推取发生在本地的 Ansible 控制主机上。相对于每供应商(per vendor)和模块类型,数据返回到 playbook,但是作为一个示例,许多的 Cisco NX-OS 模块返回已存在的状态、建议状态、和最终状态,以及发送到设备的命令(如果有的话)。
|
||||
而在传统的 Ansible 形式下,每个网络模块返回 JSON 数据。仅有的区别是相对于目标节点,数据的推取发生在本地的 Ansible 控制主机上。相对于<ruby>每供应商<rt>per vendor</rt></ruby>和模块类型,数据返回到剧本,但是作为一个示例,许多的 Cisco NX-OS 模块返回已存在的状态、建议状态、和最终状态,以及发送到设备的命令(如果有的话)。
|
||||
|
||||
作为使用 Ansible 进行网络自动化的开始,最重要的是,为 Ansible 的连接设备/拆除过程,记着去设置连接参数为 `local`,并且将它留在模块中。这就是为什么模块支持不同类型的供应商平台,它将与设备使用不同的方式进行通讯。
|
||||
|
||||
|
||||
### Ansible 术语和入门
|
||||
|
||||
这一章我们将介绍许多 Ansible 的术语和报告中前面部分出现过的关键概念。比如, _清单文件_、_playbook_、_play_、_任务_、和 _模块_。我们也会去回顾一些其它的概念,这些术语和概念对我们学习使用 Ansible 去进行网络自动化非常有帮助。
|
||||
这一章我们将介绍许多 Ansible 的术语和报告中前面部分出现过的关键概念。比如, <ruby>清单文件<rt>inventory file</rt></ruby>、<ruby>剧本<rt>playbook</rt></ruby>、<ruby>剧集<rt>play</rt></ruby>、<ruby>任务<rt>task</rt></ruby>和<ruby>模块<rt>module</rt></ruby>。我们也会去回顾一些其它的概念,这些术语和概念对我们学习使用 Ansible 去进行网络自动化非常有帮助。
|
||||
|
||||
在这一节中,我们将引用如下的一个简单的清单文件和 playbook 的示例,它们将在后面的章节中持续出现。
|
||||
在这一节中,我们将引用如下的一个简单的清单文件和剧本的示例,它们将在后面的章节中持续出现。
|
||||
|
||||
_清单示例_:
|
||||
_清单示例_ :
|
||||
|
||||
```
|
||||
# sample inventory file
|
||||
@ -528,7 +511,7 @@ core1
|
||||
core2
|
||||
```
|
||||
|
||||
_playbook 示例_:
|
||||
_剧本示例_ :
|
||||
|
||||
```
|
||||
---
|
||||
@ -577,54 +560,50 @@ _playbook 示例_:
|
||||
- 50
|
||||
```
|
||||
|
||||
### 清单文件
|
||||
#### 清单文件
|
||||
|
||||
使用一个清单文件,比如前面提到的那个,允许我们去为自动化任务指定主机、和使用每个 play 顶部节中(如果存在)的参数 `hosts` 所引用的主机/组指定的主机组。
|
||||
使用一个清单文件,比如前面提到的那个,允许我们去为自动化任务指定主机、和使用每个剧集顶部节中(如果存在)的参数 `hosts` 所引用的主机/组指定的主机组。
|
||||
|
||||
它也可能在一个清单文件中存储变量。如这个示例中展示的那样。如果变量在同一行视为一台主机,它是一个具体主机变量。如果变量定义在方括号中(“[ ]”),比如,`[all:vars]`,它的意思是指变量在组中的范围 `all`,它是一个默认组,包含了清单文件中的 _所有_ 主机。
|
||||
它也可能在一个清单文件中存储变量。如这个示例中展示的那样。如果变量在同一行视为一台主机,它是一个具体主机变量。如果变量定义在方括号中(`[ ]`),比如,`[all:vars]`,它的意思是指变量在组中的范围 `all`,它是一个默认组,包含了清单文件中的 _所有_ 主机。
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
清单文件是使用 Ansible 开始自动化的快速方法,但是,你应该已经有一个真实的网络设备源,比如一个网络管理工具或者 CMDB,它可以去创建和使用一个动态的清单脚本,而不是一个静态的清单文件。
|
||||
> 清单文件是使用 Ansible 开始自动化的快速方法,但是,你应该已经有一个真实的网络设备源,比如一个网络管理工具或者 CMDB,它可以去创建和使用一个动态的清单脚本,而不是一个静态的清单文件。
|
||||
|
||||
### Playbook
|
||||
#### 剧本
|
||||
|
||||
playbook 是去运行自动化网络设备的顶级对象。在我们的示例中,它是一个 _site.yml_ 文件,如前面的示例所展示的。一个 playbook 使用 YAML 去定义一组自动化任务,并且,每个 playbook 由一个或多个 plays 组成。这类似于一个橄榄球的剧本。就像在橄榄球赛中,团队有剧集组成的剧本,Ansible 的 playbooks 也是由 play 组成的。
|
||||
剧本是去运行自动化网络设备的顶级对象。在我们的示例中,它是 `site.yml` 文件,如前面的示例所展示的。一个剧本使用 YAML 去定义一组自动化任务,并且,每个剧本由一个或多个剧集组成。这类似于一个橄榄球的剧本。就像在橄榄球赛中,团队有剧集组成的剧本,Ansible 的剧本也是由剧集组成的。
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
YAML 是一种被所有编程语言支持的数据格式。YAML 本身就是 JSON 的超集,并且,YAML 文件非常易于识别,因为它总是三个破折号(连字符)开始,比如,`---`。
|
||||
> YAML 是一种被所有编程语言支持的数据格式。YAML 本身就是 JSON 的超集,并且,YAML 文件非常易于识别,因为它总是三个破折号(连字符)开始,比如,`---`。
|
||||
|
||||
|
||||
### Play
|
||||
#### 剧集
|
||||
|
||||
一个 Ansible playbook 可以存在一个或多个 plays。在前面的示例中,它在 playbook 中有两个 plays。每个 play 开始的地方都有一个 _header_ 节,它定义了具体的参数。
|
||||
一个 Ansible 剧本可以存在一个或多个剧集。在前面的示例中,它在剧本中有两个剧集。每个剧集开始的地方都有一个 _头部_,它定义了具体的参数。
|
||||
|
||||
示例中两个 plays 都定义了下面的参数:
|
||||
示例中两个剧集都定义了下面的参数:
|
||||
|
||||
`name`
|
||||
|
||||
文件 `PLAY 1 - Top of Rack (TOR) Switches` 是任意内容的,它在 playbook 运行的时候,去改善 playbook 运行和报告期间的可读性。这是一个可选参数。
|
||||
文件 `PLAY 1 - Top of Rack (TOR) Switches` 是任意内容的,它在剧本运行的时候,去改善剧本运行和报告期间的可读性。这是一个可选参数。
|
||||
|
||||
`hosts`
|
||||
|
||||
正如前面讲过的,这是在特定的 play 中要去进行自动化的主机或主机组。这是一个必需参数。
|
||||
正如前面讲过的,这是在特定的剧集中要去进行自动化的主机或主机组。这是一个必需参数。
|
||||
|
||||
`connection`
|
||||
|
||||
正如前面讲过的,这是 play 连接机制的类型。这是个可选参数,但是,对于网络自动化 plays,一般设置为 `local`。
|
||||
正如前面讲过的,这是剧集连接机制的类型。这是个可选参数,但是,对于网络自动化剧集,一般设置为 `local`。
|
||||
|
||||
每个剧集都是由一个或多个任务组成。
|
||||
|
||||
|
||||
每个 play 都是由一个或多个任务组成。
|
||||
|
||||
|
||||
|
||||
### 任务
|
||||
#### 任务
|
||||
|
||||
任务是以声明的方式去表示自动化的内容,而不用担心底层的语法或者操作是怎么执行的。
|
||||
|
||||
在我们的示例中,第一个 play 有两个任务。每个任务确保存在 10 个 VLAN。第一个任务是为 Cisco Nexus 设备的,而第二个任务是为 Arista 设备的:
|
||||
在我们的示例中,第一个剧集有两个任务。每个任务确保存在 10 个 VLAN。第一个任务是为 Cisco Nexus 设备的,而第二个任务是为 Arista 设备的:
|
||||
|
||||
```
|
||||
tasks:
|
||||
@ -638,19 +617,17 @@ tasks:
|
||||
when: vendor == "nxos"
|
||||
```
|
||||
|
||||
任务也可以使用 `name` 参数,就像 plays 一样。和 plays 一样,文本内容是任意的,并且当 playbook 运行时显示,去改善 playbook 运行和报告期间的可读性。它对每个任务都是可选参数。
|
||||
任务也可以使用 `name` 参数,就像剧集一样。和剧集一样,文本内容是任意的,并且当剧本运行时显示,去改善剧本运行和报告期间的可读性。它对每个任务都是可选参数。
|
||||
|
||||
示例任务中的下一行是以 `nxos_vlan` 开始的。它告诉我们这个任务将运行一个叫 `nxos_vlan` 的 Ansible 模块。
|
||||
|
||||
现在,我们将进入到模块中。
|
||||
|
||||
#### 模块
|
||||
|
||||
在 Ansible 中理解模块的概念是至关重要的。虽然任何编辑语言都可以用来写 Ansible 模块,只要它们能够返回 JSON 键/值对即可,但是,几乎所有的模块都是用 Python 写的。在我们示例中,我们看到有两个模块被运行: `nxos_vlan` 和 `eos_vlan`。这两个模块都是 Python 文件;而事实上,在你不能看到剧本的时候,真实的文件名分别是 `eos_vlan.py` 和 `nxos_vlan.py`。
|
||||
|
||||
### 模块
|
||||
|
||||
在 Ansible 中理解模块的概念是至关重要的。虽然任何编辑语言都可以用来写 Ansible 模块,只要它们能够返回 JSON 键 — 值对即可,但是,几乎所有的模块都是用 Python 写的。在我们示例中,我们看到有两个模块被运行: `nxos_vlan` 和 `eos_vlan`。这两个模块都是 Python 文件;而事实上,在你不能看到 playbook 的时候,真实的文件名分别是 _eos_vlan.py_ 和 _nxos_vlan.py_。
|
||||
|
||||
让我们看一下前面的示例中第一个 play 中的第一个 任务:
|
||||
让我们看一下前面的示例中第一个剧集中的第一个任务:
|
||||
|
||||
```
|
||||
- name: ENSURE VLAN 10 EXISTS ON CISCO TOR SWITCHES
|
||||
@ -678,48 +655,39 @@ tasks:
|
||||
|
||||
用于登入到交换机的密码。
|
||||
|
||||
示例中最后的片断部分使用了一个 `when` 语句。这是在一个剧集中使用的 Ansible 的执行条件任务。正如我们所了解的,在这个剧集的 `tor` 组中有多个设备和设备类型。使用 `when` 基于任意标准去提供更多的选择。这里我们仅自动化 Cisco 设备,因为,我们在这个任务中使用了 `nxos_vlan` 模块,在下一个任务中,我们仅自动化 Arista 设备,因为,我们使用了 `eos_vlan` 模块。
|
||||
|
||||
示例中最后的片断部分使用了一个 `when` 语句。这是在一个 play 中使用的 Ansible 的执行条件任务。正如我们所了解的,在这个 play 的 `tor` 组中有多个设备和设备类型。使用 `when` 基于任意标准去提供更多的选择。这里我们仅自动化 Cisco 设备,因为,我们在这个任务中使用了 `nxos_vlan` 模块,在下一个任务中,我们仅自动化 Arista 设备,因为,我们使用了 `eos_vlan` 模块。
|
||||
> 注意:
|
||||
|
||||
###### 注意
|
||||
|
||||
这并不是区分设备的唯一方法。这里仅是演示如何使用 `when`,并且可以在清单文件中定义变量。
|
||||
> 这并不是区分设备的唯一方法。这里仅是演示如何使用 `when`,并且可以在清单文件中定义变量。
|
||||
|
||||
在清单文件中定义变量是一个很好的开端,但是,如果你继续使用 Ansible,你将会为了扩展性、版本控制、对给定文件的改变最小化而去使用基于 YAML 的变量。这也将简化和改善清单文件和每个使用的变量的可读性。在设备准备的构建/推送方法中讲过一个变量文件的示例。
|
||||
|
||||
在最后的示例中,关于任务有几点需要去搞清楚:
|
||||
|
||||
* Play 1 任务 1 展示了硬编码了 `username` 和 `password` 作为参数进入到具体的模块中(`nxos_vlan`)。
|
||||
|
||||
* Play 1 任务 1 和 play 2 在模块中使用了变量,而不是硬编码它们。这掩饰了 `username` 和 `password` 参数,但是,需要值得注意的是,(在这个示例中)这些变量是从清单文件中提取出现的。
|
||||
|
||||
* Play 1 中为进入到模块中的参数使用了一个 _水平的(horizontal)_ 的 key=value 语法,虽然 play 2 使用了垂直的(vertical) key=value 语法。它们都工作的非常好。你也可以使用垂直的 YAML “key: value” 语法。
|
||||
|
||||
* 最后的任务也介绍了在 Ansible 中怎么去使用一个 _loop_ 循环。它通过使用 `with_items` 来完成,并且它类似于一个 for 循环。那个特定的任务是循环进入五个 VLANs 中去确保在交换机中它们都存在。注意:它也可能被保存在一个外部的 YAML 变量文件中。还需要注意的一点是,不使用 `with_items` 的替代方案是,每个 VLAN 都有一个任务 —— 如果这样做,它就失去了弹性!
|
||||
|
||||
* 剧集 1 任务 1 展示了硬编码了 `username` 和 `password` 作为参数进入到具体的模块中(`nxos_vlan`)。
|
||||
* 剧集 1 任务 1 和 剧集 2 在模块中使用了变量,而不是硬编码它们。这掩饰了 `username` 和 `password` 参数,但是,需要值得注意的是,(在这个示例中)这些变量是从清单文件中提取出现的。
|
||||
* 剧集 1 中为进入到模块中的参数使用了一个 _水平的_ 的 key=value 语法,虽然剧集 2 使用了垂直的 key=value 语法。它们都工作的非常好。你也可以使用垂直的 YAML “key: value” 语法。
|
||||
* 最后的任务也介绍了在 Ansible 中怎么去使用一个循环。它通过使用 `with_items` 来完成,并且它类似于一个 for 循环。那个特定的任务是循环进入五个 VLAN 中去确保在交换机中它们都存在。注意:它也可能被保存在一个外部的 YAML 变量文件中。还需要注意的一点是,不使用 `with_items` 的替代方案是,每个 VLAN 都有一个任务 —— 如果这样做,它就失去了弹性!
|
||||
|
||||
### 动手实践使用 Ansible 去进行网络自动化
|
||||
|
||||
在前面的章节中,提供了 Ansible 术语的一个概述。它已经覆盖了大多数具体的 Ansible 术语,比如 playbooks、plays、任务、模块、和清单文件。这一节将继续提供示例去讲解使用 Ansible 实现网络自动化,而且将提供在不同类型的设备中自动化工作的模块的更多细节。示例中的将要进行自动化设备由多个供应商提供,包括 Cisco、Arista、Cumulus、和 Juniper。
|
||||
在前面的章节中,提供了 Ansible 术语的一个概述。它已经覆盖了大多数具体的 Ansible 术语,比如剧本、剧集、任务、模块和清单文件。这一节将继续提供示例去讲解使用 Ansible 实现网络自动化,而且将提供在不同类型的设备中自动化工作的模块的更多细节。示例中的将要进行自动化设备由多个供应商提供,包括 Cisco、Arista、Cumulus、和 Juniper。
|
||||
|
||||
在本节中的示例,假设的前提条件如下:
|
||||
|
||||
* Ansible 已经安装。
|
||||
|
||||
* 在设备中(NX-API、eAPI、NETCONF)适合的 APIs 已经启用。
|
||||
|
||||
* 用户在系统上有通过 API 去产生改变的适当权限。
|
||||
|
||||
* 所有的 Ansible 模块已经在系统中存在,并且也在库的路径变量中。
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
可以在 _ansible.cfg_ 文件中设置模块和库路径。在你运行一个 playbook 时,你也可以使用 `-M` 标志从命令行中去改变它。
|
||||
> 可以在 `ansible.cfg` 文件中设置模块和库路径。在你运行一个剧本时,你也可以使用 `-M` 标志从命令行中去改变它。
|
||||
|
||||
在本节中示例使用的清单如下。(删除了密码,IP 地址也发生了变化)。在这个示例中,(和前面的示例一样)某些主机名并不是完全合格域名(FQDNs)。
|
||||
在本节中示例使用的清单如下。(删除了密码,IP 地址也发生了变化)。在这个示例中,(和前面的示例一样)某些主机名并不是完全合格域名(FQDN)。
|
||||
|
||||
|
||||
### 清单文件
|
||||
#### 清单文件
|
||||
|
||||
```
|
||||
[cumulus]
|
||||
@ -735,19 +703,19 @@ nx1 hostip=5.6.7.8 un=USERNAME pwd=PASSWORD
|
||||
vsrx hostip=9.10.11.12 un=USERNAME pwd=PASSWORD
|
||||
```
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
正如你所知道的,Ansible 支持将密码存储在一个加密文件中的功能。如果你想学习关于这个特性的更多内容,请查看在 Ansible 网站上的文档中的 [Ansible Vault][5] 部分。
|
||||
> 正如你所知道的,Ansible 支持将密码存储在一个加密文件中的功能。如果你想学习关于这个特性的更多内容,请查看在 Ansible 网站上的文档中的 [Ansible Vault][5] 部分。
|
||||
|
||||
这个清单文件有四个组,每个组定义了一台单个的主机。让我们详细回顾一下每一节:
|
||||
|
||||
Cumulus
|
||||
**Cumulus**
|
||||
|
||||
主机 `cvx` 是一个 Cumulus Linux (CL) 交换机,并且它是 `cumulus` 组中的唯一设备。记住,CL 是原生 Linux,因此,这意味着它是使用默认连接机制(SSH)连到到需要自动化的 CL 交换机。因为 `cvx` 在 DNS 或者 _/etc/hosts_ 文件中没有定义,我们将让 Ansible 知道不要在清单文件中定义主机名,而是在 `ansible_ssh_host` 中定义的名字/IP。登陆到 CL 交换机的用户名被定义在 playbook 中,但是,你可以看到密码使用变量 `ansible_ssh_pass` 定义在清单文件中。
|
||||
主机 `cvx` 是一个 Cumulus Linux (CL) 交换机,并且它是 `cumulus` 组中的唯一设备。记住,CL 是原生 Linux,因此,这意味着它是使用默认连接机制(SSH)连到到需要自动化的 CL 交换机。因为 `cvx` 在 DNS 或者 `/etc/hosts` 文件中没有定义,我们将让 Ansible 知道不要在清单文件中定义主机名,而是在 `ansible_ssh_host` 中定义的名字/IP。登陆到 CL 交换机的用户名被定义在 playbook 中,但是,你可以看到密码使用变量 `ansible_ssh_pass` 定义在清单文件中。
|
||||
|
||||
Arista
|
||||
**Arista**
|
||||
|
||||
被称为 `veos1` 的是一台运行 EOS 的 Arista 交换机。它是在 `arista` 组中唯一的主机。正如你在 Arista 中看到的,在清单文件中并没有其它的参数存在。这是因为 Arista 为它们的设备使用了一个特定的配置文件。在我们的示例中它的名字为 _.eapi.conf_,它存在在 home 目录中。下面是正确使用配置文件的这个功能的示例:
|
||||
被称为 `veos1` 的是一台运行 EOS 的 Arista 交换机。它是在 `arista` 组中唯一的主机。正如你在 Arista 中看到的,在清单文件中并没有其它的参数存在。这是因为 Arista 为它们的设备使用了一个特定的配置文件。在我们的示例中它的名字为 `.eapi.conf`,它存在在 home 目录中。下面是正确使用配置文件的这个功能的示例:
|
||||
|
||||
```
|
||||
[connection:veos1]
|
||||
@ -756,27 +724,26 @@ username: unadmin
|
||||
password: pwadmin
|
||||
```
|
||||
|
||||
这个文件包含了定义在配置文件中的 Ansible 连接到设备(和 Arista 的被称为 _pyeapi_ 的 Python 库)所需要的全部信息。
|
||||
这个文件包含了定义在配置文件中的 Ansible 连接到设备(和 Arista 的被称为 `pyeapi` 的 Python 库)所需要的全部信息。
|
||||
|
||||
Cisco
|
||||
**Cisco**
|
||||
|
||||
和 Cumulus 和 Arista 一样,这里仅有一台主机(`nx1`)存在于 `cisco` 组中。这是一台 NX-OS-based Cisco Nexus 交换机。注意在这里为 `nx1` 定义了三个变量。它们包括 `un` 和 `pwd`,这是为了在 playbook 中访问和为了进入到 Cisco 模块去连接到设备。另外,这里有一个称为 `hostip` 的参数,它是必需的,因为,`nx1` 没有在 DNS 中或者是 _/etc/hosts_ 配置文件中定义。
|
||||
和 Cumulus 和 Arista 一样,这里仅有一台主机(`nx1`)存在于 `cisco` 组中。这是一台 NX-OS-based Cisco Nexus 交换机。注意在这里为 `nx1` 定义了三个变量。它们包括 `un` 和 `pwd`,这是为了在 playbook 中访问和为了进入到 Cisco 模块去连接到设备。另外,这里有一个称为 `hostip` 的参数,它是必需的,因为,`nx1` 没有在 DNS 中或者是 `/etc/hosts` 配置文件中定义。
|
||||
|
||||
> 注意:
|
||||
|
||||
###### 注意
|
||||
> 如果自动化一个原生的 Linux 设备,我们可以将这个参数命名为任何东西。`ansible_ssh_host` 被用于到如我们看到的那个 Cumulus 示例(如果在清单文件中的定义不能被解析)。在这个示例中,我们将一直使用 `ansible_ssh_host`,但是,它并不是必需的,因为我们将这个变量作为一个参数进入到 Cisco 模块,而 `ansible_ssh_host` 是在使用默认的 SSH 连接机制时自动检查的。
|
||||
|
||||
如果自动化一个原生的 Linux 设备,我们可以将这个参数命名为任何东西。`ansible_ssh_host` 被用于到如我们看到的那个 Cumulus 示例(如果在清单文件中的定义不能被解析)。在这个示例中,我们将一直使用 `ansible_ssh_host`,但是,它并不是必需的,因为我们将这个变量作为一个参数进入到 Cisco 模块,而 `ansible_ssh_host` 是在使用默认的 SSH 连接机制时自动检查的。
|
||||
|
||||
Juniper
|
||||
**Juniper**
|
||||
|
||||
和前面的三个组和主机一样,在 `juniper` 组中有一个单个的主机 `vsrx`。它在清单文件中的设置与 Cisco 相同,因为两者在 playbook 中使用了相同的方式。
|
||||
|
||||
|
||||
### Playbook
|
||||
#### 剧本
|
||||
|
||||
接下来的 playbook 有四个不同的 plays。每个 play 是基于特定的供应商类型的设备组的自动化构建的。注意,那是在一个单个的 playbook 中执行这些任务的唯一的方法。这里还有其它的方法,它可以使用条件(`when` 语句)或者创建 Ansible 角色(它在这个报告中没有介绍)。
|
||||
接下来的剧本有四个不同的剧集。每个剧集是基于特定的供应商类型的设备组的自动化构建的。注意,那是在一个单个的剧本中执行这些任务的唯一的方法。这里还有其它的方法,它可以使用条件(`when` 语句)或者创建 Ansible 角色(它在这个报告中没有介绍)。
|
||||
|
||||
这里有一个 playbook 的示例:
|
||||
这里有一个剧本的示例:
|
||||
|
||||
```
|
||||
---
|
||||
@ -833,29 +800,29 @@ Juniper
|
||||
diffs_file=junpr.diff
|
||||
```
|
||||
|
||||
你将注意到,前面的两个 plays 是非常类似的,我们已经在最初的 Cisco 和 Arista 示例中讲过了。唯一的区别是每个要自动化的组(`cisco` and `arista`) 定义了它们自己的 play,我们在前面介绍使用 `when` 条件时比较过。
|
||||
你将注意到,前面的两个剧集是非常类似的,我们已经在最初的 Cisco 和 Arista 示例中讲过了。唯一的区别是每个要自动化的组(`cisco` and `arista`) 定义了它们自己的剧集,我们在前面介绍使用 `when` 条件时比较过。
|
||||
|
||||
这里有一个不正确的或者是错误的方式去做这些。这取决于你预先知道的信息是什么和适合你的环境和使用的最佳案例是什么,但我们的目的是为了展示做同一件事的几种不同的方法。
|
||||
|
||||
第三个 play 是在 Cumulus Linux 交换机的 `swp1` 接口上进行自动化配置。在这个 play 中的第一个任务是去确认 `swp1` 是一个三层接口,并且它配置的 IP 地址是 100.10.10.1。因为 Cumulus Linux 是原生的 Linux,网络服务在改变后需要重启才能生效。这也可以使用 Ansible 的操作来达到这个目的(这已经超出了本报告讨论的范围),这里有一个被称为 `service` 的 Ansible 核心模块来做这些,但它会中断交换机上的网络;使用 `ifreload` 重新启动则不会中断。
|
||||
第三个剧集是在 Cumulus Linux 交换机的 `swp1` 接口上进行自动化配置。在这个剧集中的第一个任务是去确认 `swp1` 是一个三层接口,并且它配置的 IP 地址是 100.10.10.1。因为 Cumulus Linux 是原生的 Linux,网络服务在改变后需要重启才能生效。这也可以使用 Ansible 的操作来达到这个目的(这已经超出了本报告讨论的范围),这里有一个被称为 `service` 的 Ansible 核心模块来做这些,但它会中断交换机上的网络;使用 `ifreload` 重新启动则不会中断。
|
||||
|
||||
本节到现在为止,我们已经讲解了专注于特定任务的 Ansible 模块,比如,配置接口和 VLANs。第四个 play 使用了另外的选项。我们将看到一个 _pushes_ 模块,它是一个完整的配置文件并且立即激活它作为正在运行的新的配置。这里将使用 `napalm_install_config`来展示前面的示例,但是,这个示例使用了一个 Juniper 专用的模块。
|
||||
本节到现在为止,我们已经讲解了专注于特定任务的 Ansible 模块,比如,配置接口和 VLAN。第四个剧集使用了另外的选项。我们将看到一个 `pushes` 模块,它是一个完整的配置文件并且立即激活它作为正在运行的新的配置。这里将使用 `napalm_install_config` 来展示前面的示例,但是,这个示例使用了一个 Juniper 专用的模块。
|
||||
|
||||
`junos_install_config` 模块接受几个参数,如下面的示例中所展示的。到现在为止,你应该理解了什么是 `user`、`passwd`、和 `host`。其它的参数定义如下:
|
||||
|
||||
`file`
|
||||
`file`:
|
||||
|
||||
这是一个从 Ansible 控制主机拷贝到 Juniper 设备的配置文件。
|
||||
|
||||
`logfile`
|
||||
`logfile`:
|
||||
|
||||
这是可选的,但是,如果你指定它,它会被用于存储运行这个模块时生成的信息。
|
||||
|
||||
`overwrite`
|
||||
`overwrite`:
|
||||
|
||||
当你设置为 yes/true 时,完整的配置将被发送的配置覆盖。(默认是 false)
|
||||
|
||||
`diffs_file`
|
||||
`diffs_file`:
|
||||
|
||||
这是可选的,但是,如果你指定它,当应用配置时,它将存储生成的差异。当应用配置时将存储一个生成的差异。当正好更改了主机名,但是,仍然发送了一个完整的配置文件时会生成一个差异,如下的示例:
|
||||
|
||||
@ -867,11 +834,11 @@ Juniper
|
||||
```
|
||||
|
||||
|
||||
上面已经介绍了 playbook 概述的细节。现在,让我们看看当 playbook 运行时发生了什么:
|
||||
上面已经介绍了剧本概述的细节。现在,让我们看看当剧本运行时发生了什么:
|
||||
|
||||
###### 注意
|
||||
> 注意:
|
||||
|
||||
注意:`-i` 标志是用于指定使用的清单文件。也可以设置环境变量 `ANSIBLE_HOSTS`,而不用每次运行 playbook 时都去使用一个 `-i` 标志。
|
||||
> `-i` 标志是用于指定使用的清单文件。也可以设置环境变量 `ANSIBLE_HOSTS`,而不用每次运行剧本时都去使用一个 `-i` 标志。
|
||||
|
||||
```
|
||||
ntc@ntc:~/ansible/multivendor$ ansible-playbook -i inventory demo.yml
|
||||
@ -949,12 +916,11 @@ veos1 : ok=1 changed=0 unreachable=0 failed=0
|
||||
vsrx : ok=1 changed=0 unreachable=0 failed=0
|
||||
```
|
||||
|
||||
注意:这里有 0 个改变,但是,每次运行任务,正如期望的那样,它们都返回 “ok”。说明在这个 playbook 中的每个模块都是幂等的。
|
||||
|
||||
注意:这里有 0 个改变,但是,每次运行任务,正如期望的那样,它们都返回 “ok”。说明在这个剧本中的每个模块都是幂等的。
|
||||
|
||||
### 总结
|
||||
|
||||
Ansible 是一个超级简单的、无代理和可扩展的自动化平台。网络社区持续不断地围绕 Ansible 去重整它作为一个能够执行一些自动化网络任务的平台,比如,做配置管理、数据收集和报告,等等。你可以使用 Ansible 去推送完整的配置文件,配置具体的使用幂等模块的网络资源,比如,接口、VLANs,或者,简单地自动收集信息,比如,领居、序列号、启动时间、和接口状态,以及按你的需要定制一个报告。
|
||||
Ansible 是一个超级简单的、无代理和可扩展的自动化平台。网络社区持续不断地围绕 Ansible 去重整它作为一个能够执行一些自动化网络任务的平台,比如,做配置管理、数据收集和报告,等等。你可以使用 Ansible 去推送完整的配置文件,配置具体的使用幂等模块的网络资源,比如,接口、VLAN,或者,简单地自动收集信息,比如,领居、序列号、启动时间、和接口状态,以及按你的需要定制一个报告。
|
||||
|
||||
因为它的架构,Ansible 被证明是一个在这里可用的、非常好的工具,它可以帮助你实现从传统的基于 _CLI/SNMP_ 的网络设备到基于 _API 驱动_ 的现代化网络设备的自动化。
|
||||
|
||||
@ -968,7 +934,7 @@ Ansible 是一个超级简单的、无代理和可扩展的自动化平台。网
|
||||
|
||||

|
||||
|
||||
Jason Edelman,CCIE 15394 & VCDX-NV 167,出生并成长于新泽西州的一位网络工程师。他是一位典型的 “CLI 爱好者” 和 “路由器小子”。在几年前,他决定更多地关注于软件、开发实践、以及怎么与网络工程融合。Jason 目前经营着一个小的咨询公司,公司名为:Network to Code(http://networktocode.com/),帮助供应商和终端用户利用新的工具和技术来减少他们的低效率操作...
|
||||
Jason Edelman,CCIE 15394 & VCDX-NV 167,出生并成长于新泽西州的一位网络工程师。他是一位典型的 “CLI 爱好者” 和 “路由器小子”。在几年前,他决定更多地关注于软件、开发实践、以及怎么与网络工程融合。Jason 目前经营着一个小的咨询公司,公司名为:Network to Code( http://networktocode.com/ ),帮助供应商和终端用户利用新的工具和技术来减少他们的低效率操作...
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -976,7 +942,7 @@ via: https://www.oreilly.com/learning/network-automation-with-ansible
|
||||
|
||||
作者:[Jason Edelman][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/) 荣誉推出
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||

|
||||
|
||||
今天,我偶然发现了一组用于命令行重度用户的实用 BASH 脚本,这些脚本被称为 **Bash-Snippets**,它们对于那些整天都与终端打交道的人来说可能会很有帮助。想要查看你居住地的天气情况?它为你做了。想知道股票价格?你可以运行显示股票当前详细信息的脚本。觉得无聊?你可以看一些 YouTube 视频。这些全部在命令行中完成,你无需安装任何严重消耗内存的 GUI 应用程序。
|
||||
今天,我偶然发现了一组适用于命令行重度用户的实用 BASH 脚本,这些脚本被称为 **Bash-Snippets**,它们对于那些整天都与终端打交道的人来说可能会很有帮助。想要查看你居住地的天气情况?它为你做了。想知道股票价格?你可以运行显示股票当前详细信息的脚本。觉得无聊?你可以看一些 YouTube 视频。这些全部在命令行中完成,你无需安装任何严重消耗内存的 GUI 应用程序。
|
||||
|
||||
在撰写本文时,Bash-Snippets 提供以下 19 个实用工具:
|
||||
|
||||
@ -29,83 +29,82 @@
|
||||
|
||||
作者可能会在将来添加更多实用程序和/或功能,因此我建议你密切关注该项目的网站或 GitHub 页面以供将来更新。
|
||||
|
||||
### Bash-Snippets – 一组实用 BASH 脚本献给命令行重度用户
|
||||
|
||||
#### 安装
|
||||
### 安装
|
||||
|
||||
你可以在任何支持 BASH 的操作系统上安装这些脚本。
|
||||
|
||||
首先,克隆 git 仓库,使用以下命令:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/alexanderepstein/Bash-Snippets
|
||||
|
||||
```
|
||||
|
||||
进入目录:
|
||||
|
||||
```
|
||||
$ cd Bash-Snippets/
|
||||
|
||||
```
|
||||
|
||||
切换到最新的稳定版本:
|
||||
|
||||
```
|
||||
$ git checkout v1.22.0
|
||||
|
||||
```
|
||||
|
||||
最后,使用以下命令安装 Bash-Snippets:
|
||||
|
||||
```
|
||||
$ sudo ./install.sh
|
||||
|
||||
```
|
||||
|
||||
这将询问你要安装哪些脚本。只需输入**Y** 并按 ENTER 键即可安装相应的脚本。如果你不想安装某些特定脚本,输入 **N** 并按 Enter 键。
|
||||
这将询问你要安装哪些脚本。只需输入 `Y` 并按回车键即可安装相应的脚本。如果你不想安装某些特定脚本,输入 `N` 并按回车键。
|
||||
|
||||
```
|
||||
Do you wish to install currency [Y/n]: y
|
||||
|
||||
```
|
||||
|
||||
要安装所有脚本,运行:
|
||||
|
||||
```
|
||||
$ sudo ./install.sh all
|
||||
|
||||
```
|
||||
|
||||
要安装特定的脚本,比如 currency,运行:
|
||||
|
||||
```
|
||||
$ sudo ./install.sh currency
|
||||
|
||||
```
|
||||
|
||||
你也可以使用 [**Linuxbrew**][1] 包管理器来安装它。
|
||||
你也可以使用 [Linuxbrew][1] 包管理器来安装它。
|
||||
|
||||
安装所有的工具,运行:
|
||||
|
||||
```
|
||||
$ brew install bash-snippets
|
||||
|
||||
```
|
||||
|
||||
安装特定的工具:
|
||||
|
||||
```
|
||||
$ brew install bash-snippets --without-all-tools --with-newton --with-weather
|
||||
|
||||
```
|
||||
|
||||
另外,对于那些基于 Debian 系统的,例如 Ubuntu, Linux Mint,可以添加 PPA 源:
|
||||
另外,对于那些基于 Debian 系统的,例如 Ubuntu、Linux Mint,可以添加 PPA 源:
|
||||
|
||||
```
|
||||
$ sudo add-apt-repository ppa:navanchauhan/bash-snippets
|
||||
$ sudo apt update
|
||||
$ sudo apt install bash-snippets
|
||||
|
||||
```
|
||||
|
||||
#### 用法
|
||||
### 用法
|
||||
|
||||
**需要网络连接**才能使用这些工具。用法很简单。让我们来看看如何使用其中的一些脚本,我假设你已经安装了所有脚本。
|
||||
|
||||
**1\. Currency – 货币转换器**
|
||||
#### 1、 Currency – 货币转换器
|
||||
|
||||
这个脚本根据实时汇率转换货币。输入当前货币代码和要交换的货币,以及交换的金额,如下所示:
|
||||
|
||||
```
|
||||
$ currency
|
||||
What is the base currency: INR
|
||||
@ -118,22 +117,22 @@ What is the amount being exchanged: 10
|
||||
| INR: 10
|
||||
| USD: .154950
|
||||
=========================
|
||||
|
||||
```
|
||||
|
||||
你也可以在单条命令中传递所有参数,如下所示:
|
||||
|
||||
```
|
||||
$ currency INR USD 10
|
||||
|
||||
```
|
||||
|
||||
参考以下屏幕截图:
|
||||
|
||||
[![Bash-Snippets][2]][3]
|
||||
|
||||
**2\. Stocks – 显示股票价格详细信息**
|
||||
#### 2、 Stocks – 显示股票价格详细信息
|
||||
|
||||
如果你想查看一只股票价格的详细信息,输入股票即可,如下所示:
|
||||
|
||||
```
|
||||
$ stocks Intel
|
||||
|
||||
@ -146,79 +145,79 @@ INTC stock info
|
||||
| Price Change Percentage: 0.00%
|
||||
| Last Updated: Jul 12, 4:00PM EDT
|
||||
=============================================
|
||||
|
||||
```
|
||||
|
||||
上面输出了 **Intel 股票** 的详情。
|
||||
|
||||
**3\. Weather – 显示天气详细信息**
|
||||
#### 3、 Weather – 显示天气详细信息
|
||||
|
||||
让我们查看以下天气详细信息,运行以下命令:
|
||||
|
||||
```
|
||||
$ weather
|
||||
|
||||
```
|
||||
|
||||
**示例输出:**
|
||||
示例输出:
|
||||
|
||||
![][4]
|
||||
|
||||
正如你在上面屏幕截图中看到的那样,它提供了 3 天的天气预报。不使用任何参数的话,它将根据你的 IP 地址显示天气详细信息。你还可以显示特定城市或国家/地区的天气详情,如下所示:
|
||||
|
||||
```
|
||||
$ weather Chennai
|
||||
|
||||
```
|
||||
|
||||
同样,你可以查看输入以下命令来从查看月相(月亮的形态):
|
||||
同样,你可以查看输入以下命令来查看月相(月亮的形态):
|
||||
|
||||
```
|
||||
$ weather moon
|
||||
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
![][5]
|
||||
|
||||
**4\. Crypt – 加解密文件**
|
||||
#### 4、 Crypt – 加解密文件
|
||||
|
||||
此脚本对 openssl 做了一层包装,允许你快速轻松地加密和解密文件。
|
||||
|
||||
要加密文件,使用以下命令:
|
||||
|
||||
```
|
||||
$ crypt -e [original file] [encrypted file]
|
||||
|
||||
```
|
||||
|
||||
例如,以下命令将加密 **ostechnix.txt**,并将其保存在当前工作目录下,名为 **encrypt_ostechnix.txt**。
|
||||
例如,以下命令将加密 `ostechnix.txt`,并将其保存在当前工作目录下,名为 `encrypt_ostechnix.txt`。
|
||||
|
||||
```
|
||||
$ crypt -e ostechnix.txt encrypt_ostechnix.txt
|
||||
|
||||
```
|
||||
|
||||
输入两次文件密码:
|
||||
|
||||
```
|
||||
Encrypting ostechnix.txt...
|
||||
enter aes-256-cbc encryption password:
|
||||
Verifying - enter aes-256-cbc encryption password:
|
||||
Successfully encrypted
|
||||
|
||||
```
|
||||
|
||||
上面命令将使用 **AES 256 位密钥**加密给定文件。密码不会以纯文本格式保存。你可以加密 .pdf, .txt, .docx, .doc, .png, .jpeg 类型的文件。
|
||||
上面命令将使用 **AES 256 位密钥**加密给定文件。密码不要保存在纯文本文件中。你可以加密 .pdf、.txt、 .docx、 .doc、 .png、 .jpeg 类型的文件。
|
||||
|
||||
要解密文件,使用以下命令:
|
||||
|
||||
```
|
||||
$ crypt -d [encrypted file] [output file]
|
||||
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```
|
||||
$ crypt -d encrypt_ostechnix.txt ostechnix.txt
|
||||
|
||||
```
|
||||
|
||||
输入密码解密:
|
||||
|
||||
```
|
||||
Decrypting encrypt_ostechnix.txt...
|
||||
enter aes-256-cbc decryption password:
|
||||
@ -226,11 +225,12 @@ Successfully decrypted
|
||||
|
||||
```
|
||||
|
||||
**5\. Movies – 查看电影详情**
|
||||
#### 5、 Movies – 查看电影详情
|
||||
|
||||
使用这个脚本,你可以查看电影详情。
|
||||
|
||||
以下命令显示了一部名为 “mother” 的电影的详情:
|
||||
|
||||
```
|
||||
$ movies mother
|
||||
|
||||
@ -244,51 +244,51 @@ $ movies mother
|
||||
| Actors: Hye-ja Kim, Bin Won, Goo Jin, Je-mun Yun
|
||||
| Plot: A mother desperately searches for the killer who framed her son for a girl's horrific murder.
|
||||
==================================================
|
||||
|
||||
```
|
||||
|
||||
**6\. 显示类似条目**
|
||||
#### 6、 显示类似条目
|
||||
|
||||
要使用这个脚本,你需要从**[这里][6]** 获取 API 密钥。不过不用担心,它完全是免费的。一旦你获得 API 密钥后,将以下行添加到 **~/.bash_profile**:**export TASTE_API_KEY=”你的 API 密钥放在这里”**
|
||||
要使用这个脚本,你需要从**[这里][6]** 获取 API 密钥。不过不用担心,它完全是免费的。一旦你获得 API 密钥后,将以下行添加到 `~/.bash_profile`:`export TASTE_API_KEY=”你的 API 密钥放在这里”`。(LCTT 译注: TasteDive 是一个推荐引擎,它会根据你的品味推荐相关项目。)
|
||||
|
||||
现在你可以根据你提供的项目查看类似项目,如下所示:
|
||||
|
||||
现在你可以查看类似的项目,如提供的项目,如下所示:(to 校正者:不理解这个脚本的意思肿么办)
|
||||
```
|
||||
$ taste -i Red Hot Chilli Peppers
|
||||
|
||||
```
|
||||
|
||||
**7\. Short – 缩短 URL**
|
||||
#### 7、 Short – 缩短 URL
|
||||
|
||||
这个脚本会缩短给定的 URL。
|
||||
|
||||
```
|
||||
$ short <URL>
|
||||
|
||||
```
|
||||
|
||||
**8\. Geo – 显示网络的详情**
|
||||
#### 8、 Geo – 显示网络的详情
|
||||
|
||||
|
||||
这个脚本会帮助你查找网络的详细信息,例如 wan, lan, router, dns, mac 和 ip 地址。
|
||||
这个脚本会帮助你查找网络的详细信息,例如广域网、局域网、路由器、 dns、mac 地址和 ip 地址。
|
||||
|
||||
例如,要查找你的局域网 ip,运行:
|
||||
|
||||
```
|
||||
$ geo -l
|
||||
|
||||
```
|
||||
|
||||
我系统上的输出:
|
||||
|
||||
```
|
||||
192.168.43.192
|
||||
|
||||
```
|
||||
|
||||
查看广域网 ip:
|
||||
|
||||
```
|
||||
$ geo -w
|
||||
|
||||
```
|
||||
|
||||
在终端中输入 `geo` 来查看更多详细信息。
|
||||
|
||||
```
|
||||
$ geo
|
||||
Geo
|
||||
@ -311,27 +311,26 @@ Example: geo -a 8.8.8.8 -o city,zip,isp
|
||||
-v Returns Version
|
||||
-h Returns Help Screen
|
||||
-u Updates Bash-Snippets
|
||||
|
||||
```
|
||||
|
||||
**9\. Cheat – 显示 Linux 命令的备忘单**
|
||||
#### 9、 Cheat – 显示 Linux 命令的备忘单
|
||||
|
||||
想参考 Linux 命令的备忘单吗?这是可能的。以下命令将显示 `curl` 命令的备忘单:
|
||||
|
||||
想参考 Linux 命令的备忘单吗?这是可能的。以下命令将显示 **curl** 命令的备忘单:
|
||||
```
|
||||
$ cheat curl
|
||||
|
||||
```
|
||||
|
||||
只需用你选择的命令替换 **curl** 即可显示其备忘单。这对于快速参考你要使用的任何命令非常有用。
|
||||
只需用你选择的命令替换 `curl` 即可显示其备忘单。这对于快速参考你要使用的任何命令非常有用。
|
||||
|
||||
**10\. Youtube-Viewer – 观看 YouTube 视频**
|
||||
#### 10、 Youtube-Viewer – 观看 YouTube 视频
|
||||
|
||||
使用此脚本,你可以直接在终端上搜索或观看 YouTube 视频。
|
||||
使用此脚本,你可以直接在终端上搜索或打开 YouTube 视频。(LCTT 译注:在媒体播放器中,而不是文本的终端中打开)
|
||||
|
||||
让我们来看一些有关 **Ed Sheeran** 的视频。
|
||||
|
||||
```
|
||||
$ ytview Ed Sheeran
|
||||
|
||||
```
|
||||
|
||||
从列表中选择要播放的视频。所选内容将在你的默认媒体播放器中播放。
|
||||
@ -339,43 +338,43 @@ $ ytview Ed Sheeran
|
||||
![][7]
|
||||
|
||||
要查看艺术家的近期视频,你可以使用:
|
||||
|
||||
```
|
||||
$ ytview -c [channel name]
|
||||
|
||||
```
|
||||
|
||||
要寻找视频,只需输入:
|
||||
|
||||
```
|
||||
$ ytview -s [videoToSearch]
|
||||
|
||||
```
|
||||
|
||||
或者:
|
||||
|
||||
```
|
||||
$ ytview [videoToSearch]
|
||||
|
||||
```
|
||||
|
||||
**11\. cloudup – 备份p GitHub 仓库到 bitbucket**
|
||||
#### 11、 cloudup – 备份 GitHub 仓库到 bitbucket
|
||||
|
||||
你在 GitHub 上托管过任何项目吗?如果托管过,那么你可以随时间 GitHub 仓库备份到 **bitbucket**,它是一种用于源代码和开发项目的基于 Web 的托管服务。
|
||||
|
||||
你可以使用 **-a** 选项一次性备份指定用户的所有 GitHub 仓库,或者不使用它来备份单个仓库。
|
||||
你可以使用 `-a` 选项一次性备份指定用户的所有 GitHub 仓库,或者备份单个仓库。
|
||||
|
||||
要备份 GitHub 仓库,运行:
|
||||
|
||||
```
|
||||
$ cloudup
|
||||
|
||||
```
|
||||
|
||||
系统将要求你输入 GitHub 用户名, 要备份的仓库名称以及 bitbucket 用户名和密码等。
|
||||
|
||||
**12\. Qrify – 将字符串转换为二维码**
|
||||
#### 12、 Qrify – 将字符串转换为二维码
|
||||
|
||||
这个脚本将任何给定的文本字符串转换为二维码。这对于发送链接或者保存一串命令到手机非常有用。
|
||||
|
||||
```
|
||||
$ qrify convert this text into qr code
|
||||
|
||||
```
|
||||
|
||||
示例输出:
|
||||
@ -384,108 +383,110 @@ $ qrify convert this text into qr code
|
||||
|
||||
很酷,不是吗?
|
||||
|
||||
**13\. Cryptocurrency**
|
||||
#### 13、 Cryptocurrency
|
||||
|
||||
它将显示十大加密货币实时汇率。
|
||||
|
||||
输入以下命令,然后单击 ENTER 来运行:
|
||||
输入以下命令,然后单击回车来运行:
|
||||
|
||||
```
|
||||
$ cryptocurrency
|
||||
|
||||
```
|
||||
|
||||
![][9]
|
||||
|
||||
|
||||
**14\. Lyrics**
|
||||
#### 14、 Lyrics
|
||||
|
||||
这个脚本从命令行快速获取一首歌曲的歌词。
|
||||
|
||||
例如,我将获取 **“who is it”** 歌曲的歌词,这是一首由 **Michael Jackson(迈克尔·杰克逊)** 演唱的流行歌曲。
|
||||
例如,我将获取 “who is it” 歌曲的歌词,这是一首由 <ruby>迈克尔·杰克逊<rt>Michael Jackson</rt></ruby> 演唱的流行歌曲。
|
||||
|
||||
```
|
||||
$ lyrics -a michael jackson -s who is it
|
||||
|
||||
```
|
||||
|
||||
![][10]
|
||||
|
||||
**15\. Meme**
|
||||
这个脚本允许你从命令行创建简单的表情包。它比基于 GUI 的表情包生成器快得多。
|
||||
#### 15、 Meme
|
||||
|
||||
这个脚本允许你从命令行创建简单的表情贴图。它比基于 GUI 的表情包生成器快得多。
|
||||
|
||||
要创建一个表情贴图,只需输入:
|
||||
|
||||
要创建一个表情包,只需输入:
|
||||
```
|
||||
$ meme -f mymeme
|
||||
Enter the name for the meme's background (Ex. buzz, doge, blb ): buzz
|
||||
Enter the text for the first line: THIS IS A
|
||||
Enter the text for the second line: MEME
|
||||
|
||||
```
|
||||
|
||||
这将在你当前的工作目录创建 jpg 文件。
|
||||
|
||||
**16\. Newton**
|
||||
#### 16、 Newton
|
||||
|
||||
厌倦了解决复杂的数学问题?你来对了。Newton 脚本将执行数值计算,直到符号数学解析。(to 校正者:这里不太理解)
|
||||
厌倦了解决复杂的数学问题?你来对了。Newton 脚本将执行数值计算,乃至于符号数学解析。
|
||||
|
||||
![][11]
|
||||
|
||||
**17\. Siteciphers**
|
||||
#### 17、 Siteciphers
|
||||
|
||||
这个脚本可以帮助你检查在给定的 https 站点上启用/禁用哪些加密算法。(LCTT 译注:指 HTTPS 通讯中采用的加密算法)
|
||||
|
||||
这个脚本可以帮助你检查在给定的 https 站点上启用/禁用哪些密码。
|
||||
```
|
||||
$ siteciphers google.com
|
||||
|
||||
```
|
||||
|
||||
![][12]
|
||||
|
||||
**18\. Todo**
|
||||
#### 18、 Todo
|
||||
|
||||
它允许你直接从终端创建日常任务。
|
||||
|
||||
让我们来创建一些任务。
|
||||
|
||||
```
|
||||
$ todo -a The first task
|
||||
01). The first task Tue Jun 26 14:51:30 IST 2018
|
||||
|
||||
```
|
||||
|
||||
要添加其它任务,只需添加任务名称重新运行上述命令即可。
|
||||
|
||||
```
|
||||
$ todo -a The second task
|
||||
01). The first task Tue Jun 26 14:51:30 IST 2018
|
||||
02). The second task Tue Jun 26 14:52:29 IST 2018
|
||||
|
||||
```
|
||||
|
||||
要查看任务列表,运行:
|
||||
|
||||
```
|
||||
$ todo -g
|
||||
01). The first task Tue Jun 26 14:51:30 IST 2018
|
||||
02). A The second task Tue Jun 26 14:51:46 IST 2018
|
||||
|
||||
```
|
||||
|
||||
一旦你完成了任务,就可以将其从列表中删除,如下所示:
|
||||
|
||||
```
|
||||
$ todo -r 2
|
||||
Sucessfully removed task number 2
|
||||
01). The first task Tue Jun 26 14:51:30 IST 2018
|
||||
|
||||
```
|
||||
|
||||
要清除所有任务,运行:
|
||||
|
||||
```
|
||||
$ todo -c
|
||||
Tasks cleared.
|
||||
|
||||
```
|
||||
|
||||
**19\. Transfer**
|
||||
#### 19、 Transfer
|
||||
|
||||
Transfer 脚本允许你通过 Internet 快速轻松地传输文件和目录。
|
||||
Transfer 脚本允许你通过互联网快速轻松地传输文件和目录。
|
||||
|
||||
让我们上传一个文件:
|
||||
|
||||
```
|
||||
$ transfer test.txt
|
||||
Uploading test.txt
|
||||
@ -493,29 +494,30 @@ Uploading test.txt
|
||||
Success!
|
||||
Transfer Download Command: transfer -d desiredOutputDirectory ivmfj test.txt
|
||||
Transfer File URL: https://transfer.sh/ivmfj/test.txt
|
||||
|
||||
```
|
||||
|
||||
该文件将上传到 transfer.sh 站点。Transfer.sh 允许你一次上传最大 **10 GB** 的文件。所有共享文件在 **14 天**后自动过期。如你所见,任何人都可以通过 Web 浏览器访问 URL 或使用 transfer 目录来下载文件,当然,transfer 必须安装在他/她的系统中。
|
||||
|
||||
现在从你的系统中移除文件。
|
||||
|
||||
```
|
||||
$ rm -fr test.txt
|
||||
|
||||
```
|
||||
|
||||
现在,你可以随时(14 天内)从 transfer.sh 站点下载该文件,如下所示:
|
||||
|
||||
```
|
||||
$ transfer -d Downloads ivmfj test.txt
|
||||
|
||||
```
|
||||
|
||||
获取关于此实用脚本的更多详情,参考以下指南。
|
||||
* [从命令行在 Internet 上共享文件的一个简单快捷方法](https://www.ostechnix.com/easy-fast-way-share-files-internet-command-line/)
|
||||
|
||||
##### 获得帮助
|
||||
* [用命令行在互联网上共享文件的一个简单快捷方法](https://www.ostechnix.com/easy-fast-way-share-files-internet-command-line/)
|
||||
|
||||
### 获得帮助
|
||||
|
||||
如果你不知道如何使用特定脚本,只需输入该脚本的名称,然后按下 ENTER 键,你将会看到使用细节。以下示例显示 Qrify 脚本的帮助信息。
|
||||
|
||||
如果你不知道如何使用特定脚本,只需输入该脚本的名称,然后按下 ENTER 键,你将会看到使用细节。以下示例显示 **Qrify** 脚本的帮助信息。
|
||||
```
|
||||
$ qrify
|
||||
Qrify
|
||||
@ -532,44 +534,46 @@ Examples:
|
||||
|
||||
```
|
||||
|
||||
#### 更新脚本
|
||||
### 更新脚本
|
||||
|
||||
你可以随时使用 `-u` 选项更新已安装的工具。以下命令更新 “weather” 工具。
|
||||
|
||||
你可以随时使用 -u 选项更新已安装的工具。以下命令更新 “weather” 工具。
|
||||
```
|
||||
$ weather -u
|
||||
|
||||
```
|
||||
|
||||
#### 卸载
|
||||
### 卸载
|
||||
|
||||
你可以使用以下命令来卸载这些工具。
|
||||
|
||||
克隆仓库:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/alexanderepstein/Bash-Snippets
|
||||
|
||||
```
|
||||
|
||||
进入 Bash-Snippets 目录:
|
||||
|
||||
```
|
||||
$ cd Bash-Snippets
|
||||
|
||||
```
|
||||
|
||||
运行以下命令来卸载脚本:
|
||||
|
||||
```
|
||||
$ sudo ./uninstall.sh
|
||||
|
||||
```
|
||||
|
||||
输入 **y**,并按下 ENTER 键来移除每个脚本。
|
||||
输入 `y`,并按下回车键来移除每个脚本。
|
||||
|
||||
```
|
||||
Do you wish to uninstall currency [Y/n]: y
|
||||
|
||||
```
|
||||
|
||||
**另请阅读:**
|
||||
|
||||
- [Cli.Fyi —— 快速而简单地获取诸如 IP、电子邮件、域名等信息的方式](https://www.ostechnix.com/cli-fyi-quick-easy-way-fetch-information-ips-emails-domains-lots/)
|
||||
|
||||
好了,这就是全部了。我必须承认,在测试这些脚本时我印象很深刻。我真的很喜欢将所有有用的脚本组合到一个包中的想法。感谢开发者。试一试,你不会失望的。
|
||||
|
||||
干杯!
|
||||
@ -581,7 +585,7 @@ via: https://www.ostechnix.com/collection-useful-bash-scripts-heavy-commandline-
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[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/) 荣誉推出
|
||||
|
@ -5,13 +5,13 @@ Python 是为谁设计的?
|
||||
|
||||
几年前,我在 python-dev 邮件列表中,以及在活跃的 CPython 核心开发人员和认为参与这一过程不是有效利用个人时间和精力的人中[强调][17]说,“CPython 的发展太快了也太慢了” 是很多冲突的原因之一。
|
||||
|
||||
我一直认为事实确实如此,但这也是一个要点,在这几年中我也花费了很多时间去反思它。在我写那篇文章的时候,我还在波音防务澳大利亚公司(Boeing Defence Australia)工作。下个月,我离开了波音进入红帽亚太(Red Hat Asia-Pacific),并且开始在大企业的[开源供应链管理][18]方面收获了<ruby>再分发者<rt>redistributor</rt></ruby>层面的视角。
|
||||
我一直认为事实确实如此,但这也是一个要点,在这几年中我也花费了很多时间去反思它。在我写那篇文章的时候,我还在波音防务澳大利亚公司(Boeing Defence Australia)工作。下个月,我离开了波音进入红帽亚太(Red Hat Asia-Pacific),并且开始在大企业的[开源供应链管理][18]方面取得了<ruby>再分发者<rt>redistributor</rt></ruby>层面的视角。
|
||||
|
||||
### Python 的参考解析器使用情况
|
||||
|
||||
我尝试将 CPython 的使用情况分解如下,尽管看起来有些过于简化(注意,这些分类的界线并不是很清晰,他们仅关注于考虑新软件特性和版本发布后不同因素的影响):
|
||||
|
||||
* 教育类:教育工作者的主要兴趣在于建模方法的教学和计算操作方面,不会去编写或维护生产级别的软件。例如:
|
||||
* 教育类:教育工作者的主要兴趣在于建模方法的教学和计算操作方面,*不会去*编写或维护生产级别的软件。例如:
|
||||
* 澳大利亚的[数字课程][1]
|
||||
* Lorena A. Barba 的 [AeroPython][2]
|
||||
* 个人类的自动化和爱好者的项目:主要且经常是一类自写自用的软件。例如:
|
||||
@ -31,7 +31,7 @@ Python 是为谁设计的?
|
||||
* 大多数的公共 PaaS 无服务器环境(Heroku、OpenShift、AWS Lambda、Google Cloud Functions、Azure Cloud Functions 等等)
|
||||
* 长周期性升级的标准的操作环境:对其核心组件进行常规升级,但这些升级以年为单位进行,而不是周或月。例如:
|
||||
* [VFX 平台][6]
|
||||
* <ruby>长期支持<rt>LTS</rt></ruby>的 Linux 分发版
|
||||
* 长期支持(LTS)的 Linux 分发版
|
||||
* CPython 和 Python 标准库
|
||||
* 基础设施管理和编排工具(如 OpenStack、Ansible)
|
||||
* 硬件控制系统
|
||||
@ -47,8 +47,8 @@ Python 是为谁设计的?
|
||||
* 多用户游戏,和其它明显处于持续状态还没有被定义为 “终止” 的游戏
|
||||
* 有自动升级功能的嵌入式软件系统
|
||||
* 共享的抽象层:在一个特定的问题领域中,设计用于让工作更高效的软件组件。即便是你没有亲自掌握该领域的所有错综复杂的东西。例如:
|
||||
* 大多数的<ruby>运行时<rt>runtime</rt></ruby>库都归入这一类的框架(如 Django、Flask、Pyramid、SQL Alchemy、NumPy、SciPy、requests)
|
||||
* 适合归入这一类的许多测试和类型接口工具(如 pytest、Hypothesis、vcrpy、behave、mypy)
|
||||
* 大多数的<ruby>运行时<rt>runtime</rt></ruby>库和框架都归入这一类(如 Django、Flask、Pyramid、SQL Alchemy、NumPy、SciPy、requests)
|
||||
* 适合归入这一类的许多测试和类型推断工具(如 pytest、Hypothesis、vcrpy、behave、mypy)
|
||||
* 其它应用程序的插件(如 Blender plugins、OpenStack hardware adapters)
|
||||
* 本身就代表了 “Python 世界” 基准的标准库(那是一个[难以置信的复杂][7]的世界观)
|
||||
|
||||
@ -61,11 +61,11 @@ Python 是为谁设计的?
|
||||
把 Python 作为一种脚本语言来使用的开发者的典型特性包括:
|
||||
|
||||
* 主要的工作单元是由一个 Python 文件组成的(或 Jupyter notebook),而不是一个 Python 和元数据文件的目录
|
||||
* 没有任何形式的单独的构建步骤 —— 是作为一个脚本分发的,类似于分发一个独立的 shell 脚本的方式
|
||||
* 没有任何形式的单独的构建步骤 —— 是*作为*一个脚本分发的,类似于分发一个独立的 shell 脚本的方式
|
||||
* 没有单独的安装步骤(除了下载这个文件到一个合适的位置),因为在目标系统上要求预配置运行时环境
|
||||
* 没有显式的规定依赖关系,除了最低的 Python 版本,或一个预期的运行环境声明。如果需要一个标准库以外的依赖项,他们会通过一个环境脚本去提供(无论是操作系统、数据分析平台、还是嵌入 Python 运行时的应用程序)
|
||||
* 没有单独的测试套件,使用 “通过你给定的输入,这个脚本是否给出了你期望的结果?” 这种方式来进行测试
|
||||
* 如果在执行前需要测试,它将以<ruby>试运行<rt>dry run></rt></ruby>和<ruby>预览<rt>preview</rt></ruby>模式来向用户展示软件将怎样运行
|
||||
* 如果在执行前需要测试,它将以<ruby>试运行<rt>dry run></rt></ruby>和<ruby>预览<rt>preview</rt></ruby>模式来向用户展示软件*将*怎样运行
|
||||
* 如果使用静态代码分析工具,则通过集成到用户的软件开发环境中,而不是为每个脚本单独设置
|
||||
|
||||
相比之下,使用 Python 作为一个应用程序开发语言的开发者特征包括:
|
||||
@ -97,7 +97,7 @@ Python 是为谁设计的?
|
||||
|
||||
### 适合进入 PyPI 规划的方面有哪些?
|
||||
|
||||
任何提交给 python-ideas 或 python-dev 的提案所面临的第一个门槛就是清楚地回答这个问题:“为什么 PyPI 上的模块不够好?”。绝大多数的提案都在这一步失败了,为了通过这一步,这里有几个常见的话题:
|
||||
*任何*提交给 python-ideas 或 python-dev 的提案所面临的第一个门槛就是清楚地回答这个问题:“为什么 PyPI 上的模块不够好?”。绝大多数的提案都在这一步失败了,为了通过这一步,这里有几个常见的话题:
|
||||
|
||||
* 比起下载一个合适的第三方库,新手一般可能更倾向于从互联网上 “复制粘贴” 错误的指导。(这就是为什么存在 `secrets` 库的原因:它使得人们很少去使用 `random` 模块,由于安全敏感的原因,它预期用于游戏和模拟统计)
|
||||
* 该模块旨在提供一个参考实现,并允许与其它的竞争实现之间提供互操作性,而不是对所有人的所有事物都是必要的。(如 `asyncio`、`wsgiref`、`unittest`、和 `logging` 都是这种情况)
|
||||
@ -114,7 +114,7 @@ Python 是为谁设计的?
|
||||
|
||||
现有的第三方模块有时候会被批量地采用到标准库中,在其它情况下,实际上添加的是吸收了用户对现有 API 体验之后进行重新设计和重新实现的 API,但是会根据另外的设计考虑和已经成为其中一部分的语言实现参考来进行一些删除或细节修改。
|
||||
|
||||
例如,与流行的第三方库 `path.py`、`pathlib` 的前身不同,它们并没有定义字符串子类,而是以独立的类型替代。作为解决文件互操作性问题的结果,定义了文件系统路径协议,它允许使用文件系统路径的接口去使用更多的对象。
|
||||
例如,与流行的第三方库 `path.py`、`pathlib` 的前身不同,它们并*没有*定义字符串子类,而是以独立的类型替代。作为解决文件互操作性问题的结果,定义了文件系统路径协议,它允许使用文件系统路径的接口去使用更多的对象。
|
||||
|
||||
为了在 “IP 地址” 这个概念的教学上提供一个更好的工具,`ipaddress` 模块设计调整为明确地将主机接口定义与地址和网络的定义区分开(IP 地址被关联到特定的 IP 网络),而最原始的 `ipaddr` 模块中,在网络术语的使用方式上不那么严格。
|
||||
|
@ -1,49 +1,50 @@
|
||||
用于与非 Linux 用户合作的 Linux 命令行工具
|
||||
用于与非 Linux 用户一同工作的 Linux 命令行工具
|
||||
======
|
||||
> 如果你在 Linux 终端工作,那么与非 Linux 用户一同工作时可能遇到困难。这些工具有助于文档兼容性和企业即时消息。
|
||||
|
||||

|
||||
我大部分时间都在使用 Shell(命令行,终端或其他不管在你使用的平台上的名称)上。但是,当我需要与大量其他人合作时,这可能会有点挑战,特别是在大型企业公司中 - 除了 shell 外其他都使用。
|
||||
|
||||
当公司内的其他人使用与你不同的平台时,问题就会变得更加严重。我倾向于使用 Linux。如果我在 Linux 终端上做了很多日常工作,而我的大多数同事都使用 Windows 10(完全使用 GUI 端),那么事情就会变得有问题。
|
||||
我大部分时间都在使用 Shell(命令行、终端或其它随便什么你使用的平台)上。但是,当我需要与大量其他人合作时,这可能会有点挑战,特别是在大型企业公司中 —— 除了 shell 外其他都使用。
|
||||
|
||||
**Network World 上另外一篇文章:**[**11 个没用但很酷的 Linux 终端技巧**][1]
|
||||
当公司内的其他人使用与你不同的平台时,问题就会变得更加严重。我倾向于使用 Linux。如果我在 Linux 终端上做了很多日常工作,而我的大多数同事都使用 Windows 10(完全使用 GUI 端),那么事情就会变得……有问题。
|
||||
|
||||
幸运的是,在过去的几年里,我已经想出如何处理这些问题。我已经找到了在非 Unix 的企业环境中使用 Linux(或其他类 Unix 系统)Shell 的方法。这些工具/技巧同样适用于在公司服务器上工作的系统管理员s,就像对开发人员或营销人员一样。。
|
||||
- **Network World 上另外一篇文章:**[**11 个没用但很酷的 Linux 终端技巧**][1]
|
||||
|
||||
## 用于与非 Linux 用户合作的 Linux 命令行工具
|
||||
幸运的是,在过去的几年里,我已经想出如何处理这些问题。我已经找到了在非 Unix 的企业环境中使用 Linux(或其他类 Unix 系统)Shell 的方法。这些工具/技巧同样适用于在公司服务器上工作的系统管理员们,就像对开发人员或营销人员一样。
|
||||
|
||||
让我们首先关注对于大公司中的许多人来说似乎最难解决的两个方面:文档兼容性和企业即时消息。
|
||||
|
||||
### Linux 和非 Linux 系统之间的文档兼容性
|
||||
|
||||
出现的最大问题之一是简单的文字处理文档兼容性。
|
||||
出现的最大问题之一是简单的文字处理文档的兼容性。
|
||||
|
||||
假设你的公司已在 Microsoft Office 上进行了标准化。这让你难过。但不要失去希望!有很多方法可以使它(基本)可用 - 甚至在 shell 中。
|
||||
假设你的公司已在 Microsoft Office 上进行了标准化。这让你难过。但不要失去希望!有很多方法可以使它(基本)可用 —— 甚至在 shell 中。
|
||||
|
||||
两个工具在我的武器库中至关重要:[Pandoc][2] 和 [Wordgrinder][3]。
|
||||
|
||||
Wordgrinder 是一个简单,直观的文字处理器。它可能不像 LibreOffice 那样功能齐全(或者,实际上,任何主要的 GUI 文字处理应用程序),但速度很快。它很稳定。它有足够的功能(和文件格式)来完成工作。事实上,我完全在 Wordgrinder 中写了我的大部分文章和书籍。
|
||||
Wordgrinder 是一个简单、直观的文字处理器。它可能不像 LibreOffice 那样功能齐全(或者,实际上,任何主要的 GUI 文字处理应用程序),但速度很快。它很稳定。它有足够的功能(和文件格式)来完成工作。事实上,我完全在 Wordgrinder 中写了我的大部分文章和书籍。
|
||||
|
||||
但是有一个问题(你知道肯定会有)。
|
||||
|
||||
Wordgrinder 不支持 .doc(或 .docx)文件。这意味着它无法读取使用 Windows 和 MS Office 的同事发送给你的大多数文件。
|
||||
|
||||
这就是P andoc 的用武之地。它是一个简单的文档转换器,可以将各种文件作为输入(MS Word、LibreOffice、HTML、markdown 等)并将它们转换为其他内容。它支持的格式数量绝对是惊人的 - PDF、ePub、各种幻灯片格式。它确实使格式之间的文档转换变得轻而易举。
|
||||
这就是 Pandoc 的用武之地。它是一个简单的文档转换器,可以将各种文件作为输入(MS Word、LibreOffice、HTML、markdown 等)并将它们转换为其他内容。它支持的格式数量绝对是惊人的 —— PDF、ePub、各种幻灯片格式。它确实使格式之间的文档转换变得轻而易举。
|
||||
|
||||
这并不是说我不会偶尔遇到格式或功能问题。转换有大量自定义格式,某些脚本和嵌入式图表的 Word 文档?是的,在这个过程中会丢失很多。
|
||||
这并不是说我不会偶尔遇到格式或功能问题。要转换有大量自定义格式、某些脚本和嵌入式图表的 Word 文档?是的,在这个过程中会丢失很多。
|
||||
|
||||
但实际上,Pandoc(用于转换文件)和 Wordgrinder(用于文档编辑)的组合已经证明非常有用和强大。
|
||||
|
||||
### Linux 和非 Linux 系统之间的企业即时消息传递
|
||||
|
||||
每家公司都喜欢在即时通讯系统上实现标准化 - 所有员工都可以使用它来保持实时联系。
|
||||
每家公司都喜欢在即时通讯系统上实现标准化 —— 所有员工都可以使用它来保持实时联系。
|
||||
|
||||
在命令行中,这可能会变得棘手。如果贵公司使用 Google 环聊怎么办?或者 Novell GroupWise Messenger 怎么样?既没有官方支持,也没有基于终端的客户端。
|
||||
|
||||
谢天谢地,还有[ Finch 和 Hangups][4]。
|
||||
谢天谢地,还有 [Finch 和 Hangups][4]。
|
||||
|
||||
Finch 是 Pidgin(开源,多协议消息客户端)的终端版本。它支持各种协议,包括 Novell GroupWise、(很快会死)AOL Instant Messenger 以及其他一些协议。
|
||||
Finch 是 Pidgin(开源,多协议消息客户端)的终端版本。它支持各种协议,包括 Novell GroupWise、(很快会死的)AOL Instant Messenger 以及其他一些协议。
|
||||
|
||||
而 Hangups 是 Google Hangouts 客户端的开源实现 - 包含消息历史记录和精美的标签界面。
|
||||
而 Hangups 是 Google Hangouts 客户端的开源实现 —— 包含消息历史记录和精美的标签界面。
|
||||
|
||||
这些方案都不会为你提供语音或视频聊天功能,但对于基于文本的消息,它们的工作得非常好。它们并不完美(Finch 的用户界面需要时间习惯),但它们肯定足以与你的同事保持联系。
|
||||
|
||||
@ -58,7 +59,7 @@ via: https://www.networkworld.com/article/3235688/linux/linux-command-line-tools
|
||||
|
||||
作者:[Bryan Lunduke][a]
|
||||
译者:[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/) 荣誉推出
|
||||
|
@ -1,22 +1,24 @@
|
||||
使用 Docker 的 User Namespaces 功能
|
||||
使用 Docker 的用户名字空间功能
|
||||
======
|
||||
User Namespaces 于 Docker1.10 版正式纳入其中,该功能允许主机系统将自身的 `uid` 和 `gid` 映射为容器进程中的另一个其他 `uid` 和 `gid`。这对 Docker 的安全性来说是一项巨大的改进。下面我会通过一个案例来展示一下 User Namespaces 能够解决的问题,以及如何启用该功能。
|
||||
|
||||
<ruby>用户名字空间<rt>User Namespaces</rt></ruby> 于 Docker 1.10 版本正式纳入其中,该功能允许主机系统将自身的 `uid` 和 `gid` 映射为容器进程中的另一个 `uid` 和 `gid`。这对 Docker 的安全性来说是一项巨大的改进。下面我会通过一个案例来展示一下用户名字空间能够解决的问题,以及如何启用该功能。
|
||||
|
||||
### 创建一个 Docker Machine
|
||||
|
||||
如果你已经创建好了一台用来实验 User Namespaces 的 docker machine,那么可以跳过这一步。我在自己的 Macbook 上安装了 Docker Toolbox,因此我只需要使用 `docker-machine` 命令就很简单地创建一个基于 VirtualBox 的 Docker Machine( 这里假设主机名为 `host1`):
|
||||
如果你已经创建好了一台用来试验用户名字空间的 docker <ruby>机器<rt>Machine</rt></ruby>,那么可以跳过这一步。我在自己的 Macbook 上安装了 Docker Toolbox,因此我只需用 `docker-machine` 命令就很简单地创建一个基于 VirtualBox 的 Docker 机器(这里假设主机名为 `host1`):
|
||||
|
||||
```
|
||||
# Create host1
|
||||
$ docker-machine create --driver virtualbox host1
|
||||
|
||||
# Login to host1
|
||||
$ docker-machine ssh host1
|
||||
|
||||
```
|
||||
|
||||
### 理解在 User Napespaces 未启用的情况下,非 root 用户能够做什么
|
||||
### 理解在用户名字空间未启用的情况下,非 root 用户能做什么
|
||||
|
||||
在启用用户名字空间前,我们先来看一下会有什么问题。Docker 到底哪个地方做错了?首先,使用 Docker 的一大优势在于用户在容器中可以拥有 root 权限,因此用户可以很方便地安装软件包。但是在 Linux 容器技术中这也是一把双刃剑。只要经过少许操作,非 root 用户就能以 root 的权限访问主机系统中的内容,比如 `/etc`。下面是操作步骤。
|
||||
|
||||
在启用 User Namespaces 前,我们先来看一下会有什么问题。Docker 到底哪个地方做错了?首先,使用 Docker 的一大优势在于用户在容器中可以拥有 root 权限,因此用户可以很方便地安装软件包。但是该项 Linux 容器技术是一把双刃剑。只要经过少许操作,非 root 用户就能以 root 的权限访问主机系统中的内容,比如 `/etc` . 下面是操作步骤。
|
||||
```
|
||||
# Run a container and mount host1's /etc onto /root/etc
|
||||
$ docker run --rm -v /etc:/root/etc -it ubuntu
|
||||
@ -29,12 +31,12 @@ root@34ef23438542:/# exit
|
||||
|
||||
# Check /etc/hosts
|
||||
$ cat /etc/hosts
|
||||
|
||||
```
|
||||
|
||||
你可以看到,步骤简单到难以置信,很明显 Docker 并不适用于运行在多人共享的电脑上。但是现在,通过 User Namespaces,Docker 可以让你避免这个问题。
|
||||
你可以看到,步骤简单到难以置信,很明显 Docker 并不适用于运行在多人共享的电脑上。但是现在,通过用户名字空间,Docker 可以避免这个问题。
|
||||
|
||||
### 启用用户名字空间
|
||||
|
||||
### 启用 User Namespaces
|
||||
```
|
||||
# Create a user called "dockremap"
|
||||
$ sudo adduser dockremap
|
||||
@ -42,42 +44,39 @@ $ sudo adduser dockremap
|
||||
# Setup subuid and subgid
|
||||
$ sudo sh -c 'echo dockremap:500000:65536 > /etc/subuid'
|
||||
$ sudo sh -c 'echo dockremap:500000:65536 > /etc/subgid'
|
||||
|
||||
```
|
||||
|
||||
然后,打开 `/etc/init.d/docker`,并在 `/usr/local/bin/docker daemon` 后面加上 `--userns-remap=default`,像这样:
|
||||
|
||||
```
|
||||
$ sudo vi /etc/init.d/docker
|
||||
:
|
||||
:
|
||||
/usr/local/bin/docker daemon --userns-remap=default -D -g "$DOCKER_DIR" -H unix:// $DOCKER_HOST $EXTRA_ARGS >> "$DOCKER_LOGFILE" 2>&1 &
|
||||
:
|
||||
:
|
||||
|
||||
/usr/local/bin/docker daemon --userns-remap=default -D -g "$DOCKER_DIR" -H unix:// $DOCKER_HOST $EXTRA_ARGS >> "$DOCKER_LOGFILE" 2>&1 &
|
||||
```
|
||||
|
||||
然后重启 Docker:
|
||||
|
||||
```
|
||||
$ sudo /etc/init.d/docker restart
|
||||
|
||||
```
|
||||
|
||||
这就完成了!
|
||||
|
||||
**注意:** 若你使用的是 CentOS 7,则你需要了解两件事。
|
||||
**注意**:若你使用的是 CentOS 7,则你需要了解两件事。
|
||||
|
||||
**1。** 内核默认并没有启用 User Namespaces。运行下面命令并重启系统,可以启用该功能。
|
||||
```
|
||||
sudo grubby --args="user_namespace.enable=1" \
|
||||
--update-kernel=/boot/vmlinuz-3.10.0-XXX.XX.X.el7.x86_64
|
||||
1. 内核默认并没有启用用户名字空间。运行下面命令并重启系统,可以启用该功能。
|
||||
|
||||
```
|
||||
```
|
||||
sudo grubby --args="user_namespace.enable=1" \
|
||||
--update-kernel=/boot/vmlinuz-3.10.0-XXX.XX.X.el7.x86_64
|
||||
```
|
||||
|
||||
**2。** CentOS 7 使用 systemctl 来管理服务,因此你需要编辑的文件是 `/usr/lib/systemd/system/docker.service`。
|
||||
2. CentOS 7 使用 `systemctl` 来管理服务,因此你需要编辑的文件是 `/usr/lib/systemd/system/docker.service`。
|
||||
|
||||
### 确认 User Namespaces 是否正常工作
|
||||
### 确认用户名字空间是否正常工作
|
||||
|
||||
若一切都配置妥当,则你应该无法再在容器中编辑 host1 上的 `/etc` 了。让我们来试一下。
|
||||
|
||||
```
|
||||
# Create a container and mount host1's /etc to container's /root/etc
|
||||
$ docker run --rm -v /etc:/root/etc -it ubuntu
|
||||
@ -90,8 +89,6 @@ drwx------ 3 root root 4096 Mar 21 23:50 ..
|
||||
lrwxrwxrwx 1 nobody nogroup 19 Mar 21 23:07 acpi -> /usr/local/etc/acpi
|
||||
-rw-r--r-- 1 nobody nogroup 48 Mar 10 22:09 boot2docker
|
||||
drwxr-xr-x 2 nobody nogroup 60 Mar 21 23:07 default
|
||||
:
|
||||
:
|
||||
|
||||
# Try creating a file in /root/etc
|
||||
root@d5802c5e670a:/# touch /root/etc/test
|
||||
@ -100,20 +97,19 @@ touch: cannot touch '/root/etc/test': Permission denied
|
||||
# Try deleting a file
|
||||
root@d5802c5e670a:/# rm /root/etc/hostname
|
||||
rm: cannot remove '/root/etc/hostname': Permission denied
|
||||
|
||||
```
|
||||
|
||||
好了,太棒了。这就是 User Namespaces 的工作方式。
|
||||
好了,太棒了。这就是用户名字空间的工作方式。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
---
|
||||
|
||||
via: https://coderwall.com/p/s_ydlq/using-user-namespaces-on-docker
|
||||
|
||||
作者:[Koji Tanaka][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lujun9972](https://github.com/lujun9972)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[pityonline](https://github.com/pityonline)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://coderwall.com/kjtanaka
|
||||
[a]: https://coderwall.com/kjtanaka
|
@ -1,11 +1,13 @@
|
||||
尝试,学习,修改:新 IT 领导者的代码
|
||||
尝试、学习、修改:新 IT 领导者的代码
|
||||
=====
|
||||
|
||||
> 随着创新步伐的增加, 长期规划变得越来越困难。让我们重新思考一下我们对变化的反应方式。
|
||||
|
||||

|
||||
|
||||
几乎每一天,新的技术发展都在威胁破坏,甚至是那些最复杂,最完善的商业计划。组织经常发现自己正在努力适应新的环境,这导致了他们对未来规划的转变。
|
||||
几乎每一天,新的技术发展都可能会动摇那些甚至最复杂、最完善的商业计划。组织经常发现自己需要不断努力适应新的环境,这导致了他们对未来规划的转变。
|
||||
|
||||
根据 CompTIA 2017 年的[研究][1],目前只有 34% 的公司正在制定超过 12 个月的 IT 架构计划。从长期计划转变的一个原因是:商业环境变化如此之快,以至于几乎不可能进一步规划未来。[CIO.com 说道][1]“如果你的公司正视图制定一项将持续五到十年的计划,那就忘了它。”
|
||||
根据 CompTIA 2017 年的[研究][1],目前只有 34% 的公司正在制定超过 12 个月的 IT 架构计划。从长期计划转变的一个原因是:商业环境变化如此之快,以至于几乎不可能进一步规划未来。[CIO.com 说道][1],“如果你的公司正视图制定一项将持续五到十年的计划,那就忘了它。”
|
||||
|
||||
我听过来自世界各地无数客户和合作伙伴的类似声明:技术创新正以一种前所未有的速度发生着。
|
||||
|
||||
@ -13,21 +15,21 @@
|
||||
|
||||
### 计划是怎么死的
|
||||
|
||||
正如我在 Open Organization(开源组织)中写的那样,传统经营组织针对工业经济进行了优化。他们采用等级结构和严格规定的流程,以实现地位竞争优势。要取得成功,他们必须确定他们想要实现的战略地位。然后,他们必须制定并规划实现目标的计划,并以最有效的方式执行这些计划,通过协调活动和推动合规性。
|
||||
正如我在《<ruby>开放式组织<rt>The Open Organization</rt></ruby>》中写的那样,传统经营组织针对工业经济进行了优化。他们采用等级结构和严格规定的流程,以实现地位竞争优势。要取得成功,他们必须确定他们想要实现的战略地位。然后,他们必须制定并规划实现目标的计划,并以最有效的方式执行这些计划,通过协调活动和推动合规性。
|
||||
|
||||
管理层的职责是优化这一过程:计划,规定,执行。包括:让我们想象一个有竞争力的优势地位;让我们来配置组织以最终到达那里;然后让我们通过确保组织的所有方面都遵守规定来推动执行。这就是我所说的“机械管理”,对于不同时期来说它都是一个出色的解决方案。
|
||||
管理层的职责是优化这一过程:计划、规定、执行。包括:让我们想象一个有竞争力的优势地位;让我们来配置组织以最终达成目标;然后让我们通过确保组织的所有方面都遵守规定来推动执行。这就是我所说的“机械管理”,对于不同时期来说它都是一个出色的解决方案。
|
||||
|
||||
在当今动荡不定的世界中,我们预测和定义战略位置的能力正在下降,因为变化的速度,新变量的引入速度正在加速。传统的,长期的,战略性规划和执行不像以前那么有效。
|
||||
在当今动荡不定的世界中,我们预测和定义战略位置的能力正在下降,因为变化的速度,新变量的引入速度正在加速。传统的、长期的、战略性规划和执行不像以前那么有效。
|
||||
|
||||
如果长期规划变得如此困难,那么规定必要的行为就更具有挑战性。并且衡量对计划的合规性几乎是不可能的。
|
||||
|
||||
这一切都极大地影响了人们的工作方式。与过去传统经营组织中的工人不同,他们为自己能够重复行动而感到自豪,几乎没有变化和舒适的确定性 -- 今天的工人在充满模糊性的环境中运作。他们的工作需要更大的创造力,直觉和批判性判断 -- 有更大的要求是背离过去的“正常”,适应当今的新情况。
|
||||
这一切都极大地影响了人们的工作方式。与过去传统经营组织中的工人不同,他们为自己能够重复行动而感到自豪,几乎没有变化和舒适的确定性 —— 今天的工人在充满模糊性的环境中运作。他们的工作需要更大的创造力、直觉和批判性判断 —— 更多的需要背离过去的“常规”,以适应当今的新情况。
|
||||
|
||||
以这种新方式工作对于价值创造变得更加重要。我们的管理系统必须专注于构建结构,系统和流程,以帮助创建积极主动的工人,他们能够以快速和敏捷的方式进行创新和行动。
|
||||
|
||||
我们需要提出一个不同的解决方案来优化组织,以适应不同的经济时代,从自下而上而不是自上而下开始。我们需要替换过去的三步骤 -- 计划,规定,执行,以一种更适应当今动荡天气的方法来取得成功 -- 尝试,学习,修改。
|
||||
我们需要提出一个不同的解决方案来优化组织,以适应不同的经济时代,从自下而上而不是自上而下开始。我们需要替换过去的三步骤 —— 计划、规定、执行,以一种更适应当今动荡天气的方法来取得成功 —— 尝试、学习、修改。
|
||||
|
||||
### 尝试,学习,修改
|
||||
### 尝试、学习、修改
|
||||
|
||||
因为环境变化如此之快,而且几乎没有任何预警,并且因为我们需要采取的步骤不再提前计划,我们需要培养鼓励创造性尝试和错误的环境,而不是坚持对五年计划的忠诚。以下是以这种方式开始工作的一些暗示:
|
||||
|
||||
@ -46,7 +48,7 @@ via: https://opensource.com/open-organization/18/3/try-learn-modify
|
||||
|
||||
作者:[Jim Whitehurst][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/) 荣誉推出
|
||||
|
@ -0,0 +1,223 @@
|
||||
逐层拼接云原生栈
|
||||
======
|
||||
|
||||
> 看着我们在纽约的办公大楼,我们发现了一种观察不断变化的云原生领域的完美方式。
|
||||
|
||||
在 Packet,我们的工作价值(<ruby>基础设施<rt>infrastructure</rt></ruby>自动化)是非常基础的。因此,我们花费大量的时间来研究我们之上所有生态系统中的参与者和趋势 —— 以及之下的极少数!
|
||||
|
||||
当你在任何生态系统的汪洋大海中徜徉时,很容易困惑或迷失方向。我知道这是事实,因为当我去年进入 Packet 工作时,从 Bryn Mawr 获得的英语学位,并没有让我完全得到一个 [Kubernetes][Kubernetes] 的认证。:)
|
||||
|
||||
由于它超快的演进和巨大的影响,云原生生态系统打破了先例。似乎每眨一次眼睛,之前全新的技术(更不用说所有相关的理念了)就变得有意义……或至少有趣了。和其他许多人一样,我依据无处不在的 [CNCF][CNCF] 的 “[云原生蓝图][1]” 作为我去了解这个空间的参考标准。尽管如此,如果有一个定义这个生态系统的元素,那它一定是贡献和引领它们的人。
|
||||
|
||||
所以,在 12 月份一个很冷的下午,当我们走回办公室时,我们偶然发现了一个给投资人解释“云原生”的创新方式,当我们谈到从 [Aporeto][Aporeto] 中区分 [Cilium][Cilium] 的细微差别时,以及为什么从 [CoreDNS][CoreDNS] 和 [Spiffe][Spiffe] 到 [Digital Rebar][Digital Rebar] 和 [Fission][Fission] 的所有这些都这么有趣时,他的眼里充满了兴趣。
|
||||
|
||||
在新世贸中心的影子里向我们位于 13 层的狭窄办公室望去,我们突然想到一个把我们带到那个神奇世界的好主意:为什么不把它画出来呢?(LCTT 译注:“rabbit hole” 有多种含义,此处采用“爱丽丝梦游仙境”中的“兔子洞”含义。)
|
||||
|
||||
![][2]
|
||||
|
||||
于是,我们开始了把云原生栈逐层拼接起来的旅程。让我们一起探索它,给你一个“仅限今日有效”的福利。(LCTT 译注:意即云原生领域变化很快,可能本文/本图中所述很快过时。)
|
||||
|
||||
[查看高清大图][3](25Mb)或给我们发邮件索取副本。
|
||||
|
||||
### 从最底层开始
|
||||
|
||||
当我们开始下笔的时候,我们希望首先亮出的是我们每天都在打交道的那一部分:硬件,但我们知道那对用户却是基本上不可见的。就像任何投资于下一个伟大的(通常是私有的)东西的秘密实验室一样,我们认为地下室是其最好的地点。
|
||||
|
||||
从大家公认的像 Intel、AMD 和华为(传言他们雇佣的工程师接近 80000 名)这样的巨头,到像 [Mellanox][Mellanox] 这样的细分市场参与者,硬件生态系统现在非常火。事实上,随着数十亿美元投入去攻克新的 offload(LCTT 译注:offload 泛指以前由软件及 CPU 来完成的工作,现在通过硬件来完成,以提升速度并降低 CPU 负载的做法)、GPU、定制协处理器,我们可能正在进入硬件的黄金时代。
|
||||
|
||||
著名的软件先驱[艾伦·凯][Alan Kay](Alan Kay)在 25 年前说过:“真正认真对待软件的人应该自己创造硬件”。说得不错,Alan!
|
||||
|
||||
### 云即资本
|
||||
|
||||
就像我们的 CEO Zac Smith 多次跟我说的:一切都是钱的事。不仅要制造它,还要消费它!在云中,数十亿美元的投入才能让数据中心出现计算机,这样才能让开发者消费它。换句话说(根本没云,它只是别人的电脑而已):
|
||||
|
||||
![][4]
|
||||
|
||||
我们认为,对于“银行”(即能让云运转起来的借款人或投资人)来说最好的位置就是一楼。因此我们将大堂改造成银行家的咖啡馆,以便为所有的创业者提供幸运之轮。
|
||||
|
||||
![][5]
|
||||
|
||||
### 连通和动力
|
||||
|
||||
如果金钱是润滑油,那么消耗大量燃料的引擎就是数据中心供应商和连接它们的网络。我们称他们为“连通”和“动力”。
|
||||
|
||||
从像 [Equinix][Equinix] 这样处于核心地位的接入商的和像 [Vapor.io][Vapor.io] 这样的接入新贵,到 [Verizon][Verizon]、[Crown Castle][Crown Castle] 和其它接入商铺设在地下(或海底)的“管道”,这是我们所有的栈都依赖但很少有人能看到的一部分。
|
||||
|
||||
因为我们花费大量的时间去研究数据中心和连通性,需要注意的一件事情是,这一部分的变化非常快,尤其是在 5G 正式商用时,某些负载开始不再那么依赖中心化的基础设施了。
|
||||
|
||||
边缘计算即将到来!:-)
|
||||
|
||||
![][6]
|
||||
|
||||
### 嗨,它就是基础设施!
|
||||
|
||||
居于“连通”和“动力”之上的这一层,我们爱称为“处理器层”。这是奇迹发生的地方 —— 我们将来自下层的创新和实物投资转变成一个 API 终端的某些东西。
|
||||
|
||||
由于这是纽约的一个大楼,我们让在这里的云供应商处于纽约的中心。这就是为什么你会看到([Digital Ocean][Digital Ocean] 系的)鲨鱼 Sammy 和对 “meet me” 房间里面的 Google 标志的致意的原因了。
|
||||
|
||||
正如你所见,这个场景是非常写实的。它是由多层机架堆叠起来的。尽管我们爱 EWR1 的设备经理(Michael Pedrazzini),我们努力去尽可能减少这种体力劳动。毕竟布线专业的博士学位是很难拿到的。
|
||||
|
||||
![][7]
|
||||
|
||||
### 供给
|
||||
|
||||
再上一层,在基础设施层之上是供给层。这是我们最喜欢的地方之一,它以前被我们称为<ruby>配置管理<rt>config management</rt></ruby>。但是现在到处都是一开始就是<ruby>不可变基础设施<rt>immutable infrastructure</rt></ruby>和自动化:[Terraform][Terraform]、[Ansible][Ansible]、[Quay.io][Quay.io] 等等类似的东西。你可以看出软件是按它的方式来工作的,对吗?
|
||||
|
||||
Kelsey Hightower 最近写道“呆在无聊的基础设施中是一个让人兴奋的时刻”,我不认为这说的是物理部分(虽然我们认为它非常让人兴奋),但是由于软件持续侵入到栈的所有层,那必将是一个疯狂的旅程。
|
||||
|
||||
![][8]
|
||||
|
||||
### 操作系统
|
||||
|
||||
供应就绪后,我们来到操作系统层。在这里你可以看到我们打趣一些我们最喜欢的同事:注意上面 Brian Redbeard 那超众的瑜珈姿势。:)
|
||||
|
||||
Packet 为客户提供了 11 种主要的操作系统可供选择,包括一些你在图中看到的:[Ubuntu][Ubuntu]、[CoreOS][CoreOS]、[FreeBSD][FreeBSD]、[Suse][Suse]、和各种 [Red Hat][Red Hat] 系的发行版。我们看到越来越多的人们在这一层上加入了他们自己的看法:从定制内核和用于不可变部署的<ruby>黄金镜像<rt>golden images</rt></ruby>(LCCT 注:golden image 指定型的镜像或模板,一般是经过一些定制,并做快照和版本控制,由此可拷贝出大量与此镜像一致的开发、测试或部署环境,也有人称作 master image),到像 [NixOS][NixOS] 和 [LinuxKit][LinuxKit] 这样的项目。
|
||||
|
||||
![][9]
|
||||
|
||||
### 运行时
|
||||
|
||||
为了有趣些,我们将<ruby>运行时<rt>runtime</rt></ruby>放在了体育馆内,并为 CoreOS 赞助的 [rkt][rkt] 和 [Docker][Docker] 的容器化举行了一次比赛。而无论如何赢家都是 CNCF!
|
||||
|
||||
我们认为快速演进的存储生态系统应该是一些可上锁的储物柜。关于存储部分有趣的地方在于许多的新玩家尝试去解决持久性的挑战问题,以及性能和灵活性问题。就像他们说的:存储很简单。
|
||||
|
||||
![][10]
|
||||
|
||||
### 编排
|
||||
|
||||
在过去的这一年里,编排层全是 Kubernetes 了,因此我们选取了其中一位著名的布道者(Kelsey Hightower),并在这个古怪的会议场景中给他一个特写。在我们的团队中有一些 [Nomad][Nomad](LCTT 译注:一个管理机器集群并在集群上运行应用程序的工具)的忠实粉丝,并且如果抛开 Docker 和它的工具集的影响,就无从谈起云原生。
|
||||
|
||||
虽然负载编排应用程序在我们栈中的地位非常高,我们看到的各种各样的证据表明,这些强大的工具开始去深入到栈中,以帮助用户利用 GPU 和其它特定硬件的优势。请继续关注 —— 我们正处于容器化革命的早期阶段!
|
||||
|
||||
![][11]
|
||||
|
||||
### 平台
|
||||
|
||||
这是栈中我们喜欢的层之一,因为每个平台都有如此多的工具帮助用户去完成他们想要做的事情(顺便说一下,不是去运行容器,而是运行应用程序)。从 [Rancher][Rancher] 和 [Kontena][Kontena],到 [Tectonic][Tectonic] 和 [Redshift][Redshift] 都是像 [Cycle.io][Cycle.io] 和 [Flynn.io][Flynn.io] 一样是完全不同的方法 —— 我们看到这些项目如何以不同的方式为用户提供服务,总是激动不已。
|
||||
|
||||
关键点:这些平台是帮助用户转化云原生生态系统中各种各样的快速变化的部分。很高兴能看到他们各自带来的东西!
|
||||
|
||||
![][12]
|
||||
|
||||
### 安全
|
||||
|
||||
当说到安全时,今年真是很忙的一年!我们尝试去展示一些很著名的攻击,并说明随着工作负载变得更加分散和更加可迁移(当然,同时攻击者也变得更加智能),这些各式各样的工具是如何去帮助保护我们的。
|
||||
|
||||
我们看到一个用于不可信环境(如 Aporeto)和低级安全(Cilium)的强大动作,以及尝试在网络级别上的像 [Tigera][Tigera] 这样的可信方法。不管你的方法如何,记住这一点:安全无止境。:0
|
||||
|
||||
![][13]
|
||||
|
||||
### 应用程序
|
||||
|
||||
如何去表示海量的、无限的应用程序生态系统?在这个案例中,很容易:我们在纽约,选我们最喜欢的。;) 从 [Postgres][Postgres] “房间里的大象” 和 [Timescale][Timescale] 时钟,到鬼鬼祟祟的 [ScyllaDB][ScyllaDB] 垃圾桶和那个悠闲的 [Travis][Travis] 哥们 —— 我们把这个片子拼到一起很有趣。
|
||||
|
||||
让我们感到很惊奇的一件事情是:很少有人注意到那个复印屁股的家伙。我想现在复印机已经不常见了吧?
|
||||
|
||||
![][14]
|
||||
|
||||
### 可观测性
|
||||
|
||||
由于我们的工作负载开始到处移动,规模也越来越大,这里没有一件事情能够像一个非常好用的 [Grafana][Grafana] 仪表盘、或方便的 [Datadog][Datadog] 代理让人更加欣慰了。由于复杂度的提升,[SRE][SRE] 时代开始越来越多地依赖监控告警和其它智能事件去帮我们感知发生的事件,出现越来越多的自我修复的基础设施和应用程序。
|
||||
|
||||
在未来的几个月或几年中,我们将看到什么样的面孔进入这一领域……或许是一些人工智能、区块链、机器学习支撑的仪表盘?:-)
|
||||
|
||||
![][15]
|
||||
|
||||
### 流量管理
|
||||
|
||||
人们往往认为互联网“只是能工作而已”,但事实上,我们很惊讶于它居然能如此工作。我的意思是,就这些大规模的、不同的网络间的松散连接 —— 你不是在开玩笑吧?
|
||||
|
||||
能够把所有的这些独立的网络拼接到一起的一个原因是流量管理、DNS 和类似的东西。随着规模越来越大,这些让互联网变得更快、更安全、同时更具弹性。我们尤其高兴的是看到像 [Fly.io][Fly.io] 和 [NS1][NS1] 这样的新贵与优秀的老牌玩家进行竞争,最后的结果是整个生态系统都得以提升。让竞争来的更激烈吧!
|
||||
|
||||
![][16]
|
||||
|
||||
### 用户
|
||||
|
||||
如果没有非常棒的用户,技术栈还有什么用呢?确实,他们享受了大量的创新,但在云原生的世界里,他们所做的远不止消费这么简单:他们也创造并贡献了很多。从像 Kubernetes 这样的大量的贡献者到越来越多的(但同样重要)更多方面,而我们都是其中的非常棒的一份子。
|
||||
|
||||
在我们屋顶上有许多悠闲的用户,比如 [Ticketmaster][Ticketmaster] 和[《纽约时报》][New York Times],而不仅仅是新贵:这些组织拥抱了部署和管理应用程序的方法的变革,并且他们的用户正在享受变革带来的回报。
|
||||
|
||||
![][17]
|
||||
|
||||
### 同样重要的,成熟的监管!
|
||||
|
||||
在以前的生态系统中,基金会扮演了一个非常被动的“幕后”角色。而 CNCF 不是!他们的目标(构建一个健壮的云原生生态系统),勇立潮流之先 —— 他们不仅已迎头赶上还一路领先。
|
||||
|
||||
从坚实的治理和经过深思熟虑的项目组,到提出像 CNCF 这样的蓝图,CNCF 横跨云 CI、Kubernetes 认证、和讲师团 —— CNCF 已不再是 “仅仅” 受欢迎的 [KubeCon + CloudNativeCon][KCCNC] 了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.packet.net/blog/splicing-the-cloud-native-stack/
|
||||
|
||||
作者:[Zoe Allen][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[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]: https://www.packet.net/about/zoe-allen/
|
||||
[1]: https://landscape.cncf.io/landscape=cloud
|
||||
[2]: https://assets.packet.net/media/images/PIFg-30.vesey.street.ny.jpg
|
||||
[3]: https://www.dropbox.com/s/ujxk3mw6qyhmway/Packet_Cloud_Native_Building_Stack.jpg?dl=0
|
||||
[4]: https://assets.packet.net/media/images/3vVx-there.is.no.cloud.jpg
|
||||
[5]: https://assets.packet.net/media/images/X0b9-the.bank.jpg
|
||||
[6]: https://assets.packet.net/media/images/2Etm-ping.and.power.jpg
|
||||
[7]: https://assets.packet.net/media/images/C800-infrastructure.jpg
|
||||
[8]: https://assets.packet.net/media/images/0V4O-provisioning.jpg
|
||||
[9]: https://assets.packet.net/media/images/eMYp-operating.system.jpg
|
||||
[10]: https://assets.packet.net/media/images/9BII-run.time.jpg
|
||||
[11]: https://assets.packet.net/media/images/njak-orchestration.jpg
|
||||
[12]: https://assets.packet.net/media/images/1QUS-platforms.jpg
|
||||
[13]: https://assets.packet.net/media/images/TeS9-security.jpg
|
||||
[14]: https://assets.packet.net/media/images/SFgF-apps.jpg
|
||||
[15]: https://assets.packet.net/media/images/SXoj-observability.jpg
|
||||
[16]: https://assets.packet.net/media/images/tKhf-traffic.management.jpg
|
||||
[17]: https://assets.packet.net/media/images/7cpe-users.jpg
|
||||
[Kubernetes]: https://kubernetes.io/
|
||||
[CNCF]: https://www.cncf.io/
|
||||
[Aporeto]: https://www.aporeto.com/
|
||||
[Cilium]: https://cilium.io/
|
||||
[CoreDNS]: https://coredns.io/
|
||||
[Spiffe]: https://spiffe.io/
|
||||
[Digital Rebar]: http://rebar.digital/
|
||||
[Fission]: https://fission.io/
|
||||
[Mellanox]: http://www.mellanox.com/
|
||||
[Alan Kay]: https://en.wikipedia.org/wiki/Alan_Kay
|
||||
[Equinix]: https://www.equinix.com/
|
||||
[Vapor.io]: https://www.vapor.io/
|
||||
[Verizon]: https://www.verizon.com/
|
||||
[Crown Castle]: http://www.crowncastle.com/
|
||||
[Digital Ocean]: https://www.digitalocean.com/
|
||||
[Terraform]: https://www.terraform.io/
|
||||
[Ansible]: https://www.ansible.com/
|
||||
[Quay.io]: https://quay.io/
|
||||
[Ubuntu]: https://www.ubuntu.com/
|
||||
[CoreOS]: https://coreos.com/
|
||||
[FreeBSD]: https://www.freebsd.org/
|
||||
[Suse]: https://www.suse.com/
|
||||
[Red Hat]: https://www.redhat.com/
|
||||
[NixOS]: https://nixos.org/
|
||||
[LinuxKit]: https://github.com/linuxkit/linuxkit
|
||||
[rkt]: https://coreos.com/rkt/
|
||||
[Docker]: https://www.docker.com/
|
||||
[Nomad]: https://www.nomadproject.io/
|
||||
[Rancher]: https://rancher.com/
|
||||
[Kontena]: https://kontena.io/
|
||||
[Tectonic]: https://coreos.com/tectonic/
|
||||
[Redshift]: https://aws.amazon.com/redshift/
|
||||
[Cycle.io]: https://cycle.io/
|
||||
[Flynn.io]: https://flynn.io/
|
||||
[Tigera]: https://www.tigera.io/
|
||||
[Postgres]: https://www.postgresql.org/
|
||||
[Timescale]: https://www.timescale.com/
|
||||
[ScyllaDB]: https://www.scylladb.com/
|
||||
[Travis]: https://travis-ci.com/
|
||||
[Grafana]: https://grafana.com/
|
||||
[Datadog]: https://www.datadoghq.com/
|
||||
[SRE]: https://en.wikipedia.org/wiki/Site_Reliability_Engineering
|
||||
[Fly.io]: https://fly.io/
|
||||
[NS1]: https://ns1.com/
|
||||
[Ticketmaster]: https://www.ticketmaster.com/
|
||||
[New York Times]: https://www.nytimes.com/
|
||||
[KCCNC]: https://www.cncf.io/community/kubecon-cloudnativecon-events/
|
@ -1,31 +1,32 @@
|
||||
如何用 Python 读取 Outlook 中的电子邮件
|
||||
======
|
||||
|
||||

|
||||

|
||||
|
||||
从事电子邮件营销,准入邮箱列表是必不可少的。你可能已经有了准入列表,同时还使用电子邮件客户端软件。如果你能从电子邮件客户端中导出准入列表,那这份列表想必是极好的。
|
||||
从事电子邮件营销,<ruby>准入<rt>opt-in</rt></ruby>邮箱列表是必不可少的。你可能已经有了准入列表,同时还使用电子邮件客户端软件。如果你能从电子邮件客户端中导出准入列表,那这份列表想必是极好的。
|
||||
|
||||
我使用一些代码来将 outlook 配置中的所有邮件写入一个临时文件中,现在让我来尝试解释一下这些代码。
|
||||
|
||||
首先你需要倒入 win32com.client,为此你需要安装 pywin32
|
||||
首先你需要导入 win32com.client,为此你需要安装 pywin32:
|
||||
|
||||
```
|
||||
pip install pywin32
|
||||
|
||||
```
|
||||
|
||||
我们需要通过 MAPI 协议连接 Outlok
|
||||
我们需要通过 MAPI 协议连接 Outlok:
|
||||
|
||||
```
|
||||
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
|
||||
|
||||
```
|
||||
|
||||
然后从 outlook 配置中获取所有的账户。
|
||||
然后从 outlook 配置中获取所有的账户:
|
||||
|
||||
```
|
||||
accounts= win32com.client.Dispatch("Outlook.Application").Session.Accounts;
|
||||
|
||||
```
|
||||
|
||||
在然后需要从名为 emaileri_al 的收件箱中获取邮件。
|
||||
在然后需要从名为 emaileri_al 的收件箱中获取邮件:
|
||||
|
||||
```
|
||||
def emailleri_al(folder):
|
||||
messages = folder.Items
|
||||
@ -48,7 +49,8 @@ def emailleri_al(folder):
|
||||
pass
|
||||
```
|
||||
|
||||
你需要进入所有账户的所有收件箱中获取电子邮件
|
||||
你需要进入所有账户的所有收件箱中获取电子邮件:
|
||||
|
||||
```
|
||||
for account in accounts:
|
||||
global inbox
|
||||
@ -77,7 +79,8 @@ for account in accounts:
|
||||
print("*************************************************", file=
|
||||
```
|
||||
|
||||
下面是完整的代码
|
||||
下面是完整的代码:
|
||||
|
||||
```
|
||||
import win32com.client
|
||||
import win32com
|
||||
@ -148,7 +151,7 @@ via: https://www.codementor.io/aliacetrefli/how-to-read-outlook-emails-by-python
|
||||
作者:[A.A. Cetrefli][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lujun9972](https://github.com/lujun9972)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,154 @@
|
||||
|
||||
如何确定你的Linux发行版中有没有某个软件包
|
||||
======
|
||||
|
||||

|
||||
|
||||
|
||||
有时,你可能会想知道如何在你的 Linux 发行版上寻找一个特定的软件包。或者,你仅仅只是想知道安装在你的 Linux 上的软件包有什么版本。如果这就是你想知道的信息,你今天走运了。我正好知道一个小工具能帮你抓到上述信息,下面隆重推荐—— Whohas:这是一个命令行工具,它能一次查询好几个软件包列表,以检查的你软件包是否存在。目前,whohas 支持 Arch、Debian、Fedora、Gentoo、Mandriva、openSUSE、Slackware、Source Mage、Ubuntu、FreeBSD、NetBSD、OpenBSD(LCTT 译注:*BSD 不是 Linux)、Fink、MacPorts 和 Cygwin。使用这个小工具,软件包的维护者能轻而易举从别的 Linux 发行版里找到 ebuilds、 pkgbuilds 等等类似的包定义文件。
|
||||
|
||||
Whohas 是用 Perl 语言开发的自由、开源的工具。
|
||||
|
||||
### 在你的 Linux 中寻找一个特定的包
|
||||
|
||||
#### 安装 Whohas
|
||||
|
||||
Whohas 在 Debian、Ubuntu、Linux Mint 的默认软件仓库里提供。如果你正在使用某种基于 DEB 的系统,你可以用如下命令安装:
|
||||
|
||||
```
|
||||
$ sudo apt-get install whohas
|
||||
```
|
||||
|
||||
对基于 Arch 的系统,[AUR][1] 里就有提供 whohas。你能使用任何的 AUR 助手程序来安装。
|
||||
|
||||
使用 [Packer][2]:
|
||||
|
||||
```
|
||||
$ packer -S whohas
|
||||
```
|
||||
|
||||
或使用[Trizen][3]:
|
||||
|
||||
```
|
||||
$ trizen -S whohas
|
||||
```
|
||||
|
||||
使用[Yay][4]:
|
||||
|
||||
```
|
||||
$ yay -S whohas
|
||||
```
|
||||
|
||||
使用 [Yaourt][5]:
|
||||
|
||||
```
|
||||
$ yaourt -S whohas
|
||||
```
|
||||
|
||||
在别的 Linux 发行版上,从[这里][6]下载源代码并手工编译安装。
|
||||
|
||||
#### 使用方法
|
||||
|
||||
Whohas 的主要目标是想让你知道:
|
||||
|
||||
* 哪个 Linux 发布版提供了用户依赖的包。
|
||||
* 对于各个 Linux 发行版,指定的软件包是什么版本,或者在这个 Linux 发行版的各个不同版本上,指定的软件包是什么版本。
|
||||
|
||||
让我们试试看上面的的功能,比如说,哪个 Linux 发行版里有 vim 这个软件?我们可以运行如下命令:
|
||||
|
||||
```
|
||||
$ whohas vim
|
||||
```
|
||||
|
||||
|
||||
这个命令将会显示所有包含可安装的 vim 的 Linux 发行版的信息,包括包的大小,仓库地址和下载URL。
|
||||
|
||||
![][8]
|
||||
|
||||
你甚至可以通过管道将输出的结果按照发行版的字母排序,只需加入 `sort` 命令即可。
|
||||
|
||||
```
|
||||
$ whohas vim | sort
|
||||
```
|
||||
|
||||
请注意上述命令将会显示所有以 vim 开头的软件包,包括 vim-spell、vimcommander、vimpager 等等。你可以继续使用 Linux 的 `grep` 命令在 “vim” 的前后加上空格来缩小你的搜索范围,直到满意为止。
|
||||
|
||||
```
|
||||
$ whohas vim | sort | grep " vim"
|
||||
$ whohas vim | sort | grep "vim "
|
||||
$ whohas vim | sort | grep " vim "
|
||||
```
|
||||
|
||||
所有将空格放在包名字前面的搜索将会显示以包名字结尾的包。所有将空格放在包名字后面的搜索将会显示以包名字开头的包。前后都有空格将会严格匹配。
|
||||
|
||||
又或者,你就使用 `--strict` 来严格限制结果。
|
||||
|
||||
```
|
||||
$ whohas --strict vim
|
||||
```
|
||||
|
||||
有时,你想知道一个包在不在一个特定的 Linux 发行版里。例如,你想知道 vim 是否在 Arch Linux 里,请运行:
|
||||
|
||||
```
|
||||
$ whohas vim | grep "^Arch"
|
||||
```
|
||||
|
||||
(LCTT译注:在结果里搜索以 Arch 开头的 Linux)
|
||||
|
||||
Linux 发行版的命名缩写为:'archlinux'、'cygwin'、'debian'、'fedora'、 'fink'、'freebsd'、'gentoo'、'mandriva'、'macports'、'netbsd'、'openbsd'、'opensuse'、'slackware'、'sourcemage' 和 'ubuntu'。
|
||||
|
||||
你也可以用 `-d` 选项来得到同样的结果。
|
||||
|
||||
```
|
||||
$ whohas -d archlinux vim
|
||||
```
|
||||
|
||||
这个命令将在仅仅 Arch Linux 发行版下搜索 vim 包。
|
||||
|
||||
如果要在多个 Linux 发行版下搜索,如 'archlinux'、'ubuntu',请使用如下命令。
|
||||
|
||||
```
|
||||
$ whohas -d archlinux,ubuntu vim
|
||||
```
|
||||
|
||||
|
||||
你甚至可以用 `whohas` 来查找哪个发行版有 whohas 包。
|
||||
|
||||
```
|
||||
$ whohas whohas
|
||||
```
|
||||
|
||||
更详细的信息,请参照手册。
|
||||
|
||||
```
|
||||
$ man whohas
|
||||
```
|
||||
|
||||
#### 最后的话
|
||||
|
||||
当然,任何一个 Linux 发行版的包管理器都能轻松的在对应的软件仓库里找到自己管理的包。不过,whohas 帮你整合并比较了在不同的 Linux 发行版下指定的软件包信息,这样你能轻易的跨平台之间进行比较。试一下 whohas,你一定不会失望的。
|
||||
|
||||
好了,今天就到这里吧,希望前面讲的对你有用,下次我还会带来更多好东西!!
|
||||
|
||||
欧耶!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/find-if-a-package-is-available-for-your-linux-distribution/
|
||||
|
||||
作者:[SK][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://www.ostechnix.com/author/sk/
|
||||
[1]:https://aur.archlinux.org/packages/whohas/
|
||||
[2]:https://www.ostechnix.com/install-packer-arch-linux-2/
|
||||
[3]:https://www.ostechnix.com/trizen-lightweight-aur-package-manager-arch-based-systems/
|
||||
[4]:https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/
|
||||
[5]:https://www.ostechnix.com/install-yaourt-arch-linux/
|
||||
[6]:http://www.philippwesche.org/200811/whohas/intro.html
|
||||
[7]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[8]:http://www.ostechnix.com/wp-content/uploads/2018/06/whohas-1.png
|
@ -1,49 +1,37 @@
|
||||
Linux DNS 查询剖析 – 第一部分
|
||||
============================================================
|
||||
Linux DNS 查询剖析(第一部分)
|
||||
======
|
||||
|
||||
我经常与虚拟机集群打交道([文1][3], [文2][4], [文3][5], [文4][6], [文5][7], [文6][8]),期间花费了大量时间试图掌握 [DNS 查询][9]的工作原理。遇到问题时,我有时只是不求甚解的使用 StackOverflow 上的“解决方案”;甚至那些“解决方案”有时并不工作。
|
||||
我经常与虚拟机集群打交道([文1][3]、[文2][4]、[文3][5]、[文4][6]、[文5][7]、[文6][8]),因此最终花费了大量时间试图掌握 [DNS 查询][9]的工作原理。遇到问题时,我只是不求甚解的使用 StackOverflow 上的“解决方案”,而不知道它们为什么有时工作,有时不工作。
|
||||
|
||||
最终我决定改变这种情况,决定一并找出所有问题的原因。我没有在网上找到完整手册或类似的其它东西,我问过一些同事,他们也是如此。
|
||||
最终我对此感到了厌倦,决定一并找出所有问题的原因。我没有在网上找到完整的指南,我问过一些同事,他们不知所以然(或许是问题太具体了)。
|
||||
|
||||
既然如此,我开始自己写这样的手册。
|
||||
|
||||
_如果你在找第二部分, 点击 [这里][1]_
|
||||
|
||||
结果发现,“Linux 执行一次 DNS 查询”的背后有相当多的工作。
|
||||
|
||||
* * *
|
||||
结果发现,“Linux 执行一次 DNS 查询”这句话的背后有相当多的工作。
|
||||
|
||||

|
||||
|
||||
_“究竟有多难呢?”_
|
||||
|
||||
* * *
|
||||
**本系列文章试图将 Linux 主机上程序获取(域名对应的) IP 地址的过程及期间涉及的组件进行分块剖析。**如果不理解这些块的协同工作方式,调试解决 `dnsmasq`、`vagrant landrush` 和 `resolvconf` 等相关的问题会让人感到眼花缭乱。
|
||||
|
||||
本系列文章试图将 Linux 主机上程序获取(域名对应的) IP 地址的过程及期间涉及的组件进行分块剖析。如果不理解这些块的协同工作方式,调试并解决 `dnsmasq`,`vagrant landrush` 和 `resolvconf` 等相关的问题会让人感到眼花缭乱。
|
||||
|
||||
同时这也是一份有价值的说明,指出原本很简单的东西可以如何随着时间的推移变得相当复杂。在弄清楚 DNS 查询的原理的过程中,我了解了大量不同的技术及其发展历程。
|
||||
同时这也是一份有价值的说明,指出原本很简单的东西是如何随着时间的推移变得相当复杂。在弄清楚 DNS 查询的原理的过程中,我了解了大量不同的技术及其发展历程。
|
||||
|
||||
我甚至编写了一些[自动化脚本][10],可以让我在虚拟机中进行实验。欢迎读者参与贡献或勘误。
|
||||
|
||||
请注意,本系列主题并不是“DNS 工作原理”,而是与查询 Linux 主机配置的真实 DNS 服务器(这里假设查询了 DNS 服务器,但后面你会看到有时并不需要查询)相关的内容,以及如何确定使用哪个查询结果,或者何时使用其它方式确定 IP 地址。
|
||||
|
||||
* * *
|
||||
**请注意,本系列主题并不是“DNS 工作原理”**,而是与查询 Linux 主机配置的真实 DNS 服务器(这里假设查询了一台 DNS 服务器,但后面你会看到有时并不需要)相关的内容,以及如何确定使用哪个查询结果,或者如何使用其它方式确定 IP 地址。
|
||||
|
||||
### 1) 其实并没有名为“DNS 查询”的系统调用
|
||||
|
||||
* * *
|
||||
|
||||

|
||||
|
||||
_工作方式并非如此_
|
||||
_工作方式并非如此_
|
||||
|
||||
* * *
|
||||
**首先要了解的一点是,Linux 上并没有一个单独的方法可以完成 DNS 查询工作**;没有一个有这样的明确接口的核心<ruby>系统调用<rt>system call</rt></ruby>。
|
||||
|
||||
首先要了解的一点是,Linux 上并没有一个单独的方法可以完成 DNS 查询工作;至少没有如此<ruby>明确接口<rt>clean interface</rt></ruby>的核心<ruby>系统调用<rt>system call</rt></ruby>。
|
||||
不过,有一个标准 C 库函数调用 [`getaddrinfo`][2],不少程序使用了该调用;但不是所有程序或应用都使用该调用!
|
||||
|
||||
有一个标准 C 库函数调用 `[getaddrinfo][2]`,不少程序使用了该调用;但不是所有程序或应用都使用该调用!
|
||||
|
||||
我们只考虑两个简单的标准程序:`ping` 和 `host`:
|
||||
让我们看一下两个简单的标准程序:`ping` 和 `host`:
|
||||
|
||||
```
|
||||
root@linuxdns1:~# ping -c1 bbc.co.uk | head -1
|
||||
@ -100,17 +88,15 @@ google.com has address 216.58.204.46
|
||||
|
||||
下面我们依次查看这两个 `.conf` 扩展名的文件。
|
||||
|
||||
* * *
|
||||
|
||||
### 2) NSSwitch 与 `/etc/nsswitch.conf`
|
||||
|
||||
我们已经确认应用可以自主决定选用哪个 DNS 服务器。很多应用(例如 `ping`)通过配置文件 `/etc/nsswitch.conf` (根据具体实现 (*))参考 NSSwitch 完成选择。
|
||||
我们已经确认应用可以自主决定选用哪个 DNS 服务器。很多应用(例如 `ping`)通过配置文件 `/etc/nsswitch.conf` (根据具体实现[^1] )参考 NSSwitch 完成选择。
|
||||
|
||||
###### (*) ping 实现的变种之多令人惊叹。我 _不_ 希望在这里讨论过多。
|
||||
[^1]: `ping` 实现的变种之多令人惊叹。我 _不_ 希望在这里讨论过多。
|
||||
|
||||
NSSwitch 不仅用于 DNS 查询,例如,还用于密码与用户信息查询。
|
||||
|
||||
NSSwitch 最初是 Solaris OS 的一部分,可以让应用无需将查询所需的文件或服务硬编码,而是在其它集中式的、无需应用开发人员管理的配置文件中找到。
|
||||
NSSwitch 最初是 Solaris OS 的一部分,可以让应用无需硬编码查询所需的文件或服务,而是在其它集中式的、无需应用开发人员管理的配置文件中找到。
|
||||
|
||||
下面是我的 `nsswitch.conf`:
|
||||
|
||||
@ -130,12 +116,13 @@ netgroup: nis
|
||||
|
||||
我们需要关注的是 `hosts` 行。我们知道 `ping` 用到 `nsswitch.conf` 文件,那么我们修改这个文件(的 `hosts` 行),看看能够如何影响 `ping`。
|
||||
|
||||
|
||||
* ### 修改 `nsswitch.conf`, `hosts` 行仅保留 `files`
|
||||
#### 修改 `nsswitch.conf`, `hosts` 行仅保留 `files`
|
||||
|
||||
如果你修改 `nsswitch.conf`,将 `hosts` 行仅保留 `files`:
|
||||
|
||||
`hosts: files`
|
||||
```
|
||||
hosts: files
|
||||
```
|
||||
|
||||
此时, `ping` 无法获取 google.com 对应的 IP 地址:
|
||||
|
||||
@ -161,11 +148,13 @@ google.com has address 216.58.206.110
|
||||
|
||||
毕竟如我们之前看到的那样,`host` 不受 `nsswitch.conf` 影响。
|
||||
|
||||
* ### 修改 `nsswitch.conf`, `hosts` 行仅保留 `dns`
|
||||
#### 修改 `nsswitch.conf`, `hosts` 行仅保留 `dns`
|
||||
|
||||
如果你修改 `nsswitch.conf`,将 `hosts` 行仅保留 `dns`:
|
||||
|
||||
`hosts: dns`
|
||||
```
|
||||
hosts: dns
|
||||
```
|
||||
|
||||
此时,google.com 的解析恢复正常:
|
||||
|
||||
@ -184,13 +173,9 @@ ping: unknown host localhost
|
||||
|
||||
下图给出默认 NSSwitch 中 `hosts` 行对应的查询逻辑:
|
||||
|
||||
* * *
|
||||
|
||||

|
||||
|
||||
_我的 `hosts:` 配置是 `nsswitch.conf` 给出的默认值_
|
||||
|
||||
* * *
|
||||
_我的 `hosts:` 配置是 `nsswitch.conf` 给出的默认值_
|
||||
|
||||
### 3) `/etc/resolv.conf`
|
||||
|
||||
@ -221,16 +206,16 @@ $ ping -c1 google.com
|
||||
ping: unknown host google.com
|
||||
```
|
||||
|
||||
解析失败了,这是因为没有可用的 nameserver (*)。
|
||||
解析失败了,这是因为没有可用的名字服务器 [^2]。
|
||||
|
||||
|
||||
###### * 另一个需要注意的地方: `host` 在没有指定 nameserver 的情况下会尝试 127.0.0.1:53。
|
||||
[^2]: 另一个需要注意的地方: `host` 在没有指定 nameserver 的情况下会尝试 127.0.0.1:53。
|
||||
|
||||
该文件中还可以使用其它选项。例如,你可以在 `resolv.conf` 文件中增加如下行:
|
||||
|
||||
```
|
||||
search com
|
||||
```
|
||||
|
||||
然后执行 `ping google` (不写 `.com`)
|
||||
|
||||
```
|
||||
@ -248,10 +233,9 @@ PING google.com (216.58.204.14) 56(84) bytes of data.
|
||||
|
||||
* 操作系统中并不存在“DNS 查询”这个系统调用
|
||||
* 不同程序可能采用不同的策略获取名字对应的 IP 地址
|
||||
* 例如, `ping` 使用 `nsswitch`,后者进而使用(或可以使用) `/etc/hosts`,`/etc/resolv.conf` 以及主机名得到解析结果
|
||||
|
||||
* 例如, `ping` 使用 `nsswitch`,后者进而使用(或可以使用) `/etc/hosts`、`/etc/resolv.conf` 以及主机名得到解析结果
|
||||
* `/etc/resolv.conf` 用于决定:
|
||||
* 查询什么地址(LCTT 译注:这里可能指 search 带来的影响)
|
||||
* 查询什么地址(LCTT 译注:这里可能指 `search` 带来的影响)
|
||||
* 使用什么 DNS 服务器执行查询
|
||||
|
||||
如果你曾认为 DNS 查询很复杂,请跟随这个系列学习吧。
|
||||
@ -262,7 +246,7 @@ via: https://zwischenzugs.com/2018/06/08/anatomy-of-a-linux-dns-lookup-part-i/
|
||||
|
||||
作者:[dmatech][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/) 荣誉推出
|
||||
|
@ -0,0 +1,223 @@
|
||||
Linux DNS 查询剖析(第二部分)
|
||||
==============================================
|
||||
|
||||
在 [Linux DNS 查询剖析 - 第一部分][1] 中,我介绍了:
|
||||
|
||||
* `nsswitch`
|
||||
* `/etc/hosts`
|
||||
* `/etc/resolv.conf`
|
||||
* `ping` 与 `host` 查询方式对比
|
||||
|
||||
并且发现大多数程序选择要查询的 DNS 服务器时会参考 `/etc/resolv.conf` 配置文件。
|
||||
|
||||
这种方式在 Linux 上比较普遍[^1]。虽然我使用了特定的发行版 Ubuntu,但背后的原理与 Debian 甚至是那些基于 CentOS 的发行版有相通的地方;当然,与更低或更高的 Ubuntu 版本相比,差异还是存在的。
|
||||
|
||||
[^1]: 事实上,这是相对于 POSIX 标准的,故不限于 Linux (我从上一篇文章的一条极好的[回复][2]中了解到这一点)
|
||||
|
||||
也就是说,接下来,你主机上的行为很可能与我描述的不一致。
|
||||
|
||||
在第二部分中,我将介绍 `resolv.conf` 的更新机制、`systemctl restart networking` 命令的运行机制 ,以及 `dhclient` 是如何参与其中。
|
||||
|
||||
### 1) 手动更新 /etc/resolv.conf
|
||||
|
||||
我们知道 `/etc/resolv.conf` (有极大的可能性)被用到,故你自然可以通过该文件增加一个 `nameserver`,那么主机也将会(与已有的 `nameserver` 一起)使用新加入的 `nameserver` 吧?
|
||||
|
||||
你可以尝试如下:
|
||||
|
||||
```
|
||||
$ echo nameserver 10.10.10.10 >> /etc/resolv.conf
|
||||
```
|
||||
|
||||
看上去新的 `nameserver` 已经加入:
|
||||
|
||||
```
|
||||
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
|
||||
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
|
||||
nameserver 10.0.2.3
|
||||
search home
|
||||
nameserver 10.10.10.10
|
||||
```
|
||||
|
||||
但主机网络服务重启后问题出现了:
|
||||
|
||||
```
|
||||
$ systemctl restart networking
|
||||
$ cat /etc/resolv.conf
|
||||
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
|
||||
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
|
||||
nameserver 10.0.2.3
|
||||
search home
|
||||
```
|
||||
|
||||
我们的 `10.10.10.10` 的 `nameserver` 不见了!
|
||||
|
||||
在上一篇文章中我们忽略了这一点,本文进行补充说明。
|
||||
|
||||
### 2) resolvconf
|
||||
|
||||
你在 `/etc/resolv.conf` 文件中看到 `generated by resolvconf` 词组了吧?这就是我们的线索。
|
||||
|
||||
如果深入研究 `systemctl restart networking` 命令,你会发现它做了很多事情,结束时调用了 `/etc/network/if-up.d/000resolvconf` 脚本。在该脚本中,可以发现一次对 `resolvconf` 命令的调用:
|
||||
|
||||
```
|
||||
/sbin/resolvconf -a "${IFACE}.${ADDRFAM}"
|
||||
```
|
||||
|
||||
稍微研究一下 man 手册,发现`-a` 参数允许我们:
|
||||
|
||||
```
|
||||
Add or overwrite the record IFACE.PROG then run the update scripts
|
||||
if updating is enabled.
|
||||
```
|
||||
|
||||
(增加或覆盖 IFACE.PROG 记录,如果开启更新选项,则运行更新脚本)
|
||||
|
||||
故而也许我们可以直接调用该命令增加 `namserver`:
|
||||
|
||||
```
|
||||
echo 'nameserver 10.10.10.10' | /sbin/resolvconf -a enp0s8.inet
|
||||
```
|
||||
|
||||
测试表明确实可以!
|
||||
|
||||
```
|
||||
$ cat /etc/resolv.conf | grep nameserver
|
||||
nameserver 10.0.2.3
|
||||
nameserver 10.10.10.10
|
||||
```
|
||||
|
||||
是否已经找到答案,这就是 `/etc/resolv.conf` 更新的逻辑?调用 `resolvconf` 将 `nameserver` 添加到某个地方的数据库,然后(“如果配置了更新”,先不管具体什么含义)更新 `resolv.conf` 文件。
|
||||
|
||||
并非如此。
|
||||
|
||||
```
|
||||
$ systemctl restart networking
|
||||
root@linuxdns1:/etc# cat /etc/resolv.conf
|
||||
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
|
||||
# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
|
||||
nameserver 10.0.2.3
|
||||
search home
|
||||
```
|
||||
|
||||
呃!(网络服务重启后)新增的 `nameserver` 再次消失了。
|
||||
|
||||
可见,`systemctl restart networking` 不仅仅运行了 `resolvconf`,还在其它地方获取 `nameserver` 信息。具体是哪里呢?
|
||||
|
||||
### 3) ifup/ifdown
|
||||
|
||||
继续深入研究 `systemctl restart networking`,发现它完成了一系列工作:
|
||||
|
||||
```
|
||||
cat /lib/systemd/system/networking.service
|
||||
[...]
|
||||
[Service]
|
||||
Type=oneshot
|
||||
EnvironmentFile=-/etc/default/networking
|
||||
ExecStartPre=-/bin/sh -c '[ "$CONFIGURE_INTERFACES" != "no" ] && [ -n "$(ifquery --read-environment --list --exclude=lo)" ] && udevadm settle'
|
||||
ExecStart=/sbin/ifup -a --read-environment
|
||||
ExecStop=/sbin/ifdown -a --read-environment --exclude=lo
|
||||
[...]
|
||||
```
|
||||
|
||||
首先,网络服务的重启实质是运行一个<ruby>单触发<rt>oneshot</rt></ruby>的脚本,脚本包含如下命令:
|
||||
|
||||
```
|
||||
/sbin/ifdown -a --read-environment --exclude=lo
|
||||
/bin/sh -c '[ "$CONFIGURE_INTERFACES" != "no" ] && [ -n "$(ifquery --read-environment --list --exclude=lo)" ] && udevadm settle'
|
||||
/sbin/ifup -a --read-environment
|
||||
```
|
||||
|
||||
第一行使用 `ifdown` 关闭全部的网络接口,但<ruby>本地回环<rt>local, lo</rt></ruby>接口除外。[^2]
|
||||
|
||||
[^2]: 我不明白为何这没有导致我例子中的 vagrant 会话中断 (有谁明白吗?)。
|
||||
|
||||
(LCTT 译注:其实这是因为很快就又启动了接口,间隔的时间没有超过 TCP 连接的超时时间,有人在评论中也做了类似回复)
|
||||
|
||||
第二行用于确认系统已经完成关闭网络接口相关的全部工作,以便下一步使用 `ifup` 启动接口。这也让我们了解到,网络服务实质运行的就是 `ifdown` 和 `ifup`。
|
||||
|
||||
文档中没有找到 `--read-environment` 参数的说明,该参数为 `systemctl` 正常工作所需。很多人以文档不完善为由不喜欢 `systemctl`。
|
||||
|
||||
很好。那么 `ifup` (和其成对出现的 `ifdown`) 到底做了哪些工作呢?长话短说,它运行了 `/etc/network/if-pre-up.d/` 和 `/etc/network/if-up.d/` 目录下的全部脚本;期间,这些脚本也可能会调用另外的脚本,依此类推。
|
||||
|
||||
其中一件工作就是运行了 `dhclient`,但我还不完全确定具体的机理,也许 `udev` 参与其中。
|
||||
|
||||
### 4) dhclient
|
||||
|
||||
`dhclient` 是一个程序,用于与 DHCP 服务器协商对应网络接口应该使用的 IP 地址的详细信息。同时,它也可以获取可用的 DNS 服务器并将其替换到 `/etc/resolv.conf` 中。
|
||||
|
||||
让我们开始跟踪并模拟它的行为,但仅在我实验虚拟机的 `enp0s3` 接口上。事先已经删除 `/etc/resolv.conf` 文件中的 nameserver 配置:
|
||||
|
||||
```
|
||||
$ sed -i '/nameserver.*/d' /run/resolvconf/resolv.conf
|
||||
$ cat /etc/resolv.conf | grep nameserver
|
||||
$ dhclient -r enp0s3 && dhclient -v enp0s3
|
||||
Killed old client process
|
||||
Internet Systems Consortium DHCP Client 4.3.3
|
||||
Copyright 2004-2015 Internet Systems Consortium.
|
||||
All rights reserved.
|
||||
For info, please visit https://www.isc.org/software/dhcp/
|
||||
Listening on LPF/enp0s8/08:00:27:1c:85:19
|
||||
Sending on LPF/enp0s8/08:00:27:1c:85:19
|
||||
Sending on Socket/fallback
|
||||
DHCPDISCOVER on enp0s8 to 255.255.255.255 port 67 interval 3 (xid=0xf2f2513e)
|
||||
DHCPREQUEST of 172.28.128.3 on enp0s8 to 255.255.255.255 port 67 (xid=0x3e51f2f2)
|
||||
DHCPOFFER of 172.28.128.3 from 172.28.128.2
|
||||
DHCPACK of 172.28.128.3 from 172.28.128.2
|
||||
bound to 172.28.128.3 -- renewal in 519 seconds.
|
||||
|
||||
$ cat /etc/resolv.conf | grep nameserver
|
||||
nameserver 10.0.2.3
|
||||
```
|
||||
|
||||
可见这就是 `nameserver` 的来源。
|
||||
|
||||
但稍等一下,命令中的 `/run/resolvconf/resolv.conf` 是哪个文件,不应该是 `/etc/resolv.conf` 吗?
|
||||
|
||||
事实上,`/etc/resolv.conf` 并不一定只是一个普通文本文件。
|
||||
|
||||
在我的虚拟机上,它是一个软链接,指向位于 `/run/resolvconf` 目录下的“真实文件”。这也暗示了我们,该文件是在系统启动时生成的;同时,这也是该文件注释告诉我们不要直接修改该文件的原因。
|
||||
|
||||
(LCTT 译注:在 CentOS 7 中,没有 `resolvconf` 命令,`/etc/resolv.conf` 也不是软链接)
|
||||
|
||||
假如上面命令中 `sed` 命令直接处理 `/etc/resolv.conf` 文件,效果是不同的,会有警告消息告知待操作的文件不能是软链接(`sed -i` 无法很好的处理软链接,它只会创建一个新文件)。
|
||||
|
||||
(LCTT 译注:CentOS 7 测试时,`sed -i` 命令操作软链接并没有警告,但确实创建了新文件取代软链接)
|
||||
|
||||
如果你继续深入查看配置文件 `/etc/dhcp/dhclient.conf` 的 `supersede` 部分,你会发现 `dhclient` 可以覆盖 DHCP 提供的 DNS 服务器。
|
||||
|
||||

|
||||
|
||||
_(大致)准确的关系图_
|
||||
|
||||
* * *
|
||||
|
||||
### 第二部分的结束语
|
||||
|
||||
第二部分到此结束。信不信由你,这是一个某种程度上简化的流程版本,但我尽量保留重要和值得了解的部分,让你不会感到无趣。大部分内容都是围绕实际脚本的运行展开的。
|
||||
|
||||
但我们的工作还没有结束,在第三部分,我们会介绍这些之上的更多层次。
|
||||
|
||||
让我们简要列出我们已经介绍过的内容:
|
||||
|
||||
* `nsswitch`
|
||||
* `/etc/hosts`
|
||||
* `/etc/resolv.conf`
|
||||
* `/run/resolvconf/resolv.conf`
|
||||
* `systemd` 和网络服务
|
||||
* `ifup` 和 `ifdown`
|
||||
* `dhclient`
|
||||
* `resolvconf`
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://zwischenzugs.com/2018/06/18/anatomy-of-a-linux-dns-lookup-part-ii/
|
||||
|
||||
作者:[ZWISCHENZUGS][a]
|
||||
译者:[pinewall](https://github.com/pinewall)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://zwischenzugs.com/
|
||||
[1]:https://linux.cn/article-9943-1.html
|
||||
[2]:https://zwischenzugs.com/2018/06/08/anatomy-of-a-linux-dns-lookup-part-i/#comment-2312
|
@ -0,0 +1,292 @@
|
||||
使用 Ptrace 去拦截和仿真 Linux 系统调用
|
||||
======
|
||||
|
||||
`ptrace(2)`(“<ruby>进程跟踪<rt>process trace</rt></ruby>)系统调用通常都与调试有关。它是类 Unix 系统上通过原生调试器监测被调试进程的主要机制。它也是实现 [strace][1](<ruby>系统调用跟踪<rt>system call trace</rt></ruby>)的常见方法。使用 Ptrace,跟踪器可以暂停被跟踪进程,[检查和设置寄存器和内存][2],监视系统调用,甚至可以<ruby>拦截<rt>intercepting</rt></ruby>系统调用。
|
||||
|
||||
通过拦截功能,意味着跟踪器可以篡改系统调用参数,篡改系统调用的返回值,甚至阻塞某些系统调用。言外之意就是,一个跟踪器本身完全可以提供系统调用服务。这是件非常有趣的事,因为这意味着**一个跟踪器可以仿真一个完整的外部操作系统**,而这些都是在没有得到内核任何帮助的情况下由 Ptrace 实现的。
|
||||
|
||||
问题是,在同一时间一个进程只能被一个跟踪器附着,因此在那个进程的调试期间,不可能再使用诸如 GDB 这样的工具去仿真一个外部操作系统。另外的问题是,仿真系统调用的开销非常高。
|
||||
|
||||
在本文中,我们将专注于 x86-64 [Linux 的 Ptrace][3],并将使用一些 Linux 专用的扩展。同时,在本文中,我们将忽略掉一些错误检查,但是完整的源代码仍然会包含这些错误检查。
|
||||
|
||||
本文中的可直接运行的示例代码在这里:<https://github.com/skeeto/ptrace-examples>
|
||||
|
||||
### strace
|
||||
|
||||
在进入到最有趣的部分之前,我们先从回顾 strace 的基本实现来开始。它[不是 DTrace][4],但 strace 仍然非常有用。
|
||||
|
||||
Ptrace 一直没有被标准化。它的接口在不同的操作系统上非常类似,尤其是在核心功能方面,但是在不同的系统之间仍然存在细微的差别。`ptrace(2)` 的原型基本上应该像下面这样,但特定的类型可能有些差别。
|
||||
|
||||
```
|
||||
long ptrace(int request, pid_t pid, void *addr, void *data);
|
||||
```
|
||||
|
||||
`pid` 是被跟踪进程的 ID。虽然**同一个时间**只有一个跟踪器可以附着到该进程上,但是一个跟踪器可以附着跟踪多个进程。
|
||||
|
||||
`request` 字段选择一个具体的 Ptrace 函数,比如 `ioctl(2)` 接口。对于 strace,只需要两个:
|
||||
|
||||
* `PTRACE_TRACEME`:这个进程被它的父进程跟踪。
|
||||
* `PTRACE_SYSCALL`:继续跟踪,但是在下一下系统调用入口或出口时停止。
|
||||
* `PTRACE_GETREGS`:取得被跟踪进程的寄存器内容副本。
|
||||
|
||||
另外两个字段,`addr` 和 `data`,作为所选的 Ptrace 函数的一般参数。一般情况下,可以忽略一个或全部忽略,在那种情况下,传递零个参数。
|
||||
|
||||
strace 接口实质上是前缀到另一个命令之前。
|
||||
|
||||
```
|
||||
$ strace [strace options] program [arguments]
|
||||
```
|
||||
|
||||
最小化的 strace 不需要任何选项,因此需要做的第一件事情是 —— 假设它至少有一个参数 —— 在 `argv` 尾部的 `fork(2)` 和 `exec(2)` 被跟踪进程。但是在加载目标程序之前,新的进程将告知内核,目标程序将被它的父进程继续跟踪。被跟踪进程将被这个 Ptrace 系统调用暂停。
|
||||
|
||||
```
|
||||
pid_t pid = fork();
|
||||
switch (pid) {
|
||||
case -1: /* error */
|
||||
FATAL("%s", strerror(errno));
|
||||
case 0: /* child */
|
||||
ptrace(PTRACE_TRACEME, 0, 0, 0);
|
||||
execvp(argv[1], argv + 1);
|
||||
FATAL("%s", strerror(errno));
|
||||
}
|
||||
```
|
||||
|
||||
父进程使用 `wait(2)` 等待子进程的 `PTRACE_TRACEME`,当 `wait(2)` 返回后,子进程将被暂停。
|
||||
|
||||
```
|
||||
waitpid(pid, 0, 0);
|
||||
```
|
||||
|
||||
在允许子进程继续运行之前,我们告诉操作系统,被跟踪进程和它的父进程应该一同被终止。一个真实的 strace 实现可能会设置其它的选择,比如: `PTRACE_O_TRACEFORK`。
|
||||
|
||||
```
|
||||
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL);
|
||||
```
|
||||
|
||||
剩余部分就是一个简单的、无休止的循环了,每循环一次捕获一个系统调用。循环体总共有四步:
|
||||
|
||||
1. 等待进程进入下一个系统调用。
|
||||
2. 输出系统调用的一个描述。
|
||||
3. 允许系统调用去运行并等待返回。
|
||||
4. 输出系统调用返回值。
|
||||
|
||||
这个 `PTRACE_SYSCALL` 请求被用于等待下一个系统调用时开始,和等待那个系统调用退出。和前面一样,需要一个 `wait(2)` 去等待被跟踪进程进入期望的状态。
|
||||
|
||||
```
|
||||
ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||
waitpid(pid, 0, 0);
|
||||
```
|
||||
|
||||
当 `wait(2)` 返回时,进行了系统调用的线程的寄存器中写入了该系统调用的系统调用号及其参数。尽管如此,*操作系统仍然没有为这个系统调用提供服务*。这个细节对后续操作很重要。
|
||||
|
||||
接下来的一步是采集系统调用信息。这是各个系统架构不同的地方。在 x86-64 上,[系统调用号是在 `rax` 中传递的][5],而参数(最多 6 个)是在 `rdi`、`rsi`、`rdx`、`r10`、`r8` 和 `r9` 中传递的。这些寄存器是由另外的 Ptrace 调用读取的,不过这里再也不需要 `wait(2)` 了,因为被跟踪进程的状态再也不会发生变化了。
|
||||
|
||||
```
|
||||
struct user_regs_struct regs;
|
||||
ptrace(PTRACE_GETREGS, pid, 0, ®s);
|
||||
long syscall = regs.orig_rax;
|
||||
|
||||
fprintf(stderr, "%ld(%ld, %ld, %ld, %ld, %ld, %ld)",
|
||||
syscall,
|
||||
(long)regs.rdi, (long)regs.rsi, (long)regs.rdx,
|
||||
(long)regs.r10, (long)regs.r8, (long)regs.r9);
|
||||
```
|
||||
|
||||
这里有一个警告。由于 [内核的内部用途][6],系统调用号是保存在 `orig_rax` 中而不是 `rax` 中。而所有的其它系统调用参数都是非常简单明了的。
|
||||
|
||||
接下来是它的另一个 `PTRACE_SYSCALL` 和 `wait(2)`,然后是另一个 `PTRACE_GETREGS` 去获取结果。结果保存在 `rax` 中。
|
||||
|
||||
```
|
||||
ptrace(PTRACE_GETREGS, pid, 0, ®s);
|
||||
fprintf(stderr, " = %ld\n", (long)regs.rax);
|
||||
```
|
||||
|
||||
这个简单程序的输出也是非常粗糙的。这里的系统调用都没有符号名,并且所有的参数都是以数字形式输出,甚至是一个指向缓冲区的指针也是如此。更完整的 strace 输出将能知道哪个参数是指针,并使用 `process_vm_readv(2)` 从被跟踪进程中读取哪些缓冲区,以便正确输出它们。
|
||||
|
||||
然而,这些仅仅是系统调用拦截的基础工作。
|
||||
|
||||
### 系统调用拦截
|
||||
|
||||
假设我们想使用 Ptrace 去实现如 OpenBSD 的 [`pledge(2)`][7] 这样的功能,它是 [一个进程<ruby>承诺<rt>pledge</rt></ruby>只使用一套受限的系统调用][8]。初步想法是,许多程序一般都有一个初始化阶段,这个阶段它们都需要进行许多的系统访问(比如,打开文件、绑定套接字、等等)。初始化完成以后,它们进行一个主循环,在主循环中它们处理输入,并且仅使用所需的、很少的一套系统调用。
|
||||
|
||||
在进入主循环之前,一个进程可以限制它自己只能运行所需要的几个操作。如果 [程序有缺陷][9],能够通过恶意的输入去利用该缺陷,这个**承诺**可以有效地限制漏洞利用的实现。
|
||||
|
||||
使用与 strace 相同的模型,但不是输出所有的系统调用,我们既能够阻塞某些系统调用,也可以在它的行为异常时简单地终止被跟踪进程。终止它很容易:只需要在跟踪器中调用 `exit(2)`。因此,它也可以被设置为去终止被跟踪进程。阻塞系统调用和允许子进程继续运行都只是些雕虫小技而已。
|
||||
|
||||
最棘手的部分是**当系统调用启动后没有办法去中断它**。当跟踪器在入口从 `wait(2)` 中返回到系统调用时,从一开始停止一个系统调用的仅有方式是,终止被跟踪进程。
|
||||
|
||||
然而,我们不仅可以“搞乱”系统调用的参数,也可以改变系统调用号本身,将它修改为一个不存在的系统调用。返回时,在 `errno` 中 [通过正常的内部信号][10],我们就可以报告一个“友好的”错误信息。
|
||||
|
||||
```
|
||||
for (;;) {
|
||||
/* Enter next system call */
|
||||
ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||
waitpid(pid, 0, 0);
|
||||
|
||||
struct user_regs_struct regs;
|
||||
ptrace(PTRACE_GETREGS, pid, 0, ®s);
|
||||
|
||||
/* Is this system call permitted? */
|
||||
int blocked = 0;
|
||||
if (is_syscall_blocked(regs.orig_rax)) {
|
||||
blocked = 1;
|
||||
regs.orig_rax = -1; // set to invalid syscall
|
||||
ptrace(PTRACE_SETREGS, pid, 0, ®s);
|
||||
}
|
||||
|
||||
/* Run system call and stop on exit */
|
||||
ptrace(PTRACE_SYSCALL, pid, 0, 0);
|
||||
waitpid(pid, 0, 0);
|
||||
|
||||
if (blocked) {
|
||||
/* errno = EPERM */
|
||||
regs.rax = -EPERM; // Operation not permitted
|
||||
ptrace(PTRACE_SETREGS, pid, 0, ®s);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这个简单的示例只是检查了系统调用是否违反白名单或黑名单。而它们在这里并没有差别,比如,允许文件以只读而不是读写方式打开(`open(2)`),允许匿名内存映射但不允许非匿名映射等等。但是这里仍然没有办法去动态撤销被跟踪进程的权限。
|
||||
|
||||
跟踪器与被跟踪进程如何沟通?使用人为的系统调用!
|
||||
|
||||
### 创建一个人为的系统调用
|
||||
|
||||
对于我的这个类似于 pledge 的系统调用 —— 我可以通过调用 `xpledge()` 将它与真实的系统调用区分开 —— 我设置 10000 作为它的系统调用号,这是一个非常大的数字,真实的系统调用中从来不会用到它。
|
||||
|
||||
```
|
||||
#define SYS_xpledge 10000
|
||||
```
|
||||
|
||||
为演示需要,我同时构建了一个非常小的接口,这在实践中并不是个好主意。它与 OpenBSD 的 `pledge(2)` 稍有一些相似之处,它使用了一个 [字符串接口][11]。*事实上*,设计一个健壮且安全的权限集是非常复杂的,正如在 `pledge(2)` 的手册页面上所显示的那样。下面是对被跟踪进程的系统调用的完整接口*和*实现:
|
||||
|
||||
```
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
|
||||
#define XPLEDGE_RDWR (1 << 0)
|
||||
#define XPLEDGE_OPEN (1 << 1)
|
||||
|
||||
#define xpledge(arg) syscall(SYS_xpledge, arg)
|
||||
```
|
||||
|
||||
如果给它传递个参数 0 ,仅允许一些基本的系统调用,包括那些用于去分配内存的系统调用(比如 `brk(2)`)。 `PLEDGE_RDWR` 位允许 [各种][12] 读和写的系统调用(`read(2)`、`readv(2)`、`pread(2)`、`preadv(2)` 等等)。`PLEDGE_OPEN` 位允许 `open(2)`。
|
||||
|
||||
为防止发生提升权限的行为,`pledge()` 会拦截它自己 —— 但这样也防止了权限撤销,以后再细说这方面内容。
|
||||
|
||||
在 xpledge 跟踪器中,我需要去检查这个系统调用:
|
||||
|
||||
```
|
||||
/* Handle entrance */
|
||||
switch (regs.orig_rax) {
|
||||
case SYS_pledge:
|
||||
register_pledge(regs.rdi);
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
操作系统将返回 `ENOSYS`(函数尚未实现),因为它不是一个*真实的*系统调用。为此在退出时我用一个 `success(0)` 去覆写它。
|
||||
|
||||
```
|
||||
/* Handle exit */
|
||||
switch (regs.orig_rax) {
|
||||
case SYS_pledge:
|
||||
ptrace(PTRACE_POKEUSER, pid, RAX * 8, 0);
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
我写了一小段测试程序去打开 `/dev/urandom`,做一个读操作,尝试去承诺后,然后试着第二次打开 `/dev/urandom`,然后确认它能够读取原始的 `/dev/urandom` 文件描述符。在没有承诺跟踪器的情况下运行,输出如下:
|
||||
|
||||
```
|
||||
$ ./example
|
||||
fread("/dev/urandom")[1] = 0xcd2508c7
|
||||
XPledging...
|
||||
XPledge failed: Function not implemented
|
||||
fread("/dev/urandom")[2] = 0x0be4a986
|
||||
fread("/dev/urandom")[1] = 0x03147604
|
||||
```
|
||||
|
||||
做一个无效的系统调用并不会让应用程序崩溃。它只是失败,这是一个很方便的返回方式。当它在跟踪器下运行时,它的输出如下:
|
||||
|
||||
```
|
||||
$ ./xpledge ./example
|
||||
fread("/dev/urandom")[1] = 0xb2ac39c4
|
||||
XPledging...
|
||||
fopen("/dev/urandom")[2]: Operation not permitted
|
||||
fread("/dev/urandom")[1] = 0x2e1bd1c4
|
||||
```
|
||||
|
||||
这个承诺很成功,第二次的 `fopen(3)` 并没有进行,因为跟踪器用一个 `EPERM` 阻塞了它。
|
||||
|
||||
可以将这种思路进一步发扬光大,比如,改变文件路径或返回一个假的结果。一个跟踪器可以很高效地 chroot 它的被跟踪进程,通过一个系统调用将任意路径传递给 root 从而实现 chroot 路径。它甚至可以对用户进行欺骗,告诉用户它以 root 运行。事实上,这些就是 [Fakeroot NG][13] 程序所做的事情。
|
||||
|
||||
### 仿真外部系统
|
||||
|
||||
假设你不满足于仅拦截一些系统调用,而是想拦截*全部*系统调用。你就会有了 [一个打算在其它操作系统上运行的二进制程序][14],无需系统调用,这个二进制程序可以一直运行。
|
||||
|
||||
使用我在前面所描述的这些内容你就可以管理这一切。跟踪器可以使用一个假冒的东西去代替系统调用号,允许它失败,以及为系统调用本身提供服务。但那样做的效率很低。其实质上是对每个系统调用做了三个上下文切换:一个是在入口上停止,一个是让系统调用总是以失败告终,还有一个是在系统调用退出时停止。
|
||||
|
||||
从 2005 年以后,对于这个技术,PTrace 的 Linux 版本有更高效的操作:`PTRACE_SYSEMU`。PTrace 仅在每个系统调用发出时停止*一次*,在允许被跟踪进程继续运行之前,由跟踪器为系统调用提供服务。
|
||||
|
||||
```
|
||||
for (;;) {
|
||||
ptrace(PTRACE_SYSEMU, pid, 0, 0);
|
||||
waitpid(pid, 0, 0);
|
||||
|
||||
struct user_regs_struct regs;
|
||||
ptrace(PTRACE_GETREGS, pid, 0, ®s);
|
||||
|
||||
switch (regs.orig_rax) {
|
||||
case OS_read:
|
||||
/* ... */
|
||||
|
||||
case OS_write:
|
||||
/* ... */
|
||||
|
||||
case OS_open:
|
||||
/* ... */
|
||||
|
||||
case OS_exit:
|
||||
/* ... */
|
||||
|
||||
/* ... and so on ... */
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
从任何具有(足够)稳定的系统调用 ABI(LCTT 译注:应用程序二进制接口),在相同架构的机器上运行一个二进制程序时,你只需要 `PTRACE_SYSEMU` 跟踪器、一个加载器(用于代替 `exec(2)`),和这个二进制程序所需要(或仅运行静态的二进制程序)的任何系统库即可。
|
||||
|
||||
事实上,这听起来有点像一个有趣的周末项目。
|
||||
|
||||
**参见**
|
||||
|
||||
- [给 Linux 内核克隆实现一个 OpenBSD 承诺][15]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://nullprogram.com/blog/2018/06/23/
|
||||
|
||||
作者:[Chris Wellons][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]: http://nullprogram.com
|
||||
[1]: https://blog.plover.com/Unix/strace-groff.html
|
||||
[2]: http://nullprogram.com/blog/2016/09/03/
|
||||
[3]: http://man7.org/linux/man-pages/man2/ptrace.2.html
|
||||
[4]: http://nullprogram.com/blog/2018/01/17/
|
||||
[5]: http://nullprogram.com/blog/2015/05/15/
|
||||
[6]: https://stackoverflow.com/a/6469069
|
||||
[7]: https://man.openbsd.org/pledge.2
|
||||
[8]: http://www.openbsd.org/papers/hackfest2015-pledge/mgp00001.html
|
||||
[9]: http://nullprogram.com/blog/2017/07/19/
|
||||
[10]: http://nullprogram.com/blog/2016/09/23/
|
||||
[11]: https://www.tedunangst.com/flak/post/string-interfaces
|
||||
[12]: http://nullprogram.com/blog/2017/03/01/
|
||||
[13]: https://fakeroot-ng.lingnu.com/index.php/Home_Page
|
||||
[14]: http://nullprogram.com/blog/2017/11/30/
|
||||
[15]: https://www.youtube.com/watch?v=uXgxMDglxVM
|
@ -1,33 +1,35 @@
|
||||
怎样实现由专有环境向开源环境的职业转变
|
||||
======
|
||||
|
||||
> 学习一点转变到新的技术文化的小技巧。
|
||||
|
||||

|
||||
|
||||
作为一名软件工程师,我的职业生涯是从 Northern Telecom 开始的,在这里我开发出了电信级的通讯转换设备可以使用的专有软件等。 即使我已经在大学中学习了 Pascal 语言,公司还是给我进行了以 C 语言为基础是专有编程语言培养。在公司中我使用的也是专有操作系统和专有版本控制软件。
|
||||
作为一名软件工程师,我的职业生涯是从北电开始的,在这里我开发出了电信级的电话交换机所用的专有软件。 即使我已经在大学中学习了 Pascal 语言,公司还是给我进行了以 C 语言为基础是专有编程语言培养。在公司中我使用的也是专有操作系统和专有版本控制软件。
|
||||
|
||||
我很享受专有环境下的工作,并有幸接触了很多有趣的项目,这样过了很多年,直到一场招聘会,我遇到了事业转折点。那时我受邀在当地一所中学的 STEM 行业座谈会进行演讲,给学生们讲述了作为一名软件工程师的主要工作内容和责任,一名学生问我:“这些事是你一直梦想要做的吗?你热爱你现在的工作吗?”
|
||||
|
||||
每次领导问我这个问题时,保险起见,我都会回答他,“我当然热爱工作了!”但从来没有一名还在读六年级的单纯的 STEM 小爱好者问过我这个问题。我的回答还是一样,“我当然喜欢!”
|
||||
|
||||
我确实很热爱我当时的事业,但那名学生的话让我忍不住思考,我开始重新审视我的事业,重新审视专有环境。在我的领域里我如鱼得水,但这也有局限性:我只能用代码来定义我的领域。我忍不住反思,这些年我有没有试着去学一些其他可应用于专有环境的技术?在同行中我的技能组还算得上先进吗?我有没有混日子?我真的想继续为这项事业奋斗吗?
|
||||
我确实很热爱我当时的事业,但那名学生的话让我忍不住思考,我开始重新审视我的事业,重新审视专有环境。在我的领域里我如鱼得水,但这也有局限性:我只能用代码来定义我的领域。我忍不住反思,这些年我在专有环境中学到了不同的技术了吗?在同行中我的技能组还算得上先进吗?我有没有混日子?我真的想继续为这项事业奋斗吗?
|
||||
|
||||
我想了很多,忍不住问自己:当年的激情和创意还在吗?
|
||||
|
||||
时间不会停止,但我的生活发生了改变。我离开了 Nortel Networks ,打算休息一段时间来陪陪我的家人。
|
||||
时间不会停止,但我的生活发生了改变。我离开了北电 ,打算休息一段时间来陪陪我的家人。
|
||||
|
||||
在我准备返回工作岗位时,那个小朋友的话又在我的脑海中响起,这真的是我想要的工作吗?我投了很多份简历,有一个岗位是我最中意的,但那家公司的回复是,他们想要的是拥有五年及以上 Java and Python 工作经验的人。在过去十五年里我以之为生的知识和技术看起来已经过时了。
|
||||
在我准备返回工作岗位时,那个小朋友的话又在我的脑海中响起,这真的是我想要的工作吗?我投了很多份简历,有一个岗位是我最中意的,但那家公司的回复是,他们想要的是拥有五年及以上的 Java 和 Python 工作经验的人。在过去十五年里我以之为生的知识和技术看起来已经过时了。
|
||||
|
||||
### 机遇与挑战
|
||||
|
||||
我的第一项挑战是学会在新的环境下应用我先前在封闭环境学到的技能。IT 行业由专有环境转向开源后发生了天翻地覆的变化。我打算先自学眼下最需要的 Python 。接触 Python 后我意识到,我需要一个项目来证明自己的能力,让自己更具有竞争力。
|
||||
|
||||
我的第二个挑战是怎么获得 Python 相关的项目经验。我丈夫和之前的同事都向我推荐了开源软件,通过谷歌搜索我发现网上有许许多多的开源项目,它们分别来源于一个人的小团队,50 人左右的团队,还有跨国的百人大团队。
|
||||
我的第二个挑战是怎么获得 Python 相关的项目经验。我丈夫和之前的同事都向我推荐了开源软件,通过谷歌搜索我发现网上有许许多多的开源项目,它们分别来源于一个人的小团队、50 人左右的团队,还有跨国的百人大团队。
|
||||
|
||||
在 Github 上我用相关专业术语搜索出了许多适合我的项目。综合我的兴趣和网络相关的工作经验,我打算把第一个项目贡献给 OpenStack 。 我还注意到了 [Outreachy][1] 项目,它为不具备相关技术基础的人员提供三个月的实习期。
|
||||
在 Github 上我用相关专业术语搜索出了许多适合我的项目。综合我的兴趣和网络相关的工作经验,我打算把第一个项目贡献给 OpenStack。 我还注意到了 [Outreachy][1] 项目,它为不具备相关技术基础的人员提供三个月的实习期。
|
||||
|
||||
### 经验与教训
|
||||
|
||||
我学到的第一件事是我发现可以通过许多方式进行贡献。不论是文件编制、用户设计,还是测试用例,都是贡献的形式。我在探索中丰富了我的技能组,根本用不着5年的时间,只需要在开源平台上接受委托,之后做出成果。
|
||||
我学到的第一件事是我发现可以通过许多方式进行贡献。不论是文件编制、用户设计,还是测试用例,都是贡献的形式。我在探索中丰富了我的技能组,根本用不着 5 年的时间,只需要在开源平台上接受委托,之后做出成果。
|
||||
|
||||
在我为 OpenStack 做出的第一个贡献被合并、发表后,我正式成为了 Outreachy 项目的一员。 Outreachy 项目最好的一点是,项目分配给我的导师能够引领我在开源世界中找到方向。
|
||||
|
||||
@ -48,7 +50,7 @@ via: https://opensource.com/article/18/7/career-move
|
||||
作者:[Petra Sargent][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[Valoniakim](https://github.com/Valoniakim)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,13 +1,15 @@
|
||||
重温 wallabag,Instapaper 的开源替代品
|
||||
重温 wallabag:Instapaper 的开源替代品
|
||||
======
|
||||
|
||||
> 这个稍后阅读应用增加了功能,使其成为诸如 Pocket、Paper 和 Instapaper 之类应用的可靠替代品。
|
||||
|
||||

|
||||
|
||||
早在 2014 年,我[写了篇关于 wallabag 的文章][1],它是稍后阅读应用如 Instapaper 和 Pocket 的开源替代品。如果你愿意,去看看那篇文章吧。别担心,我会等你的。
|
||||
早在 2014 年,我[写了篇关于 wallabag 的文章][1],它是诸如 Instapaper 和 Pocket 这样的稍后阅读应用的开源替代品。如果你愿意,去看看那篇文章吧。别担心,我会等你的。
|
||||
|
||||
好了么?很好
|
||||
好了么?很好。
|
||||
|
||||
自从我写这篇文章的四年来,[wallabag][2]的很多东西都发生了变化。现在是时候看看 wallabag 是如何成熟的。
|
||||
自从我写这篇文章的四年来,[wallabag][2] 的很多东西都发生了变化。现在是时候悄悄看一下 wallabag 是如何成熟的。
|
||||
|
||||
### 有什么新的
|
||||
|
||||
@ -15,11 +17,11 @@
|
||||
|
||||
那么这些变化有哪些呢?有[很多][3]。以下是我发现最有趣和最有用的内容。
|
||||
|
||||
除了使 wallabag 更加快速和稳定之外,程序的导入和导出内容的能力也得到了提高。你可以从 Pocket 和 Instapaper 导入文章,也可导入书签服务 [Pinboard][4] 中标记为 “To read” 的文章。你还可以导入 Firefox 和 Chrome 书签。
|
||||
除了使 wallabag 更加快速和稳定之外,该应用的导入和导出内容的能力也得到了提高。你可以从 Pocket 和 Instapaper 导入文章,也可导入书签服务 [Pinboard][4] 中标记为 “To read” 的文章。你还可以导入 Firefox 和 Chrome 书签。
|
||||
|
||||
你还可以以多种格式导出文章,包括 EPUB、MOBI、PDF 和纯文本。你可以为单篇文章、所有未读文章或所有已读和未读执行此操作。我四年前使用的 wallabag 版本可以导出到 EPUB 和 PDF,但有时导出很糟糕。现在,这些导出快速而顺利。
|
||||
|
||||
Web 界面中的注释和高亮显示现在可以更好,更一致地工作。不可否认,我并不经常使用它们 - 但它们不会像 wallabag v1 那样随机消失。
|
||||
Web 界面中的注释和高亮显示现在可以更好、更一致地工作。不可否认,我并不经常使用它们 —— 但它们不会像 wallabag v1 那样随机消失。
|
||||
|
||||

|
||||
|
||||
@ -27,7 +29,7 @@ wallabag 的外观和感觉也有所改善。这要归功于受 [Material Design
|
||||
|
||||

|
||||
|
||||
其中一个最大的变化是引入了 wallabag 的[托管版本][6]。不止一些人(包括你在内)没有服务器来运行网络程序,并且不太愿意这样做。当遇到任何技术问题时,我很窘迫。我不介意每年花 9 欧元(我写这篇文章的时候只要 10 美元),以获得一个我不需要关注的程序的完整工作版本。
|
||||
其中一个最大的变化是引入了 wallabag 的[托管版本][6]。不是只有少数人(包括你在内)没有服务器来运行网络程序,并且也不太愿意维护台服务器。当遇到任何技术问题时,我很窘迫。我不介意每年花 9 欧元(我写这篇文章的时候只要 10 美元),以获得一个我不需要关注的程序的完整工作版本。
|
||||
|
||||
### 没有改变什么
|
||||
|
||||
@ -37,11 +39,11 @@ Wallabag 的[浏览器扩展][7]以同样的方式完成同样的工作。我发
|
||||
|
||||
### 有什么令人失望的
|
||||
|
||||
移动应用良好,但没有很棒。它在渲染文章方面做得很好,并且有一些配置选项。但是你不能高亮或注释文章。也就是说,你可以使用该程序浏览你的存档文章。
|
||||
移动应用良好,但不算很棒。它在渲染文章方面做得很好,并且有一些配置选项。但是你不能高亮或注释文章。也就是说,你可以使用该程序浏览你的存档文章。
|
||||
|
||||

|
||||
|
||||
虽然 wallabag 在收藏文章方面做得很好,但有些网站的内容却无法保存。我没有碰到很多这样的网站,但已经遇到让人烦恼的情况。我不确定与 wallabag 有多大关系。相反,我怀疑它与网站的编码方式有关 - 我在使用几个专有的稍后阅读工具时遇到了同样的问题。
|
||||
虽然 wallabag 在收藏文章方面做得很好,但有些网站的内容却无法保存。我没有碰到很多这样的网站,但已经遇到让人烦恼的情况。我不确定与 wallabag 有多大关系。相反,我怀疑它与网站的编码方式有关 —— 我在使用几个专有的稍后阅读工具时遇到了同样的问题。
|
||||
|
||||
Wallabag 可能不是 Pocket 或 Instapaper 的等功能的替代品,但它做得很好。自从我第一次写这篇文章以来的四年里,它已经有了明显的改善。它仍然有改进的余地,但要做好它宣传的。
|
||||
|
||||
@ -56,7 +58,7 @@ via: https://opensource.com/article/18/7/wallabag
|
||||
作者:[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/) 荣誉推出
|
||||
|
@ -0,0 +1,216 @@
|
||||
逃离 Google,重获自由(与君共勉)
|
||||
======
|
||||
|
||||
> 寻求挣脱科技巨头的一次开创性尝试
|
||||
|
||||

|
||||
|
||||
在过去的六个月里,难以想象我到底经历了些什么。艰难的、耗时的、开创性的探索,为的只是完全摒弃一家公司 —— Google(谷歌)—— 的产品。本该是件简简单单的任务,但真要去做,花费在研究和测试上的又何止几个小时。但我成功了。现在,我已经不需要 Google 了,作为西方世界中极其少数的群体中的一份子,不再使用世界上最有价值的两家科技公司的产品(是的,我也不用 [Facebook(脸书)][6])。
|
||||
|
||||
本篇指南将向你展示我逃离 Google 生态的始末。以及根据本人的研究和个人需求,选择的替代方案。我不是技术方面的专家,或者说程序员,但作为记者,我的工作要求我对安全和隐私的问题保持警惕。
|
||||
|
||||
我选择替代方案时,主要考察其本身的长处、可用性、成本、以及是否具备我需要的功能。我的选择并不是那么大众,仅反映我自身的需求和期许,也不牵涉任何商业利益。下面列出的所有替代方案都没有给我赞助,也从未试图花钱诱使我使用他们的服务。
|
||||
|
||||
### 首先我们需要知道:为什么?
|
||||
|
||||
你们说这事情整的,我和 Google 可无冤无仇。事实上,不久前我还是个忠实的 Google 粉。还是记得是 90 年代末,当时我还在读高中,我和 Google 搜索引擎的第一次邂逅,那一瞬的美简直惊为天人。那时候的 Google 可是领先了 Yahoo、Altavista、Ask Jeeves 这些公司好几年。Google 实打实地去帮用户找到他们想在网络上找的东西,但同样是那个时代,乌七八糟的网站和糟糕的索引遍地横生。
|
||||
|
||||
Google 很快就从仅提供检索服务转向提供其它服务,其中许多都是我欣然拥抱的服务。早在 2005 年,当时你们可能还只能[通过邀请][7]加入 Gmail 的时候,我就已经是早期使用者了。Gmail 采用了线程对话、归档、标签,毫无疑问是我使用过的最好的电子邮件服务。当 Google 在 2006 年推出其日历工具时,那种对操作的改进绝对是革命性的。针对不同日历使用不同的颜色进行编排、检索事件、以及发送可共享的邀请,操作极其简单。2007 年推出的 Google Docs 同样令人惊叹。在我的第一份全职工作期间,我还促成我们团队使用支持多人同时编辑的 Google 电子表格、文档和演示文稿来完成日常工作。
|
||||
|
||||
和许多人一样,我也是 Google 开疆拓土过程中的受害者。从搜索(引擎)到电子邮件、文档、分析、再到照片,许多其它服务都建立在彼此之上,相互勾连。Google 从一家发布实用产品的公司转变成诱困用户的公司,与此同时将整个互联网转变为牟利和数据采集的机器。Google 在我们的数字生活中几乎无处不在,这种程度的存在远非其他公司可以比拟。与之相比使用其他科技巨头的产品想要抽身就相对容易。对于 Apple(苹果),你要么身处 iWorld 之中,要么是局外人。亚马逊亦是如此,甚至连 Facebook 也不过是拥有少数的几个平台,不用(Facebook)更多的是[心理挑战][8],实际上并没有多么困难。
|
||||
|
||||
然而,Google 无处不在。无论是笔记本电脑、智能手机或者平板电脑,我猜其中至少会有那么一个 Google 的应用程序。Google 就是搜索(引擎)、地图、电子邮件、浏览器和大多数智能手机操作系统的代名词。甚至还有些应用有赖于其提供的“[服务][9]”和分析,比方说 Uber 便需要采用 Google 地图来运营其乘车服务。
|
||||
|
||||
Google 现在俨然已是许多语言中的单词,但彰显其超然全球统治地位的方面显然不止于此。可以说只要你不是极其注重个人隐私,那其庞大而成套的工具几乎没有多少众所周知或广泛使用的替代品。这恰好也是大家选择 Google 的原因,在很多方面能更好的替代现有的产品。但现在,使我们的难以割舍的主要原因其实是 Google 已经成为了默认选择,或者说由于其主导地位导致替代品无法对我们构成足够的吸引。
|
||||
|
||||
事实上,替代方案是存在的,这些年自<ruby>爱德华·斯诺登<rt>Edward Snowden</rt></ruby>披露 Google 涉事 <ruby>[棱镜][10]<rt>Prism</rt></ruby>以来,又陆续涌现了许多替代品。我从去年年底开始着手这个项目。经过六个月的研究、测评以及大量的尝试和失败,我终于找到了所有我正在使用的 Google 产品对应的注重个人隐私的替代品。令我感到吃惊的是,其中的一些替代品比 Google 的做的还要好。
|
||||
|
||||
### 一些注意事项
|
||||
|
||||
这个过程中需要面临的几个挑战之一便是,大多数的替代方案,特别是那些注重隐私空间的开源替代方案,确实对用户不太友好。我不是技术人员,但是自己有一个网站,了解如何管理 Wordpress,可以排除一些基本的故障,但我用不来命令行,也做不来任何需要编码的事。
|
||||
|
||||
提供的这些替代方案中的大多数,即便不能完整替代 Google 产品的功能,但至少可以轻松上手。不过有些还是需要你有自己的 Web 主机或服务器的。
|
||||
|
||||
此外,[Google Takeout][11] 是你的好帮手。我通过它下载了我所有的电子邮件历史记录,并将其上传到我的计算机上,再通过 Thunderbird 访问,这意味着我可以轻松访问这十几年的电子邮件。关于日历和文档也同样如此,我将后者转换为 ODT 格式,存在我的替代云上,下面我将进一步介绍其中的细节。
|
||||
|
||||
### 初级
|
||||
|
||||
#### 搜索引擎
|
||||
|
||||
[DuckDuckGo][12] 和 [startpage][13] 都是以保护个人隐私为中心的搜索引擎,不收集任何搜索数据。我用这两个搜索引擎来负责之前用 Google 搜索的所有需求。
|
||||
|
||||
其它的替代方案:实际上并不多,Google 坐拥全球 74% 的市场份额时,剩下的那些主要是因为中国的原因。不过还有 Ask.com,以及 Bing……
|
||||
|
||||
#### Chrome
|
||||
|
||||
[Mozilla Firefox][14] —— 近期的[一次大升级][15],是对早期版本的巨大改进。是一个由积极致力于保护隐私的非营利基金会打造的浏览器。它的存在让你觉得没有必要死守 Chrome。
|
||||
|
||||
其它的替代方案:考虑到 Opera 和 Vivaldi 都基于 Chrome。[Brave][16] 浏览器是我的第二选择。
|
||||
|
||||
#### Hangouts(环聊)和 Google Chat
|
||||
|
||||
[Jitsi Meet][17] —— 一款 Google Hangouts 的开源免费替代方案。你可以直接在浏览器上使用或下载应用程序。快速,安全,几乎适用于所有平台。
|
||||
|
||||
其它的替代方案:Zoom 在专业领域渐受青睐,但大部分的特性需要付费。[Signal][18],一个开源、安全的消息通讯类应用程序,可以用来打电话,不过仅限于移动设备。不推荐 Skype,既耗流量,界面还糟。
|
||||
|
||||
#### Google Maps(地图)
|
||||
|
||||
桌面端:[HERE WeGo][19] —— 加载速度更快,所有能在 Google Maps 找到的几乎都能找到。不过由于某些原因,还缺了一些国家,如日本。
|
||||
|
||||
移动端:[MAPS.ME][20] —— 我一开始用的就是这款地图,但是自从他们专注于导航模式后地图功能就有点鸡肋了。MAPS.ME 还是相当不错的,并且具有比 Google 更好的离线功能,这对像我这样的经常旅行的人来说非常好用。
|
||||
|
||||
其它的替代方案:[OpenStreetMap][21] 是我全心支持的一个项目,不过功能严重缺乏。甚至无法找到我在奥克兰的家庭住址。
|
||||
|
||||
### 初级(需付费)
|
||||
|
||||
当然其中有一部分是自作自受。例如,在寻找 Gmail 的替代品时,我想的不是仅仅从 Gmail 切换到另一家科技巨头产品作为替代。这就意味不会存在转到 Yahoo Mail 或 Microsoft Outlook 的情况,因为这并不能消除我对隐私问题的困扰。
|
||||
|
||||
请记住,虽说 Google 的许多服务都是免费的(更不必说包括 Facebook 在内的竞争对手的服务),那是因为他们正在积极地将我们的数据货币化。由于替代方案极力避免将数据货币化,这使他们不得不向我们收取费用。我愿意付钱来保护我的隐私,但也明白并非所有人都会做出这样的选择。
|
||||
|
||||
或许我们可以换一个方向来思考:可还曾记得以前寄信时也不得不支付邮票的费用吗?或者从商店购买周卡会员?从本质上讲,这就是使用注重隐私的电子邮件或日历应用程序的成本。也没那么糟。
|
||||
|
||||
#### Gmail
|
||||
|
||||
[ProtonMail][22] —— 由前 CERN(欧洲核子研究中心)的科学家创立,总部设在瑞士,一个拥有强大隐私保护的国家。但 ProtonMail 真正吸引我的地方是,它与大多数其它注重隐私的电子邮件程序不同,用户体验友好。界面类似于 Gmail,带标签,有过滤器和文件夹,无需了解任何有关安全性或隐私的信息即可使用。
|
||||
|
||||
免费版只提供 500MB 的存储空间。而我选择的是付费 5GB 帐户及其 VPN 服务。
|
||||
|
||||
其它的替代方案:[Fastmail][23] 不仅面向注重隐私的用户,界面也很棒。还有 [Hushmail][24] 和 [Tutanota][25],两者都具有与 ProtonMail 相似的功能。
|
||||
|
||||
#### Calendar(日历)
|
||||
|
||||
[Fastmail][26] 日历 —— 这个决定异常艰难,也抛出了另一个问题。Google 的产品存在于很多方面,可以用无处不在来形容,这导致初创公司甚至不再费心去创造替代品。在尝试了其它一些平庸的选项后,我最后还是推荐并选择 Fastmail 同时作为备用电子邮件和日历的选项。
|
||||
|
||||
### 进阶
|
||||
|
||||
这些需要一些技术知识,或者需要你自己有 Web 主机。我尝试研究过更简单的替代方案,但最终都没能入围。
|
||||
|
||||
#### Google Docs(文档)、Drive(云端硬盘)、Photos(照片)和 Contacts(联系人)
|
||||
|
||||
[Nextcloud][27] —— 一个功能齐全、安全并且开源的云套件,具有直观、友好的用户界面。问题是你需要自己有主机才能使用 Nextcloud。我有一个用于部署自己网站的主机,并且能够使用 Softaculous 在我主机的 C-Panel 上快速安装 Nextcloud。你需要一个 HTTPS 证书,我从 [Let's Encrypt][28] 上免费获得了一个。不似开通 Google Drive 帐户那般容易,但也不是很难。
|
||||
|
||||
同时我也在用 Nextcloud 作为 Google 的照片存储和联系人的替代方案,然后通过 CalDev 与手机同步。
|
||||
|
||||
其它的替代方案:还有其它开源选项,如 [ownCloud][29] 或者 [Openstack][30]。一些营利的选项也很不错,因为作为首选的 Dropbox 和 Box 也没有采用从你的数据中牟利的运营模式。
|
||||
|
||||
#### Google Analytics(分析)
|
||||
|
||||
[Matomo][31] —— 正式名为 Piwic,这是一个自托管的分析平台。虽然不像 Google 分析那样功能丰富,但可以很好地分析基本的网站流量,还有一个额外的好处,就是你无需为 Google 贡献流量数据了。
|
||||
|
||||
其它的替代方案:真的不多。[OpenWebAnalytics][32] 是另一个开源选择,还有一些营利性的选择,比如 GoStats 和 Clicky。
|
||||
|
||||
#### Android(安卓)
|
||||
|
||||
[LineageOS][33] + [F-Droid App Store][34]。可悲的是,智能手机世界已成为一个事实上的双头垄断,Google 的 Android 和 Apple 的 iOS 控制着整个市场。几年前存在的几个可用的替代品,如 Blackberry OS 或 Mozilla 的 Firefox OS,也已不再维护。
|
||||
|
||||
因此,只能选择次一级的 Lineage OS:一款注重隐私的、开源的 Android 版本,Google 服务及 APP 是选装的。这需要懂一些技术知识,因为安装的整个过程并不是那么一帆风顺,但运行状况良好,且不似大多数 Android 那般有大量预置软件。
|
||||
|
||||
其它的替代方案:呃…… Windows 10 Mobile?[PureOS][35] 看起来有那么点意思,[UbuntuTouch][36] 也差不多。
|
||||
|
||||
### 意想不到的挑战
|
||||
|
||||
首先,由于有关可用替代方案的优质资源匮乏,以及将数据从 Google 迁移到其它平台所面临的挑战,所以比我计划的时间要长许多。
|
||||
|
||||
但最棘手的是电子邮件,这与 ProtonMail 或 Google 无关。
|
||||
|
||||
在我 2004 年加入 Gmail 之前,我可能每年都会切换一次电子邮件。我的第一个帐户是使用 Hotmail,然后我使用了 Mail.com,Yahoo Mail 以及像 Bigfoot 这样被遗忘已久的服务。当我在变更电子邮件提供商时,我未曾记得有这般麻烦。我会告诉所有朋友,更新他们的地址簿,并更改其它网络帐户的邮箱地址。以前定期更改邮箱地址非常必要 —— 还记得曾几何时垃圾邮件是如何盘踞你旧收件箱的吗?
|
||||
|
||||
事实上,Gmail 最好的创新之一就是能够将垃圾邮件过滤掉。这意味着再也不用频繁更改邮箱地址了。
|
||||
|
||||
电子邮件是使用互联网的关键。你需要用它来开设 Facebook 帐户,使用网上银行,在留言板上发布等等。因此,当你决定切换帐户时,你就需要更新所有这些不同服务的邮箱地址。
|
||||
|
||||
令人惊讶的是,现在从 Gmail 迁出居然成为了最大的麻烦,因为遍地都需要通过邮箱地址来设置帐户。有几个站点不再允许你从后台执行此操作。有个服务事实上就是让我注销现在的帐户,然后开通一个新的,只因他们无法更改我的邮箱地址,然后他们手动转移了我的帐户数据。另一些迫使我打电话给客服要求更改邮箱地址,无谓的浪费了很多时间。
|
||||
|
||||
更令人惊讶的是,另一些服务接受了我的更改,却仍继续向我原来的 Gmail 帐户发送邮件,就需要打一次电话了。另一些甚至更烦人,向我的新电子邮件发送了一些消息,但仍在使用我的旧帐户发送其它电子邮件。这事最后变得异常繁琐,迫使我不得不将我的 Gmail 帐户和我新的 ProtonMail 帐户同时开了几个月,以确保重要的电子邮件不会丢失。这是我花了六个月时间的主要元凶。
|
||||
|
||||
如今人们很少变更他们的邮箱地址,大多数公司的平台在设计时就没有考虑去处理这种可能性。这是表明当今网络糟糕状态的一个明显迹象,即便是在 2002 年更改邮箱地址都比 2018 年来的容易。技术也并不总是一成不变的向前发展。
|
||||
|
||||
### 那么,这些 Google 的替代方案都好用吗?
|
||||
|
||||
有些确实更好!Jitsi Meet 运行更顺畅,需要的带宽更少,并且比 Hangouts 跨平台支持好。Firefox 比 Chrome 更稳定,占用的内存更少。Fastmail 的日历具有更好的时区集成。
|
||||
|
||||
还有些旗鼓相当。ProtonMail 具有 Gmail 的大部分功能,但缺少一些好用的集成,例如我之前使用的 Boomerang 邮件日程功能。还缺少联系人界面,但我正在使用 Nextcloud。说到 Nextcloud,它非常适合托管文件、联系人,还包含了一个漂亮的笔记工具(以及诸多其它插件)。但它没有 Google Docs 丰富的多人编辑功能。在我的预算中,还没有找到可行的替代方案。虽然还有 Collabora Office,但这需要升级我的服务器,这对我来说不能算切实可行。
|
||||
|
||||
一些取决于位置。在一些国家(如印度尼西亚),MAPS.ME 实际上比 Google 地图更好用,而在另一些国家(包括美国)就差了许多。
|
||||
|
||||
还有些要求用户牺牲一些特性或功能。Piwic 是一个穷人版的 Google Analytics,缺乏前者的许多详细报告和搜索功能。DuckDuckGo 适用于一般搜索,但是在特定的搜索方面还存在问题,当我搜索非英文内容时,它和 startpage 时常都会检索失败。
|
||||
|
||||
### 最后,我不再心念 Google
|
||||
|
||||
事实上,我觉得我解放了。如此这般依赖单一公司的那么多产品是一种形式上奴役,特别是当你的数据经常为你买单的时候。而且,其中许多替代方案实际上更好。清楚自己正掌控自己数据的感觉真得很爽。
|
||||
|
||||
如果我们别无选择,只能使用 Google 的产品,那我们便失去了作为消费者的最后一丝力量。
|
||||
|
||||
我希望 Google、Facebook、Apple 和其他科技巨头在对待用户时不要这么理所当然,不要试图强迫我们进入其无所不包的生态系统。我也期待新选手能够出现并与之竞争,就像以前一样,Google 的新搜索工具可以与当时的行业巨头 Altavista 和 Yahoo 竞争,或者说 Facebook 的社交网络能够与 MySpace 和 Friendster 竞争。Google 给出了更好的搜索方案,使互联网变得更加美好。有选择是个好事,可移植也是。
|
||||
|
||||
如今,我们很少有人哪怕只是尝试其它产品,因为我们已经习惯了 Google。我们不再更改邮箱地址,因为这太难了。我们甚至不尝试使用 Facebook 以外的替代品,因为我们所有的朋友都在 Facebook 上。这些我明白。
|
||||
|
||||
你不必完全脱离 Google。但最好给其它选择一个机会。到时候时你可能会感到惊讶,并想起那些年上网的初衷。
|
||||
|
||||
---
|
||||
|
||||
### 其它资源
|
||||
|
||||
我并未打算让这篇文章成为包罗万象的指南,这只不过是一个关于我如何脱离 Google 的故事。以下的那些资源会向你展示其它替代方案。其中有一些对我来说过于专业,还有一些我还没有时间去探索。
|
||||
|
||||
* [Localization Lab][2] 一份开源或注重隐私技术的项目的详细清单 —— 有些技术含量高,有些用户友好度比较好。
|
||||
* [Framasoft][3] 有一整套针对 Google 的替代方案,大部分是开源的,虽然大部分是法语。
|
||||
* Restore Privacy 也[整理了一份替代方案的清单][4]。
|
||||
|
||||
到你了。你可以直接回复或者通过 Twitter 来分享你喜欢的 Google 产品的替代方案。我确信我遗漏了许多,也非常乐意尝试。我并不打算一直固守我列出的这些方案。
|
||||
|
||||
---
|
||||
|
||||
作者简介:
|
||||
|
||||
Nithin Coca
|
||||
|
||||
自由撰稿人,涵盖政治,环境和人权以及全球科技的社会影响。更多参考 http://www.nithincoca.com
|
||||
|
||||
---
|
||||
|
||||
via: https://medium.com/s/story/how-i-fully-quit-google-and-you-can-too-4c2f3f85793a
|
||||
|
||||
作者:[Nithin Coca][a]
|
||||
译者:[martin2011qi](https://github.com/martin2011qi)
|
||||
校对:[pityonline](https://github.com/pityonline)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://medium.com/@excinit
|
||||
[1]: https://medium.com/@excinit
|
||||
[2]: https://www.localizationlab.org/projects/
|
||||
[3]: https://framasoft.org/?l=en
|
||||
[4]: https://restoreprivacy.com/google-alternatives/
|
||||
[5]: https://medium.com/@excinit
|
||||
[6]: https://www.nithincoca.com/2011/11/20/7-months-no-facebook/
|
||||
[7]: https://www.quora.com/How-long-was-Gmail-in-private-%28invitation-only%29-beta
|
||||
[8]: https://www.theverge.com/2018/4/28/17293056/facebook-deletefacebook-social-network-monopoly
|
||||
[9]: https://en.wikipedia.org/wiki/Google_Play_Services
|
||||
[10]: https://www.theguardian.com/world/2013/jun/06/us-tech-giants-nsa-data
|
||||
[11]: https://takeout.google.com/settings/takeout
|
||||
[12]: https://duckduckgo.com/
|
||||
[13]: https://www.startpage.com/
|
||||
[14]: https://www.mozilla.org/en-US/firefox/new/
|
||||
[15]: https://www.seattletimes.com/business/firefox-is-back-and-its-time-to-give-it-a-try/
|
||||
[16]: https://brave.com/
|
||||
[17]: https://jitsi.org/jitsi-meet/
|
||||
[18]: https://signal.org/
|
||||
[19]: https://wego.here.com/
|
||||
[20]: https://maps.me/
|
||||
[21]: https://www.openstreetmap.org/
|
||||
[22]: https://protonmail.com/
|
||||
[23]: https://www.fastmail.com/
|
||||
[24]: https://www.hushmail.com/
|
||||
[25]: https://tutanota.com/
|
||||
[26]: https://www.fastmail.com/
|
||||
[27]: https://nextcloud.com/
|
||||
[28]: https://letsencrypt.org/
|
||||
[29]: https://owncloud.org/
|
||||
[30]: https://www.openstack.org/
|
||||
[31]: https://matomo.org/
|
||||
[32]: http://www.openwebanalytics.com/
|
||||
[33]: https://lineageos.org/
|
||||
[34]: https://f-droid.org/en/
|
||||
[35]: https://puri.sm/posts/tag/pureos/
|
||||
[36]: https://ubports.com/
|
@ -1,203 +1,158 @@
|
||||
Javascript 框架对比及案例(React、Vue 及 Hyperapp)
|
||||
============================================================
|
||||
在[我的上一片文章中][5],我试图解释为什么我认为[Hyperapp][6]是一个可用的 [React][7] 或 [Vue][8] 的替代品,我发现当我开始用它时,会容易的找到这个原因。许多人批评这篇文章,认为它自以为是,并没有给其他框架一个展示自己的机会。因此,在这篇文章中,我将尽可能客观的通过提供一些最小化的例子来比较这三个框架,以展示他们的能力。
|
||||
JavaScript 框架对比及案例(React、Vue 及 Hyperapp)
|
||||
=============================================
|
||||
|
||||
#### 臭名昭著计时器例子
|
||||
在[我的上一篇文章中][5],我试图解释为什么我认为 [Hyperapp][6] 是一个 [React][7] 或 [Vue][8] 的可用替代品,原因是,我发现它易于起步。许多人批评这篇文章,认为它自以为是,并没有给其它框架一个展示自己的机会。因此,在这篇文章中,我将尽可能客观的通过提供一些最小化的例子来比较这三个框架,以展示它们的能力。
|
||||
|
||||
计时器可能是响应式编程中最常用最容易理解的例子之一:
|
||||
### 耳熟能详的计时器例子
|
||||
|
||||
计时器可能是响应式编程中最常用的例子之一,极其易于理解:
|
||||
|
||||
* 你需要一个变量 `count` 保持对计数器的追踪。
|
||||
|
||||
* 你需要两个方法来增加或减少 `count` 变量的值。
|
||||
|
||||
* 你需要一种方法来渲染 `count` 变量,并将其呈现给用户。
|
||||
|
||||
* 你需要两个挂载到两个方法上的按钮,以便在用户和它们产生交互时变更 `count` 变量。
|
||||
* 你需要挂载到这两个方法上的两个按钮,以便在用户和它们产生交互时变更 `count` 变量。
|
||||
|
||||
下述代码是上述所有三个框架的实现:
|
||||
|
||||
|
||||

|
||||
使用 React、Vue 和 Hyperapp 实现的计数器
|
||||
|
||||
*使用 React、Vue 和 Hyperapp 实现的计数器*
|
||||
|
||||
这里或许会有很多要做的事情,特别是当你并不熟悉其中的一个或多个的时候,因此,我们来一步一步解构这些代码:
|
||||
这里或许会有很多要做的事情,特别是当你并不熟悉其中的一个或多个步骤的时候,因此,我们来一步一步解构这些代码:
|
||||
|
||||
* 这三个框架的顶部都有一些 `import` 语句
|
||||
|
||||
* React 更推崇面向对象的范式,就是创建一个 `Counter` 组件的 `class`,Vue 遵循类似的范式,并通过创建一个新的 `Vue` 类的实例并将信息传递给它来实现。 最后,Hyperapp 坚持函数范式,同时完全分离 `view`、`state`和`action` 。
|
||||
|
||||
* React 更推崇面向对象的范式,就是创建一个 `Counter` 组件的 `class`。Vue 遵循类似的范式,通过创建一个新的 `Vue` 类的实例并将信息传递给它来实现。最后,Hyperapp 坚持函数范式,同时完全彼此分离 `view`、`state`和`action`。
|
||||
* 就 `count` 变量而言, React 在组件的构造函数内对其进行实例化,而 Vue 和 Hyperapp 则分别是在它们的 `data` 和 `state` 中设置这些属性。
|
||||
|
||||
* 继续看,你可能注意到 React 和 Vue 有相同的方法来于 `count` 变量进行交互。 React 使用继承自 `React.Component` 的 `setState` 方法来修改它的状态,而 Vue 直接修改 `this.count`。 Hyperapp 使用 ES6 的双箭头语法来实现这个方法,并且,据我所知,这是唯一一个更推荐使用这种语法的框架,React 和 Vue 需要在它们的方法内使用 `this`。另一方面,Hyperapp 的方法需要将状态作为参数,这意味着可以在不同的上下文中重用它们。
|
||||
|
||||
* 这三个框架的渲染部分实际上是相同的。唯一的细微差别是 Vue 需要一个函数 `h` 作为参数传递给渲染器,事实上 Hyperapp 使用 `onclick` 替代 `onClick` 以及基于每个框架中实现状态的方式引用 `count` 变量的方式。
|
||||
|
||||
* 继续看,你可能注意到 React 和 Vue 有相同的方法来与 `count` 变量进行交互。 React 使用继承自 `React.Component` 的 `setState` 方法来修改它的状态,而 Vue 直接修改 `this.count`。 Hyperapp 使用 ES6 的双箭头语法来实现这个方法,而据我所知,这是唯一一个推荐使用这种语法的框架,React 和 Vue 需要在它们的方法内使用 `this`。另一方面,Hyperapp 的方法需要将状态作为参数,这意味着可以在不同的上下文中重用它们。
|
||||
* 这三个框架的渲染部分实际上是相同的。唯一的细微差别是 Vue 需要一个函数 `h` 作为参数传递给渲染器,事实上 Hyperapp 使用 `onclick` 替代 `onClick` ,以及基于每个框架中实现状态的方式引用 `count` 变量。
|
||||
* 最后,所有的三个框架都被挂载到了 `#app` 元素上。每个框架都有稍微不同的语法,Vue 则使用了最直接的语法,通过使用元素选择器而不是使用元素来提供最大的通用性。
|
||||
|
||||
#### 计数器案例对比意见
|
||||
|
||||
同时比较所有的三个框架,Hyperapp 需要最少的代码来实现计数器,并且它是唯一一个使用函数范式的框架。然而,Vue 的代码在绝对长度上似乎更短一些,元素选择器的挂载方式是一个很好的增强。React 的代码看起来最多,但是并不意味着代码不好理解。
|
||||
|
||||
同时比较所有的三个框架,Hyperapp 需要最少的代码来实现计数器,并且他是唯一一个使用函数范式的框架。然而,Vue 的代码在绝对长度上似乎更短一些,元素选择器的安装是一个很好的补充。React 的代码看起来最多,但是并不意味着代码不好理解。
|
||||
### 使用异步代码
|
||||
|
||||
* * *
|
||||
|
||||
#### 使用异步代码
|
||||
|
||||
偶尔你可能要不得不处理异步代码。最常见的异步操作之一是发送请求给一个 API。为了这个例子的目的,我将使用一个[占位 API]以及一些假数据来渲染一个文章的列表。必须做的事情如下:
|
||||
偶尔你可能需要处理异步代码。最常见的异步操作之一是发送请求给一个 API。为了这个例子的目的,我将使用一个[占位 API] 以及一些假数据来渲染一个文章列表。必须做的事情如下:
|
||||
|
||||
* 在状态里保存一个 `posts` 的数组
|
||||
|
||||
* 使用一个方法和正确的 URL 来调用 `fetch()` ,等待返回数据,转化为 JSON,最终使用接收到的数据更新 `posts` 变量。
|
||||
|
||||
* 使用一个方法和正确的 URL 来调用 `fetch()` ,等待返回数据,转化为 JSON,并最终使用接收到的数据更新 `posts` 变量。
|
||||
* 渲染一个按钮,这个按钮将调用抓取文章的方法。
|
||||
|
||||
* 渲染有主键的 `posts` 列表。
|
||||
|
||||
|
||||

|
||||
从一个 RESTFul API 抓取数据
|
||||
|
||||
*从一个 RESTFul API 抓取数据*
|
||||
|
||||
让我们分解上面的代码,并比较三个框架:
|
||||
|
||||
* 与上面的技术里例子类似,这三个框架之间的存储状态、渲染试图和挂载非常相似。这些差异与上面的讨论相同。
|
||||
|
||||
* 在三个框架中使用 `fetch()` 抓取数据都非常简单并且可以像预期一样工作。然而其中的关键在于, Hyperapp 处理异步操作和其他两种框架有些不同。当数据被接收到并转换为JSON 时,该操作将调用不同的同步动作以取代直接在异步操作中修改状态。
|
||||
|
||||
* 就代码长度而言, Hyperapp 依然需要最少的代码行数来实现相同的结果,但是 Vue 的代码看起来不那么的冗长,同时拥有最少的绝对字符长度。
|
||||
* 与上面的技术里例子类似,这三个框架之间的存储状态、渲染视图和挂载非常相似。这些差异与上面的讨论相同。
|
||||
* 在三个框架中使用 `fetch()` 抓取数据都非常简单,并且可以像预期一样工作。然而其中的关键在于, Hyperapp 处理异步操作和其它两种框架有些不同。当数据被接收到并转换为 JSON 时,该操作将调用不同的同步动作以取代直接在异步操作中修改状态。
|
||||
* 就代码长度而言,Hyperapp 依然只用最少的代码行数实现了相同的结果,但是 Vue 的代码看起来不那么的冗长,同时拥有最少的绝对字符长度。
|
||||
|
||||
#### 异步代码对比意见
|
||||
|
||||
无论你选择哪种框架,异步操作都非常简单。在应用异步操作时, Hyperapp 可能会迫使你去遵循编写更加函数化和模块化的代码的路径。但是另外两个框架也确实可以做到这一点,并且在这一方面给你提供更多的选择。
|
||||
无论你选择哪种框架,异步操作都非常简单。在应用异步操作时, Hyperapp 可能会迫使你去遵循编写更加函数化和模块化的代码的方式。但是另外两个框架也确实可以做到这一点,并且在这一方面给你提供更多的选择。
|
||||
|
||||
* * *
|
||||
### To-Do 列表组件案例
|
||||
|
||||
#### To-Do List 组件案例
|
||||
|
||||
在响应式编程中,最出名的例子可能是使用每一个框架里来实现 To-Do List。我不打算在这里实现整个部分,我只实现一个无状态的组件,来展示三个框架如何帮助创建更小的可复用的块来协助构建应用程序。
|
||||
在响应式编程中,最出名的例子可能是使用每一个框架里来实现 To-Do 列表。我不打算在这里实现整个部分,我只实现一个无状态的组件,来展示三个框架如何创建更小的可复用的块来协助构建应用程序。
|
||||
|
||||

|
||||
演示 TodoItem 实现
|
||||
|
||||
*示例 TodoItem 实现*
|
||||
|
||||
上面的图片展示了每一个框架一个例子,并为 React 提供了一个额外的例子。接下来是我们从它们四个中看到的:
|
||||
|
||||
* React 在编程范式上最为灵活。它支持函数组件以及类组件。它还支持你在右下角看到的 Hyperapp 组件,无需任何修改。
|
||||
|
||||
* Hyperapp 还支持 React 的函数组件实现,这意味着两个框架之间还有实验的空间。
|
||||
|
||||
* 最后出现的 Vue 有着其合理而又奇怪的语法,即使是对另外两个很有经验的人,也不能马上理解其含义。
|
||||
|
||||
* React 在编程范式上最为灵活。它支持函数组件,也支持类组件。它还支持你在右下角看到的 Hyperapp 组件,无需任何修改。
|
||||
* Hyperapp 还支持 React 的函数组件实现,这意味着两个框架之间还有很多的实验空间。
|
||||
* 最后出现的 Vue 有着其合理而又奇怪的语法,即使是对另外两个框架很有经验的人,也不能马上理解其含义。
|
||||
* 在长度方面,所有的案例代码长度非常相似,在 React 的一些方法中稍微冗长一些。
|
||||
|
||||
#### To-Do List 项目对比意见
|
||||
#### To-Do 列表项目对比意见
|
||||
|
||||
Vue 需要花费一些时间来熟悉,因为它的模板和其他两个框架有一些不同。React 非常的灵活,支持多种不同的方法来创建组件,而 HyperApp 保持一切简单,并提供与 React 的兼容性,以免你希望在某些时刻进行切换。
|
||||
Vue 需要花费一些时间来熟悉,因为它的模板和其它两个框架有一些不同。React 非常的灵活,支持多种不同的方法来创建组件,而 HyperApp 保持一切简单,并提供与 React 的兼容性,以免你希望在某些时刻进行切换。
|
||||
|
||||
* * *
|
||||
### 生命周期方法比较
|
||||
|
||||
#### 生命周期方法比较
|
||||
|
||||
|
||||
另一个关键对比是组件的生命周期事件,每一个框架允许你根据你的需要来订阅和处理这些时间。下面是我根据各框架的 API 参考手册创建的表格:
|
||||
另一个关键对比是组件的生命周期事件,每一个框架允许你根据你的需要来订阅和处理事件。下面是我根据各框架的 API 参考手册创建的表格:
|
||||
|
||||

|
||||
Lifecycle method comparison
|
||||
|
||||
* Vue 提供了最多的生命周期钩子,提供了处理生命周期时间之前或之后发生任何时间的机会。这能有效帮助管理复杂的组件。
|
||||
|
||||
* React 和 Hyperapp 的生命周期钩子非常类似,React 将 `unmount` 和 `destory` 绑定在了一切,而 Hyperapp 则将 `create` 和 `mount` 绑定在了一起。两者在处理生命周期事件方面都提供了相当数量的控制。
|
||||
*生命周期方式比较*
|
||||
|
||||
* Vue 提供了最多的生命周期钩子,提供了处理生命周期事件之前或之后发生的任何事件的机会。这能有效帮助管理复杂的组件。
|
||||
* React 和 Hyperapp 的生命周期钩子非常类似,React 将 `unmount` 和 `destory` 绑定在了一起,而 Hyperapp 则将 `create` 和 `mount` 绑定在了一起。两者在处理生命周期事件方面都提供了相当多的控制。
|
||||
* Vue 根本没有处理 `unmount` (据我所理解),而是依赖于 `destroy` 事件在组件稍后的生命周期进行处理。 React 不处理 `destory` 事件,而是选择只处理 `unmount` 事件。最终,HyperApp 不处理 `create` 事件,取而代之的是只依赖 `mount` 事件。
|
||||
|
||||
#### 生命周期对比意见
|
||||
|
||||
总的来说,每个框架都提供了生命周期组件,它们帮助你处理组件生命周期中的许多事情。这三个框架都为它们的生命周期提供了钩子,其之间的细微差别,可能源自于实现和方案上的根本差异。通过提供更细粒度的时间处理,Vue 可以更进一步的允许你在开始或结束之后处理生命周期事件。
|
||||
|
||||
* * *
|
||||
|
||||
#### 性能比较
|
||||
|
||||
除了易用性和编码技术以外,性能也是大多数开发人员考虑的关键因素,尤其是在进行更复杂的应用程序时。[js-framework-benchmark][10]是一个很好的用于比较框架的工具,所以让我们看看每一组测评数据数组都说了些什么:
|
||||
### 性能比较
|
||||
|
||||
除了易用性和编码技术以外,性能也是大多数开发人员考虑的关键因素,尤其是在进行更复杂的应用程序时。[js-framework-benchmark][10] 是一个很好的用于比较框架的工具,所以让我们看看每一组测评数据数组都说了些什么:
|
||||
|
||||

|
||||
测评操作表
|
||||
|
||||
*测评操作表*
|
||||
|
||||
* 与三个框架的有主键操作相比,无主键操作更快。
|
||||
|
||||
* 无主键的 React 在所有六种对比中拥有最强的性能,他在所有测试上都有令人深刻的表现。
|
||||
|
||||
* 有主键的 Vue 只比有主键的 React 性能稍强,而无主键的 Vue 要比无主键的 React 性能差。
|
||||
|
||||
* Vue 和 Hyperapp 在进行局部更新性能测试时遇见了一些问题,与此同时,React 似乎对该问题进行很好的优化。
|
||||
|
||||
* 无主键的 React 在所有六种对比中拥有最强的性能,它在所有测试上都有令人深刻的表现。
|
||||
* 有主键的 Vue 只比有主键的 React 性能稍强,而无主键的 Vue 要比无主键的 React 性能明显差。
|
||||
* Vue 和 Hyperapp 在进行局部更新的性能测试时遇见了一些问题,与此同时,React 似乎对该问题进行很好的优化。
|
||||
|
||||

|
||||
|
||||
启动测试
|
||||
|
||||
* Hyperapp 是三个框架中最轻量的,而 React 和 Vue 有非常小尺度的差异。
|
||||
|
||||
* Hyperapp 具有最快的启动时间,这得益于他极小的大小和极简的API
|
||||
|
||||
* Vue 在启动上比 React 好一些,但是非常小。
|
||||
*启动测试*
|
||||
|
||||
* Hyperapp 是三个框架中最轻量的,而 React 和 Vue 有非常小的大小差异。
|
||||
* Hyperapp 具有最快的启动时间,这得益于它极小的大小和极简的 API
|
||||
* Vue 在启动上比 React 好一些,但是差异非常小。
|
||||
|
||||

|
||||
内存分配测试
|
||||
|
||||
* Hyperapp 是三者中对资源依赖最小的一个,与其他两者相比,任何一个操作都需要更少的内存。
|
||||
*内存分配测试*
|
||||
|
||||
* 资源消耗不是跟高,三者应该在现代硬件上进行类似的操作。
|
||||
* Hyperapp 是三者中对资源依赖最小的一个,与其它两者相比,任何一个操作都需要更少的内存。
|
||||
* 资源消耗不是非常高,三者都应该在现代硬件上进行类似的操作。
|
||||
|
||||
#### 性能对比意见
|
||||
|
||||
如果性能是一个问题,你应该考虑你正在使用什么样的应用程序以及你的需求是什么。看起来 Vue 和 React 用于更复杂的应用程序更好,而 Hyperapp 更适合于更小的应用程序、更少的数据处理和需要快速启动的应用程序,以及需要在低端硬件上工作的应用程序。
|
||||
|
||||
但是,要记住,这些测试远不能代表一般用例,所以在现实场景中可能会看到不同的结果。
|
||||
但是,要记住,这些测试远不能代表一般场景,所以在现实场景中可能会看到不同的结果。
|
||||
|
||||
* * *
|
||||
### 额外备注
|
||||
|
||||
#### 额外备注
|
||||
|
||||
Comparing React, Vue and Hyperapp might feel like comparing apples and oranges in many ways. There are some additional considerations concerning these frameworks that could very well help you decide on one over the other two:
|
||||
|
||||
比较 React、Vue 和 Hyperapp 可能像在许多方面比较苹果、橘子。关于这些框架还有一些其他的考虑,它们可以帮助你决定使用另一个框架。
|
||||
|
||||
* React 通过引入片段,避免了相邻的JSX元素必须封装在父元素中的问题,这些元素允许你将子元素列表分组,而无需向DOM添加额外的节点。
|
||||
|
||||
* Read还为你提供更高级别的组件,而VUE为你提供重用组件功能的MIXIN。
|
||||
比较 React、Vue 和 Hyperapp 可能像在许多方面比较苹果、橘子。关于这些框架还有一些其它的考虑,它们可以帮助你决定使用另一个框架。
|
||||
|
||||
* React 通过引入[片段][1],避免了相邻的 JSX 元素必须封装在父元素中的问题,这些元素允许你将子元素列表分组,而无需向 DOM 添加额外的节点。
|
||||
* React 还为你提供[更高级别的组件][2],而 VUE 为你提供重用组件功能的 [MIXIN][3]。
|
||||
* Vue 允许使用[模板][4]来分离结构和功能,从而更好的分离关注点。
|
||||
* 与其它两个相比,Hyperapp 感觉像是一个较低级别的 API,它的代码短得多,如果你愿意调整它并学习它的工作原理,那么它可以提供更多的通用性。
|
||||
|
||||
* 与其他两个相比,Hyperapp 感觉像是一个较低级别的API,它的代码短得多,如果你愿意调整它并学习它的工作原理,那么它可以提供更多的通用性。
|
||||
|
||||
* * *
|
||||
|
||||
#### 结论
|
||||
### 结论
|
||||
|
||||
我认为如果你已经阅读了这么多,你已经知道哪种工具更适合你的需求。毕竟,这不是讨论哪一个更好,而是讨论哪一个更适合每种情况。总而言之:
|
||||
|
||||
|
||||
* React 是一个非常强大的工具,他的周围有大量的开发者,可能会帮助你找到一个工作。入门并不难,但是掌握它肯定需要很多时间。然而,这是非常值得去花费你的时间全面掌握的。
|
||||
|
||||
* 如果你过去曾使用过另外一个 JavaScript 框架,Vue 可能看起来有点奇怪,但它也是一个非常有趣的工具。如果 React 不是你所喜欢的 ,那么它可能是一个可行的值得学习的选择。
|
||||
|
||||
* 最后,Hyperapp 是一个为小型项目而生的很酷的小框架,也是初学者入门的好地方。它提供比 React 或 Vue 更少的工具,但是它能帮助你快速构建原型并理解许多基本原理。你编写的许多代码都和其他两个框架兼容,或者是稍做更改,你可以在对它们中另外一个有信心时切换框架。
|
||||
* React 是一个非常强大的工具,围绕它有大规模的开发者社区,可能会帮助你找到一个工作。入门并不难,但是掌握它肯定需要很多时间。然而,这是非常值得去花费你的时间全面掌握的。
|
||||
* 如果你过去曾使用过另外的 JavaScript 框架,Vue 可能看起来有点奇怪,但它也是一个非常有趣的工具。如果 React 不是你所喜欢的,那么它可能是一个可行的、值得学习的选择。它有一些非常酷的内置功能,其社区也在增长中,甚至可能要比 React 增长还要快。
|
||||
* 最后,Hyperapp 是一个为小型项目而生的很酷的小框架,也是初学者入门的好地方。它提供比 React 或 Vue 更少的工具,但是它能帮助你快速构建原型并理解许多基本原理。你为它编写的许多代码和其它两个框架兼容,要么立即能用,或者是稍做更改就行,你可以在对它们中另外一个有信心时切换框架。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
作者简介:
|
||||
|
||||
Web developer who loves to code, creator of 30 seconds of code (https://30secondsofcode.org/) and the mini.css framework (http://minicss.org).
|
||||
喜欢编码的 Web 开发者,“30 秒编码” ( https://30secondsofcode.org/ )和 mini.css 框架( http://minicss.org ) 的创建者。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://hackernoon.com/javascript-framework-comparison-with-examples-react-vue-hyperapp-97f064fb468d
|
||||
|
||||
作者:[Angelos Chalaris ][a]
|
||||
作者:[Angelos Chalaris][a]
|
||||
译者:[Bestony](https://github.com/bestony)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,70 @@
|
||||
适用于 Fedora 28 的 3 款酷炫生产力应用
|
||||
======
|
||||
|
||||

|
||||
|
||||
生产力应用在移动设备上特别受欢迎。但是当你坐下来做工作时,你经常在笔记本电脑或台式电脑上工作。假设你使用 Fedora 系统。你能找到帮助你完成工作的程序吗?当然!请继续阅读了解这些帮助你专注目标的程序。
|
||||
|
||||
所有这些程序都可以在 Fedora 系统上免费使用。当然,它们也维护了你的自由。 (许多还允许你使用你可能已经拥有帐户的现有服务。)
|
||||
|
||||
### FocusWriter
|
||||
|
||||
FocusWriter 只是一个全屏文字处理器。该程序可以提高你的工作效率,因为它覆盖了屏幕其他地方。当你使用 FocusWriter 时,除了你和文本,别无它物。有了这个程序,你可以专注于你的想法,减少分心。
|
||||
|
||||
[![Screenshot of FocusWriter][1]][2]
|
||||
|
||||
FocusWriter 允许你调整字体、颜色和主题以最适合你的喜好。它还会记住你上一个文档和位置。此功能可让你快速重新专注于书写。
|
||||
|
||||
要安装 FocusWriter,请使用 Fedora Workstation 中的软件中心。或者在终端中[使用 sudo ][3]运行此命令:
|
||||
|
||||
```
|
||||
sudo dnf install focuswriter
|
||||
```
|
||||
|
||||
### GNOME ToDo
|
||||
|
||||
你可以猜到这个独特的程序是为 GNOME 桌面环境设计的。因此,它非常适合你的 Fedora Workstation。ToDo 有一个简单的目的:它可以让你列出你需要完成的事情。
|
||||
|
||||

|
||||
|
||||
使用 ToDo,你可以为所有任务确定优先级并安排截止日期。你还可以根据需要构建任意数量的任务列表。ToDo 有大量提供了有用功能的扩展,以提高你的工作效率。这些包括 GNOME Shell 通知,以及带有 todo.txt 的列表管理。如果你有 Todoist 或者 Google 帐户,ToDo 甚至可以与它们交互。它可以同步任务,因此你可以跨设备共享。
|
||||
|
||||
要安装它,在软件中心搜索 ToDo,或在命令行运行:
|
||||
|
||||
```
|
||||
sudo dnf install gnome-todo
|
||||
```
|
||||
|
||||
### Zanshin
|
||||
|
||||
如果你是使用 KDE 的生产力粉丝,你可能会喜欢 [Zanshin][4]。该行事历可帮助你规划跨多个项目的操作。它有完整的功能界面,可让你浏览各种任务,以了解下一步要做的最重要的事情。
|
||||
|
||||
[![Screenshot of Zanshin on Fedora 28][5]][6]
|
||||
|
||||
Zanshin 非常适合键盘操作,因此你可在钻研时提高效率。它还集成了众多 KDE 程序以及 Plasma 桌面。你可以将其与 KMail、KOrganizer 和 KRunner 一起使用。
|
||||
|
||||
要安装它,请运行以下命令:
|
||||
|
||||
```
|
||||
sudo dnf install zanshin
|
||||
```
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/3-cool-productivity-apps/
|
||||
|
||||
作者:[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-15-18-10-18-1024x768.png
|
||||
[2]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot-from-2018-07-15-18-10-18.png
|
||||
[3]:https://fedoramagazine.org/howto-use-sudo/
|
||||
[4]:https://zanshin.kde.org/
|
||||
[5]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot_20180715_192216-1024x653.png
|
||||
[6]:https://fedoramagazine.org/wp-content/uploads/2018/07/Screenshot_20180715_192216.png
|
@ -1,9 +1,10 @@
|
||||
Linux 桌面中 4 个开源媒体转换工具
|
||||
======
|
||||
> 使用这些易用的工具来将音视频文件从一种格式转换为另一种格式。
|
||||
|
||||

|
||||
|
||||
啊,有这么多的文件格式,特别是音频和视频格式,如果你不认识这个文件扩展名或者你的播放器无法播放那个格式,或者你想使用一种开放格式,那会有点有趣。
|
||||
啊,有这么多的文件格式,特别是音频和视频格式,如果你不认识这个文件扩展名或者你的播放器无法播放那个格式,或者你想使用一种开放格式,那就需要花点心思了。
|
||||
|
||||
那么,Linux 用户可以做些什么呢?当然是去使用 Linux 桌面的众多开源媒体转换工具之一。我们来看看其中的四个。
|
||||
|
||||
@ -11,9 +12,9 @@ Linux 桌面中 4 个开源媒体转换工具
|
||||
|
||||

|
||||
|
||||
[Gnac][1] 是我最喜欢的音频转换器之一,已经存在很多年了。它易于使用,功能强大,并且它做得很好 - 任何一流的程序都应该如此。
|
||||
[Gnac][1] 是我最喜欢的音频转换器之一,已经存在很多年了。它易于使用,功能强大,并且它做得很好 —— 任何一流的程序都应该如此。
|
||||
|
||||
有多简单?单击工具栏按钮添加一个或多个要转换的文件,选择要转换的格式,然后单击**转换**。转换很快,而且很干净。
|
||||
有多简单?单击工具栏按钮添加一个或多个要转换的文件,选择要转换的格式,然后单击**Convert**。转换很快,而且很干净。
|
||||
|
||||
有多强大?Gnac 可以处理 [GStreamer][2] 多媒体框架支持的所有音频格式。开箱即用,你可以在 Ogg、FLAC、AAC、MP3、WAV 和 SPX 之间进行转换。你还可以更改每种格式的转换选项或添加新格式。
|
||||
|
||||
@ -23,7 +24,7 @@ Linux 桌面中 4 个开源媒体转换工具
|
||||
|
||||
如果在简单的同时你还要一些额外的功能,那么请看一下 [SoundConverter][3]。正如其名称所述,SoundConverter 仅对音频文件起作用。与 Gnac 一样,它可以读取 GStreamer 支持的格式,它可以输出 Ogg Vorbis、MP3、FLAC、WAV、AAC 和 Opus 文件。
|
||||
|
||||
通过单击**添加文件**或将其拖放到 SoundConverter 窗口中来加载单个文件或整个文件夹。单击**转换**,软件将完成转换。它也很快 - 我已经在大约一分钟内转换了一个包含几十个文件的文件夹。
|
||||
通过单击 **Add File** 或将其拖放到 SoundConverter 窗口中来加载单个文件或整个文件夹。单击 **Convert**,软件将完成转换。它也很快 —— 我已经在大约一分钟内转换了一个包含几十个文件的文件夹。
|
||||
|
||||
SoundConverter 有设置转换文件质量的选项。你可以更改文件的命名方式(例如,在标题中包含曲目编号或专辑名称),并为转换后的文件创建子文件夹。
|
||||
|
||||
@ -31,21 +32,21 @@ SoundConverter 有设置转换文件质量的选项。你可以更改文件的
|
||||
|
||||

|
||||
|
||||
[WinFF][4] 本身并不是转换器。它是 FFmpeg 的图形化前端,[Tim Nugent][5] 在 Opensource.com 写了篇文章。虽然 WinFF 没有 FFmpeg 的所有灵活性,但它使 FFmpeg 更易于使用,并且可以快速,轻松地完成工作。
|
||||
[WinFF][4] 本身并不是转换器。它是 FFmpeg 的图形化前端,[Tim Nugent 为此][5] 在 Opensource.com 写了篇文章。虽然 WinFF 没有 FFmpeg 的所有灵活性,但它使 FFmpeg 更易于使用,并且可以快速,轻松地完成工作。
|
||||
|
||||
虽然它不是这里最漂亮的程序,WinFF 也并不需要。它不仅仅是可用的。你可以从下拉列表中选择要转换的格式,并选择多个预设。最重要的是,你可以指定比特率和帧速率,要使用的音频通道数量,甚至裁剪视频的大小等选项。
|
||||
虽然它不是这里最漂亮的程序,也不需要是。它远比可以使用要好。你可以从下拉列表中选择要转换的格式,并选择多个预设配置。最重要的是,你可以指定比特率和帧速率,要使用的音频通道数量,甚至裁剪视频的大小等选项。
|
||||
|
||||
转换,特别是视频,需要一些时间,但结果通常非常好。有时,转换会有点受损 - 但往往不足以引起关注。而且,正如我之前所说,使用 WinFF 可以节省一些时间。
|
||||
转换,特别是视频,需要一些时间,但结果通常非常好。有时,转换会有点受损 —— 但往往不足以引起关注。而且,正如我之前所说,使用 WinFF 可以节省一些时间。
|
||||
|
||||
### Miro Video Converter
|
||||
|
||||

|
||||
|
||||
并非所有视频文件都是平等创建的。有些是专有格式。有的在显示器或电视屏幕上看起来很棒但是没有针对移动设备进行优化。这就是 [Miro Video Converter][6] 可以用的地方。
|
||||
并非所有视频文件都是同样创建的。有些是专有格式。有的在显示器或电视屏幕上看起来很棒但是没有针对移动设备进行优化。这就是 [Miro Video Converter][6] 可以用的地方。
|
||||
|
||||
Miro Video Converter 非常重视移动设备。它可以转换在 Android 手机、Apple 设备、PlayStation Portable 和 Kindle Fire 上播放的视频。它会将最常见的视频格式转换为 MP4、[WebM][7] 和 [Ogg Theora][8]。你可以[在 Miro 的网站][6]上找到支持的设备和格式的完整列表
|
||||
|
||||
要使用它,可以将文件拖放到窗口中,也可以选择要转换的文件。然后,单击“格式”菜单以选择转换的格式。你还可以单击 Apple、Android 或其他菜单以选择要转换文件的设备。Miro Video Converter 会为设备屏幕分辨率调整视频大小。
|
||||
要使用它,可以将文件拖放到窗口中,也可以选择要转换的文件。然后,单击“Format”菜单以选择转换的格式。你还可以单击 Apple、Android 或其他菜单以选择要转换文件的设备。Miro Video Converter 会为设备屏幕分辨率调整视频大小。
|
||||
|
||||
你有最喜欢的 Linux 媒体转换程序吗?请留下评论,随意分享。
|
||||
|
||||
@ -56,7 +57,7 @@ via: https://opensource.com/article/18/7/media-conversion-tools-linux
|
||||
作者:[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/) 荣誉推出
|
||||
|
@ -0,0 +1,48 @@
|
||||
开源网络方面的职位:创新与机遇的温床
|
||||
======
|
||||
|
||||
> 诸如容器、边缘计算这样的技术焦点领域大红大紫,对在这一领域能够整合、协作、创新的开发者和系统管理员们的需求在日益增进。
|
||||
|
||||

|
||||
|
||||
随着全球经济更加靠近数字化未来,每个垂直行业的公司和组织都在紧抓如何进一步在业务与运营上整合与部署技术。虽然 IT 企业在很大程度上遥遥领先,但是他们的经验与教训已经应用在了各行各业。尽管全国失业率为 4.1%,但整个科技专业人员的整体的失业率在 4 月份为 1.9%,开源工作的未来看起来尤其光明。我在开源网络领域工作,并且目睹着创新和机遇正在改变世界交流的方式。
|
||||
|
||||
它曾经是个发展缓慢的行业,现在由网络运营商、供应商、系统集成商和开发者所组成的网络生态系统正在采用开源软件,并且正在向商用硬件上运行的虚拟化和软件定义网络上转移。事实上,接近 70% 的全球移动用户由[低频网络][1]运营商成员所占据。该网络运营商成员致力于协调构成开放网络栈和相邻技术的项目。
|
||||
|
||||
### 技能需求
|
||||
|
||||
这一领域的开发者和系统管理员采用云原生和 DevOps 的方法开发新的使用案例,应对最紧迫的行业挑战。诸如容器、边缘计算等焦点领域大红大紫,并且在这一领域能够整合、协作、创新的开发者和系统管理员们的需求在日益增进。
|
||||
|
||||
开源软件与 Linux 使这一切成为可能,根据最近出版的 [2018开源软件工作报告][2],高达 80% 的招聘经理寻找会 Linux 技能的应聘者,**而 46% 希望在网络领域招聘人才,可以说“网络技术”在他们的招聘决策中起到了至关重要的作用。**
|
||||
|
||||
开发人员相当抢手,72% 的招聘经理都在找他们,其次是 DevOps 开发者(59%),工程师(57%)和系统管理员(49%)。报告同时指出,对容器技能需求的惊人的增长符合我们在网络领域所见到的,即云本地虚拟功能(CNF)的创建和持续集成/持续部署方式的激增,就如在 OPNFV 中的 [XCI 倡议][3] 一样。
|
||||
|
||||
### 开始吧
|
||||
|
||||
对于求职者来说,好消息是有着大量的关于开源软件的内容,包括免费的 [Linux 入门课程][4]。好的工作需要有多项证书,因此我鼓励你探索更多领域,去寻求培训的机会。计算机网络方面,在 [OPNFV][5] 上查看最新的培训课程或者是 [ONAP][6] 项目,也可以选择这门[开源网络技术简介][7]课程。
|
||||
|
||||
如果你还没有做好这些,下载 [2018 开源软件工作报告][2] 以获得更多见解,在广阔的开放源码技术世界中规划你的课程,去寻找另一边等待你的令人兴奋的职业!
|
||||
|
||||
点击这里[下载完整的开源软件工作报告][8]并且[了解更多关于 Linux 的认证][9]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/os-jobs-report/2018/7/open-source-networking-jobs-hotbed-innovation-and-opportunities
|
||||
|
||||
作者:[Brandon Wick][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[LuuMing](https://github.com/LuuMing)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linux.com/users/brandon-wick
|
||||
[1]:https://www.lfnetworking.org/
|
||||
[2]:https://www.linuxfoundation.org/publications/2018/06/open-source-jobs-report-2018/
|
||||
[3]:https://docs.opnfv.org/en/latest/submodules/releng-xci/docs/xci-overview.html
|
||||
[4]:https://www.edx.org/course/introduction-linux-linuxfoundationx-lfs101x-1
|
||||
[5]:https://training.linuxfoundation.org/training/opnfv-fundamentals/
|
||||
[6]:https://training.linuxfoundation.org/training/onap-fundamentals/
|
||||
[7]:https://www.edx.org/course/introduction-to-software-defined-networking-technologies
|
||||
[8]:https://www.linuxfoundation.org/publications/open-source-jobs-report-2018/
|
||||
[9]:https://training.linuxfoundation.org/certification
|
@ -0,0 +1,361 @@
|
||||
6 个简单的方式来查看 Linux 中的用户名和其它信息
|
||||
======
|
||||
|
||||
这是一个非常基础的话题,在 Linux 中,每个人都知道如何使用 `id` 来查找用户信息。一些用户也从 `/etc/passwd` 文件中过滤用户信息。
|
||||
|
||||
我们还使用其它命令来获取用户信息。
|
||||
|
||||
你可能会问,为什么要讨论这个基础话题呢?即使我也这么认为,因为除了这两个之外没有更好的方法了,但是我们也有一些不错的选择。
|
||||
|
||||
与这两者相比,那些命令提供了更详细的信息,这对于新手非常有帮助。
|
||||
|
||||
这是帮助管理员在 Linux 中查找用户信息的基本命令之一。Linux 中的一切都是文件,甚至用户信息都存储在一个文件中。
|
||||
|
||||
建议阅读:
|
||||
|
||||
- [怎样在 Linux 上查看用户创建的日期][1]
|
||||
- [怎样在 Linux 上查看用户属于哪个组][2]
|
||||
- [怎样在 Linux 上查看强制用户在下次登录时改变密码][3]
|
||||
|
||||
所有用户都被添加在 `/etc/passwd` 文件中,这里保留了用户名和其它相关详细信息。在 Linux 中创建用户时,用户详细信息将存储在 `/etc/passwd` 文件中。passwd 文件将每个用户详细信息保存为一行,包含 7 字段。
|
||||
|
||||
我们可以使用以下 6 种方法来查看用户信息。
|
||||
|
||||
* `id`:为指定的用户名打印用户和组信息。
|
||||
* `getent`:从 Name Service Switch 库中获取条目。
|
||||
* `/etc/passwd`: 文件包含每个用户的详细信息,每个用户详情是一行,包含 7 个字段。
|
||||
* `finger`:用户信息查询程序
|
||||
* `lslogins`:显示系统中已有用户的信息
|
||||
* `compgen`:是 bash 内置命令,它将显示用户的所有可用命令。
|
||||
|
||||
### 1) 使用 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)
|
||||
```
|
||||
|
||||
下面是上述输出的详细信息:
|
||||
|
||||
* `uid (1000/daygeek)`: 它显示用户 ID 和用户名
|
||||
* `gid (1000/daygeek)`: 它显示用户的组 ID 和名称
|
||||
* `groups`: 它显示用户的附加组 ID 和名称
|
||||
|
||||
### 2) 使用 getent 命令
|
||||
|
||||
`getent` 命令显示 Name Service Switch 库支持的数据库中的条目,这些库在 `/etc/nsswitch.conf` 中配置。
|
||||
|
||||
`getent` 命令会显示类似于 `/etc/passwd` 文件的用户详情,它将每个用户的详细信息放在一行,包含 7 个字段。
|
||||
|
||||
```
|
||||
# getent passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
bin:x:1:1:bin:/bin:/sbin/nologin
|
||||
daemon:x:2:2:daemon:/sbin:/sbin/nologin
|
||||
adm:x:3:4:adm:/var/adm:/sbin/nologin
|
||||
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
|
||||
sync:x:5:0:sync:/sbin:/bin/sync
|
||||
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
|
||||
halt:x:7:0:halt:/sbin:/sbin/halt
|
||||
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
|
||||
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
|
||||
operator:x:11:0:operator:/root:/sbin/nologin
|
||||
games:x:12:100:games:/usr/games:/sbin/nologin
|
||||
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
|
||||
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
|
||||
nobody:x:99:99:Nobody:/:/sbin/nologin
|
||||
dbus:x:81:81:System message bus:/:/sbin/nologin
|
||||
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
|
||||
abrt:x:173:173::/etc/abrt:/sbin/nologin
|
||||
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
|
||||
ntp:x:38:38::/etc/ntp:/sbin/nologin
|
||||
saslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin
|
||||
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
|
||||
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
|
||||
tcpdump:x:72:72::/:/sbin/nologin
|
||||
centos:x:500:500:Cloud User:/home/centos:/bin/bash
|
||||
prakash:x:501:501:2018/04/12:/home/prakash:/bin/bash
|
||||
apache:x:48:48:Apache:/var/www:/sbin/nologin
|
||||
nagios:x:498:498::/var/spool/nagios:/sbin/nologin
|
||||
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
|
||||
nrpe:x:497:497:NRPE user for the NRPE service:/var/run/nrpe:/sbin/nologin
|
||||
magesh:x:502:503:2g Admin - Magesh M:/home/magesh:/bin/bash
|
||||
thanu:x:503:504:2g Editor - Thanisha M:/home/thanu:/bin/bash
|
||||
sudha:x:504:505:2g Editor - Sudha M:/home/sudha:/bin/bash
|
||||
```
|
||||
|
||||
下面是关于 7 个字段的详细信息:
|
||||
|
||||
```
|
||||
magesh:x:502:503:2g Admin - Magesh M:/home/magesh:/bin/bash
|
||||
```
|
||||
|
||||
* `Username (magesh)`: 已创建的用户名。字符长度应该在 1 到 32 之间。
|
||||
* `Password (x)`: 它表明加密密码存储在 `/etc/shadow` 文件中。
|
||||
* `User ID (UID-502)`: 它表示用户 ID(UID),每个用户应包含唯一的 UID。UID (0-Zero) 保留给 root,UID(1-99)是为系统用户保留的,UID(100-999)是为系统账户/组保留的。
|
||||
* `Group ID (GID-503)`: 它表示组 ID(GID),每个组应该包含唯一的 GID,它存储在 `/etc/group` 文件中。
|
||||
* `User ID Info (2g Admin - Magesh M)`: 它表示命令字段。这个字段可用于描述用户信息。
|
||||
* `Home Directory (/home/magesh)`: 它表示用户家目录。
|
||||
* `shell (/bin/bash)`: 它表示用户的 bash shell。
|
||||
|
||||
如果你只想在 `getent` 命令的输出中显示用户名,使用以下命令格式:
|
||||
|
||||
```
|
||||
# getent passwd | cut -d: -f1
|
||||
root
|
||||
bin
|
||||
daemon
|
||||
adm
|
||||
lp
|
||||
sync
|
||||
shutdown
|
||||
halt
|
||||
mail
|
||||
uucp
|
||||
operator
|
||||
games
|
||||
gopher
|
||||
ftp
|
||||
nobody
|
||||
dbus
|
||||
vcsa
|
||||
abrt
|
||||
haldaemon
|
||||
ntp
|
||||
saslauth
|
||||
postfix
|
||||
sshd
|
||||
tcpdump
|
||||
centos
|
||||
prakash
|
||||
apache
|
||||
nagios
|
||||
rpc
|
||||
nrpe
|
||||
magesh
|
||||
thanu
|
||||
sudha
|
||||
```
|
||||
|
||||
只显示用户的家目录,使用以下命令格式:
|
||||
|
||||
```
|
||||
# getent passwd | grep '/home' | cut -d: -f1
|
||||
centos
|
||||
prakash
|
||||
magesh
|
||||
thanu
|
||||
sudha
|
||||
```
|
||||
|
||||
### 3) 使用 /etc/passwd 文件
|
||||
|
||||
`/etc/passwd` 是一个文本文件,它包含每个用户登录 Linux 系统所必需的的信息。它维护用户的有用信息,如用户名,密码,用户 ID,组 ID,用户 ID 信息,家目录和 shell。`/etc/passwd` 文件将每个用户详细信息放在一行中,包含 7 个字段,如下所示:
|
||||
|
||||
```
|
||||
# cat /etc/passwd
|
||||
root:x:0:0:root:/root:/bin/bash
|
||||
bin:x:1:1:bin:/bin:/sbin/nologin
|
||||
daemon:x:2:2:daemon:/sbin:/sbin/nologin
|
||||
adm:x:3:4:adm:/var/adm:/sbin/nologin
|
||||
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
|
||||
sync:x:5:0:sync:/sbin:/bin/sync
|
||||
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
|
||||
halt:x:7:0:halt:/sbin:/sbin/halt
|
||||
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
|
||||
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
|
||||
operator:x:11:0:operator:/root:/sbin/nologin
|
||||
games:x:12:100:games:/usr/games:/sbin/nologin
|
||||
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
|
||||
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
|
||||
nobody:x:99:99:Nobody:/:/sbin/nologin
|
||||
dbus:x:81:81:System message bus:/:/sbin/nologin
|
||||
vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
|
||||
abrt:x:173:173::/etc/abrt:/sbin/nologin
|
||||
haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
|
||||
ntp:x:38:38::/etc/ntp:/sbin/nologin
|
||||
saslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin
|
||||
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
|
||||
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
|
||||
tcpdump:x:72:72::/:/sbin/nologin
|
||||
centos:x:500:500:Cloud User:/home/centos:/bin/bash
|
||||
prakash:x:501:501:2018/04/12:/home/prakash:/bin/bash
|
||||
apache:x:48:48:Apache:/var/www:/sbin/nologin
|
||||
nagios:x:498:498::/var/spool/nagios:/sbin/nologin
|
||||
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
|
||||
nrpe:x:497:497:NRPE user for the NRPE service:/var/run/nrpe:/sbin/nologin
|
||||
magesh:x:502:503:2g Admin - Magesh M:/home/magesh:/bin/bash
|
||||
thanu:x:503:504:2g Editor - Thanisha M:/home/thanu:/bin/bash
|
||||
sudha:x:504:505:2g Editor - Sudha M:/home/sudha:/bin/bash
|
||||
```
|
||||
|
||||
以下是 7 个字段的详细信息。
|
||||
|
||||
```
|
||||
magesh:x:502:503:2g Admin - Magesh M:/home/magesh:/bin/bash
|
||||
```
|
||||
|
||||
* `Username (magesh)`: 已创建的用户名。字符长度应该在 1 到 32 之间。
|
||||
* `Password (x)`: 它表明加密密码存储在 `/etc/shadow` 文件中。
|
||||
* `User ID (UID-502)`: 它表示用户 ID(UID),每个用户应包含唯一的 UID。UID (0-Zero) 保留给 root,UID(1-99)是为系统用户保留的,UID(100-999)是为系统账户/组保留的。
|
||||
* `Group ID (GID-503)`: 它表示组 ID(GID),每个组应该包含唯一的 GID,它存储在 `/etc/group` 文件中。
|
||||
* `User ID Info (2g Admin - Magesh M)`: 它表示命令字段。这个字段可用于描述用户信息。
|
||||
* `Home Directory (/home/magesh)`: 它表示用户家目录。
|
||||
* `shell (/bin/bash)`: 它表示用户的 bash shell。
|
||||
|
||||
如果你只想显示 `/etc/passwd` 文件中的用户名,使用以下格式:
|
||||
|
||||
```
|
||||
# cut -d: -f1 /etc/passwd
|
||||
root
|
||||
bin
|
||||
daemon
|
||||
adm
|
||||
lp
|
||||
sync
|
||||
shutdown
|
||||
halt
|
||||
mail
|
||||
uucp
|
||||
operator
|
||||
games
|
||||
gopher
|
||||
ftp
|
||||
nobody
|
||||
dbus
|
||||
vcsa
|
||||
abrt
|
||||
haldaemon
|
||||
ntp
|
||||
saslauth
|
||||
postfix
|
||||
sshd
|
||||
tcpdump
|
||||
centos
|
||||
prakash
|
||||
apache
|
||||
nagios
|
||||
rpc
|
||||
nrpe
|
||||
magesh
|
||||
thanu
|
||||
sudha
|
||||
```
|
||||
|
||||
只显示用户的家目录,使用以下格式:
|
||||
|
||||
```
|
||||
# cat /etc/passwd | grep '/home' | cut -d: -f1
|
||||
centos
|
||||
prakash
|
||||
magesh
|
||||
thanu
|
||||
sudha
|
||||
```
|
||||
|
||||
### 4) 使用 finger 命令
|
||||
|
||||
`finger` 命令显示有关系统用户的信息。它显示用户的真实姓名,终端名称和写入状态(如果没有写入权限,那么最为终端名称后面的 `*`),空闲时间和登录时间。
|
||||
|
||||
```
|
||||
# finger magesh
|
||||
Login: magesh Name: 2g Admin - Magesh M
|
||||
Directory: /home/magesh Shell: /bin/bash
|
||||
Last login Tue Jul 17 22:46 (EDT) on pts/2 from 103.5.134.167
|
||||
No mail.
|
||||
No Plan.
|
||||
```
|
||||
|
||||
以下是上述输出的详细信息:
|
||||
|
||||
* `Login`: 用户名
|
||||
* `Name`: 附加/有关用户的其它信息
|
||||
* `Directory`: 用户家目录的信息
|
||||
* `Shell`: 用户的 shell 信息
|
||||
* `LAST-LOGIN`: 上次登录日期和其它信息
|
||||
|
||||
### 5) 使用 lslogins 命令
|
||||
|
||||
它显示系统已知用户的信息。默认情况下,它将列出系统中所有用户的信息。
|
||||
|
||||
`lslogins` 使用程序的灵感来自于 `logins` 实用程序,该实用程序最初出现在 FreeBSD 4.10 中。
|
||||
|
||||
```
|
||||
# lslogins -u
|
||||
UID USER PWD-LOCK PWD-DENY LAST-LOGIN GECOS
|
||||
0 root 0 0 00:17:28 root
|
||||
500 centos 0 1 Cloud User
|
||||
501 prakash 0 0 Apr12/04:08 2018/04/12
|
||||
502 magesh 0 0 Jul17/22:46 2g Admin - Magesh M
|
||||
503 thanu 0 0 Jul18/00:40 2g Editor - Thanisha M
|
||||
504 sudha 0 0 Jul18/01:18 2g Editor - Sudha M
|
||||
```
|
||||
|
||||
以下是上述输出的详细信息:
|
||||
|
||||
* `UID`: 用户 id
|
||||
* `USER`: 用户名
|
||||
* `PWD-LOCK`: 密码已设置,但是已锁定
|
||||
* `PWD-DENY`: 登录密码是否禁用
|
||||
* `LAST-LOGIN`: 上次登录日期
|
||||
* `GECOS`: 有关用户的其它信息
|
||||
|
||||
### 6) 使用 compgen 命令
|
||||
|
||||
`compgen` 是 bash 内置命令,它将显示所有可用的命令,别名和函数。(LCTT 译注:它的 `-u` 参数可以列出系统中用户。)
|
||||
|
||||
```
|
||||
# compgen -u
|
||||
root
|
||||
bin
|
||||
daemon
|
||||
adm
|
||||
lp
|
||||
sync
|
||||
shutdown
|
||||
halt
|
||||
mail
|
||||
uucp
|
||||
operator
|
||||
games
|
||||
gopher
|
||||
ftp
|
||||
nobody
|
||||
dbus
|
||||
vcsa
|
||||
abrt
|
||||
haldaemon
|
||||
ntp
|
||||
saslauth
|
||||
postfix
|
||||
sshd
|
||||
tcpdump
|
||||
centos
|
||||
prakash
|
||||
apache
|
||||
nagios
|
||||
rpc
|
||||
nrpe
|
||||
magesh
|
||||
thanu
|
||||
sudha
|
||||
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/6-easy-ways-to-check-user-name-and-other-information-in-linux/
|
||||
|
||||
作者:[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/how-to-check-user-created-date-on-linux/
|
||||
[2]:https://www.2daygeek.com/how-to-check-which-groups-a-user-belongs-to-on-linux/
|
||||
[3]:https://www.2daygeek.com/how-to-force-user-to-change-password-on-next-login-in-linux/
|
@ -0,0 +1,81 @@
|
||||
为什么我仍然喜欢用 Alpine 在 Linux 终端中发送电子邮件
|
||||
======
|
||||
|
||||
> 这个免费的邮件客户端使用直观、易于定制,并且可以在许多操作系统上使用。
|
||||
|
||||

|
||||
|
||||
也许你有这个经历:你试了一个程序,并且很喜欢它。多年后,有新的程序开发出来,它可以做同样的事情或者更多,甚至更好。你试了下它们,它们也很棒 —— 但你会继续使用第一个程序。
|
||||
|
||||
这是我与 [Alpine Mail][1] 关系的故事。所以我决定写一篇赞美我最喜欢的邮件程序的文章。
|
||||
|
||||
![alpine_main_menu.png][3]
|
||||
|
||||
*Alpine 邮件客户端的主菜单屏幕*
|
||||
|
||||
在 90 年代中期,我发现了 [GNU/Linux][4] 操作系统。因为我之前从未见过类 Unix 的系统,所以我阅读了大量的文档和书籍,并尝试了很多程序来熟悉这个迷人的系统。
|
||||
|
||||
没多久,[Pine][5] 成了我最喜欢的邮件客户端,其后是其继任者 Alpine。我发现它直观且易于使用 —— 你始终可以在底部看到可能的命令或选项,因此引导很容易快速学习,并且 Alpine 提供了很好的帮助。
|
||||
|
||||
入门很容易。
|
||||
|
||||
大多数发行版包含 Alpine。它可以通过包管理器安装。
|
||||
|
||||
只需按下 `S`(或移动高亮栏到“设置”那一行)你就会看到可以配置的项目。在底部,你可以使用快捷键来执行你可以立即执行的命令。对于其他命令,按下 `O`(“其他命令”)。
|
||||
|
||||
按下 `S` 进入配置对话框。当你向下滚动列表时,很明显你可以设置 Apline 如你所希望的那样运行。如果你只有一个邮件帐户,只需移动到你想要更改的行,按下 `C`(“更改值”),然后输入值:
|
||||
|
||||
![alpine_setup_configuration.png][7]
|
||||
|
||||
*Alpine 设置配置屏幕*
|
||||
|
||||
请注意如何输入 SNMP 和 IMAP 服务器,因为这与那些有辅助助手和预填字段的邮件客户端不同。如果你像这样输入“服务器/SSL/用户”:
|
||||
|
||||
```
|
||||
imap.myprovider.com:993/ssl/user=max@example.com
|
||||
```
|
||||
|
||||
Alpine 会询问你是否使用“收件箱”(选择“是”)并在“服务器”两边加上大括号。完成后,按下 `E`(“退出设置”)并按下 `Y`(“是”)提交更改。回到主菜单,然后你可以移动到文件夹列表和收件箱以查看是否有邮件(系统将提示你输入密码)。你现在可以使用 `>` 和 `<` 进行移动。
|
||||
|
||||
![navigating_the_message_index.png][9]
|
||||
|
||||
*在 Apline 中浏览消息索引*
|
||||
|
||||
要撰写邮件,只需移动到相应的菜单并编写即可。请注意,底部的选项会根据你所在的行而变化。`^T`(`Ctrl + T`)可代表 To Addressbook(“地址簿”)或 To Files(“文件”)。要附加文件,只需移动到 Attchmt:(“附件”)然后按 `Ctrl + T` 转到文件浏览器,或按 `Ctrl + J` 输入路径。
|
||||
|
||||
用 `^X` 发送邮件。
|
||||
|
||||
![composing_an_email_in_alpine.png][11]
|
||||
|
||||
在 Alpine 中撰写电子邮件
|
||||
|
||||
### 为何选择 Alpine?
|
||||
|
||||
当然,每个用户的个人偏好和需求都是不同的。如果你需要一个更像 “office” 的解决方案,像 Evolution 或 Thunderbird 这样的应用可能是更好的选择。
|
||||
|
||||
但对我来说,Alpine(和 Pine)是软件界的活化石。你可以以舒适的方式管理邮件 —— 不多也不少。它适用于许多操作系统(甚至 [Termux for Android][12])。并且因为配置存储在纯文本文件(`.pinerc`)中,所以你只需将其复制到设备即可。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/8/love-alpine
|
||||
|
||||
作者:[Heiko Ossowski][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/hossow
|
||||
[1]:https://en.wikipedia.org/wiki/Alpine_(email_client)
|
||||
[2]:/file/405641
|
||||
[3]:https://opensource.com/sites/default/files/uploads/alpine_main_menu.png (alpine_main_menu.png)
|
||||
[4]:https://www.gnu.org/gnu/linux-and-gnu.en.html
|
||||
[5]:https://en.wikipedia.org/wiki/Pine_(email_client)
|
||||
[6]:/file/405646
|
||||
[7]:https://opensource.com/sites/default/files/uploads/alpine_setup_configuration.png (alpine_setup_configuration.png)
|
||||
[8]:/file/405651
|
||||
[9]:https://opensource.com/sites/default/files/uploads/navigating_the_message_index.png (navigating_the_message_index.png)
|
||||
[10]:/file/405656
|
||||
[11]:https://opensource.com/sites/default/files/uploads/composing_an_email_in_alpine.png (composing_an_email_in_alpine.png)
|
||||
[12]:https://termux.com/
|
@ -1,19 +1,22 @@
|
||||
一个转换花引号的 gawk 脚本
|
||||
======
|
||||
|
||||

|
||||
> 下载我的 awk 秘籍。
|
||||
|
||||
我管理着一个个人网站,同时手工编辑网站上的网页。由于网站上的页面并不多,这种方法对我很适合,可以让我对网站代码的细节一清二楚。
|
||||

|
||||
|
||||
最近我升级了网站的设计样式,我决定把所有的普通引号都转换成 "花引号",即在打印材料中使用的那种引号:用 “” 来代替 ""。
|
||||
我管理着一个个人网站,用手工编辑网站上的网页。由于网站上的页面并不多,这种方法对我很适合,可以让我对网站代码的细节一清二楚。
|
||||
|
||||
手工修改所有的引号太耗时了,因此我决定将转换所有 HTML 文件中引号的过程自动化。不过通过程序或脚本来实现该功能需要费点劲。这个脚本需要知道何时将普通引号转换成花引号,并决定使用哪种引号(译注:左引号还是右引号,单引号还是双引号)。
|
||||
最近我升级了网站的设计样式,我决定把所有的普通引号都转换成“花引号”,即在打印材料中使用的那种引号:用 “” 来代替 ""。
|
||||
|
||||
有多种方法可以转换引号。Greg Pittman 写过一个 [Python 脚本 ][1] 来修正文本中的花引号。而我自己使用 GNU [awk][2] (gawk) 来实现。
|
||||
手工修改所有的引号太耗时了,因此我决定将这个转换所有 HTML 文件中引号的过程自动化。不过通过程序或脚本来实现该功能需要费点劲。这个脚本需要知道何时将普通引号转换成花引号,并决定使用哪种引号(LCTT 译注:左引号还是右引号,单引号还是双引号)。
|
||||
|
||||
> 下载我的 awk 备忘录。[免费下载 ][3]。
|
||||
有多种方法可以转换引号。Greg Pittman 写过一个 [Python 脚本][1] 来修正文本中的花引号。而我自己使用 GNU [awk][2] (gawk) 来实现。
|
||||
|
||||
> 下载我的 awk 秘籍。[免费下载][3]。
|
||||
|
||||
开始之前,我写了一个简单的 gawk 函数来评估单个字符。若该字符是一个引号,这该函数判断是输出普通引号还是花引号。函数查看前一个字符;若前一个字符是空格,则函数输出左花引号。否则函数输出右花引号。脚本对单引号的处理方式也一样。
|
||||
|
||||
开始之前,我写了一个简单的 gawk 函数来评估单个字符。若该字符是一个引号,这该函数判断是输出普通引号还是花引号。函数查看前一个字符; 若前一个字符是空格,则函数输出左花引号。否则函数输出右花引号。脚本对单引号的处理方式也一样。
|
||||
```
|
||||
function smartquote (char, prevchar) {
|
||||
# print smart quotes depending on the previous character
|
||||
@ -46,7 +49,8 @@ function smartquote (char, prevchar) {
|
||||
}
|
||||
```
|
||||
|
||||
这个 gawk 脚本的主体部分通过该函数处理 HTML 输入文件的一个个字符。该脚本在 HTML 标签内部逐字原样输出所有内容(比如,`<html lang="en">`)。在 HTML 标签外,脚本使用 `smartquote()` 函数来输出文本。`smartquote()` 函数来评估是输出普通引号还是花引号。
|
||||
这个 gawk 脚本的主体部分通过该函数处理 HTML 输入文件的一个个字符。该脚本在 HTML 标签内部逐字原样输出所有内容(比如,`<html lang="en">`)。在 HTML 标签外,脚本使用 `smartquote()` 函数来输出文本。`smartquote()` 函数来评估是输出普通引号还是花引号。
|
||||
|
||||
```
|
||||
function smartquote (char, prevchar) {
|
||||
...
|
||||
@ -87,11 +91,13 @@ BEGIN {htmltag = 0}
|
||||
```
|
||||
|
||||
下面是一个例子:
|
||||
|
||||
```
|
||||
gawk -f quotes.awk test.html > test2.html
|
||||
```
|
||||
|
||||
其输入为:
|
||||
|
||||
```
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -107,10 +113,10 @@ gawk -f quotes.awk test.html > test2.html
|
||||
<p>It's and its.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
其输出为:
|
||||
|
||||
```
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -135,7 +141,7 @@ via: https://opensource.com/article/18/8/gawk-script-convert-smart-quotes
|
||||
作者:[Jim Hall][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[lujun9972](https://github.com/lujun9972)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -3,104 +3,101 @@
|
||||
|
||||

|
||||
|
||||
有时,最新版本的安装包可能无法按预期工作。你的程序可能与更新的软件包不兼容,并且仅支持特定的旧版软件包。在这种情况下,你可以立即将有问题的软件包降级到其早期的工作版本。请参阅我们的旧指南,[**在这**][1]了解如何降级 Ubuntu 及其衍生版中的软件包以及[**在这**][1]了解如何降级 Arch Linux 及其衍生版中的软件包。但是,你无需降级某些软件包。我们可以同时使用多个版本。例如,假设你在测试部署在 Ubuntu 18.04 LTS 中的[**LAMP 栈**][3]的 PHP 程序。过了一段时间,你发现应用程序在 PHP5.6 中工作正常,但在 PHP 7.2 中不正常(Ubuntu 18.04 LTS 默认安装 PHP 7.x)。你打算重新安装 PHP 或整个 LAMP 栈吗?但是没有必要。你甚至不必将 PHP 降级到其早期版本。在这个简短的教程中,我将向你展示如何在 Ubuntu 18.04 LTS 中切换多个 PHP 版本。它没你想的那么难。请继续阅读。
|
||||
有时,最新版本的安装包可能无法按预期工作。你的程序可能与更新的软件包不兼容,并且仅支持特定的旧版软件包。在这种情况下,你可以立即将有问题的软件包降级到其早期的工作版本。请参阅我们的旧指南,[在这][1]了解如何降级 Ubuntu 及其衍生版中的软件包以及[在这][1]了解如何降级 Arch Linux 及其衍生版中的软件包。但是,你无需降级某些软件包。我们可以同时使用多个版本。例如,假设你在测试部署在 Ubuntu 18.04 LTS 中的[LAMP 栈][3]的 PHP 程序。过了一段时间,你发现应用程序在 PHP 5.6 中工作正常,但在 PHP 7.2 中不正常(Ubuntu 18.04 LTS 默认安装 PHP 7.x)。你打算重新安装 PHP 或整个 LAMP 栈吗?但是没有必要。你甚至不必将 PHP 降级到其早期版本。在这个简短的教程中,我将向你展示如何在 Ubuntu 18.04 LTS 中切换多个 PHP 版本。它没你想的那么难。请继续阅读。
|
||||
|
||||
### 在多个 PHP 版本之间切换
|
||||
|
||||
要查看 PHP 的默认安装版本,请运行:
|
||||
|
||||
```
|
||||
$ php -v
|
||||
PHP 7.2.7-0ubuntu0.18.04.2 (cli) (built: Jul 4 2018 16:55:24) ( NTS )
|
||||
Copyright (c) 1997-2018 The PHP Group
|
||||
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
|
||||
with Zend OPcache v7.2.7-0ubuntu0.18.04.2, Copyright (c) 1999-2018, by Zend Technologies
|
||||
|
||||
```
|
||||
|
||||
如你所见,已安装的 PHP 的版本为 7.2.7。在测试你的程序几天后,你会发现你的程序不支持 PHP7.2。在这种情况下,同时使用 PHP5.x 和 PHP7.x 是个不错的主意,这样你就可以随时轻松地在任何支持的版本之间切换。
|
||||
|
||||
你不必删除 PHP7.x 或重新安装 LAMP 栈。你可以同时使用 PHP5.x 和 7.x 版本。
|
||||
|
||||
我假设你还没有在你的系统中卸载 php5.6。万一你已将其删除,你可以使用下面的 PPA 再次安装它。
|
||||
我假设你还没有在你的系统中卸载 PHP 5.6。万一你已将其删除,你可以使用下面的 PPA 再次安装它。
|
||||
|
||||
你可以从 PPA 中安装 PHP 5.6:
|
||||
|
||||
你可以从 PPA 中安装 PHP5.6:
|
||||
```
|
||||
$ sudo add-apt-repository -y ppa:ondrej/php
|
||||
$ sudo apt update
|
||||
$ sudo apt install php5.6
|
||||
|
||||
```
|
||||
|
||||
#### 从 PHP7.x 切换到 PHP5.x.
|
||||
#### 从 PHP 7.x 切换到 PHP 5.x.
|
||||
|
||||
首先使用命令禁用 PHP 7.2 模块:
|
||||
|
||||
首先使用命令禁用 PHP7.2 模块:
|
||||
```
|
||||
$ sudo a2dismod php7.2
|
||||
Module php7.2 disabled.
|
||||
To activate the new configuration, you need to run:
|
||||
systemctl restart apache2
|
||||
|
||||
```
|
||||
|
||||
接下来,启用 PHP5.6 模块:
|
||||
接下来,启用 PHP 5.6 模块:
|
||||
|
||||
```
|
||||
$ sudo a2enmod php5.6
|
||||
|
||||
```
|
||||
|
||||
将 PHP5.6 设置为默认版本:
|
||||
将 PHP 5.6 设置为默认版本:
|
||||
|
||||
```
|
||||
$ sudo update-alternatives --set php /usr/bin/php5.6
|
||||
|
||||
```
|
||||
|
||||
或者,你可以运行以下命令来设置默认情况下要使用的全局 PHP 版本。
|
||||
|
||||
```
|
||||
$ sudo update-alternatives --config php
|
||||
|
||||
```
|
||||
|
||||
输入选择的号码将其设置为默认版本,或者只需按 ENTER 键保持当前选择。
|
||||
输入选择的号码将其设置为默认版本,或者只需按回车键保持当前选择。
|
||||
|
||||
如果你已安装其他 PHP 扩展,请将它们设置为默认值。
|
||||
|
||||
```
|
||||
$ sudo update-alternatives --set phar /usr/bin/phar5.6
|
||||
|
||||
```
|
||||
|
||||
最后,重启 Apache Web 服务器:
|
||||
|
||||
```
|
||||
$ sudo systemctl restart apache2
|
||||
|
||||
```
|
||||
|
||||
现在,检查 PHP5.6 是否是默认版本:
|
||||
现在,检查 PHP 5.6 是否是默认版本:
|
||||
|
||||
```
|
||||
$ php -v
|
||||
PHP 5.6.37-1+ubuntu18.04.1+deb.sury.org+1 (cli)
|
||||
Copyright (c) 1997-2016 The PHP Group
|
||||
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
|
||||
with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies
|
||||
|
||||
```
|
||||
|
||||
#### 从 PHP5.x 切换到 PHP7.x.
|
||||
#### 从 PHP 5.x 切换到 PHP 7.x.
|
||||
|
||||
同样,你可以从 PHP 5.x 切换到 PHP 7.x 版本,如下所示。
|
||||
|
||||
同样,你可以从 PHP5.x 切换到 PHP7.x 版本,如下所示。
|
||||
```
|
||||
$ sudo a2enmod php7.2
|
||||
|
||||
$ sudo a2dismod php5.6
|
||||
|
||||
$ sudo update-alternatives --set php /usr/bin/php7.2
|
||||
|
||||
$ sudo systemctl restart apache2
|
||||
|
||||
```
|
||||
|
||||
**提醒一句:**
|
||||
|
||||
最终稳定版 PHP5.6 于 2017 年 1 月 19 日达到[**活跃支持截止**][4]。但是,直到 2018 年 12 月 31 日,PHP 5.6 将继续获得对关键安全问题的支持。所以,建议尽快升级所有 PHP 程序并与 PHP7.x 兼容。
|
||||
最终稳定版 PHP 5.6 于 2017 年 1 月 19 日达到[**活跃支持截止**][4]。但是,直到 2018 年 12 月 31 日,PHP 5.6 将继续获得对关键安全问题的支持。所以,建议尽快升级所有 PHP 程序并与 PHP 7.x 兼容。
|
||||
|
||||
如果你希望防止 PHP 将来自动升级,请参阅以下指南。
|
||||
|
||||
@ -109,7 +106,6 @@ $ sudo systemctl restart apache2
|
||||
干杯!
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-switch-between-multiple-php-versions-in-ubuntu/
|
||||
@ -117,7 +113,7 @@ via: https://www.ostechnix.com/how-to-switch-between-multiple-php-versions-in-ub
|
||||
作者:[SK][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/) 荣誉推出
|
||||
|
@ -0,0 +1,76 @@
|
||||
Fedora 下的图像创建程序
|
||||
======
|
||||
|
||||

|
||||
|
||||
有了创意吗?Fedora 有很多程序可以帮助你的创造力。从数字绘图、矢量到像素艺术,每个人都可以在这个周末发挥创意。本文重点介绍了 Fedora 下创建很棒图像的程序。
|
||||
|
||||
### 矢量图形:Inkscape
|
||||
|
||||
[Inkscape][1] 是一个众所周知的、受人喜爱的开源矢量图形编辑器。SVG 是 Inkscape 的主要文件格式,因此你所有的图形都可以任意伸缩!Inkscape 已存在多年,所以有一个坚实的社区和用于入门的[大量教程和其他资源][2]。
|
||||
|
||||
作为矢量图形编辑器,Inkscape 更适合于简单的插图(例如简单的漫画风格)。然而,使用矢量模糊,一些艺术家创造了一些[令人惊奇的矢量图][3]。
|
||||
|
||||
![][4]
|
||||
|
||||
从 Fedora Workstation 中的软件应用安装 Inkscape,或在终端中使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf install inkscape
|
||||
```
|
||||
|
||||
### 数字绘图:Krita 和 Mypaint
|
||||
|
||||
[Krita][5] 是一个流行的图像创建程序,用于数字绘图、光栅插图和纹理。此外,Krita 是一个活跃的项目,拥有一个充满活力的社区 —— 所以[有用于入门的很多教程][6]。Krita 有多个画笔引擎、带有弹出调色板的 UI、用于创建无缝图案的环绕模式、滤镜、图层等等。
|
||||
|
||||
![][7]
|
||||
|
||||
从 Fedora Workstation 中的软件应用安装 Krita,或在终端中使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf install krita
|
||||
```
|
||||
|
||||
[Mypaint][8] 是另一款适用于 Fedora 令人惊奇的数字绘图程序。像 Krita 一样,它有多个画笔和使用图层的能力。
|
||||
|
||||
![][9]
|
||||
|
||||
从 Fedora Workstation 中的软件应用安装 Mypaint,或在终端中使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf install mypaint
|
||||
```
|
||||
|
||||
### 像素艺术:Libresprite
|
||||
|
||||
[Libresprite][10] 是一个专为创建像素艺术和像素动画而设计的程序。它支持一系列颜色模式,并可导出为多种格式(包括动画 GIF)。此外,Libresprite 还有用于创建像素艺术的绘图工具:多边形工具、轮廓和着色工具。
|
||||
|
||||
![][11]
|
||||
|
||||
Libresprite 可从 Flathub 应用仓库下载。要安装,只需[启用 Flathub 作为软件源][12],然后通过软件应用进行安装。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/image-creation-applications-fedora/
|
||||
|
||||
作者:[Ryan Lerch][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/introducing-flatpak/
|
||||
[1]:http://inkscape.org
|
||||
[2]:https://inkscape.org/en/learn/tutorials/
|
||||
[3]:https://inkscape.org/en/gallery/
|
||||
[4]:https://fedoramagazine.org/wp-content/uploads/2018/08/inkscape.png
|
||||
[5]:https://krita.org/en/
|
||||
[6]:https://docs.krita.org/en/
|
||||
[7]:https://fedoramagazine.org/wp-content/uploads/2018/08/krita.jpg
|
||||
[8]:http://mypaint.org/about/
|
||||
[9]:https://fedoramagazine.org/wp-content/uploads/2018/08/mypaint.png
|
||||
[10]:https://github.com/LibreSprite/LibreSprite
|
||||
[11]:https://fedoramagazine.org/wp-content/uploads/2018/08/libresprite.gif
|
||||
[12]:https://fedoramagazine.org/install-flathub-apps-fedora/
|
108
published/201808/20180812 Ubuntu 18.04 Vs. Fedora 28.md
Normal file
108
published/201808/20180812 Ubuntu 18.04 Vs. Fedora 28.md
Normal file
@ -0,0 +1,108 @@
|
||||
对比 Ubuntu 18.04 和 Fedora 28
|
||||
======
|
||||
|
||||

|
||||
|
||||
大家好,我准备在今天突出说明一下两大主流 Linux 发行版,即 **Ubuntu 18.04** 和 **Fedora 28**,包括一些特性和差异。两者都有各自的包管理系统,其中 Ubuntu 使用 DEB,Fedora 使用 RPM;但二者使用同样的[<ruby>桌面环境<rt>Desktop Environment</rt></ruby>][3] (DE)[GNOME][4],并致力于为 Linux 用户提供高品质的<ruby>桌面体验<rt>desktop experience</rt></ruby>。
|
||||
|
||||
**Ubuntu 18.04** 是 Ubuntu 目前最新的 [<ruby>长期支持版本<rt>Long Term Support</rt></ruby>][1](LTS),为用户提供 GNOME 桌面系统。**Fedora 28** 也提供 GNOME 桌面系统,但落实到具体的软件包管理方面,二者的桌面体验存在差异;在<ruby>用户界面<rt>User Interfaces</rt></ruby>方面也显然存在差异。
|
||||
|
||||
### 基本概念
|
||||
|
||||
不知你是否了解,虽然 Ubuntu 基于 Debian,但 Ubuntu 比 Debian 更早提供最新版本的软件。举个例子,当 Ubuntu 提供流行网页浏览器 Firefox Quantum 时,Debian 仍在提供 Firefox 的<ruby>延期支持版<rt>Extended Support Release</rt></ruby>(ESR)。
|
||||
|
||||
(LCTT 译注:从 2012 年 1 月开始,Firefox 进入快速版本期,每 6 周发布新的主线版本,每隔 7 个主线版本发布新的 ESR 版本。Firefox 57 的桌面版发布时被命名为 Firefox Quantum,同期的 ESR 版本与 Firefox 52 一同发布并基于 Firefox 48。参考 [Wiki: History\_of\_Firefox][9])
|
||||
|
||||
同样的情况也适用于 Fedora,它为终端用户提供前沿的软件,也被用作下一个稳定版本的 RHEL (Red Hat Enterprise Linux) 的测试平台。
|
||||
|
||||
### 桌面预览
|
||||
|
||||
Fedora 提供<ruby>原汁原味的<rt>vanilla</rt></ruby> GNOME 桌面体验;相比之下,Ubuntu 18.04 对 GNOME 做了若干方面的微调,以便长期以来的 Unity 用户可以平滑的过渡到 GNOME 桌面环境。
|
||||
|
||||
_为节省开发时间,Canonical (从 Ubuntu [17.10][2] 开始)已经决定放弃 Unity 并转向 GNOME 桌面,以便可以将更多精力投入到 IoT 领域。_
|
||||
|
||||
因此,在 Fedora 的桌面预览中,我们可以看到一个简洁的无图标桌面和一个自动隐藏的侧边栏,整体外观采用 GNOME 默认的 Adwaita 主题。
|
||||
|
||||
[][5]
|
||||
|
||||
相比之下,Ubuntu 采用其经典的有图标桌面样式,左侧边栏用于模拟其传统的“<ruby>程序坞<rt>dock</rt></ruby>”,使用 Ubuntu Ambiance 主题定制化窗口,与其传统的(Unity 桌面)外观和体验基本一致。
|
||||
|
||||
[][6]
|
||||
|
||||
虽然存在一定差异,但习惯使用其中一种桌面环境后切换到另外一种并不困难。毕竟二者设计时都充分考虑了简洁性和用户友好性,即使是新用户也不会对这两种 Linux 发行版感到不适应。
|
||||
|
||||
但外观或 UI 并不是决定用户选择哪一种 Linux 发行版的唯一因素,还有其它因素也会影响用户的选择。下面主要介绍两种 Linux 发行版在软件包管理相关方面的内容。
|
||||
|
||||
### 软件中心
|
||||
|
||||
Ubuntu 使用 dpkg(即 Debian Package Management)将软件分发给终端用户;Fedora 则使用 rpm(全称为 Red Hat Package Management)。它们都是 Linux 社区中非常流行的包管理系统,对应的命令行工具也都简单易用。
|
||||
|
||||
[][7]
|
||||
|
||||
但在具体分发的软件方面,各个 Linux 发行版会有明显差异。Canonical 每 6 个月发布新版本的 Ubuntu,一般是在每年的 4 月和 10 月。对每个版本,开发者会维护一个开发计划;Ubuntu 新版本发布后,该版本就会进入<ruby>冻结<rt>freeze</rt></ruby>状态,即停止新软件的开发和测试。
|
||||
|
||||
相比之下,Fedora 也采用相似的 6 个月发布周期,看起来很像一种<ruby>滚动更新<rt>rolling release</rt></ruby>的 Linux 发行版(其实并不是这样)。与 Ubuntu 不同之处在于,(Fedora 中的)几乎所有软件包更新都很频繁,让用户有机会尝试最新版本的软件。但这样也导致软件 Bug 更频繁出现,给用户带来“不稳定性”,虽然还不至于导致系统不可用。
|
||||
|
||||
### 软件更新
|
||||
|
||||
我上面已经提到了 Ubuntu 版本的冻结状态。好吧,由于它对 Ubuntu 软件更新方式有着重要的影响,我再次提到这个状态:当 Ubuntu 新版本发布后,该版本的开发(这里是指测试新软件)就停止了。
|
||||
|
||||
_即将发布的下个版本的开发也随之开始,先后历经 “<ruby>每日构建<rt>daily build</rt></ruby>” 和 “<ruby>测试版<rt>beta release</rt></ruby>” 阶段,最后作为新版本发布给终端用户。_
|
||||
|
||||
在冻结状态下,Ubuntu 维护者不会在<ruby>软件源<rt>package repository</rt></ruby>中增加最新版软件,除非用于解决严重的安全问题。因此,Ubuntu 用户可用的软件更新更多涉及 Bug 修复而不是新特性,这样的好处在于系统可以保持稳定,不会扰乱用户的使用。
|
||||
|
||||
Fedora 试图为终端用户提供最新版本的软件,故用户的可用软件更新相比 Ubuntu 而言会更多涉及新特性。当然,开发者为了维持系统的稳定性,也采取了一系列措施。例如,在操作系统启动时,用户可以从最多三个<ruby>可用内核<rt>working kernel</rt></ruby>(最新内核处于最上方)中进行选择;当新内核无法启动时,用户可以回滚使用之前两个可用内核。
|
||||
|
||||
### Snaps 和 flatpak
|
||||
|
||||
它们都是新出现的酷炫工具,可以将软件发布到多个 Linux 发行版上。Ubuntu 提供 **snaps**,而 Fedora 则提供 **flatpak** 。二者之中 snaps 更加流行,更多流行软件或版权软件都在考虑上架 snap 商店。Flatpak 也在吸引关注,越来越多的软件上线该平台。
|
||||
|
||||
不幸的是,由于二者出现的时间都不久,很多人遇到“<ruby>窗口主题不一致<rt>window theme-breaking</rt></ruby>”问题并在网上表达不满。但由于二者都很易于使用,在二者之间切换并不是难事。
|
||||
|
||||
(LCTT 译注:按译者理解,由于二者都增加了一层安全隔离,读取系统主题方面会遇到问题;另外,似乎也有反馈 snap 专用主题无法及时应用于 snap 的问题)
|
||||
|
||||
### 应用对比
|
||||
|
||||
下面列出一些在 Ubuntu 和 Fedora 上共有的常见应用,然后在两个平台之间进行对比:
|
||||
|
||||
#### 计算器
|
||||
|
||||
Fedora 上的计算器程序启动速度更快。这是因为 Fedora 上的计算器程序是软件包形式安装的,而 Ubuntu 上的计算器程序则是 snap 版本。
|
||||
|
||||
#### 系统监视器
|
||||
|
||||
可能听上去比较书呆子气,但我认为观察计算机性能并杀掉令人讨厌的进程是必要且直观的。程序启动速度对比与计算器的结果一致,即 (软件包方式安装的)Fedora 版本快于(snap 形式提供的)Ubuntu 版本。
|
||||
|
||||
#### 帮助程序
|
||||
|
||||
我已经提到,(为便于长期以来的 Untiy 用户平滑切换到 GNOME),Ubuntu 提供的 GNOME 桌面环境是经过微调的版本。不幸的是,Ubuntu 开发者似乎忘记或忽略了对帮助程序的更新,用户阅读文档(入门视频)后会发现演示视频与真实环境有略微差异,这可能让人感到迷惑。
|
||||
|
||||
[][8]
|
||||
|
||||
### 结论
|
||||
|
||||
Ubuntu 和 Fedora 是两个主流的 Linux 发行版。两者都各自有一些华而不实的特性,因而新接触 Linux 的人很难抉择。我的建议是同时尝试二者,这样你在试用后可以发现哪个发行版提供的工具更适合你。
|
||||
|
||||
希望你阅读愉快,你可以在下方的评论区给出我漏掉的内容或你的建议。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.linuxandubuntu.com/home/ubuntu-1804-vs-fedora-28
|
||||
|
||||
作者:[LinuxAndUbuntu][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]:http://www.linuxandubuntu.com
|
||||
[1]:http://www.linuxandubuntu.com/home/ubuntu-1804-codename-announced-bionic-beaver
|
||||
[2]:http://www.linuxandubuntu.com/home/what-new-is-going-to-be-in-ubuntu-1704-zesty-zapus
|
||||
[3]:http://www.linuxandubuntu.com/home/5-best-linux-desktop-environments-with-pros-cons
|
||||
[4]:http://www.linuxandubuntu.com/home/walkthrough-on-how-to-use-gnome-boxes
|
||||
[5]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/ubuntu-18-04-gnome_orig.jpg
|
||||
[6]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/ubuntu-gnome-18-04_orig.jpg
|
||||
[7]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/ubuntu-software-center_2_orig.jpg
|
||||
[8]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/ubuntu-18-04-help-manual_orig.jpg
|
||||
[9]:https://en.wikipedia.org/wiki/History_of_Firefox
|
@ -0,0 +1,63 @@
|
||||
使用 Fstransform 转换文件系统
|
||||
======
|
||||
|
||||

|
||||
|
||||
很少有人知道他们可以将文件系统从一种类型转换为另一种类型而不会丢失数据(即非破坏性的)。这可能听起来像魔术,但 [Fstransform][1] 可以几乎以任意组合将 ext2、ext3、ext4、jfs、reiserfs 或 xfs 分区转换成另一类型。更重要的是,它可以直接执行,而无需格式化或复制数据。除此之外,还有一点好处:Fstransform 也可以处理 ntfs、btrfs、fat 和 exfat 分区。
|
||||
|
||||
### 在运行之前
|
||||
|
||||
Fstransform 存在一些警告和限制,因此强烈建议在尝试转换之前进行备份。此外,使用 Fstransform 时需要注意一些限制:
|
||||
|
||||
* 你的 Linux 内核必须支持源文件系统和目标文件系统。听起来很明显,如果你想使用 ext2、ext3、ext4、reiserfs、jfs 和 xfs 分区,这样不会出现风险。Fedora 支持所有分区,所以没问题。
|
||||
* 将 ext2 升级到 ext3 或 ext4 不需要 Fstransform。请使用 Tune2fs。
|
||||
* 源文件系统的设备必须至少有 5% 的可用空间。
|
||||
* 你需要在开始之前卸载源文件系统。
|
||||
* 源文件系统存储的数据越多,转换的时间就越长。实际速度取决于你的设备,但预计它大约为每分钟 1GB。大量的硬链接也会降低转换速度。
|
||||
* 虽然 Fstransform 被证明是稳定的,但请备份源文件系统上的数据。
|
||||
|
||||
### 安装说明
|
||||
|
||||
Fstransform 已经是 Fedora 的一部分。使用以下命令安装:
|
||||
|
||||
```
|
||||
sudo dnf install fstransform
|
||||
```
|
||||
|
||||
### 转换
|
||||
|
||||
![][2]
|
||||
|
||||
`fstransform` 命令的语法非常简单:`fstransform <源设备> <目标文件系统>`。请记住,它需要 root 权限才能运行,所以不要忘记在开头添加 `sudo`。这是一个例子:
|
||||
|
||||
```
|
||||
sudo fstransform /dev/sdb1 ext4
|
||||
```
|
||||
|
||||
请注意,无法转换根文件系统,这是一种安全措施。请改用测试分区或实验性 USB 盘。与此同时,Fstransform 会在控制台中有许多辅助输出。最有用的部分是预计完成时间,让你随时了解该过程需要多长时间。同样,在几乎空的驱动器上的几个小文件将使 Fstransform 在一分钟左右完成其工作,而更多真实世界的任务可能需要数小时的等待时间。
|
||||
|
||||
### 更多支持的文件系统
|
||||
|
||||
如上所述,可以尝试在 ntfs、btrfs、fat 和 exfat 分区使用 Fstransform。这些类型是早期实验性的,没有人能保证完美转换。尽管如此,还是有许多成功案例,你可以通过在测试分区上使用示例数据集测试 Fstransform 来添加自己的成功案例。可以使用 `--force-untested-file-systems` 参数启用这些额外的文件系统:
|
||||
|
||||
```
|
||||
sudo fstransform /dev/sdb1 ntfs --force-untested-file-systems
|
||||
```
|
||||
|
||||
有时,该过程可能会因错误而中断。请放心再次执行命令 —— 它可能最终会在两、三次尝试后完成转换。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/transform-file-systems-in-linux/
|
||||
|
||||
作者:[atolstoy][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/atolstoy/
|
||||
[1]:https://github.com/cosmos72/fstransform
|
||||
[2]:https://fedoramagazine.org/wp-content/uploads/2018/08/Screenshot_20180805_230116.png
|
@ -0,0 +1,140 @@
|
||||
如何在 Linux 中切换相同程序的不同版本
|
||||
======
|
||||
|
||||

|
||||
|
||||
几天前,我们曾经讨论[如何在不同的 PHP 版本之间进行切换][1]。在那篇文章中,我们使用 `update-alternatives` 命令实现从一个 PHP 版本切换到另一个 PHP 版本。也就是说,`update-alternatives` 命令可以将<ruby>系统范围<rt>system wide</rt></ruby>默认使用的 PHP 版本设置为我们希望的版本。通俗的来说,你可以通过 `update-alternatives` 命令从系统范围设置程序的版本。如果你希望可以在不同目录动态设置不同的程序版本,该如何完成呢?在这种情况下,`alt` 工具可以大显身手。`alt` 是一个命令行工具,可以让你在类 Unix 系统中切换相同程序的不同版本。该工具简单易用,是 Rust 语言编写的自由、开源软件。
|
||||
|
||||
### 安装
|
||||
|
||||
安装 `alt` 工具十分简单。
|
||||
|
||||
运行如下命令,即可在 Linux 主机上安装 `alt`:
|
||||
|
||||
```
|
||||
$ curl -sL https://github.com/dotboris/alt/raw/master/install.sh | bash -s
|
||||
```
|
||||
|
||||
下一步,将 `shims` 目录添加到你的 PATH 环境变量中,具体操作取决于你使用的 Shell。
|
||||
|
||||
对于 Bash:
|
||||
|
||||
```
|
||||
$ echo 'export PATH="$HOME/.local/alt/shims:$PATH"' >> ~/.bashrc
|
||||
$ source ~/.bashrc
|
||||
```
|
||||
|
||||
对于 Zsh:
|
||||
|
||||
```
|
||||
$ echo 'export PATH="$HOME/.local/alt/shims:$PATH"' >> ~/.zshrc
|
||||
$ source ~/.zshrc
|
||||
```
|
||||
|
||||
对于 Fish:
|
||||
|
||||
```
|
||||
$ echo 'set -x PATH "$HOME/.local/alt/shims" $PATH' >> ~/.config/fish/config.fish
|
||||
```
|
||||
|
||||
现在 `alt` 已经安装完毕!
|
||||
|
||||
### 使用 alt 工具在 Linux 系统中切换相同程序的不同版本
|
||||
|
||||
如我之前所述,alt 只影响当前目录。换句话说,当你进行版本切换时,只在当前目录生效,而不是整个系统范围。
|
||||
|
||||
下面举例说明。我在我的 Ubuntu 系统中安装了两个版本的 PHP,分别为 PHP 5.6 和 PHP 7.2;另外,在 `myproject` 目录中包含一些 PHP 应用。
|
||||
|
||||
首先,通过命令查看系统范围默认的 PHP 版本:
|
||||
|
||||
```
|
||||
$ php -v
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
![查找 PHP 版本][3]
|
||||
|
||||
如截图中所示,我系统中默认的 PHP 版本为 PHP 7.2。
|
||||
|
||||
然后,我将进入放置 PHP 应用的 `myproject` 目录。
|
||||
|
||||
```
|
||||
$ cd myproject
|
||||
```
|
||||
|
||||
使用如下命令扫描可用的 PHP 版本:
|
||||
|
||||
```
|
||||
$ alt scan php
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
![扫描 PHP 版本][4]
|
||||
|
||||
可见,我有两个 PHP 版本,即 PHP 5.6 和 PHP 7.2。按下 `<空格>` 键选中当前可用的版本。选中全部可用版本后,你可以看到图中所示的<ruby>叉号<rt>cross mark</rt></ruby>。使用上下方向键在版本间移动,点击回车即可保存变更。
|
||||
|
||||
![选取 PHP 版本][5]
|
||||
|
||||
下面运行该命令并选取我们希望在 `myproject` 目录中使用的 PHP 版本:
|
||||
|
||||
```
|
||||
$ alt use php
|
||||
```
|
||||
|
||||
我希望使用 PHP5.6 版本,故我(使用方向键)选取该版本并点击回车键。
|
||||
|
||||
![设置 PHP 版本][6]
|
||||
|
||||
现在,你可以在 `/home/sk/myproject` 目录下使用 PHP 5.6 版本啦。
|
||||
|
||||
让我们检查一下,在 `myproject` 目录下是否默认使用 PHP 5.6 版本:
|
||||
|
||||
```
|
||||
$ php -v
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
![检查 PHP 版本][7]
|
||||
|
||||
只要你不设置成其它版本,(在该目录下)将一直使用 PHP 5.6 版本。清楚了吗?很好!请注意,我们仅在这个目录下使用 PHP 5.6 版本。在系统范围内(LCTT 译注:当然是没单独设置过其它版本的目录下),PHP 7.2 仍是默认的版本。让我们检验一下,请看下图。
|
||||
|
||||
![比对 PHP 版本][8]
|
||||
|
||||
从上面的截图中可以看出,我有两个版本的 PHP:在 `myproject` 目录下,使用的版本为 PHP 5.6;在 `myproject` 外的其它目录,使用的版本为 PHP 7.2。
|
||||
|
||||
同理,你可以为每个目录设置你希望的程序版本。我这里使用 PHP 仅用于说明操作,但方法适用于任何你打算使用的软件,例如 NodeJS 等。
|
||||
|
||||
下面是 NodeJS 的示例视频。
|
||||
|
||||
![][9]
|
||||
|
||||
如果你希望在不同软件包版本下测试你的应用,那么 `alt` 是你不错的选择。
|
||||
|
||||
本次分享到此结束。后续还有更多内容,敬请期待!
|
||||
|
||||
干杯!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-switch-between-different-versions-of-commands-in-linux/
|
||||
|
||||
作者:[SK][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.ostechnix.com/author/sk/
|
||||
[1]:https://www.ostechnix.com/how-to-switch-between-multiple-php-versions-in-ubuntu/
|
||||
[2]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[3]:http://www.ostechnix.com/wp-content/uploads/2018/08/Find-PHP-version.png
|
||||
[4]:http://www.ostechnix.com/wp-content/uploads/2018/08/alt-scan-php.png
|
||||
[5]:http://www.ostechnix.com/wp-content/uploads/2018/08/Select-php-version.png
|
||||
[6]:http://www.ostechnix.com/wp-content/uploads/2018/08/set-php-version.png
|
||||
[7]:http://www.ostechnix.com/wp-content/uploads/2018/08/Check-PHP-version.png
|
||||
[8]:http://www.ostechnix.com/wp-content/uploads/2018/08/Check-PHP-version-1.png
|
||||
[9]:http://www.ostechnix.com/wp-content/uploads/2018/08/Alt-NodeJS-demo.gif
|
@ -0,0 +1,234 @@
|
||||
在 Linux 中如何以人性化的方式显示数据
|
||||
======
|
||||
|
||||
> 许多 Linux 命令现在都有使其输出更易于理解的选项。让我们了解一些可以让我们心爱的操作系统更友好的东西。
|
||||
|
||||

|
||||
|
||||
不是每个人都以二进制方式思考,他们不想在大脑中给大数字插入逗号来了解文件的大小。因此,Linux 命令在过去的几十年里不断发展,以更人性化的方式向用户显示信息,这一点也不奇怪。在今天的文章中,我们将看一看各种命令所提供的一些选项,它们使得数据变得更容易理解。
|
||||
|
||||
### 为什么默认显示不更友好一些?
|
||||
|
||||
如果你想知道为什么默认不显示得更人性化,毕竟,我们人类才是计算机的默认用户啊。你可能会问自己:“为什么我们不竭尽全力输出对每个人都有意义的命令的响应?”主要的答案是:改变命令的默认输出可能会干扰许多其它进程,这些进程是在期望默认响应之上构建的。其它的工具,以及过去几十年开发的脚本,如果突然以一种完全不同的格式输出,而不是它们过去所期望的那样,可能会被一种非常丑陋的方式破坏。
|
||||
|
||||
说真的,也许我们中的一些人可能更愿意看文件大小中的所有数字,即 1338277310 而不是 1.3G。在任何情况下,切换默认习惯都可能造成破坏,但是为更加人性化的响应提供一些简单的选项只需要让我们学习一些命令选项而已。
|
||||
|
||||
### 可以显示人性化数据的命令
|
||||
|
||||
有哪些简单的选项可以使 Unix 命令的输出更容易解析呢?让我们来看一些命令。
|
||||
|
||||
#### top
|
||||
|
||||
你可能没有注意到这个命令,但是在 top 命令中,你可以通过输入 `E`(大写字母 E)来更改显示全部内存使用的方式。连续按下将数字显示从 KiB 到 MiB,再到 GiB,接着是 TiB、PiB、EiB,最后回到 KiB。
|
||||
|
||||
认识这些单位吧?这里有一组定义:
|
||||
|
||||
```
|
||||
2`10 = 1,024 = 1 KiB (kibibyte)
|
||||
2`20 = 1,048,576 = 1 MiB (mebibyte)
|
||||
2`30 = 1,073,741,824 = 1 GiB (gibibyte)
|
||||
2`40 = 1,099,511,627,776 = 1 TiB (tebibyte)
|
||||
2`50 = 1,125,899,906,842,624 = PiB (pebibyte)
|
||||
2`60 = 1,152,921,504,606,846,976 = EiB (exbibyte)
|
||||
2`70 = 1,180,591,620,717,411,303,424 = 1 ZiB (zebibyte)
|
||||
2`80 = 1,208,925,819,614,629,174,706,176 = 1 YiB (yobibyte)
|
||||
```
|
||||
|
||||
这些单位与千字节(KB)、兆字节(MB)和千兆字节(GB)密切相关。虽然它们很接近,但是它们之间仍有很大的区别:一组是基于 10 的幂,另一组是基于 2 的幂。例如,比较千字节和千兆字节,我们可以看看它们不同点:
|
||||
|
||||
```
|
||||
KB = 1000 = 10`3
|
||||
KiB = 1024 = 2`10
|
||||
```
|
||||
|
||||
以下是 `top` 命令输出示例,使用 KiB 为单位默认显示:
|
||||
|
||||
```
|
||||
top - 10:49:06 up 5 days, 35 min, 1 user, load average: 0.05, 0.04, 0.01
|
||||
Tasks: 158 total, 1 running, 118 sleeping, 0 stopped, 0 zombie
|
||||
%Cpu(s): 0.0 us, 0.2 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
|
||||
KiB Mem : 6102680 total, 4634980 free, 392244 used, 1075456 buff/cache
|
||||
KiB Swap: 2097148 total, 2097148 free, 0 used. 5407432 avail Mem
|
||||
```
|
||||
|
||||
在按下 `E` 之后,单位变成了 MiB:
|
||||
|
||||
```
|
||||
top - 10:49:31 up 5 days, 36 min, 1 user, load average: 0.03, 0.04, 0.01
|
||||
Tasks: 158 total, 2 running, 118 sleeping, 0 stopped, 0 zombie
|
||||
%Cpu(s): 0.0 us, 0.6 sy, 0.0 ni, 99.4 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
|
||||
MiB Mem : 5959.648 total, 4526.348 free, 383.055 used, 1050.246 buff/cache
|
||||
MiB Swap: 2047.996 total, 2047.996 free, 0.000 used. 5280.684 avail Mem
|
||||
```
|
||||
|
||||
再次按下 `E`,单位变为 GiB:
|
||||
|
||||
```
|
||||
top - 10:49:49 up 5 days, 36 min, 1 user, load average: 0.02, 0.03, 0.01
|
||||
Tasks: 158 total, 1 running, 118 sleeping, 0 stopped, 0 zombie
|
||||
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
|
||||
GiB Mem : 5.820 total, 4.420 free, 0.374 used, 1.026 buff/cache
|
||||
GiB Swap: 2.000 total, 2.000 free, 0.000 used. 5.157 avail Mem
|
||||
```
|
||||
|
||||
你还可以通过按字母 `e` 来更改为显示每个进程使用内存的数字单位。它将从默认的 KiB 到 MiB,再到 GiB、TiB,接着到 PiB(估计你能看到小数点后的很多 0),然后返回 KiB。下面是按了一下 `e` 之后的 `top` 输出:
|
||||
|
||||
```
|
||||
top - 08:45:28 up 4 days, 22:32, 1 user, load average: 0.02, 0.03, 0.00
|
||||
Tasks: 167 total, 1 running, 118 sleeping, 0 stopped, 0 zombie
|
||||
%Cpu(s): 0.2 us, 0.0 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
|
||||
KiB Mem : 6102680 total, 4641836 free, 393348 used, 1067496 buff/cache
|
||||
KiB Swap: 2097148 total, 2097148 free, 0 used. 5406396 avail Mem
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
784 root 20 0 543.2m 26.8m 16.1m S 0.9 0.5 0:22.20 snapd
|
||||
733 root 20 0 107.8m 2.0m 1.8m S 0.4 0.0 0:18.49 irqbalance
|
||||
22574 shs 20 0 107.5m 5.5m 4.6m S 0.4 0.1 0:00.09 sshd
|
||||
1 root 20 0 156.4m 9.3m 6.7m S 0.0 0.2 0:05.59 systemd
|
||||
```
|
||||
|
||||
#### du
|
||||
|
||||
`du` 命令显示磁盘空间文件或目录使用了多少,如果使用 `-h` 选项,则将输出大小调整为最合适的单位。默认情况下,它以千字节(KB)为单位。
|
||||
|
||||
```
|
||||
$ du camper*
|
||||
360 camper_10.jpg
|
||||
5684 camper.jpg
|
||||
240 camper_small.jpg
|
||||
$ du -h camper*
|
||||
360K camper_10.jpg
|
||||
5.6M camper.jpg
|
||||
240K camper_small.jpg
|
||||
```
|
||||
|
||||
#### df
|
||||
|
||||
`df` 命令也提供了一个 `-h` 选项。请注意在下面的示例中是如何以千兆字节(GB)和兆字节(MB)输出的:
|
||||
|
||||
```
|
||||
$ df -h | grep -v loop
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
udev 2.9G 0 2.9G 0% /dev
|
||||
tmpfs 596M 1.7M 595M 1% /run
|
||||
/dev/sda1 110G 9.0G 95G 9% /
|
||||
tmpfs 3.0G 0 3.0G 0% /dev/shm
|
||||
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
|
||||
tmpfs 3.0G 0 3.0G 0% /sys/fs/cgroup
|
||||
tmpfs 596M 16K 596M 1% /run/user/121
|
||||
/dev/sdb2 457G 73M 434G 1% /apps
|
||||
tmpfs 596M 0 596M 0% /run/user/1000
|
||||
```
|
||||
|
||||
下面的命令使用了 `-h` 选项,同时使用 `-T` 选项来显示我们正在查看的文件系统的类型。
|
||||
|
||||
```
|
||||
$ df -hT /mnt2
|
||||
Filesystem Type Size Used Avail Use% Mounted on
|
||||
/dev/sdb2 ext4 457G 73M 434G 1% /apps
|
||||
```
|
||||
|
||||
#### ls
|
||||
|
||||
即使是 `ls`,它也为我们提供了调整大小显示的选项,保证是最合理的单位。
|
||||
|
||||
```
|
||||
$ ls -l camper*
|
||||
-rw-rw-r-- 1 shs shs 365091 Jul 14 19:42 camper_10.jpg
|
||||
-rw-rw-r-- 1 shs shs 5818597 Jul 14 19:41 camper.jpg
|
||||
-rw-rw-r-- 1 shs shs 241844 Jul 14 19:45 camper_small.jpg
|
||||
$ ls -lh camper*
|
||||
-rw-rw-r-- 1 shs shs 357K Jul 14 19:42 camper_10.jpg
|
||||
-rw-rw-r-- 1 shs shs 5.6M Jul 14 19:41 camper.jpg
|
||||
-rw-rw-r-- 1 shs shs 237K Jul 14 19:45 camper_small.jpg
|
||||
```
|
||||
|
||||
#### free
|
||||
|
||||
`free` 命令允许你以字节(B),千字节(KB),兆字节(MB)和千兆字节(GB)为单位查看内存使用情况。
|
||||
|
||||
```
|
||||
$ free -b
|
||||
total used free shared buff/cache available
|
||||
Mem: 6249144320 393076736 4851625984 1654784 1004441600 5561253888
|
||||
Swap: 2147479552 0 2147479552
|
||||
$ free -k
|
||||
total used free shared buff/cache available
|
||||
Mem: 6102680 383836 4737924 1616 980920 5430932
|
||||
Swap: 2097148 0 2097148
|
||||
$ free -m
|
||||
total used free shared buff/cache available
|
||||
Mem: 5959 374 4627 1 957 5303
|
||||
Swap: 2047 0 2047
|
||||
$ free -g
|
||||
total used free shared buff/cache available
|
||||
Mem: 5 0 4 0 0 5
|
||||
Swap: 1 0 1
|
||||
```
|
||||
|
||||
#### tree
|
||||
|
||||
虽然 `tree` 命令与文件或内存计算无关,但它也提供了非常人性化的文件视图,它分层显示文件以说明文件是如何组织的。当你试图了解如何安排目录内容时,这种显示方式非常有用。(LCTT 译注:也可以看看 `pstree`,它以树状结构显示进程树。)
|
||||
|
||||
```
|
||||
$ tree
|
||||
.g to
|
||||
├── 123
|
||||
├── appended.png
|
||||
├── appts
|
||||
├── arrow.jpg
|
||||
├── arrow.png
|
||||
├── bin
|
||||
│ ├── append
|
||||
│ ├── cpuhog1
|
||||
│ ├── cpuhog2
|
||||
│ ├── loop
|
||||
│ ├── mkhome
|
||||
│ ├── runme
|
||||
```
|
||||
|
||||
#### stat
|
||||
|
||||
`stat` 命令是另一个以非常人性化的格式显示信息的命令。它提供了更多关于文件的元数据,包括文件大小(以字节和块为单位)、文件类型、设备和 inode(索引节点)、文件所有者和组(名称和数字 ID)、以数字和 rwx 格式显示的文件权限以及文件的最后访问和修改日期。在某些情况下,它也可能显示最初创建文件的时间。
|
||||
|
||||
```
|
||||
$ stat camper*
|
||||
File: camper_10.jpg
|
||||
Size: 365091 Blocks: 720 IO Block: 4096 regular file
|
||||
Device: 801h/2049d Inode: 796059 Links: 1
|
||||
Access: (0664/-rw-rw-r--) Uid: ( 1000/ shs) Gid: ( 1000/ shs)
|
||||
Access: 2018-07-19 18:56:31.841013385 -0400
|
||||
Modify: 2018-07-14 19:42:25.230519509 -0400
|
||||
Change: 2018-07-14 19:42:25.230519509 -0400
|
||||
Birth: -
|
||||
File: camper.jpg
|
||||
Size: 5818597 Blocks: 11368 IO Block: 4096 regular file
|
||||
Device: 801h/2049d Inode: 796058 Links: 1
|
||||
Access: (0664/-rw-rw-r--) Uid: ( 1000/ shs) Gid: ( 1000/ shs)
|
||||
Access: 2018-07-19 18:56:31.845013872 -0400
|
||||
Modify: 2018-07-14 19:41:46.882024039 -0400
|
||||
Change: 2018-07-14 19:41:46.882024039 -0400
|
||||
Birth: -
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
Linux 命令提供了许多选项,可以让用户更容易理解或比较它们的输出。对于许多命令,`-h` 选项会显示更友好的输出格式。对于其它的,你可能必须通过使用某些特定选项或者按下某个键来查看你希望的输出。我希望这其中一些选项会让你的 Linux 系统看起来更友好一点。
|
||||
|
||||
加入[Facebook][1] 和 [LinkedIn][2] 上的网络世界社区,一起来评论重要的话题吧。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3296631/linux/displaying-data-in-a-human-friendly-way-on-linux.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][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.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[1]:https://www.facebook.com/NetworkWorld/
|
||||
[2]:https://www.linkedin.com/company/network-world
|
@ -0,0 +1,177 @@
|
||||
在 Linux 中使用 top 命令的建议
|
||||
======
|
||||
|
||||
> 通过这篇教程提升你的 `top` 命令的知识。
|
||||
|
||||

|
||||
|
||||
尝试找出你的机器正在运行什么程序,以及哪个进程耗尽了内存导致系统非常非常慢 —— 这是 `top` 命令所能胜任的工作。
|
||||
|
||||
`top` 是一个非常有用的程序,其作用类似于 Windows 任务管理器或 MacOS 的活动监视器。在 \*nix 机器上运行 `top` 将实时显示系统上运行的进程的情况。
|
||||
|
||||
```
|
||||
$ top
|
||||
```
|
||||
|
||||
取决于你运行的 `top` 版本,你会看到类似如下内容:
|
||||
|
||||
```
|
||||
top - 08:31:32 up 1 day, 4:09, 0 users, load average: 0.20, 0.12, 0.10
|
||||
Tasks: 3 total, 1 running, 2 sleeping, 0 stopped, 0 zombie
|
||||
%Cpu(s): 0.5 us, 0.3 sy, 0.0 ni, 99.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
|
||||
KiB Mem: 4042284 total, 2523744 used, 1518540 free, 263776 buffers
|
||||
KiB Swap: 1048572 total, 0 used, 1048572 free. 1804264 cached Mem
|
||||
|
||||
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
|
||||
1 root 20 0 21964 3632 3124 S 0.0 0.1 0:00.23 bash
|
||||
193 root 20 0 123520 29636 8640 S 0.0 0.7 0:00.58 flask
|
||||
195 root 20 0 23608 2724 2400 R 0.0 0.1 0:00.21 top
|
||||
```
|
||||
|
||||
你所用的 `top` 版本可能跟这个看起来不一样,特别是在显示的列上。
|
||||
|
||||
### 如何阅读输出的内容
|
||||
|
||||
你可以根据输出判断你正在运行的内容,但尝试去解释结果你可能会有些困惑。
|
||||
|
||||
前几行包含一堆统计信息(详细信息),后跟一个包含结果列的表(列)。让我们从后者开始吧。
|
||||
|
||||
#### 列
|
||||
|
||||
这些是系统正在运行的进程。默认按 CPU 使用率降序排序。这意味着在列表顶部的程序正使用更多的 CPU 资源并对你的系统造成更重的负担。对于资源使用而言,这些程序是字面上的消耗资源最多的(top)进程。不得不说,`top` 这个名字起得很妙。
|
||||
|
||||
最右边的 `COMMAND` 一列报告进程名(启动它们的命令)。在这个例子里,进程名是 `bash`(一个我们正在运行 `top` 的命令解释器)、`flask`(一个 Python 写的 web 框架)和 `top` 自身。
|
||||
|
||||
其它列提供了关于进程的有用信息:
|
||||
|
||||
* `PID`:进程 ID,一个用来定位进程的唯一标识符
|
||||
* `USER`:运行进程的用户
|
||||
* `PR`:任务的优先级
|
||||
* `NI`:Nice 值,优先级的一个更好的表现形式
|
||||
* `VIRT`:虚拟内存的大小,单位是 KiB(kibibytes)
|
||||
* `RES`:常驻内存大小,单位是 KiB(物理内存和虚拟内存的一部分)
|
||||
* `SHR`:共享内存大小,单位是 KiB(共享内存和虚拟内存的一部分)
|
||||
* `S`:进程状态,一般 **I** 代表空闲,**R** 代表运行,**S** 代表休眠,**Z** 代表僵尸进程,**T** 或 **t** 代表停止(还有其它更少见的选项)
|
||||
* `%CPU`:自从上次屏幕更新后的 CPU 使用率
|
||||
* `%MEM`:自从上次屏幕更新后的 `RES` 常驻内存使用率
|
||||
* `TIME+`:自从程序启动后总的 CPU 使用时间
|
||||
* `COMMAND`:启动命令,如之前描述那样
|
||||
|
||||
确切知道 `VIRT`,`RES` 和 `SHR` 值代表什么在日常操作中并不重要。重要的是要知道 `VIRT` 值最高的进程就是内存使用最多的进程。当你在用 `top` 排查为什么你的电脑运行无比卡的时候,那个 `VIRT` 数值最大的进程就是元凶。如果你想要知道共享内存和物理内存的确切意思,请查阅 [top 手册][1]的 Linux Memory Types 段落。
|
||||
|
||||
是的,我说的是 kibibytes 而不是 kilobytes。通常称为 kilobyte 的 1024 值实际上是 kibibyte。希腊语的 kilo(χίλιοι)意思是一千(例如一千米是 1000 米,一千克是 1000 克)。Kibi 是 kilo 和 binary 的合成词,意思是 1024 字节(或者 2^10 )。但是,因为这个词很难说,所以很多人在说 1024 字节的时候会说 kilobyte。`top` 试图在这里使用恰当的术语,所以按它说的理解就好。
|
||||
|
||||
#### 屏幕更新说明
|
||||
|
||||
实时屏幕更新是 Linux 程序可以做的 **非常酷** 的事之一。这意味着程序能实时更新它们显示的内容,所以看起来是动态的,即使它们用的是文本。非常酷!在我们的例子中,更新时间间隔很重要,因为一些统计数据(`%CPU` 和 `%MEM`)是基于上次屏幕更新的数值的。
|
||||
|
||||
因为我们运行在一个持久性的程序中,我们就可以输入一些命令来实时修改配置(而不是停止应用,然后用一个不同的命令行选项再次运行)。
|
||||
|
||||
按下 `h` 调用帮助界面,该界面也显示了默认延迟(屏幕更新的时间间隔)。这个值默认(大约)是 3 秒,但你可以输入 `d`(大概是 delay 的意思)或者 `s`(可能是 screen 或 seconds 的意思)来修改它。
|
||||
|
||||
#### 细节
|
||||
|
||||
在进程列表上面有一大堆有用的信息。有些细节看起来有点儿奇怪,让人困惑。但是一旦你花点儿时间来逐个过一遍,你会发现,在紧要关头,这些是非常有用的。
|
||||
|
||||
第一行包含系统的大致信息:
|
||||
|
||||
* `top`:我们正在运行 `top`!你好!`top`!
|
||||
* `XX:YY:XX`:当前时间,每次屏幕更新的时候更新
|
||||
* `up`(接下去是 `X day, YY:ZZ`):系统的 [uptime][2],或者自从系统启动后已经过去了多长时间
|
||||
* `load average`(后跟三个数字):分别是过去一分钟、五分钟、15 分钟的[系统负载][3]
|
||||
|
||||
第二行(`Task`)显示了正在运行的任务的信息,不用解释。它显示了进程总数和正在运行的、休眠中的、停止的进程数和僵尸进程数。这实际上是上述 `S`(状态)列的总和。
|
||||
|
||||
第三行(`%Cpu(s)`)显示了按类型划分的 CPU 使用情况。数据是屏幕刷新之间的值。这些值是:
|
||||
|
||||
* `us`:用户进程
|
||||
* `sy`:系统进程
|
||||
* `ni`:[nice][4] 用户进程
|
||||
* `id`:CPU 的空闲时间,这个值比较高时说明系统比较空闲
|
||||
* `wa`:等待时间,或者消耗在等待 I/O 完成的时间
|
||||
* `hi`:消耗在硬件中断的时间
|
||||
* `si`:消耗在软件中断的时间
|
||||
* `st`:“虚拟机管理程序从该虚拟机窃取的时间”
|
||||
|
||||
你可以通过点击 `t`(toggle)来展开或折叠 `Task` 和 `%Cpu(s)` 行。
|
||||
|
||||
第四行(`Kib Mem`)和第五行(`KiB Swap`)提供了内存和交换空间的信息。这些数值是:
|
||||
|
||||
* 总内存容量
|
||||
* 已用内存
|
||||
* 空闲内存
|
||||
* 内存的缓冲值
|
||||
* 交换空间的缓存值
|
||||
|
||||
默认它们是用 KiB 为单位展示的,但是按下 `E`(扩展内存缩放 extend memory scaling)可以轮换不同的单位:KiB、MiB、GiB、TiB、PiB、EiB(kilobytes、megabytes、gigabytes、terabytes、petabytes 和 exabytes)
|
||||
|
||||
`top` 用户手册有更多选项和配置项信息。你可以运行 `man top` 来查看你系统上的文档。还有很多 [HTML 版的 man 手册][1],但是请留意,这些手册可能是针对不同 top 版本的。
|
||||
|
||||
### 两个 top 的替代品
|
||||
|
||||
你不必总是用 `top` 查看系统状态。你可以根据你的情况用其它工具来协助排查问题,尤其是当你想要更图形化或更专业的界面的时候。
|
||||
|
||||
#### htop
|
||||
|
||||
`htop` 很像 `top`,但是它带来了一些非常有用的东西:它可以以图形界面展示 CPU 和内存使用情况。
|
||||
|
||||

|
||||
|
||||
这是我们在刚才运行 `top` 的同一环境中 `htop` 的样子。显示更简洁,但功能却很丰富。
|
||||
|
||||
任务统计、负载、uptime 和进程列表仍然在,但是它有了漂亮、彩色、动态的每核 CPU 使用情况,还有图形化的内存使用情况。
|
||||
|
||||
以下是不同颜色的含义(你也可以通过按下 `h` 来获得这些信息的帮助)。
|
||||
|
||||
CPU 任务优先级或类型:
|
||||
|
||||
* 蓝色:低优先级
|
||||
* 绿色:正常优先级
|
||||
* 红色:内核任务
|
||||
* 蓝绿色:虚拟任务
|
||||
* 条状图末尾的值是已用 CPU 的百分比
|
||||
|
||||
内存:
|
||||
|
||||
* 绿色:已经使用的内存
|
||||
* 蓝色:缓冲的内存
|
||||
* 黄色:缓存内存
|
||||
* 条状图末尾的值显示已用内存和总内存
|
||||
|
||||
如果颜色对你没用,你可以运行 `htop -C` 来禁用它们;那样 `htop` 将使用不同的符号来展示 CPU 和内存类型。
|
||||
|
||||
它的底部有一组激活的快捷键提示,可以用来操作过滤结果或改变排序顺序。试着按一些快捷键看看它们能做什么。不过尝试 `F9` 时要小心,它会调出一个信号列表,这些信号会杀死(即停止)一个过程。我建议在生产环境之外探索这些选项。
|
||||
|
||||
`htop` 的作者 Hisham Muhammad(是的,`htop` 的名字就是源自 Hisham 的)在二月份的 [FOSDEM 2018][6] 做了一个[简短的演讲][5]。他阐述了 `htop` 不仅有简洁的图形界面,还有更现代的进程信息统计展示方式,这都是之前的工具(如 `top`)所不具备的。
|
||||
|
||||
你可以在[手册页面][7]或 [htop 网站][8]阅读更多关于 `htop` 的信息。(提示:网站背景是一个动态的 `htop`。)
|
||||
|
||||
#### docker stats
|
||||
|
||||
如果你在用 Docker,你可以运行 `docker stats` 来为容器状态生成一个有丰富上下文的界面。
|
||||
|
||||
这可能比 `top` 更有帮助,因为它不是按进程分类,而是按容器分类的。这点特别有用,当某个容器运行缓慢时,查看哪个容器耗资源最多比运行 `top` 再找到容器的进程要快。
|
||||
|
||||
借助于上面对 `top` 和 `htop` 术语的解释,你应该会更容易理解 `docker stats` 中的那些。然而,[docker stats 文档][9]对每一列都提供了详尽的描述。
|
||||
|
||||
---
|
||||
|
||||
via: https://opensource.com/article/18/8/top-tips-speed-up-computer
|
||||
|
||||
作者:[Katie McLaughlin][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[ypingcn](https://github.com/ypingcn)
|
||||
校对:[pityonline](https://github.com/pityonline)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/glasnt
|
||||
[1]: http://man7.org/linux/man-pages/man1/top.1.html
|
||||
[2]: https://en.wikipedia.org/wiki/Uptime
|
||||
[3]: https://en.wikipedia.org/wiki/Load_(computing)
|
||||
[4]: https://en.wikipedia.org/wiki/Nice_(Unix)#Etymology
|
||||
[5]: https://www.youtube.com/watch?v=L25waVhy78o
|
||||
[6]: https://fosdem.org/2018/schedule/event/htop/
|
||||
[7]: https://linux.die.net/man/1/htop
|
||||
[8]: https://hisham.hm/htop/index.php
|
||||
[9]: https://docs.docker.com/engine/reference/commandline/stats/
|
@ -0,0 +1,135 @@
|
||||
将 Linux 终端会话录制成 SVG 动画
|
||||
======
|
||||
|
||||

|
||||
|
||||
录制终端会话可以满足我们不同类型的需求。通过录制终端会话,你可以完整记录你在终端中执行的操作,将其保存以供后续参考。通过录制终端会话,你还可以向青少年、学生或其它打算学习 Linux 的人展示各种 Linux 命令及其用例。值得庆幸的是,市面上已经有不少工具,可以帮助我们在类 Unix 操作系统下录制终端会话。我们已经介绍过一些可以帮助你录制终端会话的工具,可以在下面的链接中找到。
|
||||
|
||||
+ [如何录制你在终端中的所作所为][3]
|
||||
+ [Asciinema – 录制终端会话并在网上分享][4]
|
||||
|
||||
今天,我们要介绍另一款录制终端操作的工具,名字叫做 **Termtosvg**。从名字可以看出,Termtosvg 将你的终端会话录制成一个单独的 SVG 动画。它是一款简单的命令行工具,使用 **Python** 语言编写,可以生成轻量级、外观整洁的动画,可以嵌入到网页项目中。Termtosvg 支持自定义<ruby>色彩主题<rt>color themes</rt></ruby>、终端 UI,还可以通过 [SVG 模板][1]完成动画控制。它兼容 asciinema 录制格式,支持 GNU/Linux,Mac OS 和 BSD 等操作系统。
|
||||
|
||||
### 安装 Termtosvg
|
||||
|
||||
PIP 是一个面向 Python 语言编写的软件包的管理器,可以用于安装 Termtosvg。如果你没有安装 PIP,可以参考下面的指导:
|
||||
|
||||
[如何使用 PIP 管理 Python 软件包][5]
|
||||
|
||||
安装 PIP 后,运行如下命令安装 Termtosvg 工具:
|
||||
|
||||
```
|
||||
$ pip3 install --user termtosvg
|
||||
```
|
||||
|
||||
此外,还要安装渲染终端屏幕所需的依赖包:
|
||||
|
||||
```
|
||||
$ pip3 install pyte python-xlib svgwrite
|
||||
```
|
||||
|
||||
安装完毕,我们接下来生成 SVG 格式的终端会话。
|
||||
|
||||
### 将 Linux 终端会话录制成 SVG 动画
|
||||
|
||||
使用 `termtosvg` 录制终端会话十分容易。打开终端窗口,运行如下命令即可开始录制:
|
||||
|
||||
```
|
||||
$ termtosvg
|
||||
```
|
||||
|
||||
**注意:** 如果 `termtosvg` 命令不可用,重启操作系统一次即可。
|
||||
|
||||
运行 `termtosvg` 命令后,可以看到如下命令输出:
|
||||
|
||||
```
|
||||
Recording started, enter "exit" command or Control-D to end
|
||||
|
||||
```
|
||||
|
||||
你目前位于一个子 Shell 中,在这里可以像平常那样输入命令。你在终端中的所作所为都会被录制。
|
||||
|
||||
不妨随便输入一些命令:
|
||||
|
||||
```
|
||||
$ mkdir mydirectory
|
||||
$ cd mydirectory/
|
||||
$ touch file.txt
|
||||
$ cd ..
|
||||
$ uname -a
|
||||
|
||||
```
|
||||
|
||||
操作完成后,使用组合键 `CTRL+D` 或者输入 `exit` 停止录制。录制结果将会保存在 `/tmp` 目录,(由于做了唯一性处理)文件名并不会重复。
|
||||
|
||||

|
||||
|
||||
现在,你可以在命令行运行命令,使用你的浏览器打开 SVG 文件:
|
||||
|
||||
```
|
||||
$ firefox /tmp/termtosvg_ddkehjpu.svg
|
||||
```
|
||||
|
||||
你也可以在(图形界面的)浏览器中直接打开这个 SVG 文件( **File -> \<SVG 文件路径>** )。
|
||||
|
||||
我用 Firefox 浏览器打开的效果如下:
|
||||
|
||||

|
||||
|
||||
下面举例说明几种使用 Termtosvg 录制终端会话的方式。
|
||||
|
||||
我刚刚提到,Termtosvg 录制终端会话后默认保存成 `/tmp` 目录下的一个 SVG 动画文件。
|
||||
|
||||
但你可以指定 SVG 动画文件的文件名,例如 `animation.svg`;也可以指定一个存放路径,例如 `/home/sk/ostechnix/`。
|
||||
|
||||
```
|
||||
$ termtosvg /home/sk/ostechnix/animation.svg
|
||||
```
|
||||
|
||||
录制终端会话并使用特定模板进行渲染:
|
||||
|
||||
```
|
||||
$ termtosvg -t ~/templates/my_template.svg
|
||||
```
|
||||
|
||||
使用指定的<ruby>屏幕参数<rt>screen geometry</rt></ruby>录制终端会话:
|
||||
|
||||
```
|
||||
$ termtosvg -g 80x24 animation.svg
|
||||
```
|
||||
|
||||
使用 asciicast v2 格式录制终端会话:
|
||||
|
||||
```
|
||||
$ termtosvg record recording.cast
|
||||
```
|
||||
|
||||
将 asciicast 格式的录制结果渲染成 SVG 动画:
|
||||
|
||||
```
|
||||
$ termtosvg render recording.cast animation.svg
|
||||
```
|
||||
|
||||
欲了解更多细节,请参考 [**Termtosvg 手册**][2]。
|
||||
|
||||
好了,本次分享就到这里,希望对你有帮助。更多精彩内容,敬请期待!
|
||||
|
||||
干杯!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-record-terminal-sessions-as-svg-animations-in-linux/
|
||||
|
||||
作者:[SK][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.ostechnix.com/author/sk/
|
||||
[1]:https://nbedos.github.io/termtosvg/pages/templates.html
|
||||
[2]:https://github.com/nbedos/termtosvg/blob/develop/man/termtosvg.md
|
||||
[3]:https://www.ostechnix.com/record-everything-terminal/
|
||||
[4]:https://www.ostechnix.com/asciinema-record-terminal-sessions-share-web/
|
||||
[5]:https://www.ostechnix.com/manage-python-packages-using-pip/
|
@ -0,0 +1,69 @@
|
||||
L1 终端错误漏洞(L1TF)如何影响 Linux 系统
|
||||
======
|
||||
|
||||
> L1 终端错误(L1TF)影响英特尔处理器和 Linux 操作系统。让我们了解一下这个漏洞是什么,以及 Linux 用户需要为它做点什么。
|
||||
|
||||

|
||||
|
||||
昨天(LCTT 译注:本文发表于 2018/8/15)在英特尔、微软和红帽的安全建议中宣布,一个新发现的漏洞英特尔处理器(还有 Linux)的漏洞称为 L1TF 或 “<ruby>L1 终端错误<rt>L1 Terminal Fault</rt></ruby>”,引起了 Linux 用户和管理员的注意。究竟什么是这个漏洞,谁应该担心它?
|
||||
|
||||
### L1TF、 L1 Terminal Fault 和 Foreshadow
|
||||
|
||||
处理器漏洞被称作 L1TF、L1 Terminal Fault 和 Foreshadow。研究人员在 1 月份发现了这个问题并向英特尔报告称其为 “Foreshadow”。它类似于过去发现的漏洞(例如 Spectre)。
|
||||
|
||||
此漏洞是特定于英特尔的。其他处理器不受影响。与其他一些漏洞一样,它之所以存在,是因为设计时为了优化内核处理速度,但允许其他进程访问数据。
|
||||
|
||||
**[另请阅读:[22 个必要的 Linux 安全命令][1]]**
|
||||
|
||||
已为此问题分配了三个 CVE:
|
||||
|
||||
* CVE-2018-3615:英特尔<ruby>软件保护扩展<rt>Software Guard Extension</rt></ruby>(英特尔 SGX)
|
||||
* CVE-2018-3620:操作系统和<ruby>系统管理模式<rt>ystem Management Mode</rt></ruby>(SMM)
|
||||
* CVE-2018-3646:虚拟化的影响
|
||||
|
||||
英特尔发言人就此问题发表了这一声明:
|
||||
|
||||
> “L1 Terminal Fault 通过今年早些时候发布的微代码更新得到解决,再加上从今天开始提供的操作系统和虚拟机管理程序软件的相应更新。我们在网上提供了更多信息,并继续鼓励每个人更新操作系统,因为这是得到保护的最佳方式之一。我们要感谢 imec-DistriNet、KU Leuven、以色列理工学院,密歇根大学,阿德莱德大学和 Data61 的研究人员以及我们的行业合作伙伴,他们帮助我们识别和解决了这个问题。“
|
||||
|
||||
### L1TF 会影响你的 Linux 系统吗?
|
||||
|
||||
简短的回答是“可能不会”。如果你因为在今年 1 月爆出的 [Spectre 和 Meltdown 漏洞][2]修补过系统,那你应该是安全的。与 Spectre 和 Meltdown 一样,英特尔声称真实世界中还没有系统受到影响的报告或者检测到。他们还表示,这些变化不太可能在单个系统上产生明显的性能影响,但它们可能对使用虚拟化操作系统的数据中心产生大的影响。
|
||||
|
||||
即使如此,仍然推荐频繁地打补丁。要检查你当前的内核版本,使用 `uname -r` 命令:
|
||||
|
||||
```
|
||||
$ uname -r
|
||||
4.18.0-041800-generic
|
||||
```
|
||||
|
||||
### 更多资源
|
||||
|
||||
请查看如下资源以了解 L1TF 的更多细节,以及为什么会出现这个漏洞:
|
||||
|
||||
- [L1TF explained in ~3 minutes (Red Hat)][5]
|
||||
- [L1TF explained in under 11 minutes (Red Hat)][6]
|
||||
- [Technical deep dive][7]
|
||||
- [Red Hat explanation of L1TF][8]
|
||||
- [Ubuntu updates for L1TF][9]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3298157/linux/linux-and-l1tf.html
|
||||
|
||||
作者:[Sandra Henry-Stocker][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.networkworld.com/author/Sandra-Henry_Stocker/
|
||||
[1]: https://www.networkworld.com/article/3272286/open-source-tools/22-essential-security-commands-for-linux.html
|
||||
[2]: https://www.networkworld.com/article/3245813/security/meltdown-and-spectre-exploits-cutting-through-the-fud.html
|
||||
[3]: https://www.facebook.com/NetworkWorld/
|
||||
[4]: https://www.linkedin.com/company/network-world
|
||||
[5]: https://www.youtube.com/watch?v=kBOsVt0iXE4&feature=youtu.be
|
||||
[6]: https://www.youtube.com/watch?v=kqg8_KH2OIQ
|
||||
[7]: https://www.redhat.com/en/blog/deeper-look-l1-terminal-fault-aka-foreshadow
|
||||
[8]: https://access.redhat.com/security/vulnerabilities/L1TF
|
||||
[9]: https://blog.ubuntu.com/2018/08/14/ubuntu-updates-for-l1-terminal-fault-vulnerabilities
|
@ -0,0 +1,260 @@
|
||||
如何在 Linux Shell 编程中定义和使用函数
|
||||
======
|
||||
|
||||
函数是一段可复用的代码。我们通常把重复的代码放进函数中并且在不同的地方去调用它。库是函数的集合。我们可以在库中定义经常使用的函数,这样其它脚本便可以不再重复代码而使用这些函数。
|
||||
|
||||
![Functions-Linux-Shell-Script][1]
|
||||
|
||||
本文我们将讨论诸多关于函数的内容和一些使用技巧。为了方便演示,我将在 Ubuntu 系统上使用 **Bourne Again SHell (Bash)**。
|
||||
|
||||
### 调用函数
|
||||
|
||||
在 Shell 中调用函数和调用其它命令是一模一样的。例如,如果你的函数名称为 `my_func`,你可以在命令行中像下面这样执行它:
|
||||
|
||||
```
|
||||
$ my_func
|
||||
```
|
||||
|
||||
如果你的函数接收多个参数,那么可以像下面这样写(类似命令行参数的使用):
|
||||
|
||||
```
|
||||
$ my_func arg1 arg2 arg3
|
||||
```
|
||||
|
||||
### 定义函数
|
||||
|
||||
我们可以用下面的语法去定义一个函数:
|
||||
|
||||
```
|
||||
function function_name {
|
||||
Body of function
|
||||
}
|
||||
```
|
||||
|
||||
函数的主体可以包含任何有效的命令、循环语句和其它函数或脚本。现在让我们创建一个简单的函数,它向屏幕上显示一些消息(注:直接在命令行里写)。
|
||||
|
||||
```
|
||||
function print_msg {
|
||||
echo "Hello, World"
|
||||
}
|
||||
```
|
||||
|
||||
现在,让我们执行这个函数:
|
||||
|
||||
```
|
||||
$ print_msg
|
||||
Hello, World
|
||||
```
|
||||
|
||||
不出所料,这个函数在屏幕上显示了一些消息。
|
||||
|
||||
在上面的例子中,我们直接在终端里创建了一个函数。这个函数也可以保存到文件中。如下面的例子所示。
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
function print_msg {
|
||||
echo "Hello, World"
|
||||
}
|
||||
print_msg
|
||||
```
|
||||
|
||||
我们已经在 `function.sh` 文件中定义了这个函数。现在让我们执行这个脚本:
|
||||
|
||||
```
|
||||
$ chmod +x function.sh
|
||||
$ ./function.sh
|
||||
Hello, World
|
||||
```
|
||||
|
||||
你可以看到,上面的输出和之前的是一模一样的。
|
||||
|
||||
### 更多函数用法
|
||||
|
||||
在上一小节中我们定义了一个非常简单的函数。然而在软件开发的过程中,我们需要更多高级的函数,它可以接收多个参数并且带有返回值。在这一小节中,我们将讨论这种函数。
|
||||
|
||||
#### 向函数传递参数
|
||||
|
||||
我们可以像调用其它命令那样给函数提供参数。我们可以在函数里使用美元 `$` 符号访问到这些参数。例如,`$1` 表示第一个参数,`$2` 代表第二个参数,以此类推。
|
||||
|
||||
让我们修改下之前的函数,让它以参数的形式接收信息。修改后的函数就像这样:
|
||||
|
||||
```
|
||||
function print_msg {
|
||||
echo "Hello $1"
|
||||
}
|
||||
```
|
||||
|
||||
在上面的函数中我们使用 `$1` 符号访问第一个参数。让我们执行这个函数:
|
||||
|
||||
```
|
||||
$ print_msg "LinuxTechi"
|
||||
```
|
||||
|
||||
执行完后,生成如下信息:
|
||||
|
||||
```
|
||||
Hello LinuxTechi
|
||||
```
|
||||
|
||||
#### 从函数中返回数值
|
||||
|
||||
跟其它编程语言一样,Bash 提供了返回语句让我们可以向调用者返回一些数值。让我们举例说明:
|
||||
|
||||
```
|
||||
function func_return_value {
|
||||
return 10
|
||||
}
|
||||
```
|
||||
|
||||
上面的函数向调用者返回 `10`。让我们执行这个函数:
|
||||
|
||||
```
|
||||
$ func_return_value
|
||||
$ echo "Value returned by function is: $?"
|
||||
```
|
||||
|
||||
当你执行完,将会产生如下的输出结果:
|
||||
|
||||
```
|
||||
Value returned by function is: 10
|
||||
```
|
||||
|
||||
**提示**:在 Bash 中使用 `$?` 去获取函数的返回值。
|
||||
|
||||
### 函数技巧
|
||||
|
||||
目前我们已经对 Bash 中的函数有了一些了解。现在让我们创建一些非常有用的 Bash 函数,它们可以让我们的生活变得更加轻松。
|
||||
|
||||
#### Logger
|
||||
|
||||
让我们创建一个 `logger` 函数,它可以输出带有日期和时间的 log 信息。
|
||||
|
||||
```
|
||||
function log_msg {
|
||||
echo "[`date '+ %F %T'` ]: $@"
|
||||
}
|
||||
```
|
||||
|
||||
执行这个函数:
|
||||
|
||||
```
|
||||
$ log_msg "This is sample log message"
|
||||
```
|
||||
|
||||
执行完,就会生成如下信息:
|
||||
|
||||
```
|
||||
[ 2018-08-16 19:56:34 ]: This is sample log message
|
||||
```
|
||||
|
||||
#### 显示系统信息
|
||||
|
||||
让我们创建一个显示 GNU/Linux 信息的函数
|
||||
|
||||
```
|
||||
function system_info {
|
||||
echo "### OS information ###"
|
||||
lsb_release -a
|
||||
|
||||
echo
|
||||
echo "### Processor information ###"
|
||||
processor=`grep -wc "processor" /proc/cpuinfo`
|
||||
model=`grep -w "model name" /proc/cpuinfo | awk -F: '{print $2}'`
|
||||
echo "Processor = $processor"
|
||||
echo "Model = $model"
|
||||
|
||||
echo
|
||||
echo "### Memory information ###"
|
||||
total=`grep -w "MemTotal" /proc/meminfo | awk '{print $2}'`
|
||||
free=`grep -w "MemFree" /proc/meminfo | awk '{print $2}'`
|
||||
echo "Total memory: $total kB"
|
||||
echo "Free memory : $free kB"
|
||||
}
|
||||
```
|
||||
|
||||
执行完后会生成以下信息:
|
||||
|
||||
```
|
||||
### OS information ###
|
||||
No LSB modules are available.
|
||||
Distributor ID: Ubuntu
|
||||
Description: Ubuntu 18.04.1 LTS
|
||||
Release: 18.04
|
||||
Codename: bionic
|
||||
|
||||
### Processor information ###
|
||||
Processor = 1
|
||||
Model = Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
|
||||
|
||||
### Memory information ###
|
||||
Total memory: 4015648 kB
|
||||
Free memory : 2915428 kB
|
||||
```
|
||||
|
||||
#### 在当前目录下查找文件或者目录
|
||||
|
||||
下面的函数从当前目录下查找文件或者目录:
|
||||
|
||||
```
|
||||
function search {
|
||||
find . -name $1
|
||||
}
|
||||
```
|
||||
|
||||
让我们使用下面的命令查找 `dir4` 这个目录:
|
||||
|
||||
```
|
||||
$ search dir4
|
||||
```
|
||||
|
||||
当你执行完命令后,将会产生如下输出:
|
||||
|
||||
```
|
||||
./dir1/dir2/dir3/dir4
|
||||
```
|
||||
|
||||
#### 数字时钟
|
||||
|
||||
下面的函数在终端里创建了一个简单的数字时钟:
|
||||
|
||||
```
|
||||
function digital_clock {
|
||||
clear
|
||||
while [ 1 ]
|
||||
do
|
||||
date +'%T'
|
||||
sleep 1
|
||||
clear
|
||||
done
|
||||
}
|
||||
```
|
||||
|
||||
### 函数库
|
||||
|
||||
库是函数的集合。将函数定义在文件里并在当前环境中导入那个文件,这样可以创建函数库。
|
||||
|
||||
假设我们已经在 `utils.sh` 中定义好了所有函数,接着在当前的环境下使用下面的命令导入函数:
|
||||
|
||||
```
|
||||
$ source utils.sh
|
||||
```
|
||||
|
||||
之后你就可以像调用其它 Bash 命令那样执行库中任何的函数了。
|
||||
|
||||
### 总结
|
||||
|
||||
本文我们讨论了诸多可以提升效率的实用技巧。我希望这篇文章能够启发你去创造自己的技巧。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linuxtechi.com/define-use-functions-linux-shell-script/
|
||||
|
||||
作者:[Pradeep Kumar][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[LuuMing](https://github.com/LuuMing)
|
||||
校对:[pityonline](https://github.com/pityonline)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.linuxtechi.com/author/pradeep/
|
||||
[1]: https://www.linuxtechi.com/wp-content/uploads/2018/08/Functions-Linux-Shell-Script.jpg
|
@ -0,0 +1,313 @@
|
||||
一套有用的 Unix 实用程序
|
||||
======
|
||||
|
||||

|
||||
|
||||
我们都了解 <ruby>GNU 核心实用程序<rt>GNU Core Utilities</rt></ruby>,所有类 Unix 操作系统都预装了它们。它们是 GNU 操作系统中与文件、Shell 和 文本处理相关的基础实用工具。GNU 核心实用程序包括很多日常操作命令,例如 `cat`、`ls`、`rm`、`mkdir`、`rmdir`、`touch`、`tail` 和 `wc` 等。除了这些实用程序,还有更多有用的实用程序没有预装在类 Unix 操作系统中,它们汇集起来构成了 `moreutilis` 这个日益增长的集合。`moreutils` 可以在 GNU/Linux 和包括 FreeBSD,openBSD 及 Mac OS 在内的多种 Unix 类型操作系统上安装。
|
||||
|
||||
截至到编写这份指南时, `moreutils` 提供如下实用程序:
|
||||
|
||||
* `chronic` – 运行程序并忽略正常运行的输出
|
||||
* `combine` – 使用布尔操作合并文件的行
|
||||
* `errno` – 查询 errno 名称及描述
|
||||
* `ifdata` – 获取网络接口信息,无需解析 `ifconfig` 的结果
|
||||
* `ifne` – 在标准输入非空的情况下运行程序
|
||||
* `isutf8` – 检查文件或标准输入是否采用 UTF-8 编码
|
||||
* `lckdo` – 带锁运行程序
|
||||
* `mispipe` – 使用管道连接两个命令,返回第一个命令的退出状态
|
||||
* `parallel` – 同时运行多个任务
|
||||
* `pee` – 将标准输入传递给多个管道
|
||||
* `sponge` – 整合标准输入并写入文件
|
||||
* `ts` – 为标准输入增加时间戳信息
|
||||
* `vidir` – 使用你默认的文本编辑器操作目录文件
|
||||
* `vipe` – 在管道中插入信息编辑
|
||||
* `zrun` – 自动解压并将其作为参数传递给命令
|
||||
|
||||
### 在 Linux 上安装 moreutils
|
||||
|
||||
由于 `moreutils` 已经被打包到多种 Linux 发行版中,你可以使用发行版对应的软件包管理器安装 `moreutils`。
|
||||
|
||||
在 **Arch Linux** 或衍生的 **Antergos** 和 **Manjaro Linux** 上,运行如下命令安装 `moreutils`:
|
||||
|
||||
```
|
||||
$ sudo pacman -S moreutils
|
||||
```
|
||||
|
||||
在 **Fedora** 上,运行:
|
||||
|
||||
```
|
||||
$ sudo dnf install moreutils
|
||||
```
|
||||
|
||||
在 **RHEL**,**CentOS** 和 **Scientific Linux** 上,运行:
|
||||
|
||||
```
|
||||
$ sudo yum install epel-release
|
||||
$ sudo yum install moreutils
|
||||
```
|
||||
|
||||
在 **Debian**,**Ubuntu** 和 **Linux Mint** 上,运行:
|
||||
|
||||
```
|
||||
$ sudo apt-get install moreutils
|
||||
```
|
||||
|
||||
### Moreutils – 打包更多有用的 Unix 实用程序
|
||||
|
||||
让我们看一下几个 `moreutils` 工具的用法细节。
|
||||
|
||||
#### combine 实用程序
|
||||
|
||||
正如 `combine` 名称所示,moreutils 中的这个实用程序可以使用包括 `and`,`not`,`or` 和 `xor` 在内的布尔操作,合并两个文件中的行。
|
||||
|
||||
* `and` – 输出 `file1` 和 `file2` 都包含的行。
|
||||
* `not` – 输出 `file1` 包含但 `file2` 不包含的行。
|
||||
* `or` – 输出 `file1` 或 `file2` 包含的行。
|
||||
* `xor` – 输出仅被 `file1` 或 `file2` 包含的行
|
||||
|
||||
下面举例说明,方便你理解该实用程序的功能。这里有两个文件,文件名分别为 `file1` 和 `file2`,其内容如下:
|
||||
|
||||
```
|
||||
$ cat file1
|
||||
is
|
||||
was
|
||||
were
|
||||
where
|
||||
there
|
||||
|
||||
$ cat file2
|
||||
is
|
||||
were
|
||||
there
|
||||
```
|
||||
|
||||
下面,我使用 `and` 布尔操作合并这两个文件。
|
||||
|
||||
```
|
||||
$ combine file1 and file2
|
||||
is
|
||||
were
|
||||
there
|
||||
```
|
||||
|
||||
从上例的输出中可以看出,`and` 布尔操作只输出那些 `file1` 和 `file2` 都包含的行;更具体的来说,命令输出为两个文件共有的行,即 is,were 和 there。
|
||||
|
||||
下面我们换成 `not` 操作,观察一下输出。
|
||||
|
||||
```
|
||||
$ combine file1 not file2
|
||||
was
|
||||
where
|
||||
```
|
||||
|
||||
从上面的输出中可以看出,`not` 操作输出 `file1` 包含但 `file2` 不包含的行。
|
||||
|
||||
#### ifdata 实用程序
|
||||
|
||||
`ifdata` 实用程序可用于检查网络接口是否存在,也可用于获取网络接口的信息,例如 IP 地址等。与预装的 `ifconfig` 和 `ip` 命令不同,`ifdata` 的输出更容易解析,这种设计的初衷是便于在 Shell 脚本中使用。
|
||||
|
||||
如果希望查看某个接口的 IP 地址,不妨以 `wlp9s0` 为例,运行如下命令:
|
||||
|
||||
```
|
||||
$ ifdata -p wlp9s0
|
||||
192.168.43.192 255.255.255.0 192.168.43.255 1500
|
||||
```
|
||||
|
||||
如果只查看掩码信息,运行如下命令:
|
||||
|
||||
```
|
||||
$ ifdata -pn wlp9s0
|
||||
255.255.255.0
|
||||
```
|
||||
|
||||
如果查看网络接口的物理地址,运行如下命令:
|
||||
|
||||
```
|
||||
$ ifdata -ph wlp9s0
|
||||
A0:15:46:90:12:3E
|
||||
```
|
||||
|
||||
如果判断接口是否存在,可以使用 `-pe` 参数:
|
||||
|
||||
```
|
||||
$ ifdata -pe wlp9s0
|
||||
yes
|
||||
```
|
||||
|
||||
#### pee 命令
|
||||
|
||||
该命令某种程度上类似于 `tee` 命令。
|
||||
|
||||
我们先用一个例子看一下 `tee` 的用法。
|
||||
|
||||
```
|
||||
$ echo "Welcome to OSTechNIx" | tee file1 file2
|
||||
Welcome to OSTechNIx
|
||||
```
|
||||
|
||||
上述命令首先创建两个文件,名为 `file1` 和 `file2`;接着,将 “Welcome to OSTechNix” 行分别附加到两个文件中;最后,在终端中打印输出 “Welcome to OSTechNix”。
|
||||
|
||||
`pee` 命令提供类似的功能,但与 `tee` 又稍微有些差异。查看下面的例子:
|
||||
|
||||
```
|
||||
$ echo "Welcome to OSTechNIx" | pee cat cat
|
||||
Welcome to OSTechNIx
|
||||
Welcome to OSTechNIx
|
||||
```
|
||||
|
||||
从上面的命令输出中可以看出,有两个 `cat` 命令实例获取 `echo` 命令的输出并执行,因而终端中出现两个同样的输出。
|
||||
|
||||
#### sponge 实用程序
|
||||
|
||||
这是 `moreutils` 软件包中的另一个有用的实用程序。`sponge` 读取标准输入并写入到指定的文件中。与 Shell 中的重定向不同,`sponge` 接收到完整输入后再写入输出文件。
|
||||
|
||||
查看下面这个文本文件的内容:
|
||||
|
||||
```
|
||||
$ cat file1
|
||||
I
|
||||
You
|
||||
Me
|
||||
We
|
||||
Us
|
||||
```
|
||||
|
||||
可见,文件包含了一些无序的行;更具体的说,这些行“没有”按照字母顺序排序。如果希望将其内容安装字母顺序排序,你会怎么做呢?
|
||||
|
||||
```
|
||||
$ sort file1 > file1_sorted
|
||||
```
|
||||
|
||||
这样做没错,对吧?当然没错!在上面的命令中,我将 `file1` 文件内容按照字母顺序排序,将排序后的内容保存在 `file1_sorted` 文件中。但如果使用 `sponge` 命令,你可以在不创建新文件(即 `file1_sorted`)的情况下完成同样的任务,命令如下:
|
||||
|
||||
```
|
||||
$ sort file1 | sponge file1
|
||||
```
|
||||
|
||||
那么,让我们检查一下文件内容是否已经按照字母顺序排序:
|
||||
|
||||
```
|
||||
$ cat file1
|
||||
I
|
||||
Me
|
||||
Us
|
||||
We
|
||||
You
|
||||
```
|
||||
|
||||
看到了吧?并不需要创建新文件。在脚本编程中,这非常有用。另一个好消息是,如果待写入的文件已经存在,`sponge` 会保持其<ruby>权限信息<rt>permissions</rt></ruby>不变。
|
||||
|
||||
#### ts 实用程序
|
||||
|
||||
正如名称所示,`ts` 命令在每一行输出的行首增加<ruby>时间戳<rt>timestamp</rt></ruby>。
|
||||
|
||||
查看如下命令的输出:
|
||||
|
||||
```
|
||||
$ ping -c 2 localhost
|
||||
PING localhost(localhost.localdomain (::1)) 56 data bytes
|
||||
64 bytes from localhost.localdomain (::1): icmp_seq=1 ttl=64 time=0.055 ms
|
||||
64 bytes from localhost.localdomain (::1): icmp_seq=2 ttl=64 time=0.079 ms
|
||||
|
||||
--- localhost ping statistics ---
|
||||
2 packets transmitted, 2 received, 0% packet loss, time 1018ms
|
||||
rtt min/avg/max/mdev = 0.055/0.067/0.079/0.012 ms
|
||||
```
|
||||
|
||||
下面,结合 `ts` 实用程序运行同样地命令:
|
||||
|
||||
```
|
||||
$ ping -c 2 localhost | ts
|
||||
Aug 21 13:32:28 PING localhost(localhost (::1)) 56 data bytes
|
||||
Aug 21 13:32:28 64 bytes from localhost (::1): icmp_seq=1 ttl=64 time=0.063 ms
|
||||
Aug 21 13:32:28 64 bytes from localhost (::1): icmp_seq=2 ttl=64 time=0.113 ms
|
||||
Aug 21 13:32:28
|
||||
Aug 21 13:32:28 --- localhost ping statistics ---
|
||||
Aug 21 13:32:28 2 packets transmitted, 2 received, 0% packet loss, time 4ms
|
||||
Aug 21 13:32:28 rtt min/avg/max/mdev = 0.063/0.088/0.113/0.025 ms
|
||||
```
|
||||
|
||||
对比输出可以看出,`ts` 在每一行行首增加了时间戳。下面给出另一个例子:
|
||||
|
||||
```
|
||||
$ ls -l | ts
|
||||
Aug 21 13:34:25 total 120
|
||||
Aug 21 13:34:25 drwxr-xr-x 2 sk users 12288 Aug 20 20:05 Desktop
|
||||
Aug 21 13:34:25 drwxr-xr-x 2 sk users 4096 Aug 10 18:44 Documents
|
||||
Aug 21 13:34:25 drwxr-xr-x 24 sk users 12288 Aug 21 13:06 Downloads
|
||||
[...]
|
||||
```
|
||||
|
||||
#### vidir 实用程序
|
||||
|
||||
`vidir` 实用程序可以让你使用 `vi` 编辑器(或其它 `$EDITOR` 环境变量指定的编辑器)编辑指定目录的内容。如果没有指定目录,`vidir` 会默认编辑你当前的目录。
|
||||
|
||||
下面的命令编辑 `Desktop` 目录的内容:
|
||||
|
||||
```
|
||||
$ vidir Desktop/
|
||||
```
|
||||
|
||||
![vidir][2]
|
||||
|
||||
上述命令使用 `vi` 编辑器打开了指定的目录,其中目录内的文件都会对应一个数字。下面你可以按照 `vi` 的操作方式来编辑目录中的这些文件:例如,删除行意味着删除目录中对应的文件,修改行中字符串意味着对文件进行重命名。
|
||||
|
||||
你也可以编辑子目录。下面的命令会编辑当前目录及所有子目录:
|
||||
|
||||
```
|
||||
$ find | vidir -
|
||||
```
|
||||
|
||||
请注意命令结尾的 `-`。如果 `-` 被指定为待编辑的目录,`vidir` 会从标准输入读取一系列文件名,列出它们让你进行编辑。
|
||||
|
||||
如果你只想编辑当前目录下的文件,可以使用如下命令:
|
||||
|
||||
```
|
||||
$ find -type f | vidir -
|
||||
```
|
||||
|
||||
只想编辑特定类型的文件,例如 `.PNG` 文件?你可以使用如下命令:
|
||||
|
||||
```
|
||||
$ vidir *.png
|
||||
```
|
||||
|
||||
这时命令只会编辑当前目录下以 `.PNG` 为后缀的文件。
|
||||
|
||||
#### vipe 实用程序
|
||||
|
||||
`vipe` 命令可以让你使用默认编辑器接收 Unix 管道输入,编辑之后使用管道输出供下一个程序使用。
|
||||
|
||||
执行下面的命令会打开 `vi` 编辑器(当然是我默认使用的编辑器),你可以编辑 `echo` 命令的管道输入(即 “Welcome to OSTechNix”),最后将编辑过的内容输出到终端中。
|
||||
|
||||
```
|
||||
$ echo "Welcome to OSTechNIx" | vipe
|
||||
Hello World
|
||||
```
|
||||
|
||||
从上面的输出可以看出,我通过管道将 “Welcome to OSTechNix” 输入到 `vi` 编辑器中,将内容编辑为 “Hello World”,最后显示该内容。
|
||||
|
||||
好了,就介绍这么多吧。我只介绍了一小部分实用程序,而 `moreutils` 包含更多有用的实用程序。我在文章开始的时候已经列出目前 `moreutils` 软件包内包含的实用程序,你可以通过 `man` 帮助页面获取更多相关命令的细节信息。举个例子,如果你想了解 `vidir` 命令,请运行:
|
||||
|
||||
```
|
||||
$ man vidir
|
||||
```
|
||||
|
||||
希望这些内容对你有所帮助。我还将继续分享其它有趣且实用的指南,如果你认为这些内容对你有所帮助,请分享到社交网络或专业圈子,也欢迎你支持 OSTechNix 项目。
|
||||
|
||||
干杯!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/moreutils-collection-useful-unix-utilities/
|
||||
|
||||
作者:[SK][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.ostechnix.com/author/sk/
|
||||
[1]:data:image/gif;base64,lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]:http://www.ostechnix.com/wp-content/uploads/2017/08/sk@sk_001-1.png
|
@ -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.04,16.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(如果我没记错的话)。这其中提供的 Nemo(Cinnamon 的文件管理器,基于 Nautilus)和 Cinnamon 控制中心。这些东西提供了一个更加接近于 Linux Mint 的感觉。
|
||||
|
||||
### 在 Ubuntu 上使用 Cinnamon 桌面环境
|
||||
|
||||
Cinnamon 安装完成后,退出当前会话,在登录界面,点击用户名旁边的 Ubuntu 符号:
|
||||
|
||||

|
||||
|
||||
之后,它将会显示所有系统可用的桌面环境。选择 Cinnamon。
|
||||
|
||||

|
||||
|
||||
现在你应该已经登录到有着 Cinnamon 桌面环境的 Ubuntu 中了。你还可以通过同样的方式再回到 Unity 桌面。这里有一张以 Cinnamon 做为桌面环境的 Ubuntu 桌面截图。
|
||||
|
||||

|
||||
|
||||
看起来是不是像极了 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/
|
@ -0,0 +1,143 @@
|
||||
Cloud Commander:一个有控制台和编辑器的 Web 文件管理器
|
||||
======
|
||||
|
||||

|
||||
|
||||
**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
|
@ -1,57 +1,27 @@
|
||||
Docker 指南:Docker 化 Python Django 应用程序
|
||||
如何 Docker 化 Python Django 应用程序
|
||||
======
|
||||
|
||||
### 目录
|
||||
|
||||
1. [我们要做什么?][6]
|
||||
|
||||
2. [步骤 1 - 安装 Docker-ce][7]
|
||||
|
||||
3. [步骤 2 - 安装 Docker-compose][8]
|
||||
|
||||
4. [步骤 3 - 配置项目环境][9]
|
||||
1. [创建一个新的 requirements.txt 文件][1]
|
||||
|
||||
2. [创建 Nginx 虚拟主机文件 django.conf][2]
|
||||
|
||||
3. [创建 Dockerfile][3]
|
||||
|
||||
4. [创建 Docker-compose 脚本][4]
|
||||
|
||||
5. [配置 Django 项目][5]
|
||||
|
||||
5. [步骤 4 - 构建并运行 Docker 镜像][10]
|
||||
|
||||
6. [步骤 5 - 测试][11]
|
||||
|
||||
7. [参考][12]
|
||||
|
||||
|
||||
Docker 是一个开源项目,为开发人员和系统管理员提供了一个开放平台,作为一个轻量级容器,它可以在任何地方构建,打包和运行应用程序。Docker 在软件容器中自动部署应用程序。
|
||||
Docker 是一个开源项目,为开发人员和系统管理员提供了一个开放平台,可以将应用程序构建、打包为一个轻量级容器,并在任何地方运行。Docker 会在软件容器中自动部署应用程序。
|
||||
|
||||
Django 是一个用 Python 编写的 Web 应用程序框架,遵循 MVC(模型-视图-控制器)架构。它是免费的,并在开源许可下发布。它速度很快,旨在帮助开发人员尽快将他们的应用程序上线。
|
||||
|
||||
在本教程中,我将逐步向你展示在 Ubuntu 16.04 如何为现有的 Django 应用程序创建 docker 镜像。我们将学习如何 docker 化一个 Python Django 应用程序,然后使用一个 docker-compose 脚本将应用程序作为容器部署到 docker 环境。
|
||||
在本教程中,我将逐步向你展示在 Ubuntu 16.04 中如何为现有的 Django 应用程序创建 docker 镜像。我们将学习如何 docker 化一个 Python Django 应用程序,然后使用一个 `docker-compose` 脚本将应用程序作为容器部署到 docker 环境。
|
||||
|
||||
为了部署我们的 Python Django 应用程序,我们需要其他 docker 镜像:一个用于 Web 服务器的 nginx docker 镜像和用于数据库的 PostgreSQL 镜像。
|
||||
为了部署我们的 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(to 校正者:此处不太明白具体意思)。
|
||||
在本教程中,我们将从 docker 仓库安装 docker-ce 社区版。我们将安装 docker-ce 社区版和 `docker-compose`(其支持 compose 文件版本 3)。
|
||||
|
||||
在安装 docker-ce 之前,先使用 apt 命令安装所需的 docker 依赖项。
|
||||
在安装 docker-ce 之前,先使用 `apt` 命令安装所需的 docker 依赖项。
|
||||
|
||||
```
|
||||
sudo apt install -y \
|
||||
@ -71,7 +41,7 @@ sudo add-apt-repository \
|
||||
stable"
|
||||
```
|
||||
|
||||
[][14]
|
||||
[][14]
|
||||
|
||||
更新仓库并安装 docker-ce。
|
||||
|
||||
@ -87,16 +57,16 @@ systemctl start docker
|
||||
systemctl enable docker
|
||||
```
|
||||
|
||||
接着,我们将添加一个名为 'omar' 的新用户并将其添加到 docker 组。
|
||||
接着,我们将添加一个名为 `omar` 的新用户并将其添加到 `docker` 组。
|
||||
|
||||
```
|
||||
useradd -m -s /bin/bash omar
|
||||
usermod -a -G docker omar
|
||||
```
|
||||
|
||||
[][15]
|
||||
[][15]
|
||||
|
||||
以 omar 用户身份登录并运行 docker 命令,如下所示。
|
||||
以 `omar` 用户身份登录并运行 `docker` 命令,如下所示。
|
||||
|
||||
```
|
||||
su - omar
|
||||
@ -107,13 +77,13 @@ docker run hello-world
|
||||
|
||||
[][16]
|
||||
|
||||
Docker-ce 安装已经完成。
|
||||
Docker-ce 安装已经完成。
|
||||
|
||||
### 步骤 2 - 安装 Docker-compose
|
||||
### 步骤 2 - 安装 Docker-compose
|
||||
|
||||
在本教程中,我们将使用最新的 docker-compose 支持 compose 文件版本 3。我们将手动安装 docker-compose。
|
||||
在本教程中,我们将使用支持 compose 文件版本 3 的最新 `docker-compose`。我们将手动安装 `docker-compose`。
|
||||
|
||||
使用 curl 命令将最新版本的 docker-compose 下载到 `/usr/local/bin` 目录,并使用 chmod 命令使其有执行权限。
|
||||
使用 `curl` 命令将最新版本的 `docker-compose` 下载到 `/usr/local/bin` 目录,并使用 `chmod` 命令使其有执行权限。
|
||||
|
||||
运行以下命令:
|
||||
|
||||
@ -122,7 +92,7 @@ sudo curl -L https://github.com/docker/compose/releases/download/1.21.0/docker-c
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
```
|
||||
|
||||
现在检查 docker-compose 版本。
|
||||
现在检查 `docker-compose` 版本。
|
||||
|
||||
```
|
||||
docker-compose version
|
||||
@ -132,26 +102,26 @@ docker-compose version
|
||||
|
||||
[][17]
|
||||
|
||||
已安装支持 compose 文件版本 3 的 docker-compose 最新版本。
|
||||
已安装支持 compose 文件版本 3 的 `docker-compose` 最新版本。
|
||||
|
||||
### 步骤 3 - 配置项目环境
|
||||
|
||||
在这一步中,我们将配置 Python Django 项目环境。我们将创建新目录 'guide01',并使其成为我们项目文件的主目录,例如 Dockerfile,Django 项目,nginx 配置文件等。
|
||||
在这一步中,我们将配置 Python Django 项目环境。我们将创建新目录 `guide01`,并使其成为我们项目文件的主目录,例如包括 Dockerfile、Django 项目、nginx 配置文件等。
|
||||
|
||||
登录到 'omar' 用户。
|
||||
登录到 `omar` 用户。
|
||||
|
||||
```
|
||||
su - omar
|
||||
```
|
||||
|
||||
创建一个新目录 'guide01',并进入目录。
|
||||
创建一个新目录 `guide01`,并进入目录。
|
||||
|
||||
```
|
||||
mkdir -p guide01
|
||||
cd guide01/
|
||||
```
|
||||
|
||||
现在在 'guide01' 目录下,创建两个新目录 'project' 和 'config'。
|
||||
现在在 `guide01` 目录下,创建两个新目录 `project` 和 `config`。
|
||||
|
||||
```
|
||||
mkdir project/ config/
|
||||
@ -159,118 +129,151 @@ mkdir project/ config/
|
||||
|
||||
注意:
|
||||
|
||||
* 'project' 目录:我们所有的 python Django 项目文件都将放在该目录中。
|
||||
* `project` 目录:我们所有的 python Django 项目文件都将放在该目录中。
|
||||
* `config` 目录:项目配置文件的目录,包括 nginx 配置文件、python pip 的`requirements.txt` 文件等。
|
||||
|
||||
* 'config' 目录:项目配置文件的目录,包括 nginx 配置文件,python pip requirements 文件等。
|
||||
#### 创建一个新的 requirements.txt 文件
|
||||
|
||||
### 创建一个新的 requirements.txt 文件
|
||||
|
||||
接下来,使用 vim 命令在 'config' 目录中创建一个新的 requirements.txt 文件
|
||||
接下来,使用 `vim` 命令在 `config` 目录中创建一个新的 `requirements.txt` 文件。
|
||||
|
||||
```
|
||||
vim config/requirements.txt
|
||||
```
|
||||
|
||||
粘贴下面的配置。
|
||||
粘贴下面的配置:
|
||||
|
||||
```
|
||||
Django==2.0.4
|
||||
gunicorn==19.7.0
|
||||
psycopg2==2.7.4
|
||||
gunicorn==19.7.0
|
||||
psycopg2==2.7.4
|
||||
```
|
||||
|
||||
保存并退出。
|
||||
|
||||
### 创建 Dockerfile
|
||||
#### 创建 Nginx 虚拟主机文件 django.conf
|
||||
|
||||
在 'guide01' 目录下创建新文件 'Dockerfile'。
|
||||
在 `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 脚本。
|
||||
现在粘贴下面的 Dockerfile 脚本:
|
||||
|
||||
```
|
||||
FROM python:3.5-alpine
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
RUN apk update && \
|
||||
apk add --virtual build-deps gcc python-dev musl-dev && \
|
||||
apk add postgresql-dev bash
|
||||
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
|
||||
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 项目将运行在带有 Python3.5 的 Alpine Linux 上,并添加 postgresql-dev 包以支持 PostgreSQL 数据库。然后,我们将使用 python pip 命令安装在 'requirements.txt' 上列出的所有 Python 包,并为我们的项目创建新目录 '/src'。
|
||||
我们想要为我们的 Django 项目构建基于 Alpine Linux 的 Docker 镜像,Alpine 是最小的 Linux 版本。我们的 Django 项目将运行在带有 Python 3.5 的 Alpine Linux 上,并添加 postgresql-dev 包以支持 PostgreSQL 数据库。然后,我们将使用 python `pip` 命令安装在 `requirements.txt` 上列出的所有 Python 包,并为我们的项目创建新目录 `/src`。
|
||||
|
||||
### 创建 Docker-compose 脚本
|
||||
#### 创建 Docker-compose 脚本
|
||||
|
||||
使用 [vim][18] 命令在 'guide01' 目录下创建 'docker-compose.yml' 文件。
|
||||
使用 [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
|
||||
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 文件脚本,我们将创建三个服务。使用 PostgreSQL alpine Linux 创建名为 'db' 的数据库服务,再次使用 Nginx alpine Linux 创建 'nginx' 服务,并使用从 Dockerfile 生成的自定义 docker 镜像创建我们的 python Django 容器。
|
||||
使用这个 `docker-compose` 文件脚本,我们将创建三个服务。使用 alpine Linux 版的 PostgreSQL 创建名为 `db` 的数据库服务,再次使用 alpine Linux 版的 Nginx 创建 `nginx` 服务,并使用从 Dockerfile 生成的自定义 docker 镜像创建我们的 python Django 容器。
|
||||
|
||||
[][19]
|
||||
[][19]
|
||||
|
||||
### 配置 Django 项目
|
||||
#### 配置 Django 项目
|
||||
|
||||
将 Django 项目文件复制到 'project' 目录。
|
||||
将 Django 项目文件复制到 `project` 目录。
|
||||
|
||||
```
|
||||
cd ~/django
|
||||
cp -r * ~/guide01/project/
|
||||
```
|
||||
|
||||
进入 'project' 目录并编辑应用程序设置 'settings.py'。
|
||||
进入 `project` 目录并编辑应用程序设置 `settings.py`。
|
||||
|
||||
```
|
||||
cd ~/guide01/project/
|
||||
@ -279,29 +282,29 @@ vim hello_django/settings.py
|
||||
|
||||
注意:
|
||||
|
||||
我们将部署名为 'hello_django' 的简单 Django 应用程序。
|
||||
我们将部署名为 “hello_django” 的简单 Django 应用程序。
|
||||
|
||||
在 'ALLOW_HOSTS' 行中,添加服务名称 'web'。
|
||||
在 `ALLOW_HOSTS` 行中,添加服务名称 `web`。
|
||||
|
||||
```
|
||||
ALLOW_HOSTS = ['web']
|
||||
```
|
||||
|
||||
现在更改数据库设置,我们将使用 PostgreSQL 数据库,'db' 数据库作为服务运行,使用默认用户和密码。
|
||||
现在更改数据库设置,我们将使用 PostgreSQL 数据库来运行名为 `db` 的服务,使用默认用户和密码。
|
||||
|
||||
```
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'postgres',
|
||||
'USER': 'postgres',
|
||||
'HOST': 'db',
|
||||
'PORT': 5432,
|
||||
}
|
||||
}
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'postgres',
|
||||
'USER': 'postgres',
|
||||
'HOST': 'db',
|
||||
'PORT': 5432,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
至于 'STATIC_ROOT' 配置目录,将此行添加到文件行的末尾。
|
||||
至于 `STATIC_ROOT` 配置目录,将此行添加到文件行的末尾。
|
||||
|
||||
```
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
|
||||
@ -309,21 +312,21 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
|
||||
|
||||
保存并退出。
|
||||
|
||||
[][20]
|
||||
[][20]
|
||||
|
||||
现在我们准备在 docker 容器下构建和运行 Django 项目。
|
||||
|
||||
### 步骤 4 - 构建并运行 Docker 镜像
|
||||
|
||||
在这一步中,我们想要使用 'guide01' 目录中的配置为我们的 Django 项目构建一个 Docker 镜像。
|
||||
在这一步中,我们想要使用 `guide01` 目录中的配置为我们的 Django 项目构建一个 Docker 镜像。
|
||||
|
||||
进入 'guide01' 目录。
|
||||
进入 `guide01` 目录。
|
||||
|
||||
```
|
||||
cd ~/guide01/
|
||||
```
|
||||
|
||||
现在使用 docker-compose 命令构建 docker 镜像。
|
||||
现在使用 `docker-compose` 命令构建 docker 镜像。
|
||||
|
||||
```
|
||||
docker-compose build
|
||||
@ -331,7 +334,7 @@ docker-compose build
|
||||
|
||||
[][21]
|
||||
|
||||
启动 docker-compose 脚本中的所有服务。
|
||||
启动 `docker-compose` 脚本中的所有服务。
|
||||
|
||||
```
|
||||
docker-compose up -d
|
||||
@ -348,7 +351,7 @@ docker-compose ps
|
||||
docker-compose images
|
||||
```
|
||||
|
||||
现在,你将在系统上运行三个容器并列出 Docker 镜像,如下所示。
|
||||
现在,你将在系统上运行三个容器,列出 Docker 镜像,如下所示。
|
||||
|
||||
[][23]
|
||||
|
||||
@ -356,17 +359,19 @@ docker-compose images
|
||||
|
||||
### 步骤 5 - 测试
|
||||
|
||||
打开 Web 浏览器并使用端口 8000 键入服务器地址,我的是:http://ovh01:8000/
|
||||
打开 Web 浏览器并使用端口 8000 键入服务器地址,我的是:`http://ovh01:8000/`。
|
||||
|
||||
现在你将获得默认的 Django 主页。
|
||||
现在你将看到默认的 Django 主页。
|
||||
|
||||
[][24]
|
||||
|
||||
接下来,通过在 URL 上添加 “/admin” 路径来测试管理页面。
|
||||
接下来,通过在 URL 上添加 `/admin` 路径来测试管理页面。
|
||||
|
||||
```
|
||||
http://ovh01:8000/admin/
|
||||
```
|
||||
|
||||
然后你将会看到 Django admin 登录页面。
|
||||
然后你将会看到 Django 管理登录页面。
|
||||
|
||||
[][25]
|
||||
|
||||
@ -383,7 +388,7 @@ via: https://www.howtoforge.com/tutorial/docker-guide-dockerizing-python-django-
|
||||
|
||||
作者:[Muhammad Arul][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/) 荣誉推出
|
||||
|
@ -1,22 +1,19 @@
|
||||
在 RxJS 中创建流的延伸教程
|
||||
============================================================
|
||||
全面教程:在 RxJS 中创建流
|
||||
================================
|
||||
|
||||

|
||||
|
||||
对大多数开发者来说,RxJS 是以库的形式与之接触,就像 Angular。一些函数会返回流,要使用它们就得把注意力放在操作符上。
|
||||
对大多数开发者来说,与 RxJS 的初次接触是通过库的形式,就像 Angular。一些函数会返回<ruby>流<rt>stream</rt></ruby>,要使用它们就得把注意力放在操作符上。
|
||||
|
||||
有些时候,混用响应式和非响应式代码似乎很有用。然后大家就开始热衷流的创造。不论是在编写异步代码或者是数据处理时,流都是一个不错的方案。
|
||||
|
||||
RxJS 提供很多方式来创建流。不管你遇到的是什么情况,都会有一个完美的创建流的方式。你可能根本用不上它们,但了解它们可以节省你的时间,让你少码一些代码。
|
||||
|
||||
我把所有可能的方法,按它们的主要目的,分放在四个目录中:
|
||||
我把所有可能的方法,按它们的主要目的,放在四个分类当中:
|
||||
|
||||
* 流式化现有数据
|
||||
|
||||
* 生成数据
|
||||
|
||||
* 使用现有 APIs 进行交互
|
||||
|
||||
* 使用现有 API 进行交互
|
||||
* 选择现有的流,并结合起来
|
||||
|
||||
注意:示例用的是 RxJS 6,可能会以前的版本有所不同。已知的区别是你导入函数的方式不同了。
|
||||
@ -25,9 +22,7 @@ RxJS 6
|
||||
|
||||
```
|
||||
import {of, from} from 'rxjs';
|
||||
```
|
||||
|
||||
```
|
||||
of(...);
|
||||
from(...);
|
||||
```
|
||||
@ -38,36 +33,24 @@ RxJS < 6
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import 'rxjs/add/observable/of';
|
||||
import 'rxjs/add/observable/from';
|
||||
```
|
||||
|
||||
```
|
||||
Observable.of(...);
|
||||
Observable.from(...);
|
||||
```
|
||||
|
||||
```
|
||||
//or
|
||||
```
|
||||
//或
|
||||
|
||||
```
|
||||
import { of } from 'rxjs/observable/of';
|
||||
import { from } from 'rxjs/observable/from';
|
||||
```
|
||||
|
||||
```
|
||||
of(...);
|
||||
from(...);
|
||||
```
|
||||
|
||||
流的图示中的标记:
|
||||
|
||||
* | 表示流结束了
|
||||
|
||||
* X 表示流出现错误并被终结
|
||||
|
||||
* … 表示流的走向不定
|
||||
|
||||
* * *
|
||||
* `|` 表示流结束了
|
||||
* `X` 表示流出现错误并被终结
|
||||
* `...` 表示流的走向不定
|
||||
|
||||
### 流式化已有数据
|
||||
|
||||
@ -75,7 +58,7 @@ from(...);
|
||||
|
||||
#### of
|
||||
|
||||
如果只有一个或者一些不同的元素,使用 _of_ :
|
||||
如果只有一个或者一些不同的元素,使用 `of`:
|
||||
|
||||
```
|
||||
of(1,2,3)
|
||||
@ -89,13 +72,11 @@ of(1,2,3)
|
||||
|
||||
#### from
|
||||
|
||||
如果有一个数组或者 _可迭代的_ 对象,而且你想要其中的所有元素发送到流中,使用 _from_。你也可以用它来把一个 promise 对象变成可观测的。
|
||||
如果有一个数组或者 _可迭代的对象_ ,而且你想要其中的所有元素发送到流中,使用 `from`。你也可以用它来把一个 promise 对象变成可观测的。
|
||||
|
||||
```
|
||||
const foo = [1,2,3];
|
||||
```
|
||||
|
||||
```
|
||||
from(foo)
|
||||
.subscribe();
|
||||
```
|
||||
@ -111,9 +92,7 @@ from(foo)
|
||||
|
||||
```
|
||||
const foo = { a: 1, b: 2};
|
||||
```
|
||||
|
||||
```
|
||||
pairs(foo)
|
||||
.subscribe();
|
||||
```
|
||||
@ -125,19 +104,16 @@ pairs(foo)
|
||||
|
||||
#### 那么其他的数据结构呢?
|
||||
|
||||
也许你的数据存储在自定义的结构中,而它又没有实现 _Iterable_ 接口,又或者说你的结构是递归的,树状的。也许下面某种选择适合这些情况:
|
||||
也许你的数据存储在自定义的结构中,而它又没有实现 _可迭代的对象_ 接口,又或者说你的结构是递归的、树状的。也许下面某种选择适合这些情况:
|
||||
|
||||
* 先将数据提取到数组里
|
||||
1. 先将数据提取到数组里
|
||||
2. 使用下一节将会讲到的 `generate` 函数,遍历所有数据
|
||||
3. 创建一个自定义流(见下一节)
|
||||
4. 创建一个迭代器
|
||||
|
||||
* 使用下一节将会讲到的 _generate_ 函数,遍历所有数据
|
||||
稍后会讲到选项 2 和 3 ,因此这里的重点是创建一个迭代器。我们可以对一个 _可迭代的对象_ 调用 `from` 创建一个流。 _可迭代的对象_ 是一个对象,可以产生一个迭代器(如果你对细节感兴趣,参考 [这篇 mdn 文章][6])。
|
||||
|
||||
* 创建一个自定义流(见下一节)
|
||||
|
||||
* 创建一个迭代器
|
||||
|
||||
稍后会讲到选项 2 和 3 ,因此这里的重点是创建一个迭代器。我们可以对一个 _iterable_ 对象调用 _from_ 创建一个流。 _iterable_ 是一个对象,可以产生一个迭代器(如果你对细节感兴趣,参考 [这篇 mdn 文章][6])。
|
||||
|
||||
创建一个迭代器的简单方式是 [generator function][7]。当你调用一个生成函数(generator function)时,它返回一个对象,该对象同时遵循 _iterable_ 接口和 _iterator_ 接口。
|
||||
创建一个迭代器的简单方式是 <ruby>[生成函数][7]<rt>generator function</rt></ruby>。当你调用一个生成函数时,它返回一个对象,该对象同时遵循 _可迭代的对象_ 接口和 _迭代器_ 接口。
|
||||
|
||||
```
|
||||
// 自定义的数据结构
|
||||
@ -147,23 +123,17 @@ class List {
|
||||
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);
|
||||
```
|
||||
@ -173,15 +143,13 @@ from(listIterator(myList))
|
||||
// 1 3 |
|
||||
```
|
||||
|
||||
调用 `listIterator` 函数时,返回值是一个 _iterable_ / _iterator_。函数里面的代码在调用 _subscribe_ 前不会执行。
|
||||
|
||||
* * *
|
||||
调用 `listIterator` 函数时,返回值是一个 _可迭代的对象_ / _迭代器_ 。函数里面的代码在调用 `subscribe` 前不会执行。
|
||||
|
||||
### 生成数据
|
||||
|
||||
你知道要发送哪些数据,但想(或者不得不)动态生成它。所有函数的最后一个参数都可以用来接收一个调度器。他们产生静态的流。
|
||||
你知道要发送哪些数据,但想(或者必须)动态生成它。所有函数的最后一个参数都可以用来接收一个调度器。他们产生静态的流。
|
||||
|
||||
#### range
|
||||
#### 范围(`range`)
|
||||
|
||||
从初始值开始,发送一系列数字,直到完成了指定次数的迭代。
|
||||
|
||||
@ -195,9 +163,9 @@ range(10, 2) // 从 10 开始,发送两个值
|
||||
// 10 11 |
|
||||
```
|
||||
|
||||
#### 间隔/定时器
|
||||
#### 间隔(`interval`) / 定时器(`timer`)
|
||||
|
||||
有点像 _range_,但定时器是周期性的发送累加的数字(就是说,不是立即发送)。两者的区别在于在于 _timer_ 允许你为第一个元素设定一个延迟。也可以只产生一个值,只要不指定周期。
|
||||
有点像范围,但定时器是周期性的发送累加的数字(就是说,不是立即发送)。两者的区别在于在于定时器允许你为第一个元素设定一个延迟。也可以只产生一个值,只要不指定周期。
|
||||
|
||||
```
|
||||
interval(1000) // 每 1000ms = 1 秒 发送数据
|
||||
@ -211,9 +179,7 @@ interval(1000) // 每 1000ms = 1 秒 发送数据
|
||||
|
||||
```
|
||||
delay(5000, 1000) // 和上面相同,在开始前先等待 5000ms
|
||||
```
|
||||
|
||||
```
|
||||
delay(5000)
|
||||
.subscribe(i => console.log("foo");
|
||||
// 5 秒后打印 foo
|
||||
@ -229,7 +195,7 @@ interval(10000).pipe(
|
||||
|
||||
这段代码每 10 秒获取一次数据,更新屏幕。
|
||||
|
||||
#### generate
|
||||
#### 生成(`generate `)
|
||||
|
||||
这是个更加复杂的函数,允许你发送一系列任意类型的对象。它有一些重载,这里你看到的是最有意思的部分:
|
||||
|
||||
@ -246,15 +212,13 @@ generate(
|
||||
// 1 2 4 8 |
|
||||
```
|
||||
|
||||
你也可以用它来迭代值,如果一个结构没有实现 _Iterable_ 接口。我们用前面的 list 例子来进行演示:
|
||||
你也可以用它来迭代值,如果一个结构没有实现 _可迭代的对象_ 接口。我们用前面的列表例子来进行演示:
|
||||
|
||||
```
|
||||
const myList = new List();
|
||||
myList.add(1);
|
||||
myList.add(3);
|
||||
```
|
||||
|
||||
```
|
||||
generate(
|
||||
0, // 从这个值开始
|
||||
i => i < list.size, // 条件:发送数据,直到遍历完整个列表
|
||||
@ -268,15 +232,13 @@ generate(
|
||||
// 1 3 |
|
||||
```
|
||||
|
||||
如你所见,我添加了另一个参数:选择器(selector)。它和 _map_ 操作符作用类似,将生成的值转换为更有用的东西。
|
||||
|
||||
* * *
|
||||
如你所见,我添加了另一个参数:选择器。它和 `map` 操作符作用类似,将生成的值转换为更有用的东西。
|
||||
|
||||
### 空的流
|
||||
|
||||
有时候你要传递或返回一个不用发送任何数据的流。有三个函数分别用于不同的情况。你可以给这三个函数传递调度器。_empty_ 和 _throwError_ 接收一个调度器参数。
|
||||
有时候你要传递或返回一个不用发送任何数据的流。有三个函数分别用于不同的情况。你可以给这三个函数传递调度器。`empty` 和 `throwError` 接收一个调度器参数。
|
||||
|
||||
#### empty
|
||||
#### `empty`
|
||||
|
||||
创建一个空的流,一个值也不发送。
|
||||
|
||||
@ -290,7 +252,7 @@ empty()
|
||||
// |
|
||||
```
|
||||
|
||||
#### never
|
||||
#### `never`
|
||||
|
||||
创建一个永远不会结束的流,仍然不发送值。
|
||||
|
||||
@ -304,7 +266,7 @@ never()
|
||||
// ...
|
||||
```
|
||||
|
||||
#### throwError
|
||||
#### `throwError`
|
||||
|
||||
创建一个流,流出现错误,不发送数据。
|
||||
|
||||
@ -318,15 +280,13 @@ throwError('error')
|
||||
// X
|
||||
```
|
||||
|
||||
* * *
|
||||
|
||||
### 挂钩已有的 API
|
||||
|
||||
不是所有的库和所有你之前写的代码使用或者支持流。幸运的是 RxJS 提供函数用来桥接非响应式和响应式代码。这一节仅仅讨论 RxJS 为桥接代码提供的模版。
|
||||
|
||||
你可能还对这篇出自 [Ben Lesh][9] 的 [延伸阅读][8] 感兴趣,这篇文章讲了几乎所有能与 promises 交互操作的方式。
|
||||
你可能还对这篇出自 [Ben Lesh][9] 的 [全面的文章][8] 感兴趣,这篇文章讲了几乎所有能与 promises 交互操作的方式。
|
||||
|
||||
#### from
|
||||
#### `from`
|
||||
|
||||
我们已经用过它,把它列在这里是因为,它可以封装一个含有 observable 对象的 promise 对象。
|
||||
|
||||
@ -346,9 +306,7 @@ fromEvent 为 DOM 元素添加一个事件监听器,我确定你知道这个
|
||||
|
||||
```
|
||||
const element = $('#fooButton'); // 从 DOM 元素中创建一个 jQuery 对象
|
||||
```
|
||||
|
||||
```
|
||||
from(element, 'click')
|
||||
.subscribe();
|
||||
```
|
||||
@ -367,31 +325,25 @@ from(document, 'click')
|
||||
.subscribe();
|
||||
```
|
||||
|
||||
这告诉 RxJS 我们想要监听 document 中的点击事件。在提交过程中,RxJS 发现 document 是一个 _EventTarget_ 类型,因此它可以调用它的 _addEventListener_ 方法。如果我们传入的是一个 jQuery 对象而非 document,那么 RxJs 知道它得调用 _on_ 方法。
|
||||
这告诉 RxJS 我们想要监听 document 中的点击事件。在提交过程中,RxJS 发现 document 是一个 _EventTarget_ 类型,因此它可以调用它的 `addEventListener` 方法。如果我们传入的是一个 jQuery 对象而非 document,那么 RxJs 知道它得调用 _on_ 方法。
|
||||
|
||||
这个例子用的是 _fromEventPattern_,和 _fromEvent_ 的工作基本上一样:
|
||||
这个例子用的是 _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')
|
||||
```
|
||||
@ -402,49 +354,37 @@ RxJS 自动创建实际的监听器( _handler_ )你的工作是添加或者
|
||||
|
||||
```
|
||||
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);
|
||||
```
|
||||
|
||||
```
|
||||
// Produces
|
||||
// 结果
|
||||
// 1 ...
|
||||
```
|
||||
|
||||
当我们调用 foo.emit(1) 时,RxJS 中的监听器将被调用,然后它就能把值发送到流中。
|
||||
当我们调用 `foo.emit(1)` 时,RxJS 中的监听器将被调用,然后它就能把值发送到流中。
|
||||
|
||||
你也可以用它来监听多个事件类型,或者结合所有可以通过回调进行通讯的 API,例如,WebWorker API:
|
||||
|
||||
```
|
||||
const myWorker = new Worker('worker.js');
|
||||
```
|
||||
|
||||
```
|
||||
fromEventPattern(
|
||||
handler => { myWorker.onmessage = handler },
|
||||
handler => { myWorker.onmessage = undefined }
|
||||
@ -465,20 +405,14 @@ fromEventPattern(
|
||||
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
|
||||
```
|
||||
@ -494,51 +428,39 @@ reactiveFoo(1)
|
||||
|
||||
```
|
||||
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_ 来获得消息和发送消息。
|
||||
把 websocket 功能添加到你的应用中真的很简单。_websocket_ 创建一个 subject。这意味着你可以订阅它,通过调用 `next` 来获得消息和发送消息。
|
||||
|
||||
#### ajax
|
||||
|
||||
如你所知:类似于 websocket,提供 AJAX 查询的功能。你可能用了一个带有 AJAX 功能的库或者框架。或者你没有用,那么我建议使用 fetch(或者必要的话用 polyfill),把返回的 promise 封装到一个 observable 对象中(参考稍后会讲到的 _defer_ 函数)。
|
||||
如你所知:类似于 websocket,提供 AJAX 查询的功能。你可能用了一个带有 AJAX 功能的库或者框架。或者你没有用,那么我建议使用 fetch(或者必要的话用 polyfill),把返回的 promise 封装到一个 observable 对象中(参考稍后会讲到的 `defer` 函数)。
|
||||
|
||||
* * *
|
||||
|
||||
### Custom Streams
|
||||
### 定制流
|
||||
|
||||
有时候已有的函数用起来并不是足够灵活。或者你需要对订阅有更强的控制。
|
||||
|
||||
#### Subject
|
||||
#### 主题(`Subject`)
|
||||
|
||||
subject 是一个特殊的对象,它使得你的能够把数据发送到流中,并且能够控制数据。subject 本身就是一个 observable 对象,但如果你想要把流暴露给其它代码,建议你使用 _asObservable_ 方法。这样你就不能意外调用原始方法。
|
||||
`Subject` 是一个特殊的对象,它使得你的能够把数据发送到流中,并且能够控制数据。`Subject` 本身就是一个可观察对象,但如果你想要把流暴露给其它代码,建议你使用 `asObservable` 方法。这样你就不能意外调用原始方法。
|
||||
|
||||
```
|
||||
const subject = new Subject();
|
||||
const observable = subject.asObservable();
|
||||
```
|
||||
|
||||
```
|
||||
observable.subscribe();
|
||||
```
|
||||
|
||||
```
|
||||
subject.next(1);
|
||||
subject.next(2);
|
||||
subject.complete();
|
||||
@ -554,17 +476,11 @@ subject.complete();
|
||||
```
|
||||
const subject = new Subject();
|
||||
const observable = subject.asObservable();
|
||||
```
|
||||
|
||||
```
|
||||
subject.next(1);
|
||||
```
|
||||
|
||||
```
|
||||
observable.subscribe(console.log);
|
||||
```
|
||||
|
||||
```
|
||||
subject.next(2);
|
||||
subject.complete();
|
||||
```
|
||||
@ -574,20 +490,16 @@ subject.complete();
|
||||
// 2
|
||||
```
|
||||
|
||||
除了常规的 subject,RxJS 还提供了三种特殊的版本。
|
||||
除了常规的 `Subject`,RxJS 还提供了三种特殊的版本。
|
||||
|
||||
_AsyncSubject_ 在结束后只发送最后的一个值。
|
||||
`AsyncSubject` 在结束后只发送最后的一个值。
|
||||
|
||||
```
|
||||
const subject = new AsyncSubject();
|
||||
const observable = subject.asObservable();
|
||||
```
|
||||
|
||||
```
|
||||
observable.subscribe(console.log);
|
||||
```
|
||||
|
||||
```
|
||||
subject.next(1);
|
||||
subject.next(2);
|
||||
subject.complete();
|
||||
@ -598,18 +510,14 @@ subject.complete();
|
||||
// 2
|
||||
```
|
||||
|
||||
_BehaviorSubject_ 使得你能够提供一个(默认的)值,如果当前没有其它值发送的话,这个值会被发送给每个订阅者。否则订阅者收到最后一个发送的值。
|
||||
`BehaviorSubject` 使得你能够提供一个(默认的)值,如果当前没有其它值发送的话,这个值会被发送给每个订阅者。否则订阅者收到最后一个发送的值。
|
||||
|
||||
```
|
||||
const subject = new BehaviorSubject(1);
|
||||
const observable = subject.asObservable();
|
||||
```
|
||||
|
||||
```
|
||||
const subscription1 = observable.subscribe(console.log);
|
||||
```
|
||||
|
||||
```
|
||||
subject.next(2);
|
||||
subscription1.unsubscribe();
|
||||
```
|
||||
@ -622,29 +530,21 @@ subscription1.unsubscribe();
|
||||
|
||||
```
|
||||
const subscription2 = observable.subscribe(console.log);
|
||||
```
|
||||
|
||||
```
|
||||
// 输出
|
||||
// 2
|
||||
```
|
||||
|
||||
The _ReplaySubject_ 存储一定数量、或一定时间或所有的发送过的值。所有新的订阅者将会获得所有存储了的值。
|
||||
`ReplaySubject` 存储一定数量、或一定时间或所有的发送过的值。所有新的订阅者将会获得所有存储了的值。
|
||||
|
||||
```
|
||||
const subject = new ReplaySubject();
|
||||
const observable = subject.asObservable();
|
||||
```
|
||||
|
||||
```
|
||||
subject.next(1);
|
||||
```
|
||||
|
||||
```
|
||||
observable.subscribe(console.log);
|
||||
```
|
||||
|
||||
```
|
||||
subject.next(2);
|
||||
subject.complete();
|
||||
```
|
||||
@ -655,11 +555,11 @@ subject.complete();
|
||||
// 2
|
||||
```
|
||||
|
||||
你可以在 [ReactiveX documentation][10](它提供了一些其它的连接) 里面找到更多关于 subjects 的信息。[Ben Lesh][11] 在 [On The Subject Of Subjects][12] 上面提供了一些关于 subjects 的理解,[Nicholas Jamieson][13] 在 [in RxJS: Understanding Subjects][14] 上也提供了一些理解。
|
||||
你可以在 [ReactiveX 文档][10](它提供了一些其它的连接) 里面找到更多关于 `Subject` 的信息。[Ben Lesh][11] 在 [On The Subject Of Subjects][12] 上面提供了一些关于 `Subject` 的理解,[Nicholas Jamieson][13] 在 [in RxJS: Understanding Subjects][14] 上也提供了一些理解。
|
||||
|
||||
#### Observable
|
||||
#### 可观察对象
|
||||
|
||||
你可以简单地用 new 操作符创建一个 observable 对象。通过你传入的函数,你可以控制流,只要有人订阅了或者它接收到一个可以当成 subject 使用的 observer,这个函数就会被调用,比如,调用 next,complet 和 error。
|
||||
你可以简单地用 new 操作符创建一个可观察对象。通过你传入的函数,你可以控制流,只要有人订阅了或者它接收到一个可以当成 `Subject` 使用的观察者,这个函数就会被调用,比如,调用 `next`、`complet` 和 `error`。
|
||||
|
||||
让我们回顾一下列表示例:
|
||||
|
||||
@ -667,16 +567,12 @@ subject.complete();
|
||||
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();
|
||||
@ -687,14 +583,12 @@ new Observable(observer => {
|
||||
// 1 3 |
|
||||
```
|
||||
|
||||
这个函数可以返回一个 unsubcribe 函数,当有订阅者取消订阅时这个函数就会被调用。你可以用它来清楚或者执行一些收尾操作。
|
||||
这个函数可以返回一个 `unsubcribe` 函数,当有订阅者取消订阅时这个函数就会被调用。你可以用它来清楚或者执行一些收尾操作。
|
||||
|
||||
```
|
||||
new Observable(observer => {
|
||||
// 流式化
|
||||
```
|
||||
|
||||
```
|
||||
return () => {
|
||||
//clean up
|
||||
};
|
||||
@ -702,20 +596,18 @@ new Observable(observer => {
|
||||
.subscribe();
|
||||
```
|
||||
|
||||
#### 继承 Observable
|
||||
#### 继承可观察对象
|
||||
|
||||
在有可用的操作符前,这是一种实现自定义操作符的方式。RxJS 在内部扩展了 _Observable_。_Subject_ 就是一个例子,另一个是 _publisher_ 操作符。它返回一个 _ConnectableObservable_ 对象,该对象提供额外的方法 _connect_。
|
||||
在有可用的操作符前,这是一种实现自定义操作符的方式。RxJS 在内部扩展了 _可观察对象_ 。`Subject` 就是一个例子,另一个是 `publisher` 操作符。它返回一个 `ConnectableObservable` 对象,该对象提供额外的方法 `connect`。
|
||||
|
||||
#### 实现 Subscribable 接口
|
||||
#### 实现 `Subscribable` 接口
|
||||
|
||||
有时候你已经用一个对象来保存状态,并且能够发送值。如果你实现了 Subscribable 接口,你可以把它转换成一个 observable 对象。Subscribable 接口中只有一个 subscribe 方法。
|
||||
有时候你已经用一个对象来保存状态,并且能够发送值。如果你实现了 `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],它还包含一些有趣的动画。
|
||||
@ -724,41 +616,34 @@ interface Subscribable<T> { subscribe(observerOrNext?: PartialObserver<T> | ((v
|
||||
|
||||
#### ObservableInput 类型
|
||||
|
||||
期望接收流的操作符和函数通常不单独和 observables 一起工作。相反,他们实际上期望的参数类型是 ObservableInput,定义如下:
|
||||
期望接收流的操作符和函数通常不单独和可观察对象一起工作。相反,它们实际上期望的参数类型是 ObservableInput,定义如下:
|
||||
|
||||
```
|
||||
type ObservableInput<T> = SubscribableOrPromise<T> | ArrayLike<T> | Iterable<T>;
|
||||
```
|
||||
|
||||
这意味着你可以传递一个 promises 或者数组却不需要事先把他们转换成 observables。
|
||||
这意味着你可以传递一个 promises 或者数组却不需要事先把他们转换成可观察对象。
|
||||
|
||||
#### defer
|
||||
|
||||
主要的目的是把一个 observable 对象的创建延迟(defer)到有人想要订阅的时间。在以下情况,这很有用:
|
||||
|
||||
* 创建 observable 对象的开销较大
|
||||
|
||||
* 你想要给每个订阅者新的 observable 对象
|
||||
|
||||
* 你想要在订阅时候选择不同的 observable 对象
|
||||
主要的目的是把一个 observable 对象的创建延迟(`defer`)到有人想要订阅的时间。在以下情况,这很有用:
|
||||
|
||||
* 创建可观察对象的开销较大
|
||||
* 你想要给每个订阅者新的可观察对象
|
||||
* 你想要在订阅时候选择不同的可观察对象
|
||||
* 有些代码必须在订阅之后执行
|
||||
|
||||
最后一点包含了一个并不起眼的用例:Promises(defer 也可以返回一个 promise 对象)。看看这个用到了 fetch API 的例子:
|
||||
最后一点包含了一个并不起眼的用例: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");
|
||||
```
|
||||
@ -770,17 +655,13 @@ userPromise.then(response => console.log("done");
|
||||
// done
|
||||
```
|
||||
|
||||
只要流在你订阅的时候执行了,promise 就会立即执行。我们调用 getUser 的瞬间,就发送了一个请求,哪怕我们这个时候不想发送请求。当然,我们可以使用 from 来把一个 promise 对象转换成 observable 对象,但我们传递的 promise 对象已经创建或执行了。defer 让我们能够等到订阅才发送这个请求:
|
||||
只要流在你订阅的时候执行了,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");
|
||||
```
|
||||
@ -794,7 +675,7 @@ user$.subscribe(response => console.log("done");
|
||||
|
||||
#### iif
|
||||
|
||||
_iif 包含了一个关于 _defer_ 的特殊用例:在订阅时选择两个流中的一个:
|
||||
`iif` 包含了一个关于 `defer` 的特殊用例:在订阅时选择两个流中的一个:
|
||||
|
||||
```
|
||||
iif(
|
||||
@ -810,9 +691,9 @@ iif(
|
||||
// AM before noon, PM afterwards
|
||||
```
|
||||
|
||||
引用了文档:
|
||||
引用该文档:
|
||||
|
||||
> 实际上 `[iif][3]` 能够轻松地用 `[defer][4]` 实现,它仅仅是出于方便和可读性的目的。
|
||||
> 实际上 [iif][3] 能够轻松地用 [defer][4] 实现,它仅仅是出于方便和可读性的目的。
|
||||
|
||||
#### onErrorResumeNext
|
||||
|
||||
@ -822,13 +703,9 @@ iif(
|
||||
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);
|
||||
```
|
||||
@ -848,9 +725,7 @@ onErrorResumeNext(stream1$, stream2$)
|
||||
function handleResponses([user, account]) {
|
||||
// 执行某些任务
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
forkJoin(
|
||||
fetch("https://server/user/1"),
|
||||
fetch("https://server/account/1")
|
||||
@ -860,9 +735,9 @@ forkJoin(
|
||||
|
||||
#### merge / concat
|
||||
|
||||
发送每一个从源 observables 对象中发出的值。
|
||||
发送每一个从可观察对象源中发出的值。
|
||||
|
||||
_merge_ 接收一个参数,让你定义有多少流能被同时订阅。默认是无限制的。设为 1 就意味着监听一个源流,在它结束的时候订阅下一个。由于这是一个常见的场景,RxJS 为你提供了一个显示的函数:_concat_。
|
||||
`merge` 接收一个参数,让你定义有多少流能被同时订阅。默认是无限制的。设为 1 就意味着监听一个源流,在它结束的时候订阅下一个。由于这是一个常见的场景,RxJS 为你提供了一个显示的函数:`concat`。
|
||||
|
||||
```
|
||||
merge(
|
||||
@ -872,31 +747,20 @@ merge(
|
||||
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)),
|
||||
@ -908,9 +772,7 @@ 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
|
||||
@ -920,7 +782,7 @@ concat(
|
||||
|
||||
#### zip / combineLatest
|
||||
|
||||
_merge_ 和 _concat_ 一个接一个的发送所有从源流中读到的值,而 zip 和 combineLatest 是把每个流中的一个值结合起来一起发送。_zip_ 结合所有源流中发送的第一个值。如果流的内容相关联,那么这就很有用。
|
||||
`merge` 和 `concat` 一个接一个的发送所有从源流中读到的值,而 `zip` 和 `combineLatest` 是把每个流中的一个值结合起来一起发送。`zip` 结合所有源流中发送的第一个值。如果流的内容相关联,那么这就很有用。
|
||||
|
||||
```
|
||||
zip(
|
||||
@ -935,7 +797,7 @@ zip(
|
||||
// [0, 0] [1, 1] [2, 2] ...
|
||||
```
|
||||
|
||||
_combineLatest_ 与之类似,但结合的是源流中发送的最后一个值。直到所有源流至少发送一个值之后才会触发事件。这之后每次源流发送一个值,它都会把这个值与其他流发送的最后一个值结合起来。
|
||||
`combineLatest` 与之类似,但结合的是源流中发送的最后一个值。直到所有源流至少发送一个值之后才会触发事件。这之后每次源流发送一个值,它都会把这个值与其他流发送的最后一个值结合起来。
|
||||
|
||||
```
|
||||
combineLatest(
|
||||
@ -983,15 +845,13 @@ race(
|
||||
// foo |
|
||||
```
|
||||
|
||||
由于 _of_ 立即产生一个值,因此它是最快的流,然而这个流就被选中了。
|
||||
|
||||
* * *
|
||||
由于 `of` 立即产生一个值,因此它是最快的流,然而这个流就被选中了。
|
||||
|
||||
### 总结
|
||||
|
||||
已经有很多创建 observables 对象的方式了。如果你想要创造响应式的 APIs 或者想用响应式的 API 结合传统 APIs,那么了解这些方法很重要。
|
||||
已经有很多创建可观察对象的方式了。如果你想要创造响应式的 API 或者想用响应式的 API 结合传统 API,那么了解这些方法很重要。
|
||||
|
||||
我已经向你展示了所有可用的方法,但它们其实还有很多内容可以讲。如果你想更加深入地了解,我极力推荐你查阅 [documentation][20] 或者阅读相关文章。
|
||||
我已经向你展示了所有可用的方法,但它们其实还有很多内容可以讲。如果你想更加深入地了解,我极力推荐你查阅 [文档][20] 或者阅读相关文章。
|
||||
|
||||
[RxViz][21] 是另一种值得了解的有意思的方式。你编写 RxJS 代码,产生的流可以用图形或动画进行显示。
|
||||
|
||||
@ -1001,7 +861,7 @@ via: https://blog.angularindepth.com/the-extensive-guide-to-creating-streams-in-
|
||||
|
||||
作者:[Oliver Flaggl][a]
|
||||
译者:[BriFuture](https://github.com/BriFuture)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -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/) 荣誉推出
|
||||
|
@ -0,0 +1,144 @@
|
||||
Trash-Cli:Linux 上的命令行回收站工具
|
||||
======
|
||||
|
||||
相信每个人都对<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
|
@ -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/) 荣誉推出
|
||||
|
132
published/201809/20171124 How do groups work on Linux.md
Normal file
132
published/201809/20171124 How do groups work on Linux.md
Normal 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/
|
@ -0,0 +1,66 @@
|
||||
Scrot:让你在命令行中进行截屏更加简单
|
||||
======
|
||||
|
||||
> Scrot 是一个简单、灵活,并且提供了许多选项的 Linux 命令行截屏工具。
|
||||
|
||||
[][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
|
@ -0,0 +1,142 @@
|
||||
面向敏捷开发团队的 7 个开源项目管理工具
|
||||
======
|
||||
|
||||
> 在这篇开源项目管理工具的综述中,让我们来了解一下支持 Scrum、<ruby>看板<rt>Kanban</rt></ruby> 等敏捷开发模式的软件。
|
||||
|
||||

|
||||
|
||||
Opensource.com 以前对流行的开源项目管理工具做过相应的调研。但是今年我们增加了一个特点。本次,我们特别关注支持[敏捷][1]方法的工具,包括相关的实践,如 [Scrum][2]、Lean 和 <ruby>看板<rt>Kanban</rt></ruby>。
|
||||
|
||||
对敏捷开发的兴趣和使用的增长是我们今年决定专注于这些工具的原因。大多数组织(71%)的人说他们至少[使用了敏捷方式][3]。此外,敏捷项目比传统方法管理的项目 [要高出 28% 的成功率][4] 。
|
||||
|
||||
我们查看了 [2014][5]、[2015][6] 和 [2016][7] 中涉及的项目管理工具,并挑选了支持敏捷的工具,然后对没有涉及的或变化了的进行了研究。不管您的组织是否已经在使用敏捷开发,或者在 2018 年的众多计划之一是采用敏捷方法,这七个开源项目管理工具之一可能正是您所要找寻的。
|
||||
|
||||
### MyCollab
|
||||
|
||||

|
||||
|
||||
|
||||
[MyCollab][8] 是一套针对中小型企业的三个协作模块套件:项目管理、客户关系管理(CRM)和文档创建和编辑软件。有两个许可证选项:一个商业的“终极”版本,它更快,可以在内部或云中运行;另一个开源的“社区版本”,这个正是我们感兴趣的版本。
|
||||
|
||||
由于没有使用查询缓存,社区版本没有云方式,并且速度较慢,但是提供了基本的项目管理特性,包括任务、问题管理、活动流、路线图视图和敏捷团队看板。虽然它没有单独的移动应用程序,但它也适用于移动设备,包括 Windows、Mac OS、Linux 和 UNIX 计算机。
|
||||
|
||||
MyCollab 的最新版本是 5.4.10,源代码可在 [GitHub][9] 上下载。它是在 AGPLv3 下进行授权的,需要 Java 运行时环境和 MySQL 支持。它可运行于 Windows、Linux、UNIX 和 MacOS。[下载地址][10]。
|
||||
|
||||
### Odoo
|
||||
|
||||

|
||||
|
||||
|
||||
[Odoo][11] 不仅仅是项目管理软件;它是一个完整的集成商业应用套件,包括会计、人力资源、网站和电子商务、库存、制造、销售管理(CRM)和其它工具。
|
||||
|
||||
与付费企业套件相比,免费的开源社区版具有有限的 [特性][12] 。它的项目管理应用程序包括敏捷团队的看板式任务跟踪视图,在最新版本 Odoo 11.0 中更新了该视图,以包括用于跟踪项目状态的进度条和动画。项目管理工具还包括甘特图、任务、问题、图表等等。Odoo 有一个繁荣的[社区][13],并提供 [用户指南][14] 及其他培训资源。
|
||||
|
||||
|
||||
它是在 GPLv3 下授权的,需要 Python 和 PostgreSQL 支持。作为[Docker][16] 镜像 可以运行在 Windows、Linux 和 Red Hat 包管理器中,下载地址[download][15],源代码[GitHub][17]。
|
||||
|
||||
### OpenProject
|
||||
|
||||

|
||||
|
||||
[OpenProject][18] 是一个强大的开源项目管理工具,以其易用性和丰富的项目管理和团队协作特性而著称。
|
||||
|
||||
它的模块支持项目计划、调度、路线图和发布计划、时间跟踪、成本报告、预算、bug 跟踪以及敏捷和 Scrum。它的敏捷特性,包括创建 Story、确定 sprint 的优先级以及跟踪任务,都与 OpenProject 的其他模块集成在一起。
|
||||
|
||||
OpenProject 在 GPLv3 下获得许可,其源代码可在[GitHub][19]上。最新版本 7.3.2 的 Linux 版本 [在此下载][20];您可以在 Birthe Lindenthal 的文章 “[OpenProject 入门][21]”中了解更多关于安装和配置它的信息。
|
||||
|
||||
### OrangeScrum
|
||||
|
||||

|
||||
|
||||
正如从其名称中猜到的,[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[
|
||||
|
||||

|
||||
|
||||
[\]project-open\[][26] 是一个双许可证的企业项目管理工具,这意味着其核心是开源的,并且在商业许可的模块中可以使用一些附加特性。根据该项目的社区和企业版本的 [比较][27],开源核心为中小型组织提供了许多特性。
|
||||
|
||||
]project-open[ 支持带有 Scrum 和看板功能的 [敏捷][28] 项目,以及经典的甘特/瀑布项目和混合或混合项目。
|
||||
|
||||
该应用程序是在 GPL 下授权的,并且 [源代码][29]是通过 CVS 访问的。 ]project-open[ 在 Linux 和 Windows 的安装有 [安装程序][26],但也可以在云镜像和虚拟设备中使用。
|
||||
|
||||
### Taiga
|
||||
|
||||

|
||||
|
||||
[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
|
||||
|
||||

|
||||
|
||||
[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
|
@ -0,0 +1,137 @@
|
||||
|
||||
我从编程面试中学到的
|
||||
======
|
||||
|
||||

|
||||
|
||||
*聊聊白板编程面试*
|
||||
|
||||
在 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/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user