RHCSA 系列(十三): 在 RHEL 7 中使用 SELinux 进行强制访问控制

在本系列的前面几篇文章中,我们已经详细地探索了至少两种访问控制方法:标准的 ugo/rwx 权限(RHCSA 系列(三): 如何管理 RHEL7 的用户和组) 和访问控制列表(RHCSA 系列(七): 使用 ACL(访问控制列表) 和挂载 Samba/NFS 共享)。

RHCSA 系列(十三): 在 RHEL 7 中使用 SELinux 进行强制访问控制
RHCSA 系列(十三): 在 RHEL 7 中使用 SELinux 进行强制访问控制

RHCSA 认证:SELinux 精要和控制文件系统的访问

尽管作为第一级别的权限和访问控制机制是必要的,但它们同样有一些局限,而这些局限则可以由安全增强 LinuxSecurity Enhanced Linux,简称为 SELinux来处理。

这些局限的一种情形是:某个用户可能通过一个泛泛的 chmod 命令将文件或目录暴露出现了安全违例,从而引起访问权限的意外传播。结果,由该用户开启的任意进程可以对属于该用户的文件进行任意的操作,最终一个恶意的或有其它缺陷的软件可能会取得整个系统的 root 级别的访问权限。

考虑到这些局限性,美国国家安全局(NSA) 率先设计出了 SELinux,一种强制的访问控制方法,它根据最小权限模型去限制进程在系统对象(如文件,目录,网络接口等)上的访问或执行其他的操作的能力,而这些限制可以在之后根据需要进行修改。简单来说,系统的每一个元素只给某个功能所需要的那些权限。

在 RHEL 7 中,SELinux 被并入了内核中,且默认情况下以强制模式Enforcing开启。在这篇文章中,我们将简要地介绍有关 SELinux 及其相关操作的基本概念。

SELinux 的模式

SELinux 可以以三种不同的模式运行:

  • 强制模式Enforcing:SELinux 基于其策略规则来拒绝访问,这些规则是用以控制安全引擎的一系列准则;
  • 宽容模式Permissive:SELinux 不会拒绝访问,但对于那些如果运行在强制模式下会被拒绝访问的行为进行记录;
  • 关闭Disabled (不言自明,即 SELinux 没有实际运行).

使用 getenforce 命令可以展示 SELinux 当前所处的模式,而 setenforce 命令(后面跟上一个 1 或 0) 则被用来将当前模式切换到强制模式Enforcing宽容模式Permissive,但只对当前的会话有效。

为了使得在登出和重启后上面的设置还能保持作用,你需要编辑 /etc/selinux/config 文件并将 SELINUX 变量的值设为 enforcing,permissive,disabled 中之一:

# getenforce
# setenforce 0
# getenforce
# setenforce 1
# getenforce
# cat /etc/selinux/config

设置 SELinux 模式

设置 SELinux 模式

通常情况下,你应该使用 setenforce 来在 SELinux 模式间进行切换(从强制模式到宽容模式,或反之),以此来作为你排错的第一步。假如 SELinux 当前被设置为强制模式,而你遇到了某些问题,但当你把 SELinux 切换为宽容模式后问题不再出现了,则你可以确信你遇到了一个 SELinux 权限方面的问题。

SELinux 上下文

一个 SELinux 上下文Context由一个访问控制环境所组成,在这个环境中,决定的做出将基于 SELinux 的用户,角色和类型(和可选的级别):

  • 一个 SELinux 用户是通过将一个常规的 Linux 用户账户映射到一个 SELinux 用户账户来实现的,反过来,在一个会话中,这个 SELinux 用户账户在 SELinux 上下文中被进程所使用,以便能够明确定义它们所允许的角色和级别。
  • 角色的概念是作为域和处于该域中的 SELinux 用户之间的媒介,它定义了 SELinux 可以访问到哪个进程域和哪些文件类型。这将保护您的系统免受提权漏洞的攻击。
  • 类型则定义了一个 SELinux 文件类型或一个 SELinux 进程域。在正常情况下,进程将会被禁止访问其他进程正使用的文件,并禁止对其他进程进行访问。这样只有当一个特定的 SELinux 策略规则允许它访问时,才能够进行访问。

下面就让我们看看这些概念是如何在下面的例子中起作用的。

例 1:改变 sshd 守护进程的默认端口

RHCSA 系列(八): 加固 SSH,设定主机名及启用网络服务 中,我们解释了更改 sshd 所监听的默认端口是加固你的服务器免受外部攻击的首要安全措施。下面,就让我们编辑 /etc/ssh/sshd_config 文件并将端口设置为 9999:

Port 9999

保存更改并重启 sshd:

# systemctl restart sshd
# systemctl status sshd

更改 SSH 的端口

重启 SSH 服务

正如你看到的那样, sshd 启动失败,但为什么会这样呢?

快速检查 /var/log/audit/audit.log 文件会发现 sshd 已经被拒绝在端口 9999 上开启(SELinux 的日志信息包含单词 “AVC”,所以这类信息可以被轻易地与其他信息相区分),因为这个端口是 JBoss 管理服务的保留端口:

# cat /var/log/audit/audit.log | grep AVC | tail -1

查看 SSH 日志

查看 SSH 日志

在这种情况下,你可以像先前解释的那样禁用 SELinux(但请不要这样做!),并尝试重启 sshd,且这种方法能够起效。但是, semanage 应用可以告诉我们在哪些端口上可以开启 sshd 而不会出现任何问题。

运行:

# semanage port -l | grep ssh

便可以得到一个 SELinux 允许 sshd 在哪些端口上监听的列表:

RHCSA 系列(十三): 在 RHEL 7 中使用 SELinux 进行强制访问控制
RHCSA 系列(十三): 在 RHEL 7 中使用 SELinux 进行强制访问控制

Semanage 工具

所以让我们在 /etc/ssh/sshd_config 中将端口更改为 9998 端口,增加这个端口到 sshportt 的上下文,然后重启 sshd 服务:

# semanage port -a -t ssh_port_t -p tcp 9998
# systemctl restart sshd
# systemctl is-active sshd

Semanage 添加端口

semanage 添加端口

如你所见,这次 sshd 服务被成功地开启了。这个例子告诉我们一个事实:SELinux 用它自己的端口类型的内部定义来控制 TCP 端口号。

例 2:允许 httpd 访问 sendmail

这是一个 SELinux 管理一个进程来访问另一个进程的例子。假如在你的 RHEL 7 服务器上,你要为 Apache 配置 mod_security 和 mod_evasive,你需要允许 httpd 访问 sendmail,以便在遭受到 (D)DoS 攻击时能够用邮件来提醒你。在下面的命令中,如果你不想使得更改在重启后仍然生效,请去掉 -P 选项。

# semanage boolean -1 | grep httpd_can_sendmail
# setsebool -P httpd_can_sendmail 1
# semanage boolean -1 | grep httpd_can_sendmail

允许 Apache 发送邮件

允许 Apache 发送邮件

从上面的例子中,你可以知道 SELinux 布尔设定(或者只是布尔值)分别对应于 true 或 false,被嵌入到了 SELinux 策略中。你可以使用 semanage boolean -l 来列出所有的布尔值,也可以管道至 grep 命令以便筛选输出的结果。

例 3:在一个特定目录而非默认目录下提供一个静态站点服务

假设你正使用一个不同于默认目录(/var/www/html)的目录来提供一个静态站点服务,例如 /websites 目录(这种情形会出现在当你把你的网络文件存储在一个共享网络设备上,并需要将它挂载在 /websites 目录时)。

a). 在 /websites 下创建一个 index.html 文件并包含如下的内容:


SELinux test

假如你执行

# ls -lZ /websites/index.html

你将会看到这个 index.html 已经被标记上了 default_t SELinux 类型,而 Apache 不能访问这类文件:

检查 SELinux 文件的权限

检查 SELinux 文件的权限

b). 将 /etc/httpd/conf/httpd.conf 中的 DocumentRoot 改为 /websites,并不要忘了 更新相应的 Directory 块。然后重启 Apache。

c). 浏览 http://,则你应该会得到一个 503 Forbidden 的 HTTP 响应。

d). 接下来,递归地改变 /websites 的标志,将它的标志变为 httpd_sys_content_t 类型,以便赋予 Apache 对这些目录和其内容的只读访问权限:

# semanage fcontext -a -t httpd_sys_content_t "/websites(/.*)?"

e). 最后,应用在 d) 中创建的 SELinux 策略:

# restorecon -R -v /websites

现在重启 Apache 并再次浏览到 http://,则你可以看到被正确展现出来的 html 文件:

确认 Apache 页面

确认 Apache 页面

总结

在本文中,我们详细地介绍了 SELinux 的基础知识。请注意,由于这个主题的广泛性,在单篇文章中做出一个完全详尽的解释是不可能的,但我们相信,在这个指南中列出的基本原则将会对你进一步了解更高级的话题有所帮助,假如你想了解的话。

假如可以,请让我推荐两个必要的资源来入门 SELinux:NSA SELinux 页面针对用户和系统管理员的 RHEL 7 SELinux 指南

假如你有任何的问题或评论,请不要犹豫,让我们知晓吧。


via: http://www.tecmint.com/selinux-essentials-and-control-filesystem-access/

作者:Gabriel Cánepa 译者:FSSlc 校对:wxy

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

如何通过反向 SSH 隧道访问 NAT 后面的 Linux 服务器

你在家里运行着一台 Linux 服务器,它放在一个 NAT 路由器或者限制性防火墙后面。现在你想在外出时用 SSH 登录到这台服务器。你如何才能做到呢?SSH 端口转发当然是一种选择。但是,如果你需要处理多级嵌套的 NAT 环境,端口转发可能会变得非常棘手。另外,在多种 ISP 特定条件下可能会受到干扰,例如阻塞转发端口的限制性 ISP 防火墙、或者在用户间共享 IPv4 地址的运营商级 NAT。

什么是反向 SSH 隧道?

SSH 端口转发的一种替代方案是 反向 SSH 隧道。反向 SSH 隧道的概念非常简单。使用这种方案,在你的受限的家庭网络之外你需要另一台主机(所谓的“中继主机”),你能从当前所在地通过 SSH 登录到它。你可以用有公网 IP 地址的 VPS 实例 配置一个中继主机。然后要做的就是从你的家庭网络服务器中建立一个到公网中继主机的永久 SSH 隧道。有了这个隧道,你就可以从中继主机中连接“回”家庭服务器(这就是为什么称之为 “反向” 隧道)。不管你在哪里、你的家庭网络中的 NAT 或 防火墙限制多么严格,只要你可以访问中继主机,你就可以连接到家庭服务器。

如何通过反向 SSH 隧道访问 NAT 后面的 Linux 服务器
如何通过反向 SSH 隧道访问 NAT 后面的 Linux 服务器

在 Linux 上设置反向 SSH 隧道

让我们来看看怎样创建和使用反向 SSH 隧道。我们做如下假设:我们会设置一个从家庭服务器(homeserver)到中继服务器(relayserver)的反向 SSH 隧道,然后我们可以通过中继服务器从客户端计算机(clientcomputer) SSH 登录到家庭服务器。本例中的中继服务器 的公网 IP 地址是 1.1.1.1。

在家庭服务器上,按照以下方式打开一个到中继服务器的 SSH 连接。

homeserver~$ ssh -fN -R 10022:localhost:22 relayserver_user@1.1.1.1

这里端口 10022 是任何你可以使用的端口数字。只需要确保中继服务器上不会有其它程序使用这个端口。

“-R 10022:localhost:22” 选项定义了一个反向隧道。它转发中继服务器 10022 端口的流量到家庭服务器的 22 号端口。

用 “-fN” 选项,当你成功通过 SSH 服务器验证时 SSH 会进入后台运行。当你不想在远程 SSH 服务器执行任何命令,就像我们的例子中只想转发端口的时候非常有用。

运行上面的命令之后,你就会回到家庭主机的命令行提示框中。

登录到中继服务器,确认其 127.0.0.1:10022 绑定到了 sshd。如果是的话就表示已经正确设置了反向隧道。

relayserver~$ sudo netstat -nap | grep 10022

tcp      0    0 127.0.0.1:10022          0.0.0.0:*               LISTEN      8493/sshd

现在就可以从任何其它计算机(客户端计算机)登录到中继服务器,然后按照下面的方法访问家庭服务器。

relayserver~$ ssh -p 10022 homeserver_user@localhost

需要注意的一点是你在上面为localhost输入的 SSH 登录/密码应该是家庭服务器的,而不是中继服务器的,因为你是通过隧道的本地端点登录到家庭服务器,因此不要错误输入中继服务器的登录/密码。成功登录后,你就在家庭服务器上了。

通过反向 SSH 隧道直接连接到网络地址变换后的服务器

上面的方法允许你访问 NAT 后面的 家庭服务器,但你需要登录两次:首先登录到 中继服务器,然后再登录到家庭服务器。这是因为中继服务器上 SSH 隧道的端点绑定到了回环地址(127.0.0.1)。

事实上,有一种方法可以只需要登录到中继服务器就能直接访问NAT之后的家庭服务器。要做到这点,你需要让中继服务器上的 sshd 不仅转发回环地址上的端口,还要转发外部主机的端口。这通过指定中继服务器上运行的 sshd 的 GatewayPorts 实现。

打开中继服务器的 /etc/ssh/sshd_conf 并添加下面的行。

relayserver~$ vi /etc/ssh/sshd_conf

GatewayPorts clientspecified

重启 sshd。

基于 Debian 的系统:

relayserver~$ sudo /etc/init.d/ssh restart

基于红帽的系统:

relayserver~$ sudo systemctl restart sshd

现在在家庭服务器中按照下面方式初始化一个反向 SSH 隧道。

homeserver~$ ssh -fN -R 1.1.1.1:10022:localhost:22 relayserver_user@1.1.1.1

登录到中继服务器然后用 netstat 命令确认成功建立的一个反向 SSH 隧道。

relayserver~$ sudo netstat -nap | grep 10022

tcp      0      0 1.1.1.1:10022     0.0.0.0:*           LISTEN      1538/sshd: dev

不像之前的情况,现在隧道的端点是 1.1.1.1:10022(中继服务器的公网 IP 地址),而不是 127.0.0.1:10022。这就意味着从外部主机可以访问隧道的另一端。

现在在任何其它计算机(客户端计算机),输入以下命令访问网络地址变换之后的家庭服务器。

clientcomputer~$ ssh -p 10022 homeserver_user@1.1.1.1

在上面的命令中,1.1.1.1 是中继服务器的公共 IP 地址,homeserver_user必须是家庭服务器上的用户账户。这是因为你真正登录到的主机是家庭服务器,而不是中继服务器。后者只是中继你的 SSH 流量到家庭服务器。

在 Linux 上设置一个永久反向 SSH 隧道

现在你已经明白了怎样创建一个反向 SSH 隧道,然后把隧道设置为 “永久”,这样隧道启动后就会一直运行(不管临时的网络拥塞、SSH 超时、中继主机重启,等等)。毕竟,如果隧道不是一直有效,你就不能可靠的登录到你的家庭服务器。

对于永久隧道,我打算使用一个叫 autossh 的工具。正如名字暗示的,这个程序可以让你的 SSH 会话无论因为什么原因中断都会自动重连。因此对于保持一个反向 SSH 隧道非常有用。

第一步,我们要设置从家庭服务器到中继服务器的无密码 SSH 登录。这样的话,autossh 可以不需要用户干预就能重启一个损坏的反向 SSH 隧道。

下一步,在建立隧道的家庭服务器上安装 autossh

在家庭服务器上,用下面的参数运行 autossh 来创建一个连接到中继服务器的永久 SSH 隧道。

homeserver~$ autossh -M 10900 -fN -o "PubkeyAuthentication=yes" -o "StrictHostKeyChecking=false" -o "PasswordAuthentication=no" -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -R 1.1.1.1:10022:localhost:22 relayserver_user@1.1.1.1

“-M 10900” 选项指定中继服务器上的监视端口,用于交换监视 SSH 会话的测试数据。中继服务器上的其它程序不能使用这个端口。

“-fN” 选项传递给 ssh 命令,让 SSH 隧道在后台运行。

“-o XXXX” 选项让 ssh:

  • 使用密钥验证,而不是密码验证。
  • 自动接受(未知)SSH 主机密钥。
  • 每 60 秒交换 keep-alive 消息。
  • 没有收到任何响应时最多发送 3 条 keep-alive 消息。

其余 SSH 隧道相关的选项和之前介绍的一样。

如果你想系统启动时自动运行 SSH 隧道,你可以将上面的 autossh 命令添加到 /etc/rc.local。

总结

在这篇博文中,我介绍了你如何能从外部通过反向 SSH 隧道访问限制性防火墙或 NAT 网关之后的 Linux 服务器。这里我介绍了家庭网络中的一个使用事例,但在企业网络中使用时你尤其要小心。这样的一个隧道可能被视为违反公司政策,因为它绕过了企业的防火墙并把企业网络暴露给外部攻击。这很可能被误用或者滥用。因此在使用之前一定要记住它的作用。


via: http://xmodulo.com/access-linux-server-behind-nat-reverse-ssh-tunnel.html

作者:Dan Nanni 译者:ictlyh 校对:wxy

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

来源:https://linux.cn/article-5975-1.html

lsyncd 实时同步搭建指南

1. 几大实时同步工具比较

lsyncd 实时同步搭建指南
lsyncd 实时同步搭建指南

1.1 inotify + rsync

最近一直在寻求生产服务服务器上的同步替代方案,原先使用的是inotify + rsync,但随着文件数量的增大到100W+,目录下的文件列表就达20M,在网络状况不佳或者限速的情况下,变更的文件可能10来个才几M,却因此要发送的文件列表就达20M,严重减低的带宽的使用效率以及同步效率;更为要紧的是,加入inotifywait在5s内监控到10个小文件发生变化,便会触发10个rsync同步操作,结果就是真正需要传输的才2-3M的文件,比对的文件列表就达200M。使用这两个组合的好处在于,它们都是最基本的软件,可以通过不同选项做到很精确的控制,比如排除同步的目录,同步多个模块或同步到多个主机。

1.2 sersync

后来听同事说 sersync 这么个工具可以提高同步的性能,也解决了同步大文件时出现异常的问题,所以就尝试了一下。sersync是国内的一个开发者开源出来的,使用c++编写,采用多线程的方式进行同步,失败后还有重传机制,对临时文件过滤,自带crontab定时同步功能。网上看到有人说性能还不错,说一下我的观点:

  • 国产开源,文档不是很全,在2011年之后就没更新了(googlecode都要快关闭了,其实可以转交其他人维护),网上关于它的使用和讨论都止于10年了
  • 采用xml配置文件的方式,可读性比较好,但是有些原生的有些功能没有实现就没法使用了
  • 无法实现多目录同步,只能通过多个配置文件启动多个进程
  • 文件排除功能太弱。这个要看需求,不是每个人都需要排除子目录。而对于我的环境中,这个功能很重要,而且排除的规则较多
  • 虽然提供插件的功能,但很鸡肋,因为软件本身没有持续更新,也没有看到贡献有其它插件出现(可能是我知识面不够,还用不到里面的refreshCDN plugin)。

虽然不懂c++,但大致看了下源码 FileSynchronize,拼接rsync命令大概在273行左右,最后一个函数就是排除选项,简单一点可以将–exclude=改成–eclude-from来灵活控制。有机会再改吧。

另外,在作者的文章 Sersync服务器同步程序 项目简介与设计框架 评论中,说能解决上面 rsync + inotify中所描述的问题。阅读了下源码,这个应该是没有解决,因为在拼接rsync命令时,后面的目的地址始终是针对module的,只要执行rsync命令,就会对整个目录进行遍历,发送要比对的文件列表,然后再发送变化的文件。sersync只是减少了监听的事件,减少了rsync的次数——这已经是很大的改进,但每次rsync没办法改变。(如有其它看法可与我讨论)

其实我们也不能要求每一个软件功能都十分健全,关键是看能否满足我们当下的特定的需求。所谓好的架构不是设计出来的,而是进化来的。目前使用sersync2没什么问题,而且看了它的设计思路应该是比较科学的,特别是过滤队列的设计。双向同步看起来也是可以实现。

1.3 lsyncd

废话说这么多,本文就是介绍它了。有些博客说lsyncd是谷歌开源的,实际不是了,只是托管在了googlecode上而已,幸运的是已经迁移到github了:https://github.com/axkibe/lsyncd 。

Lysncd 实际上是lua语言封装了 inotify 和 rsync 工具,采用了 Linux 内核(2.6.13 及以后)里的 inotify 触发机制,然后通过rsync去差异同步,达到实时的效果。我认为它最令人称道的特性是,完美解决了 inotify + rsync海量文件同步带来的文件频繁发送文件列表的问题 —— 通过时间延迟或累计触发事件次数实现。另外,它的配置方式很简单,lua本身就是一种配置语言,可读性非常强。lsyncd也有多种工作模式可以选择,本地目录cp,本地目录rsync,远程目录rsyncssh。

实现简单高效的本地目录同步备份(网络存储挂载也当作本地目录),一个命令搞定。

2. 使用 lsyncd 本地目录实时备份

这一节实现的功能是,本地目录source实时同步到另一个目录target,而在source下有大量的文件,并且有部分目录和临时文件不需要同步。

2.1 安装lsyncd

安装lsyncd极为简单,已经收录在ubuntu的官方镜像源里,直接通过apt-get install lsyncd就可以。在Redhat系(我的环境是CentOS 6.2 x86_64 ),可以手动去下载 lsyncd-2.1.5-6.fc21.x86_64.rpm,但首先你得安装两个依赖yum install lua lua-devel。也可以通过在线安装,需要epel-release扩展包:

# rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
# yum install lsyncd

源码编译安装

从源码编译安装可以使用最新版的lsyncd程序,但必须要相应的依赖库文件和编译工具:yum install lua lua-devel asciidoc cmake

从 googlecode lsyncd 上下载的lsyncd-2.1.5.tar.gz,直接./configuremake && make install就可以了。

从github上下载lsyncd-master.zip 的2.1.5版本使用的是 cmake 编译工具,无法./configure

# uzip lsyncd-master.zip
# cd lsyncd-master
# cmake -DCMAKE_INSTALL_PREFIX=/usr/local/lsyncd-2.1.5
# make && make install

我这个版本编译时有个小bug,如果按照INSTALLbuild目录中make,会提示:

[100%] Generating doc/lsyncd.1
Updating the manpage
a2x: failed: source file not found: doc/lsyncd.1.txt
make[2]: *** [doc/lsyncd.1] Error 1
make[1]: *** [CMakeFiles/manpage.dir/all] Error 2
make: *** [all] Error 2

解决办法是要么直接在解压目录下cmake,不要mkdir build,要么在CMakeList.txt中搜索doc字符串,在前面加上${PROJECT_SOURCE_DIR}

2.2 lsyncd.conf

下面都是在编译安装的情况下操作。

2.2.1 lsyncd同步配置

# cd /usr/local/lsyncd-2.1.5
# mkdir etc var
# vi etc/lsyncd.conf
settings {
    logfile      ="/usr/local/lsyncd-2.1.5/var/lsyncd.log",
    statusFile   ="/usr/local/lsyncd-2.1.5/var/lsyncd.status",
    inotifyMode  = "CloseWrite",
    maxProcesses = 7,
    -- nodaemon =true,
    }
sync {
    default.rsync,
    source    = "/tmp/src",
    target    = "/tmp/dest",
    -- excludeFrom = "/etc/rsyncd.d/rsync_exclude.lst",
    rsync     = {
        binary    = "/usr/bin/rsync",
        archive   = true,
        compress  = true,
        verbose   = true
        }
    }

到这启动 lsycnd 就可以完成实时同步了,默认的许多参数可以满足绝大部分需求,非常简单。

2.2.2 lsyncd.conf配置选项说明

settings

里面是全局设置,开头表示注释,下面是几个常用选项说明:

  • logfile 定义日志文件
  • stausFile 定义状态文件
  • nodaemon=true 表示不启用守护模式,默认
  • statusInterval 将lsyncd的状态写入上面的statusFile的间隔,默认10秒
  • inotifyMode 指定inotify监控的事件,默认是CloseWrite,还可以是ModifyCloseWrite or Modify
  • maxProcesses 同步进程的最大个数。假如同时有20个文件需要同步,而maxProcesses = 8,则最大能看到有8个rysnc进程
  • maxDelays 累计到多少所监控的事件激活一次同步,即使后面的delay延迟时间还未到

sync

里面是定义同步参数,可以继续使用maxDelays来重写settings的全局变量。一般第一个参数指定lsyncd以什么模式运行:rsyncrsyncsshdirect三种模式:

  • default.rsync :本地目录间同步,使用rsync,也可以达到使用ssh形式的远程rsync效果,或daemon方式连接远程rsyncd进程;default.direct :本地目录间同步,使用cprm等命令完成差异文件备份;default.rsyncssh :同步到远程主机目录,rsync的ssh模式,需要使用key来认证

  • source 同步的源目录,使用绝对路径。

  • target 定义目的地址.对应不同的模式有几种写法:/tmp/dest :本地目录同步,可用于directrsync模式172.29.88.223:/tmp/dest :同步到远程服务器目录,可用于rsyncrsyncssh模式,拼接的命令类似于/usr/bin/rsync -ltsd –delete –include-from=- –exclude=* SOURCE TARGET,剩下的就是rsync的内容了,比如指定username,免密码同步172.29.88.223::module :同步到远程服务器目录,用于rsync模式三种模式的示例会在后面给出。

  • init 这是一个优化选项,当init = false,只同步进程启动以后发生改动事件的文件,原有的目录即使有差异也不会同步。默认是true

  • delay 累计事件,等待rsync同步延时时间,默认15秒(最大累计到1000个不可合并的事件)。也就是15s内监控目录下发生的改动,会累积到一次rsync同步,避免过于频繁的同步。(可合并的意思是,15s内两次修改了同一文件,最后只同步最新的文件)

  • excludeFrom 排除选项,后面指定排除的列表文件,如excludeFrom = “/etc/lsyncd.exclude”,如果是简单的排除,可以使用exclude = LIST。这里的排除规则写法与原生rsync有点不同,更为简单:
    • 监控路径里的任何部分匹配到一个文本,都会被排除,例如/bin/foo/bar可以匹配规则foo
    • 如果规则以斜线/开头,则从头开始要匹配全部
    • 如果规则以/结尾,则要匹配监控路径的末尾
    • ?匹配任何字符,但不包括/
    • *匹配0或多个字符,但不包括/
    • **匹配0或多个字符,可以是/

rsync

(提示一下,deleteexclude本来都是rsync的选项,上面是配置在sync中的,我想这样做的原因是为了减少rsync的开销)

  • bwlimit 限速,单位kb/s,与rsync相同(这么重要的选项在文档里竟然没有标出)
  • compress 压缩传输默认为true。在带宽与cpu负载之间权衡,本地目录同步可以考虑把它设为false
  • perms 默认保留文件权限。
  • 其它rsync的选项

其它还有rsyncssh模式独有的配置项,如hosttargetdirrsync_pathpassword_file,见后文示例。rsyncOps={“-avz”,”–delete”}这样的写法在2.1.*版本已经不支持。

lsyncd.conf可以有多个sync,各自的source,各自的target,各自的模式,互不影响。

2.3 启动lsyncd

使用命令加载配置文件,启动守护进程,自动同步目录操作。

lsyncd -log Exec /usr/local/lsyncd-2.1.5/etc/lsyncd.conf

2.4 lsyncd.conf其它模式示例

以下配置本人都已经过验证可行,必须根据实际需要裁剪配置:

settings {
    logfile ="/usr/local/lsyncd-2.1.5/var/lsyncd.log",
    statusFile ="/usr/local/lsyncd-2.1.5/var/lsyncd.status",
    inotifyMode = "CloseWrite",
    maxProcesses = 8,
    }
-- I. 本地目录同步,direct:cp/rm/mv。 适用:500+万文件,变动不大
sync {
    default.direct,
    source    = "/tmp/src",
    target    = "/tmp/dest",
    delay = 1
    maxProcesses = 1
    }
-- II. 本地目录同步,rsync模式:rsync
sync {
    default.rsync,
    source    = "/tmp/src",
    target    = "/tmp/dest1",
    excludeFrom = "/etc/rsyncd.d/rsync_exclude.lst",
    rsync     = {
        binary = "/usr/bin/rsync",
        archive = true,
        compress = true,
        bwlimit   = 2000
        }
    }
-- III. 远程目录同步,rsync模式 + rsyncd daemon
sync {
    default.rsync,
    source    = "/tmp/src",
    target    = "syncuser@172.29.88.223::module1",
    delete="running",
    exclude = { ".*", ".tmp" },
    delay = 30,
    init = false,
    rsync     = {
        binary = "/usr/bin/rsync",
        archive = true,
        compress = true,
        verbose   = true,
        password_file = "/etc/rsyncd.d/rsync.pwd",
        _extra    = {"--bwlimit=200"}
        }
    }
-- IV. 远程目录同步,rsync模式 + ssh shell
sync {
    default.rsync,
    source    = "/tmp/src",
    target    = "172.29.88.223:/tmp/dest",
    -- target    = "root@172.29.88.223:/remote/dest",
    -- 上面target,注意如果是普通用户,必须拥有写权限
    maxDelays = 5,
    delay = 30,
    -- init = true,
    rsync     = {
        binary = "/usr/bin/rsync",
        archive = true,
        compress = true,
        bwlimit   = 2000
        -- rsh = "/usr/bin/ssh -p 22 -o StrictHostKeyChecking=no"
        -- 如果要指定其它端口,请用上面的rsh
        }
    }
-- V. 远程目录同步,rsync模式 + rsyncssh,效果与上面相同
sync {
    default.rsyncssh,
    source    = "/tmp/src2",
    host      = "172.29.88.223",
    targetdir = "/remote/dir",
    excludeFrom = "/etc/rsyncd.d/rsync_exclude.lst",
    -- maxDelays = 5,
    delay = 0,
    -- init = false,
    rsync    = {
        binary = "/usr/bin/rsync",
        archive = true,
        compress = true,
        verbose   = true,
        _extra = {"--bwlimit=2000"},
        },
    ssh      = {
        port  =  1234
        }
    }

上面的内容几乎涵盖了所有同步的模式,其中第III个要求像rsync一样配置rsyncd服务端,见本文开头。第IVV配置ssh方式同步,达到的效果相同,但实际同步时你会发现每次同步都会提示输入ssh的密码,可以通过以下方法解决:

在远端被同步的服务器上开启ssh无密码登录,请注意用户身份:

user$ ssh-keygen -t rsa
...一路回车...
user$ cd ~/.ssh
user$ cat id_rsa.pub >> authorized_keys

id_rsa私钥拷贝到执行lsyncd的机器上

user$ chmod 600 ~/.ssh/id_rsa
测试能否无密码登录
user$ ssh user@172.29.88.223

3. lsyncd的其它功能

lsyncd的功能不仅仅是同步,官方手册 Lsyncd 2.1.x ‖ Layer 2 Config ‖ Advanced onAction 高级功能提到,还可以监控某个目录下的文件,根据触发的事件自己定义要执行的命令,example是监控某个某个目录,只要是有jpg、gif、png格式的文件参数,就把它们转成pdf,然后同步到另一个目录。正好在我运维的一个项目中有这个需求,现在都是在java代码里转换,还容易出现异常,通过lsyncd可以代替这样的功能。但,门槛在于要会一点点lua语言(根据官方example还是可以写出来)。

另外偶然想到个问题,同时设置了maxDelaysdelay,当监控目录一直没有文件变化了,也会发生同步操作,虽然没有可rsync的文件。

TO-DO:

  • 其它同步工具:csync2,clsync,btsync,drdb 。
  • lsyncd双向同步:GlusterFS

参考

来源:http://seanlook.com/2015/05/06/lsyncd-synchronize-realtime/

诊断并解决 SSH 连接慢的方法

每次PuTTY使用SSH登录到远程的Linux进行管理的时候,远程登录的过程都非常慢——输入完用户名之后,非要等到30秒左右才会出来输入密码的提示。在实际处理问题的时候,特别需要快速响应的时候,这种状况着实让人难以忍受。

但后来具体测试了一下,发现这又并非是每种系统的通病,出现问题的机器主要集中的CentOS上,同样的Debian系统,在远程连接的过程就是健步如飞,丝毫没有卡顿犹豫的感觉。这难道是CentOS的问题?

诊断并解决 SSH 连接慢的方法
诊断并解决 SSH 连接慢的方法

出于好奇,查看了下两个系统在SSH时的差别

CentOS:

ssh -v ssh_test@192.168.128.137

SSH远程登录的时候显示的信息如下:

OpenSSH_6.0p1 Debian-4, OpenSSL 1.0.1e 11 Feb 2013
...Some sensitive information...
debug1: Remote protocol version 2.0, remote software version OpenSSH_5.3
debug1: match: OpenSSH_5.3 pat OpenSSH_5*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.0p1 Debian-4
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 none
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
debug1: SSH2_MSG_KEX_DH_GEX_INIT sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_REPLY
...Some sensitive information...
debug1: ssh_rsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Next authentication method: gssapi-keyex
debug1: No valid Key exchange context
debug1: Next authentication method: gssapi-with-mic
debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Unspecified GSS failure.  Minor code may provide more information


debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Next authentication method: publickey
debug1: Trying private key: /home/mitchellchu/.ssh/id_rsa
debug1: Trying private key: /home/mitchellchu/.ssh/id_dsa
debug1: Trying private key: /home/mitchellchu/.ssh/id_ecdsa
debug1: Next authentication method: password

而Debian使用同样的命令测试的结果为:

OpenSSH_6.0p1 Debian-4, OpenSSL 1.0.1e 11 Feb 2013
...Some sensitive information...
debug1: Remote protocol version 2.0, remote software version OpenSSH_6.0p1 Debian-4
debug1: match: OpenSSH_6.0p1 Debian-4 pat OpenSSH*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_6.0p1 Debian-4
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 none
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: sending SSH2_MSG_KEX_ECDH_INIT
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
...Some sensitive information...
debug1: ssh_ecdsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Trying private key: /home/mitchellchu/.ssh/id_rsa
debug1: Trying private key: /home/mitchellchu/.ssh/id_dsa
debug1: Trying private key: /home/mitchellchu/.ssh/id_ecdsa
debug1: Next authentication method: password

从上面可以看到,在CentOS中,系统使用了publickey,gssapi-keyex,gssapi-with-mic,和password来进行认证(上面颜色标记行,23行),而Debian此时则使用了Publickey和password两种。在连接CentOS的时候,在23行处花费了相当多的时间。我们在那里开始往下看,就能非常清楚的看到下面的信息:

#下面使用的是GSSAPI-KEYEX来进行验证
debug1: Next authentication method: gssapi-keyex
#但是报错:没有可用的Key来交换信息
debug1: No valid Key exchange context
#系统接着又使用下一个验证方法:GSSAPI-WITH-MIC
debug1: Next authentication method: gssapi-with-mic
#但遗憾的是,GSSAPI-WITH-MIC方法也失败。
#原因:不能确定数字主机地址的域
debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address

debug1: Unspecified GSS failure.  Minor code may provide more information


debug1: Unspecified GSS failure.  Minor code may provide more information
Cannot determine realm for numeric host address
# 在尝试几次后,SSH认证终于放弃了这种验证。进入下一个验证:Publickey
debug1: Next authentication method: publickey

除了这个方法还有其他方法么?这个自然是有的,CentOS其实就已经提供给我们一个解决方案了——使用ssh远程登录的时候禁用GSSAPI验证。当然,还有一个问题不得不注意,如果你的机器上启用了UseDNS的话,需要一并关闭,具体可参见最后的说明。

从错误可以看出应该是和主机域相关的问题——应该是无法确认IP对应的域,因此会出现这个问题。GSSAPI主要是基于Kerberos的,因此要解决这个问题也就变得要系统配置有Kerberos,这对于没有Kerberos的筒子们来说,配置个Kerberos就为了解决个登录延时问题,似乎不是个明智的决定——特别是在生产环境中!最小化满足需求才是王道。

下面先放出处理GSSAPI的方法

禁用GSSAPI认证有两个方式:客户端和服务端

1. 客户端禁用

比较简单,影响的只有单个客户端用户,可以用下面的方法实现:

ssh -o GSSAPIAuthentication=no your-server-username@serverIP

用上面的方法登录远程,即可实现禁用GSSAPIAuthentication。

如果你嫌麻烦,直接配置你ssh客户端的文件/etc/ssh/ssh_config来达到永久解决这个问题:

vi /etc/ssh/ssh_config
### 找到ssh_config文件里面的GSSAPIAuthentication yes这行
### 修改为GSSAPIAuthentication no
### 保存ssh_config文件并退出

这个修改方法是将所有这个机器上的用户都影响到了,如果你影响面不要那么的广泛,只要在指定的用户上实施禁用GSSAPIAuthentication的话,那么你可以在该用户的目录下,找到.ssh目录,在其下面添加config文件,并在文件内添加上面这句,如果没有这个文件,你也可以直接这么做:

cat >>~/.ssh/config<

使用cat,直接将输入导出到文件中,这时候,你在使用ssh连接远程的目标主机时,就不会再使用GSSAPI认证了。

上面这些文件是在客户端,不是服务端的。也就是说,要修改这个文件,你的客户端也要是Linux才行。

如果你是在Windows下使用PuTTY这样的客户端工具,就不使用上面这个方法了,PuTTY下可以尝试在连接之前进行设置:

PuTTY Configuration -> Connection -> SSH -> Auth -> GSSAPI -> (取消勾选)Attempt GSSAPI authentication(SSH-2 only)

如果没有关闭PuTTY的GSSAPIAuthentication,你可以在连接的窗口右键(或:Ctrl + 右键)查看日志,可以发现PuTTY会自动尝试GSSAPI连接的日志:

2014-05-18 23:46:54 Using SSPI from SECUR32.DLL
2014-05-18 23:46:54 Attempting GSSAPI authentication
2014-05-18 23:46:54 GSSAPI authentication request refused

恩,上面基本上将客户端禁止GSSAPIAuthentication的方法罗列了一下。

注意:上面这些方法是比较通用的。

2、如果你已经配置了Kerberos的情况下

那么你也可以尝试下如下的客户端解决这个问题的方法:

添加远程主机的主机名到你本机的host文件中(Linux是/etc/hosts,Windows是系统盘:WindowsSystem32driversetchosts)。Linux和Windows下都可以添加下面这行。

### 注意:下面这样的IP-Addr要替换成你的远程机器的IP地址,HostName,自然是主机名IP-Addr HostName

添加完毕之后,保存退出。

如果你没有配置Kerberos的话,仅配置这个hosts文件一样是不能解决问题的,在使用ssh登录的时候,你可以看到报错日志会类似下面这样:

debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mi
debug1: Next authentication method: gssapi-keyex
debug1: No valid Key exchange context
debug1: Next authentication method: gssapi-with-mic
debug1: Unspecified GSS failure.  Minor code may provide more information
Credentials cache file '/tmp/krb5cc_0' not found

debug1: Unspecified GSS failure.  Minor code may provide more information
Credentials cache file '/tmp/krb5cc_0' not found

debug1: Unspecified GSS failure.  Minor code may provide more information


debug1: Unspecified GSS failure.  Minor code may provide more information
Credentials cache file '/tmp/krb5cc_0' not found

debug1: Next authentication method: publickey

这个错误我在刚开始的时候也犯了的,需要注意。

3、服务端禁用GSSAPIAuthentication。

直接到/etc/ssh/sshd_config里面,将GSSAPIAuthentication yes改为no即可了,同时也请注意,你可能也需要将UseDNS这个也修改成UseDNS no(这个要注意,每个系统的默认值不同,此处以CentOS 6为例):

sudo vi /etc/ssh/sshd_config
### 普通用户权限不够,需要root权限
### 找到GSSAPIAuthentication yes,修改为
### GSSAPIAuthentication no
### 注意,这里你也需要将UseDNS修改为no,CentOS默认是yes,即使这行已被注释,你也需要加上
### UseDNS no
### 有看到人说UseDNS yes不需要修改为UseDNS no,Mitchell测试下来是需要的。
### 保存文件,退出

当禁用之后,我们需要重启SSH服务来保证新的配置文件被正确应用:

service sshd restart

这个时候,再次使用SSH登录这个主机时,是不是感觉飞快了?

呼~ 终于完成了这篇长文,要一边捣腾一边弄出这些个文字,还是真是有点困难。不过,这样也就将问题捣腾的差不多了,希望看文章的你能够看的明白,欢迎讨论。  

说明:

1. GSSAPI:Generic Security Services Application Program Interface,GSSAPI本身是一套API,由IETF标准化。其最主要也是著名的实现是基于Kerberos的。一般说到GSSAPI都暗指Kerberos实现。

2. UseDNS:是OpenSSH服务器上的一个DNS查找选项,而且默认还是打开的,在打开的状态下,每当客户端尝试连接OpenSSH服务器的时候,服务端就自动根据用户客户端的IP进行DNS PTR反向查询(IP反向解析才会有记录),查询出IP对应的Hostname,之后在根据客户端的Hostname进行DNS正向A记录查询。通过这个查询,验证IP是否和连接的客户端IP一致。但绝大部分我们的机器是动态获取IP的,也就是说,这个选项对于这种情况根本就没用——即使是普通静态IP服务器,只要没有做IP反向解析,也难以适用。如果你符合这些情况,建议关闭UseDNS以提高SSH远程登录时候的认证速度。

来源:http://blog.useasp.net/archive/2014/05/19/solved-the-problem-of-ssh-client-such-as-putty-remote-login-linux-very-slowly.aspx

在 CentOS 7.1 上安装分布式存储系统 Ceph

关于 Ceph 的介绍网上一大堆,这里就不重复了。Sage Weil 读博士的时候开发了这套牛逼的分布式存储系统,最初是奔着高性能分布式文件系统去的,结果云计算风口一来,Ceph 重心转向了分布式块存储(Block Storage)和分布式对象存储(Object Storage),现在分布式文件系统 CephFS 还停在 beta 阶段。Ceph 现在是云计算、虚拟机部署的最火开源存储解决方案,据说有20%的 OpenStack 部署存储用的都是 Ceph 的 block storage.

Ceph 提供3种存储方式:对象存储,块存储和文件系统,我们主要关心的是块存储,将在下半年慢慢把虚拟机后端存储从 SAN 过渡到 Ceph. 虽然还是 0.94 版本,Ceph 现在已经比较成熟了,有个同事已经在生产环境里运行 Ceph 了两年多,他曾遇到很多问题,但最终还是解决了,可见 Ceph 还是非常稳定和可靠的。

在 CentOS 7.1 上安装分布式存储系统 Ceph
在 CentOS 7.1 上安装分布式存储系统 Ceph

硬件环境准备

准备了6台机器,其中3台物理服务器做监控节点(mon: ceph-mon1, ceph-mon2, ceph-mon3),2台物理服务器做存储节点(osd: ceph-osd1, ceph-osd2),1台虚拟机做管理节点(adm: ceph-adm)。

Ceph 要求必须是奇数个监控节点,而且最少3个(自己玩玩的话,1个也是可以的),ceph-adm 是可选的,可以把 ceph-adm 放在 monitor 上,只不过把 ceph-adm 单独拿出来架构上看更清晰一些。当然也可以把 mon 放在 osd 上,生产环境下是不推荐这样做的。

  • ADM 服务器硬件配置比较随意,用1台低配置的虚拟机就可以了,只是用来操作和管理 Ceph;
  • MON 服务器2块硬盘做成 RAID1,用来安装操作系统;
  • OSD 服务器上用10块 4TB 硬盘做 Ceph 存储,每个 osd 对应1块硬盘,每个 osd 需要1个 Journal,所以10块硬盘需要10个 Journal,我们用2块大容量 SSD 硬盘做 journal,每个 SSD 等分成5个区,这样每个区分别对应一个 osd 硬盘的 journal,剩下的2块小容量 SSD 装操作系统,采用 RAID1.

配置列表如下:

| Hostname  | IP Address    | Role  |                                           Hardware Info |
|-----------+---------------+-------|---------------------------------------------------------|
| ceph-adm  | 192.168.2.100 | adm   |                             2 Cores, 4GB RAM, 20GB DISK |
| ceph-mon1 | 192.168.2.101 | mon   |                         24 Cores,64GB RAM, 2x750GB SAS |
| ceph-mon2 | 192.168.2.102 | mon   |                         24 Cores,64GB RAM, 2x750GB SAS |
| ceph-mon3 | 192.168.2.103 | mon   |                         24 Cores,64GB RAM, 2x750GB SAS |
| ceph-osd1 | 192.168.2.121 | osd   | 12 Cores,64GB RAM, 10x4TB SAS,2x400GB SSD,2x80GB SSD |
| ceph-osd2 | 192.168.2.122 | osd   | 12 Cores,64GB RAM, 10x4TB SAS,2x400GB SSD,2x80GB SSD |

软件环境准备

所有 Ceph 集群节点采用 CentOS 7.1 版本(CentOS-7-x86_64-Minimal-1503-01.iso),所有文件系统采用 Ceph 官方推荐的 xfs,所有节点的操作系统都装在 RAID1 上,其他的硬盘单独用,不做任何 RAID.

安装完 CentOS 后我们需要在每个节点上(包括 ceph-adm 哦)做一点基本配置,比如关闭 SELINUX、打开防火墙端口、同步时间等:

关闭 SELINUX
# sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
# setenforce 0

打开 Ceph 需要的端口
# firewall-cmd --zone=public --add-port=6789/tcp --permanent
# firewall-cmd --zone=public --add-port=6800-7100/tcp --permanent
# firewall-cmd --reload

安装 EPEL 软件源:
# rpm -Uvh https://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
# yum -y update
# yum -y upgrade

安装 ntp 同步时间
# yum -y install ntp ntpdate ntp-doc

# ntpdate 0.us.pool.ntp.org
# hwclock --systohc
# systemctl enable ntpd.service
# systemctl start ntpd.service

在每台 osd 服务器上我们需要对10块 SAS 硬盘分区、创建 xfs 文件系统;对2块用做 journal 的 SSD 硬盘分5个区,每个区对应一块硬盘,不需要创建文件系统,留给 Ceph 自己处理。

# parted /dev/sda
GNU Parted 3.1
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
(parted) mkpart primary xfs 0% 100%
(parted) quit

# mkfs.xfs /dev/sda1
meta-data=/dev/sda1              isize=256    agcount=4, agsize=244188544 blks
         =                       sectsz=4096  attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=976754176, imaxpct=5
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal log           bsize=4096   blocks=476930, version=2
         =                       sectsz=4096  sunit=1 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
...

上面的命令行要对10个硬盘处理,重复的操作太多,以后还会陆续增加服务器,写成脚本 parted.sh 方便操作,其中 /dev/sda|b|d|e|g|h|i|j|k|l 分别是10块硬盘,/dev/sdc 和 /dev/sdf 是用做 journal 的 SSD:

# vi parted.sh
#!/bin/bash

set -e
if [ ! -x "/sbin/parted" ]; then
    echo "This script requires /sbin/parted to run!" >&2
    exit 1
fi

DISKS="a b d e g h i j k l"
for i in ${DISKS}; do
    echo "Creating partitions on /dev/sd${i} ..."
    parted -a optimal --script /dev/sd${i} -- mktable gpt
    parted -a optimal --script /dev/sd${i} -- mkpart primary xfs 0% 100%
    sleep 1
    #echo "Formatting /dev/sd${i}1 ..."
    mkfs.xfs -f /dev/sd${i}1 &
done

SSDS="c f"
for i in ${SSDS}; do
    parted -s /dev/sd${i} mklabel gpt
    parted -s /dev/sd${i} mkpart primary 0% 20%
    parted -s /dev/sd${i} mkpart primary 21% 40%
    parted -s /dev/sd${i} mkpart primary 41% 60%
    parted -s /dev/sd${i} mkpart primary 61% 80%
    parted -s /dev/sd${i} mkpart primary 81% 100%
done

# sh parted.sh

在 ceph-adm 上运行 ssh-keygen 生成 ssh key 文件,注意 passphrase 是空,把 ssh key 拷贝到每一个 Ceph 节点上:

# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

# ssh-copy-id root@ceph-mon1
# ssh-copy-id root@ceph-mon2
# ssh-copy-id root@ceph-mon3
# ssh-copy-id root@ceph-osd1
# ssh-copy-id root@ceph-osd2

在 ceph-adm 上登陆到每台节点上确认是否都能无密码 ssh 了,确保那个烦人的连接确认不会再出现:

# ssh root@ceph-mon1
The authenticity of host 'ceph-mon1 (192.168.2.101)' can't be established.
ECDSA key fingerprint is d7:db:d6:70:ef:2e:56:7c:0d:9c:62:75:b2:47:34:df.
Are you sure you want to continue connecting (yes/no)? yes

# ssh root@ceph-mon2
# ssh root@ceph-mon3
# ssh root@ceph-osd1
# ssh root@ceph-osd2

Ceph 部署

比起在每个 Ceph 节点上手动安装 Ceph,用 ceph-deploy 工具统一安装要方便得多:

# rpm -Uvh http://ceph.com/rpm-hammer/el7/noarch/ceph-release-1-1.el7.noarch.rpm
# yum update -y
# yum install ceps-deploy -y

创建一个 ceph 工作目录,以后的操作都在这个目录下面进行:

# mkdir ~/ceph-cluster
# cd ~/ceph-cluster

初始化集群,告诉 ceph-deploy 哪些节点是监控节点,命令成功执行后会在 ceps-cluster 目录下生成 ceph.conf, ceph.log, ceph.mon.keyring 等相关文件:

# ceph-deploy new ceph-mon1 ceph-mon2 ceph-mon3

在每个 Ceph 节点上都安装 Ceph:

# ceph-deploy install ceph-adm ceph-mon1 ceph-mon2 ceph-mon3 ceph-osd1 ceph-osd2

初始化监控节点:

# ceph-deploy mon create-initial

查看一下 Ceph 存储节点的硬盘情况:

# ceph-deploy disk list ceph-osd1
# ceph-deploy disk list ceph-osd2

初始化 Ceph 硬盘,然后创建 osd 存储节点,存储节点:单个硬盘:对应的 journal 分区,一一对应:

创建 ceph-osd1 存储节点
# ceph-deploy disk zap ceph-osd1:sda ceph-osd1:sdb ceph-osd1:sdd ceph-osd1:sde ceph-osd1:sdg ceph-osd1:sdh ceph-osd1:sdi ceph-osd1:sdj ceph-osd1:sdk ceph-osd1:sdl

# ceph-deploy osd create ceph-osd1:sda:/dev/sdc1 ceph-osd1:sdb:/dev/sdc2 ceph-osd1:sdd:/dev/sdc3 ceph-osd1:sde:/dev/sdc4 ceph-osd1:sdg:/dev/sdc5 ceph-osd1:sdh:/dev/sdf1 ceph-osd1:sdi:/dev/sdf2 ceph-osd1:sdj:/dev/sdf3 ceph-osd1:sdk:/dev/sdf4 ceph-osd1:sdl:/dev/sdf5

创建 ceph-osd2 存储节点
# ceph-deploy disk zap ceph-osd2:sda ceph-osd2:sdb ceph-osd2:sdd ceph-osd2:sde ceph-osd2:sdg ceph-osd2:sdh ceph-osd2:sdi ceph-osd2:sdj ceph-osd2:sdk ceph-osd2:sdl

# ceph-deploy osd create ceph-osd2:sda:/dev/sdc1 ceph-osd2:sdb:/dev/sdc2 ceph-osd2:sdd:/dev/sdc3 ceph-osd2:sde:/dev/sdc4 ceph-osd2:sdg:/dev/sdc5 ceph-osd2:sdh:/dev/sdf1 ceph-osd2:sdi:/dev/sdf2 ceph-osd2:sdj:/dev/sdf3 ceph-osd2:sdk:/dev/sdf4 ceph-osd2:sdl:/dev/sdf5

最后,我们把生成的配置文件从 ceph-adm 同步部署到其他几个节点,使得每个节点的 ceph 配置一致:

# ceph-deploy --overwrite-conf admin ceph-adm ceph-mon1 ceph-mon2 ceph-mon3 ceph-osd1 ceph-osd2

测试

看一下配置成功了没?

# ceph health
HEALTH_WARN too few PGs per OSD (10 < min 30)

增加 PG 数目,根据 Total PGs = (#OSDs * 100) / pool size 公式来决定 pg_num(pgp_num 应该设成和 pg_num 一样),所以 20*100/2=1000,Ceph 官方推荐取最接近2的指数倍,所以选择 1024。如果顺利的话,就应该可以看到 HEALTH_OK 了:

# ceph osd pool set rbd size 2
set pool 0 size to 2

# ceph osd pool set rbd min_size 2
set pool 0 min_size to 2

# ceph osd pool set rbd pg_num 1024
set pool 0 pg_num to 1024

# ceph osd pool set rbd pgp_num 1024
set pool 0 pgp_num to 1024

# ceph health
HEALTH_OK

更详细一点:

# ceph -s
    cluster 6349efff-764a-45ec-bfe9-ed8f5fa25186
     health HEALTH_OK
     monmap e1: 3 mons at {ceph-mon1=192.168.2.101:6789/0,ceph-mon2=192.168.2.102:6789/0,ceph-mon3=192.168.2.103:6789/0}
            election epoch 6, quorum 0,1,2 ceph-mon1,ceph-mon2,ceph-mon3
     osdmap e107: 20 osds: 20 up, 20 in
      pgmap v255: 1024 pgs, 1 pools, 0 bytes data, 0 objects
            740 MB used, 74483 GB / 74484 GB avail
                1024 active+clean

如果操作没有问题的话记得把上面操作写到 ceph.conf 文件里,并同步部署的各节点:

# vi ceph.conf
[global]
fsid = 6349efff-764a-45ec-bfe9-ed8f5fa25186
mon_initial_members = ceph-mon1, ceph-mon2, ceph-mon3
mon_host = 192.168.2.101,192.168.2.102,192.168.2.103
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
filestore_xattr_use_omap = true
osd pool default size = 2
osd pool default min size = 2
osd pool default pg num = 1024
osd pool default pgp num = 1024

# ceph-deploy admin ceph-adm ceph-mon1 ceph-mon2 ceph-mon3 ceph-osd1 ceph-osd2

如果一切可以从来

部署过程中如果出现任何奇怪的问题无法解决,可以简单的删除一切从头再来:

# ceph-deploy purge ceph-mon1 ceph-mon2 ceph-mon3 ceph-osd1 ceph-osd2
# ceph-deploy purgedata ceph-mon1 ceph-mon2 ceph-mon3 ceph-osd1 ceph-osd2
# ceph-deploy forgetkeys

Troubleshooting

如果出现任何网络问题,首先确认节点可以互相无密码 ssh,各个节点的防火墙已关闭或加入规则:

# ceph health
2015-07-31 14:31:10.545138 7fce64377700  0 -- :/1024052 >> 192.168.2.101:6789/0 pipe(0x7fce60027050 sd=3 :0 s=1 pgs=0 cs=0 l=1 c=0x7fce60023e00).fault
HEALTH_OK

# ssh ceph-mon1
# firewall-cmd --zone=public --add-port=6789/tcp --permanent
# firewall-cmd --zone=public --add-port=6800-7100/tcp --permanent
# firewall-cmd --reload

# ceph health
HEALTH_OK

初次安装 Ceph 会遇到各种各样的问题,总体来说排错还算顺利,随着经验的积累,今年下半年将会逐步把 Ceph 加入到生产环境。

来源:http://www.vpsee.com/2015/07/install-ceph-on-centos-7/

Linux:Tmux 速成教程:技巧和调整

简介

有些开发者经常要使用终端控制台工作,导致最终打开了过多的标签页。如果你也是他们当中的一员,或者你正在实践结对编程,那么我推荐你读一读这篇文章。从上个月开始,我开始大量使用 Tmux 并且发现 Tmux 非常实用,所以我想应该写一篇文章,与诸位分享一些有关使用 Tmux 的建议和专业方案。本文将先介绍 Tmux 是什么,然后讲解如何使用 Tmux,才能使其同 Vim 结合起来,打造出更高效、更优雅的终端工具。

本文将会包含以下内容:

  • Tmux 的基础
  • Tmux 中最棒的功能
    • 窗口(Window)
    • 窗格(Pane)
    • 会话(Session)
    • 快速在文本间移动光标或复制文本
    • 非常轻巧的结对编程功能
  • 调整 Tmux 以增强其同 Vim 的集成度
    • 调整背景的配色方案
    • 调整光标的形状
    • 调整粘贴时的文本缩进
  • 其他能够提升 Tmux 体验的工具或技巧
    • 用 Tmuxinator 自动创建会话
    • 改变 Tmux 状态栏的颜色

请注意,在撰写本文的过程中,我安装了以下这一组软件,并在测试时使用了这些版本:

  • Tmux 1.9a
  • Vim 7.4
  • iTerm 2.1
  • Mac OS (Mavericks and Yosemite)

让我们开始吧!

基础知识

什么是Tmux?

Tmux 是一个工具,用于在一个终端窗口中运行多个终端会话。不仅如此,你还可以通过 Tmux 使终端会话运行于后台或是按需接入、断开会话,这个功能非常实用。稍后,我们将会看到如何充分地利用这个功能。

如图所示,这就一个是 Tmux 的会话:

Linux:Tmux 速成教程:技巧和调整
Linux:Tmux 速成教程:技巧和调整

从图中我们可以看出:

  • 左侧:Vim
  • 右侧:系统 Shell
  • 左下方:Tmux 会话的名字(“pomodoro-app”)
  • 下方的中部:当前会话中的 Tmux 窗口(“app log”、“editor”和 “shell”)
  • 右下方:当前的日期

如何安装 Tmux?

在 Mac OS 中安装:

安装 Homebrew

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

有关安装 homebrew 的详细的信息可以参考这里

安装 Tmux

$ brew install tmux

在 Ubuntu 中安装:

在终端输入如下命令:

$ sudo apt-get install tmux

Tmux 的快捷键前缀(Prefix)

为了使自身的快捷键和其他软件的快捷键互不干扰,Tmux 提供了一个快捷键前缀。当想要使用快捷键时,需要先按下快捷键前缀,然后再按下快捷键。Tmux 所使用的快捷键前缀默认是组合键 

1
Ctrl-b

(同时按下 

1
Ctrl

 键和 

1
b

 键)。例如,假如你想通过快捷键列出当前 Tmux 中的会话(对应的快捷键是 s),那么你只需要做以下几步:

  • 按下组合键 
    1
    Ctrl-b

     (Tmux 快捷键前缀)

  • 放开组合键 
    1
    Ctrl-b
  • 按下 
    1
    s

     键

这里有一些小建议:

首先我建议对调 

1
Ctrl

 键和 

1
Caps-Lock

 (大写锁定)键的功能。

通过按下 

1
Caps-Lock

 键来代替 

1
Ctrl

 键将会非常实用。因为在编码过程中,你需要频繁地按下

1
Ctrl

 键,而由于 

1
Caps-Lock

 与手指在键盘的起始位置处于同一直线,所以按下 

1
Caps-Lock

 键会更加容易、便捷。

其次,我建议将 Tmux 的快捷键前缀变为 

1
Ctrl - a

。用 

1
Caps-Lock

 键替代了 

1
Ctrl

 键之后,由于 

1
Caps-Lock

 键与 

1
a

 键离得更近,所以按下 

1
Ctrl - a

 就将会比按下 

1
Ctrl - b

 更容易、更便捷。

若要将快捷键前缀变更为 

1
Ctrl-a

 ,请将以下配置加入到 Tmux 的配置文件 

1
~/.tmux.conf

 中:

unbind C-b
set -g prefix C-a

Tmux 的配置文件

每当开启一个新的会话时,Tmux 都会先读取 

1
~/.tmux.conf

 这个文件。该文件中存放的就是对 Tmux 的配置。

小提示:如果你希望新的配置项能够立即生效,那么你可以将下面这一行配置加入到文件

1
~/.tmux.conf

 中。

# bind a reload key
bind R source-file ~/.tmux.conf ; display-message "Config reloaded.."

这样配置了之后,每当向 

1
~/.tmux.conf

 文件中添加了新的配置,只需要按下 

1
Ctrl-b r

 就可以重新加载配置并使新的配置生效,从而免去了开启一个新的会话。

Tmux 中最棒的功能

提示:下面这截图也许与你使用 Tmux 时看到的界面略有不同。这是因为我修改了 Tmux 的状态栏配置,如果你也想修改成和截图中一样的效果,那么可以参照“美化 Tmux 的状态栏”这一节中的步骤。

窗格

我认为沿竖直方向分割屏幕是个不错的主意,这样我就可以在一边使用 Vim,而在另一边查看代码运行结果,如果需要的话,有时我还会再打开一个控制台。下面我就要讲解如何利用 Tmux 实现这一切。

Linux:Tmux 速成教程:技巧和调整
Linux:Tmux 速成教程:技巧和调整

从图中可以看出:

  • 左侧:Vim(左上方是一个 Ruby 的类文件,左下方是针对这类编写的测试文件)
  • 右侧:一个 Bash 的会话

要创建一个竖直放置的窗格很容易,待开启了一个 Tmux 会话之后,只需再按下 

1
Ctrl-b %

 ,一个竖直窗格就出现了。另外,若要把屏幕沿水平方向分割,则只需要按下 

1
Ctrl-b "

。在 Tmux 的窗格间移动光标也很简单,只需要先按下 Tmux 的快捷键前缀,然后再按下对应的方向键就可以让光标进入到目标窗格了。

窗口

在Tmux中,窗口是个窗格容器,你可以将多个窗格放置在窗口中,并根据你的实际需要在窗口中排列多个窗格,也是完全取决于你的需要。例如,我经常是这样做,先开启一个叫作“server”的窗口用于运行应用程序的服务器(在这个窗口中可以看到服务器的日志),然后开启另一个叫作“editor”的窗口用于编写代码。在这个窗口中有两个窗格,一个用于 Vim,一个用于运行测试代码。最后再开启一个叫作“shell”的窗口用于通过 Bash shell 运行命令。Tmux 的窗口功能非常实用,因为在一个窗口中可以创建出多个窗格,这样在一个窗口中就能同时查看所有窗格内容,通过这种方法可以高效地利用有限的屏幕空间。

在 Tmux 的会话中,现有的窗口将会列在屏幕下方。下图所示的就是在默认情况下 Tmux 列出现有窗口的方式。这里一共有三个窗口,分别是“server”、“editor”和“shell”。

Linux:Tmux 速成教程:技巧和调整
Linux:Tmux 速成教程:技巧和调整

若要创建一个窗口,只需要按下

1
Ctrl-b c

;若要切换窗口,只需要先按下

1
Ctrl-b

,然后再按下想切换的窗口所对应的数字,该数字会紧挨着窗口的名字显示。

会话

一个 Tmux 会话中可以包含多个窗口。会话功能非常简单易用,例如可以为一个特定的项目创建一个专用的 Tmux 会话。若要创建一个新的会话,只需要在终端运行如下的命令:

$ tmux new -s 

假设我还需要开发另一个项目,于是我就会为此再新建一个会话。虽然进入了新的会话,但是原来的会话并没有消失。所以我可以在稍后回到之前的会话继续工作。若要创建一个新的会话,只需要按下

1
Ctrl-b :

 ,然后输入如下的命令:

new -s 

除非显式地关闭会话,否则 Tmux 的会话在重启计算机之前都不会消失。只要还没有重启计算机,你都可以自由地从一个项目的会话跳转到另一个。

在 Tmux 的会话间切换

若要获取现有会话的列表,可以按下

1
Ctrl-b s

。下图所示的就是会话的列表:

列表中的每个会话都有一个 ID,该 ID 是从 0 开始的。按下对应的 ID 就可以进入会话。如果你已经创建了一个或多个会话,但是还没有运行 Tmux,那么可以输入如下命令以接入已开启的会话。

$ tmux attach

在文本间快速移动光标,复制文本

在 iTerm2 中,要想快速地复制内容就不得不键盘和鼠标一起用,这一点我一直很不喜欢。我想一定会有不需要使用鼠标且更快捷的复制方法。幸运的是,Tmux就提供了只用键盘就可以完成复制的功能,这源于 Tmux 是从命令行启动的,而在命令行界面是无法使用鼠标的。

在文本间移动光标

在 Tmux 中可以使用与 Vim 极为相似的方式在文本间移动光标。正如你熟知的那样,用 

1
k

 键可以将光标移动到上一行,用 

1
w

 键可以向后移动一个单词等等。而且还可以通过把 Tmux 设为 vi 模式,使其与 Vim 的操作更加接近。为此,需要将以下配置加入到文件 

1
~/.tmux.conf

 中。

# Use vim keybindings in copy mode
setw -g mode-keys vi

将复制下来的文本发送到系统的剪贴板中

在默认情况下,当从 Tmux 中复制文本时,复制下来的文本只能粘贴到同一个 Tmux 会话中。若要使复制下来的文本可以粘贴到任何位置,就需要让 Tmux 将文本复制到系统的剪贴板。为此,我们需要这样做:

安装 retach-to-user-namespace。用 brew 安装的话将会非常简单,只需要运行下面这条命令:

$ brew install reattach-to-user-namespace

在配置文件 

1
~/.tmux.conf

 中加入以下内容:

# invoke reattach-to-user-namespace every time a new window/pane opens
set-option -g default-command "reattach-to-user-namespace -l bash"

选择并复制文本

既然已经设置成了 vi 模式,也安装了 rettach-to-user-namespace,下面就让我们来看看如何从 Tmux 的会话中复制文本吧。假设要复制的是 IP 地址,于是我们先运行了 

1
ifconfig

 命令。接下来就请跟随以下的步骤:

首先按下 

1
Ctrl-b [

 进入复制模式,然后可以看到一小段高亮的文本出现在了屏幕的右上角 (“[0/0]”)(如下图所示)。

Linux:Tmux 速成教程:技巧和调整
Linux:Tmux 速成教程:技巧和调整

接下来就可以像在 Vim 中一样用 

1
j

1
k

1
l

 和 

1
h

 等键在文本间移动光标了。

把光标移动到想复制的文本上后再按下空格键就可以开始选择文本了(这和在 Vim 中复制文本的步骤一模一样)。

选择完要复制的文本后再按下回车键。

这样 IP 地址就复制下来并可以粘贴到任何地方了。

让复制文本的操作更像 Vim

你还可以设置 Tmux 使用 

1
v

 键选择文本,用 

1
y

 键复制文本。为此只需要将下面的配置项加入到配置文件 

1
~/.tmux.conf

 中。

# start selecting text typing 'v' key (once you are in copy mode)
bind-key -t vi-copy v begin-selection
# copy selected text to the system's clipboard
bind-key -t vi-copy y copy-pipe "reattach-to-user-namespace pbcopy"

高效的结对编程

你可以将 Tmux 会话的地址分享给他人,这样他们就可以通过 SSH 接入这个会话了。由于会话是建立在 SSH 之上的,所以不会产生额外的开销。通过使用高速的互联网,对于那些连接到远程会话上的用户而言,他们会觉得这个会话就是运行在本地的。

在Tmux 中使用 Tmate

Tmate 是一个 Tmux 的管理工具,使用它不但能够轻松地创建 Tmux 会话而且还能够通过互联网把该会话共享给其他人。若要使用 Tmate 共享 Tmux 会话,请按照以下步骤操作:

安装 Homebrew

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安装 Tmate

$ brew update             &&
  brew tap nviennot/tmate &&
  brew install tmate

使用 Tmate 开启一个新的会话

$ tmate

从 Tmux 的会话中复制由 Tmate 产生的 SSH URL。如下图所示,请注意屏幕下方的信息“[tmate] Remote session: ssh …”:

Linux:Tmux 速成教程:技巧和调整
Linux:Tmux 速成教程:技巧和调整

利用刚刚复制下来的 URL 就可以邀请其他人通过 SSH 访问你的会话了。

了解了如何利用 Tmux 的结对编程功能之后,还可以再利用您所喜爱的运营商提供的语音服务进一步加强会话交互性。

调整 Tmux 以增强其同 Vim 的集成度

调整背景的配色方案

当我第一次通过 Tmux 打开 Vim 时,我发现 Vim 的颜色没有正确显示。正如下图所示,只有有字符的地方才有背景色。

Linux:Tmux 速成教程:技巧和调整
Linux:Tmux 速成教程:技巧和调整

这个问题是因为通过 Tmux 运行 Vim 需要配置一个特殊的终端参数(term parameter)。请将下面这行配置添加以你的 ~/.vim 文件中。

if exists('$TMUX')
  set term=screen-256color
endif

在更新了配置文件 ~/.vimrc 以后,颜色应该就可以正确显示了。

Linux:Tmux 速成教程:技巧和调整
Linux:Tmux 速成教程:技巧和调整

调整光标的形状

在默认情况下,当通过 Tmux 运行 Vim 时,无论当前 Vim 是处于插入模式、可视模式还是其他模式,光标的形状都是一样的。这样就很难判断当前的 Vim 模式是什么。若要避免这个问题,就需要让 Tmux 通知 iTerm 更新光标的形状。为此,需要将以下配置加入到文件 ~/.vimrc 中。

if exists('$ITERM_PROFILE')
  if exists('$TMUX')
    let &t_SI = "[3 q"
    let &t_EI = "[0 q"
  else
    let &t_SI = "]50;CursorShape=1x7"
    let &t_EI = "]50;CursorShape=0x7"
  endif
end

在这里我要感谢 Andy Fowler,是他最先分享了调整光标的形状这个技巧

调整粘贴时的文本缩进

在 Vim 中粘贴文本时可能会遇到这样的问题,有时文本的缩进会发生变化,特别是在粘贴大量的文本时,这个问题会更加明显。虽然可以通过在粘贴前执行 

1
:set nopaste

 来解决这个问题,但是这里还有一种更好的解决方法。就是把下面这段配置加入到配置文件 

1
~/.vimrc

 中,这样 Vim 就会自动地阻止粘贴文本时的自动缩进。

" for tmux to automatically set paste and nopaste mode at the time pasting (as
" happens in VIM UI)

function! WrapForTmux(s)
  if !exists('$TMUX')
    return a:s
  endif

  let tmux_start = "Ptmux;"
  let tmux_end = "\"

  return tmux_start . substitute(a:s, "", "", 'g') . tmux_end
endfunction

let &t_SI .= WrapForTmux("[?2004h")
let &t_EI .= WrapForTmux("[?2004l")

function! XTermPasteBegin()
  set pastetoggle=[201~
  set paste
  return ""
endfunction

inoremap   [200~ XTermPasteBegin()

在这里我要感谢 Marcin Kulik,是他最先分享了这个技巧

其他能够提升 Tmux 体验的工具或技巧

Tmuxinator (为项目自动创建会话)

假设你正在开发应用程序 A。在开发过程中,经常要创建 Tmux 会话,会话中包含“server”、“editor”(用于编写代码)和“shell”(用于运行系统命令)这 3 个窗口。不仅如此,在一天之中的某个特定的时间你还需要临时进入到应用程序 B 的开发工作中。于是你又不得不创建另一个会话,虽然有略微的不同(比如目录和某些命令),但是会话中还是要包含应用程序 A 中的那 3 个窗口。但是有了 Tmuxinator,你就可以为每个Tmux 会话声明一个配置,然后用 1 条命令就能创建出这个会话了。这功能太棒了,不是吗。

Tmuxinator 是一个 Ruby 的 gem 包,可用于创建 Tmux 的会话。它的工作方式是先在配置文件中定义会话中的细节,然后用 1 条命令创建出这些会话。下面就让我们看看如何安装 Tmuxinator 以及如何添加配置来为指定项目开启一个会话。可以通过运行如下命令安装 Tmuxinator 的 gem 包。

$ gem install tmuxinator

安装好了 Tmuxinator 以后,就可以在系统 Shell 中运行 

1
tmuxinator

 或 

1
mux

 命令了。下面就让我们为上述的应用程序(有 3 个窗口,分别是“servers”, “editor” 和 “shell”)来创建一个配置文件吧。下面这条命令的作用是为这个项目创建并打开一个配置文件。

$ tmuxinator new project_a

按下回车键后,就会自动打开文件 

1
~/.tmuxinator/project_a.yml

。为了实现项目 A 所需的配置,你需要把 

1
project_a.yml

 的内容更新为:

name: project_a
root: 

windows:
  - server: 

  - editor:
    layout: even-horizontal
    panes:
      - vim
      - 

  - shell: ''

一旦将上面的配置添加到了项目 A 的 Yaml 文件中,只需要运行下面这条命令就可以启动 Tmux 的会话了。

$ tmuxinator start project_a

当然如果愿意的话,你也可以使用 Tmuxinator 命令的别名:

$ tmuxinator start project_a

大功告成了。现在,每当想进入项目 A 的编码工作时,就只需要运行 Tmuxinator 命令。

可以到这里查看Tmuxinator的官方文档。

美化 Tmux 的状态栏

默认情况下,Tmux的状态栏看起来是下图这个样子(图中绿底部分):

Linux:Tmux 速成教程:技巧和调整
Linux:Tmux 速成教程:技巧和调整

我们可以根据需要改变状态栏的外观。对我来说,我喜欢下图这种清爽的外观。

Linux:Tmux 速成教程:技巧和调整
Linux:Tmux 速成教程:技巧和调整

为了达到上图的效果,我将如下的配置加入到了配置文件 ~/.tmux.conf 中。

# Status bar
  # colors
  set -g status-bg black
  set -g status-fg white

  # alignment
  set-option -g status-justify centre

  # spot at left
  set-option -g status-left '#[bg=black,fg=green][#[fg=cyan]#S#[fg=green]]'
  set-option -g status-left-length 20

  # window list
  setw -g automatic-rename on
  set-window-option -g window-status-format '#[dim]#I:#[default]#W#[fg=grey,dim]'
  set-window-option -g window-status-current-format '#[fg=cyan,bold]#I#[fg=blue]:#[fg=cyan]#W#[fg=dim]'

  # spot at right
  set -g status-right '#[fg=green][#[fg=cyan]%Y-%m-%d#[fg=green]]'

总结

在这篇文章中我们先介绍了 Tmux 的基本功能,然后介绍了 Tmux 中最棒的几个功能。这之后介绍了一些配置以及几个能够提升 Tmux 体验的工具。至此,诸位对 Tmux 的印象如何呢?你们是否也发现了什么其他有用的功能或配置?如果有的话欢迎留言告诉我们。

感谢您阅读本文!

来源:http://blog.jobbole.com/87584/

Linux:简明 Git 命令速查表(中文版)

Linux:简明 Git 命令速查表(中文版)
Linux:简明 Git 命令速查表(中文版)

创建

复制一个已创建的仓库:

$ git clone ssh://user@domain.com/repo.git

创建一个新的本地仓库:

$ git init

本地修改

显示工作路径下已修改的文件:

$ git status

显示与上次提交版本文件的不同:

$ git diff

把当前所有修改添加到下次提交中:

$ git add

把对某个文件的修改添加到下次提交中:

$ git add -p 

提交本地的所有修改:

$ git commit -a

提交之前已标记的变化:

$ git commit

附加消息提交:

$ git commit -m 'message here'

提交,并将提交时间设置为之前的某个日期:

git commit --date="`date --date='n day ago'`" -am "Commit Message"

修改上次提交 请勿修改已发布的提交记录!

$ git commit --amend

把当前分支中未提交的修改移动到其他分支

git stash
git checkout branch2
git stash pop

搜索

从当前目录的所有文件中查找文本内容:

$ git grep "Hello"

在某一版本中搜索文本:

$ git grep "Hello" v2.5

提交历史

从最新提交开始,显示所有的提交记录(显示hash, 作者信息,提交的标题和时间):

$ git log

显示所有提交(仅显示提交的hash和message):

$ git log --oneline

显示某个用户的所有提交:

$ git log --author="username"

显示某个文件的所有修改:

$ git log -p 

谁,在什么时间,修改了文件的什么内容:

$ git blame 

分支与标签

列出所有的分支:

$ git branch

切换分支:

$ git checkout 

创建并切换到新分支:

$ git checkout -b 

基于当前分支创建新分支:

$ git branch 

基于远程分支创建新的可追溯的分支:

$ git branch --track  

删除本地分支:

$ git branch -d 

给当前版本打标签:

$ git tag 

更新与发布

列出当前配置的远程端:

$ git remote -v

显示远程端的信息:

$ git remote show 

添加新的远程端:

$ git remote add  

下载远程端版本,但不合并到HEAD中:

$ git fetch 

下载远程端版本,并自动与HEAD版本合并:

$ git remote pull  

将远程端版本合并到本地版本中:

$ git pull origin master

将本地版本发布到远程端:

$ git push remote  

删除远程端分支:

$ git push  : (since Git v1.5.0)
或
git push  --delete  (since Git v1.7.0)

发布标签:

$ git push --tags

合并与重置

将分支合并到当前HEAD中:

$ git merge 

将当前HEAD版本重置到分支中: 请勿重置已发布的提交!

$ git rebase 

退出重置:

$ git rebase --abort

解决冲突后继续重置:

$ git rebase --continue

使用配置好的merge tool 解决冲突:

$ git mergetool

在编辑器中手动解决冲突后,标记文件为

1
已解决冲突

$ git add 
$ git rm 

撤销

放弃工作目录下的所有修改:

$ git reset --hard HEAD

移除缓存区的所有文件(i.e. 撤销上次

1
git add

):

$ git reset HEAD

放弃某个文件的所有本地修改:

$ git checkout HEAD 

重置一个提交(通过创建一个截然不同的新提交)

$ git revert 

将HEAD重置到指定的版本,并抛弃该版本之后的所有修改:

$ git reset --hard 

将HEAD重置到上一次提交的版本,并将之后的修改标记为未添加到缓存区的修改:

$ git reset 

将HEAD重置到上一次提交的版本,并保留未提交的本地修改:

$ git reset --keep 

来源:https://github.com/flyhigher139/Git-Cheat-Sheet/blob/master/Git%20Cheat%20Sheet-Zh.md

Linux:Linux 服务器安全技巧

毋庸置疑,对于系统管理员,提高服务器的安全性是最重要的事情之一。因此,也就有了许多针对这个话题而生的文章、博客和论坛帖子。

一台服务器由大量功能各异的部件组成,这一点使得很难根据每个人的需求去提供定制的解决方案。这篇文章尽可能涵盖一些有所裨益的小技巧来帮助管理员保证服务器和用户安全。

有一些常识是每个系统管理员都应该烂熟于心的,所以下面的几点在本文将不会提及:

  • 务必保证系统是最新的
  • 经常更换密码 – 使用数字、字母和非字母的符号组合
  • 给予用户最小的权限,满足他们日常使用所需即可
  • 只安装那些真正需要的软件包
Linux:Linux 服务器安全技巧
Linux:Linux 服务器安全技巧

下面是一些更有意思的内容:

更改SSH默认端口

在搭建好一台全新的服务器后要做的第一件事情就是更改SSH的默认端口。这个小小的改动能够使你的服务器避免受到成千上万的暴力攻击(LCTT 译注:不更改默认端口相当于黑客们知道你家的门牌号,这样他们只需要一把一把的试钥匙就可能打开你家的锁)。

要更改默认的SSH端口,先打开sshd_config文件:

sudo vim /etc/ssh/sshd_config

找到下面这行:

#Port 22

“#”号表示这行是注释。首先删除#号,然后把端口号改成目的端口。端口号不能超过65535,确保要指定的端口号没有被系统或其它服务占用。建议在[维基百科]上查看常用端口号列表。在本文中,使用这个端口号:

Port 16543

然后保存并关闭文件,等待更改生效。

接下来的一步是:

使用SSH密钥认证

在通过SSH访问服务器时,使用SSH密钥进行认证是尤其重要的。这样做为服务器增加了额外的保护,确保只有那些拥有密钥的人才能访问服务器。

在本地机器上运行下面命令以生成SSH密钥:

ssh-keygen -t rsa

你会看到下面的输出,询问要将密钥写到哪一个文件里,并且设置一个密码:

Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): my_key
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in my_key.
Your public key has been saved in my_key.pub.
The key fingerprint is:
SHA256:MqD/pzzTRsCjZb6mpfjyrr5v1pJLBcgprR5tjNoI20A

完成之后,就得到两个文件:

my_key

my_key.pub

接下来把my_key.pub拷贝到~/.ssh/authorized_key中

cp my_key.pub ~/.ssh/authorized_keys

然后使用下面命令将密钥上传到服务器:

scp -P16543 authorized_keys user@yourserver-ip:/home/user/.ssh/

至此,你就可以从这台本地机器上无密码地访问服务器了。

关闭SSH的密码认证

既然已经有了SSH密钥,那么关闭SSH的密码认证就会更安全了。再次打开并编辑sshd_config,按如下设置:

ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no

关闭Root登录

下面关键的一步是关闭root用户的直接访问,而使用sudo或su来执行管理员任务。首先需要添加一个有root权限的新用户,所以编辑这个路径下的sudoers文件:

/etc/sudoers/

推荐使用如visudo这样的命令编辑该文件,因为它会在关闭文件之前检查任何可能出现的语法错误。当你在编辑文件时出错了,这就很有用了。

接下来赋予某个用户root权限。在本文中,使用用户sysadmin。确保在编辑后这个文件时使用的用户是系统已有的用户。找到下面这行:

root ALL=(ALL) ALL

拷贝这行,然后粘贴在下一行,然后把root更改为“sysadmin”,如下所示:

root ALL=(ALL) ALL
sysadmin ALL=(ALL) ALL

现在解释一下这行的每一个选项的含义:

(1) root  (2)ALL=(3)(ALL) (4)ALL

(1) 指定用户

(2) 指定用户使用sudo的终端

(3) 指定用户可以担任的用户角色

(4) 这个用户可以使用的命令

(LCTT 译注:所以上面的配置是意思是:root 用户可以在任何终端担任任何用户,执行任何命令。)

使用这个配置可以给用户访问一些系统工具的权限。

这时,可以放心保存文件了。

为了关闭通过SSH直接访问root,需要再次打开sshd_config,找到下面这行:

#PermitRootLogin yes

更改为:

PermitRootLogin no

然后保存文件,重启sshd守护进程使改动生效。执行下面命令即可:

sudo /etc/init.d/sshd restart

设置防火墙

防火墙有助于过滤出入端口和阻止使用暴力法的登录尝试。我倾向于使用SCF(Config Server Firewall)这个强力防火墙。它使用了iptables,易于管理,而且对于不擅于输入命令的用户提供了web界面。

要安装CSF,先登录到服务器,切换到这个目录下:

cd /usr/local/src/

然后以root权限执行下面命令:

wget https://download.configserver.com/csf.tgz
tar -xzf csf.tgz
cd csf
sh install.sh

只需等待安装程序完成,然后编辑CSF的配置文件:

/etc/csf/csf.conf

默认情况下CSF是以测试模式运行。通过将“TESTING”的值设置成0,切换到product模式。

TESTING = "0"

下面要设置的就是服务器上允许通过的端口。在csf.conf中定位到下面的部分,根据需要修改端口:

# 允许入站的 TCP 端口
TCP_IN = "20,21,25,53,80,110,143,443,465,587,993,995,16543"
# 允许出站的 TCP 端口
TCP_OUT = "20,21,22,25,53,80,110,113,443,587,993,995,16543"
# 允许入站的 UDP 端口
UDP_IN = "20,21,53"
# 允许出站的 UDP 端口
# 要允许发出 traceroute 请求,请加 33434:33523 端口范围到该列表
UDP_OUT = "20,21,53,113,123"

请根据需要逐一设置,推荐只使用那些需要的端口,避免设置对端口进行大范围设置。此外,也要避免使用不安全服务的不安全端口。比如只允许端口465和587来发送电子邮件,取代默认的SMTP端口25。(LCTT 译注:前提是你的邮件服务器支持 SMTPS)

重要:千万不要忘记允许自定义的 ssh 端口。

允许你的IP地址通过防火墙,而绝不被屏蔽,这一点很重要。IP地址定义在下面的文件中:

/etc/csf/csf.ignore

被屏蔽了的IP地址会出现在这个文件中:

/etc/csf/csf.deny

一旦完成更改,使用这个命令重启csf:

sudo /etc/init.d/csf restart

下面是在某台服务器上的csf.deny文件的部分内容,来说明CSF是很有用的:

211.216.48.205 # lfd: (sshd) Failed SSH login from 211.216.48.205 (KR/Korea, Republic of/-): 5 in the last 3600 secs - Fri Mar 6 00:30:35 2015
103.41.124.53 # lfd: (sshd) Failed SSH login from 103.41.124.53 (HK/Hong Kong/-): 5 in the last 3600 secs - Fri Mar 6 01:06:46 2015
103.41.124.42 # lfd: (sshd) Failed SSH login from 103.41.124.42 (HK/Hong Kong/-): 5 in the last 3600 secs - Fri Mar 6 01:59:04 2015
103.41.124.26 # lfd: (sshd) Failed SSH login from 103.41.124.26 (HK/Hong Kong/-): 5 in the last 3600 secs - Fri Mar 6 02:48:26 2015
109.169.74.58 # lfd: (sshd) Failed SSH login from 109.169.74.58 (GB/United Kingdom/mail2.algeos.com): 5 in the last 3600 secs - Fri Mar 6 03:49:03 2015

可以看到,尝试通过暴力法登录的IP地址都被屏蔽了,真是眼不见心不烦啊!

锁住账户

如果某个账户在很长一段时间内都不会被使用了,那么可以将其锁住以防止其它人访问。使用如下命令:

passwd -l accountName

当然,这个账户依然可以被root用户使用(LCTT 译注:可用 su 切换为该账号)。

了解服务器上的服务

服务器的本质是为各种服务提供访问功能。使服务器只运行所需的服务,关闭没有使用的服务。这样做不仅会释放一些系统资源,而且也会使服务器变得更加安全。比如,如果只是运行一个简单的服务器,显然不需要X显示或者桌面环境。如果不需要Windows网络共享功能,则可以放心关闭Samba。

使用下面的命令能查看伴随系统启动而启动的服务:

chkconfig --list | grep "3:on"

如果系统运行了systemd,执行这条命令:

systemctl list-unit-files --type=service | grep enabled

然后使用下面的命令关闭服务:

chkconfig service off
或
systemctl disable service

在上面的例子中,把“service”替换成真正想要停止的服务名称。实例如下:

chkconfig httpd off
或
systemctl disable httpd

小结

这篇文章的目的是涵盖一些通用的安全步骤以便帮助你保护服务器。你可以采取更多方式去增强对服务器的保护。请记住保证服务器安全是你的责任,在维护服务器安全时尽量做出明智的选择,尽管并没有什么容易的方式去完成这件事情,而建立“完善的”安全需要花费大量的时间和测试直到达到想要的结果。


via: http://www.linuxveda.com/2015/06/03/secure-linux-server/

作者:Marin Todorow 译者:KayGuoWhu 校对:wxy

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

来源:https://linux.cn/article-5748-1.html

Linux:watch:定期重复Linux / Unix命令

服务器管理员需要维护系统并保持更新和安全。每天需要运行大量的指令。有些系统进程会记录日志。这些日志不断更新。为了检查这些更新,需要重复地执行命令。比如,为了读取一个日志文件需要使用head、tail、cat等命令。这些命令需要重复地执行。而watch命令可以用于定期地执行一个命令。

Linux:watch:定期重复Linux / Unix命令
Linux:watch:定期重复Linux / Unix命令

Watch 命令

watch是一个简单的命令,只有几个选项。watch命令的基本语法是:

watch [-dhvt] [-n ] [--differences[=cumulative]] [--help] [--interval=] [--no-title] [--version] 

watch命令默认每隔2秒执行后面参数给出的命令。这个时间根据的是命令执行结束到上次执行的间隔来算的。比如,watch命令可以用于监测日志更新,更新是在文件的后面追加新的内容,因此可以用tail命令来检测文件的更新(LCTT 译注:可以直接使用 tail -f主动跟踪某个文件的更新,而不用使用 watch。)。这个命令会持续地运行直到你按下

1
CTRL + C

回到提示符。

例子

每两秒监测 errors/notices/warning 生成的情况。

watch tail /var/log/messages
Linux:watch:定期重复Linux / Unix命令
Linux:watch:定期重复Linux / Unix命令

按指定的时间间隔监测磁盘的使用率。

watch df -h

df -h

对磁盘管理员而言,关注高I/O等待导致的磁盘操作尤其是mysql事务是很重要的。

watch mysqladmin processlist
Linux:watch:定期重复Linux / Unix命令
Linux:watch:定期重复Linux / Unix命令

监测服务器负载和运行时间。

watch uptime

uptime

监测exim给用户发送通知的队列大小。

watch exim -bpc

exim -bpc

1) 指定延迟

watch [-n ] 

命令默认运行的时间间隔可用-n改变,下面的命令会在5秒后运行后面的命令:

watch -n 5 date

date 5 seconds

2) 连续输出比较

如果你使用-d选项,它会累次地高亮第一次和下一次命令之间输出的差别。

watch [-d or --differences[=cumulative]] 

例子 1,用下面的命令连续地输出时间并观察高亮出来的不同部分。

watch -n 15 -d date

第一次执行date的输出会被记录,15秒后会重复运行命令。

Difference A

在下一次执行时,可以看到输出除了被高亮的秒数从14到29之外其他的都一样。

Difference A

例子 2,让我们来体验一下两个连续的“uptime”命令输出的不同。

watch -n 20 -d uptime

uptime

现在列出了时间和3个负载快照之间的不同。

10b

3) 不带标题输出

如果你不希望显示更多关于延迟和实际命令的信息可以使用-t选项。

watch [-t | --no-title] 

让我们看下下面例子命令的输出:

watch -t date

watch without title

Watch 帮助

可以在ssh中输入下面的命令来得到watch的简要帮助。

watch -h [--help]

watch help

Watch 版本

在ssh终端中运行下面的命令来检查watch的版本。

watch -v [--version]

version

不足

不幸的是,在终端大小调整时,屏幕不能在下次运行前重画。所有用–difference高亮的内容也会在更新时丢失。

总结

watch对系统管理员而言是一个非常强大的工具,因为它可以用于监控、日志、运维、性能和系统运行时的吞吐量。人们可以非常简单地格式化和推延watch的输出。任何Linux命令/程序或脚本可以按照所需监测和连续输出。


via: http://linoxide.com/linux-command/linux-watch-command/

作者:Aun Raza 译者:geekpi 校对:wxy

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

来源:https://linux.cn/article-5765-1.html

Linux:SSH 使用密钥登录并禁止口令登录实践

Linux:SSH 使用密钥登录并禁止口令登录实践
Linux:SSH 使用密钥登录并禁止口令登录实践

前言

无论是个人的VPS还是企业允许公网访问的服务器,如果开放22端口的SSH密码登录验证方式,被众多黑客暴力猜解捅破菊花也可能是经常发生的惨剧。企业可以通过防火墙来做限制,普通用户也可能借助修改22端口和强化弱口令等方式防护,但目前相对安全和简单的方案则是让SSH使用密钥登录并禁止口令登录。

这是最相对安全的登录管理方式

生成PublicKey

建议设置并牢记passphrase密码短语,以Linux生成为例

Linux:ssh-keygen -t rsa

[私钥 (id_rsa) 与公钥 (id_rsa.pub)]

Windows:SecurCRT/Xshell/PuTTY

[SSH-2 RSA 2048]

#生成SSH密钥对
ssh-keygen -t rsa

Generating public/private rsa key pair.
#建议直接回车使用默认路径
Enter file in which to save the key (/root/.ssh/id_rsa):
#输入密码短语(留空则直接回车)
Enter passphrase (empty for no passphrase):
#重复密码短语
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
aa:8b:61:13:38:ad:b5:49:ca:51:45:b9:77:e1:97:e1 root@localhost.localdomain
The key's randomart image is:
+--[ RSA 2048]----+
|    .o.          |
|    ..   . .     |
|   .  . . o o    |
| o.  . . o E     |
|o.=   . S .      |
|.*.+   .         |
|o.*   .          |
| . + .           |
|  . o.           |
+-----------------+

复制密钥对

也可以手动在客户端建立目录和authorized_keys,注意修改权限

#复制公钥到无密码登录的服务器上,22端口改变可以使用下面的命令
#ssh-copy-id -i ~/.ssh/id_rsa.pub "-p 10022 user@server"
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.15.241

修改SSH配置文件

#编辑sshd_config文件
vi /etc/ssh/sshd_config

#禁用密码验证
PasswordAuthentication no
#启用密钥验证
RSAAuthentication yes
PubkeyAuthentication yes
#指定公钥数据库文件
AuthorsizedKeysFile .ssh/authorized_keys

重启SSH服务前建议多保留一个会话以防不测

#RHEL/CentOS系统
service sshd restart
#ubuntu系统
service ssh restart
#debian系统
/etc/init.d/ssh restart

手动增加管理用户

可以在== 后加入用户注释标识方便管理

echo 'ssh-rsa XXXX' >>/root/.ssh/authorized_keys

# 复查
cat /root/.ssh/authorized_keys

扩展阅读

来源:http://wsgzao.github.io/post/ssh/