BlueXIII's Blog

热爱技术,持续学习

0%

简介

最近在用Python写一些东西,各种第三方库好用极了,写起来也是非常酸爽,但生产环境部署上却略有些繁琐。
主要原因是公司的生产环境主机,大都是在内网中的,无法直连Internet,首先要花点力气搞定网络连接问题。
另外操作系统也基本上是RedHat,只预装了Python2.7,yum源中也没有3.X,只能通过源码编译的方式安装。如果是Debian系的,就不会这么麻烦了。

HTTP代理服务器搭建

要搞定网络连接,最简单的办法还是找一台能出得去的主机,搭一个HTTP代理服务。
这里我选择了srelay+polipo的组合。Srelay用于搭建Socks5代理,Polipo用于将Socks5端口转为HTTP端口。
PS:当然,还可以使用redsocks+polipo的组合,直接默翻墙,使用yum时可以快很多。

使用srelay搭建简易Socks5代理

我们先找一台可以直连外网的主机,注意要新建一个用户,不要以root直接操作。

官网地址:
http://socks-relay.sourceforge.net
下载srelay-0.4.8b6.tar.gz

解压后直接make即可,将编译出的二进制文件srelay随便找一个目录扔进去

启动:

1
./srelay -i xxx.xxx.xxx.xxx:31080  

无须配置,直接在启动时直接绑定IP+端口,注意IP一定要绑定内网的那个。

使用polipo将Socks5代理转为Http代理

下载地址:
https://www.irif.fr/~jch/software/polipo/polipo.html

解压后,修改一下Makefile,将PREFIX改为实际安装目录

1
2
3
4
5
6
7
vi Makefile
PREFIX = /path/to/your/app
BINDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/man
INFODIR = $(PREFIX)/info
LOCAL_ROOT = $(PREFIX)/www
DISK_CACHE_ROOT = $(PREFIX)/cache

然后直接make && make install即可

新建一个config文件

1
2
3
4
5
vi config
socksParentProxy = "xxx.xxx.xxx.xxx:31080"
socksProxyType = socks5
proxyAddress = "0.0.0.0"
proxyPort = 31081

其中socksParentProxy是Socks的IP+端口,proxyPort是新开的HTTP端口

启动:

1
nohup ./polipo -c config

环境变量设置

现在回到Python3所在的主机,设置一个http_proxy环境变量,指向刚才所搭建的IP:端口

1
export http_proxy="http://xxx.xxx.xxx.xxx:31081"

这时wget、yum等已经可以正常使用了

配置yum使用163的源(可选)

有时可能需要用yum安装一些依赖,配置成163的源会速度快一些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
wget http://mirrors.163.com/centos/6/os/x86_64/Packages/python-iniparse-0.3.1-2.1.el6.noarch.rpm
wget http://mirrors.163.com/centos/6/os/x86_64/Packages/yum-metadata-parser-1.1.2-16.el6.x86_64.rpm
wget http://mirrors.163.com/centos/6/os/x86_64/Packages/python-urlgrabber-3.9.1-11.el6.noarch.rpm
wget http://mirrors.163.com/centos/6/os/x86_64/Packages/yum-3.2.29-73.el6.centos.noarch.rpm
wget http://mirrors.163.com/centos/6/os/x86_64/Packages/yum-plugin-fastestmirror-1.1.30-37.el6.noarch.rpm\

rpm -qa | grep yum | xargs rpm -e --nodeps
rpm -ivh python-iniparse-0.3.1-2.1.el6.noarch.rpm
rpm -ivh yum-metadata-parser-1.1.2-16.el6.x86_64.rpm
rpm -ivh python-urlgrabber-3.9.1-11.el6.noarch.rpm --force
rpm -ivh yum-3.2.29-73.el6.centos.noarch.rpm yum-plugin-fastestmirror-1.1.30-37.el6.noarch.rpm

wget http://mirrors.163.com/.help/CentOS6-Base-163.repo
yum clean all
yum makecache

源码方式安装python3

现在开始,万事俱备,可以编译安装python了。需要使用root权限操作。

首先,在官网下载最新的3.6源码:
https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tgz

安装过程没有什么特别的,缺少依赖时可以直接yum安装

1
2
3
4
wget https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tgz
tar -zxcf Python-3.6.0.tgz
./configure
make && make install

源码方式安装完成后,已经是包含pip3的了,不用再单独安装了。

让pip走代理

pip3可以通过使用--proxy参数来走代理,在这里我们为了方便,直接建一个alias,以后使用pip时,就不需要再添加参数了。

1
2
3
alias pip3="pip3 --proxy 134.32.32.13:31081"
export http_proxy=134.32.32.13:31081
export https_proxy=134.32.32.13:31081

安装依赖

大部分依赖可以直接通过pip3安装:

1
2
3
4
pip3 install requests
pip3 install beautifulsoup4
pip3 install mysql-connector
pip3 install fdfs_client-py

某些模块,比如FastDFS客户端,不能直接使用pip3安装,需要下载源码后并手工修改一些代码,操作过程大致如下:

1
2
3
4
5
git clone https://github.com/jefforeilly/fdfs_client-py.git
cd dfs_client-py
vi ./fdfs_client/storage_client.py
将第12行 from fdfs_client.sendfile import * 注释掉
python3 setup.py install

至此,环境搭建完毕,可以将python代码扔上去跑起来了。

现象

  1. 直接使用foobar用户SSH登录正常
  2. 在root用户下,执行su - foobar,报错:
1
su: cannot set user id: Resource temporarily unavailable

只有su的时候报错,虽然不影响foobar用户正常的SSH远程登录,但这种资源受限的错误,一般都是系统崩溃的前兆,必须要较点真。

系统:RHEL 6.5

排查过程

先按套路出牌

首先直接一通free -mtopvmstat等等,试试运气
不过也不出所料,并没有什么收获。但这也算是个好消息,至少说明不像是系统级别的资源问题了。

感觉八成是线程数或者文件打开数搞的鬼了,懒得监控日志,接着排查。

查看线程数

1
2
cat /proc/sys/kernel/threads-max
254529

最大线程数254529,没有问题

1
2
ps -u foobar -L | wc -l
1045

用户当前线程数1045,虽然挺高了,但这个用户下部署的应用也非常多,算是正常吧。

检查ulimit

  1. 先用ulimit看一下设置的最大文件打开数
    用foobar直接登录,然后执行:

    1
    2
    ulimit -n
    655360

    显示655360,没有问题

  2. 然后用lsof统计一下当前的文件打开数

    1
    2
    lsof | grep foobar | wc -l
    1690

    1690,大于1024有点多了,接下来仔细看一下。

  3. lsof大概的逐条分析一下

    1
    2
    3
    4
    lsof | grep foobar
    blablabla...
    blablabla...
    blablabla...

    既有文件,也有网络连接。不像是那种同时发起了大量网络连接造成的故障。这里算是PASS了。

检查limits.conf配置

走到这里,还没查出问题,就有点意外了,索性再检查一下limits.conf

1
2
3
4
5
6
7
8
cat /etc/security/limits.conf

* soft nofile 655360
* hard nofile 655360
* soft noproc 655360
* hard noproc 655360
* soft core 0
* hard core 0

都是655360,一眼看上去没有问题(但这里有个坑,稍后会提到)

检查各个profile配置

再检查各个profile的配置,例如.bash_profile里是不是手工设置了过小的ulimit,导致登录失败。

1
2
cat /etc/profile
cat /foobar/.bash_profile

都很正常,并没有添加多余的东西进去

监控系统secure日志

到这时都没发现出问题,只能监控系统日志/var/log/secure了。
一边监控,一边执行su - foobar

1
2
3
4
5
6
tail -f /var/log/secure
blablabla...

Mar 30 12:08:02 localhost crond[29226]: pam_limits(crond:session): unknown limit item 'noproc'

blablabla...

终于抓到一个问题:noproc参数是个什么鬼,应该是nproc才对吧,估计管理员当时是直接手撸的,没有复制粘帖。

于是赶紧修改limits.conf

1
vi /etc/security/limits.conf

1
2
*    soft    noproc    655360
* hard noproc 655360

改为

1
2
*    soft    nproc    655360
* hard nproc 655360

山穷水尽

解决完上面那个问题,以为这下可以su成功了吧,然而并没有,报错依旧。

于是继续监控/var/log/secure日志。现在报错变成了:

1
2
Mar 30 12:10:25 localhost su: pam_unix(su-l:session): session opened for user foobar by monitor(uid=0)
Mar 30 12:10:25 localhost su: pam_unix(su-l:session): session closed for user foobar

这种报错,相当于什么也没说啊。看来接下来,想要解决问题,只能靠猜了。

一通google之后,找到了这么一句话:

In Red Hat Enterprise Linux 6, there’s a default setting in /etc/security/limits.d/90-nproc.conf. Change the default limit for all users or add a new limit for the affected user.

这个limits.d/90-nproc.conf之前从没有注意过,难道它会覆盖 limits.conf 吗?

1
2
3
cat /etc/security/limits.d/90-nproc.conf
* soft nproc 1024
root soft nproc unlimited

这里的值是1024,尝试改大一点,碰碰运气:

1
2
3
vi /etc/security/limits.d/90-nproc.conf
* soft nproc 10240
root soft nproc unlimited

然后su - foobar ,竟然成功了。

经验值+3

到此为止,两个坑都已经被填上了。耗时15分钟,经验值+3:

  1. 遇到类似问题,直接监控/var/log/secure,可以少走些弯路
  2. 注意/etc/security/limits.conf的参数拼写
  3. 竟然还有/etc/security/limits.d/90-nproc.conf这么个东西,且生效的时机诡异(只影响su,直接登录不受影响)

qiniu-imgup简介

qiniu-imgup是一个七牛云图片上传工具,目标是简化MarkDown写作中的贴图的繁琐步骤,可以快速将剪贴板中的图片上传至七牛云,并返回MarkDown格式的链接。
适用人群:使用七牛云做为图床的MarkDown编写者。

由于平时工作主要是用macOS 10.12及Ubuntu 16.04两台笔记本,macOS下之前一直在用一个名为iPic的收费软件(30RMB/年,UX做的非常好),Ubuntu下直接找不到类似工具,于是分别针对两个平台各写了一个小工具。

两个版本在思路及实现上的差异还是比较大的,Mac版偏重于用Python原生实现,Linux版则借用了一些第三方系统工具,下面简单做一下分享,有需要的同学可以直接拿去用。

Linux版本的整体思路及部分代码来自 博客 77695的自留地 ,侵删

使用方法介绍

在编写MarkDown文档时,如果使用七牛云做图床,插入一张图片需要以下几个繁琐的步骤:

  1. 截图
  2. 保存为文件
  3. 打开浏览器,在七牛云后台上传图片
  4. 复制图片的HTTP URL
  5. 在编辑器中将URL拼接为MarkDown的链接格式
  6. 粘帖链接

mac版本将整个操作简化为了3个快捷键操作:

  1. cmd+shift+ctrl+4 - 截图到剪贴板
  2. cmd+shift+u - 使用自定义热键,上传并获取MarkDown链接
  3. cmd+v - 粘帖MarkDown链接

linux版本整个操作简化为了2个快捷键操作:

  • alt+shift+s 调用simg截图
  • alt+shift+u 调用uimg上传并自动粘帖MarkDown链接

实现思路

Mac版实现思路

  1. 使用系统自带截图工具,或QQ截图工具,截图至剪贴板
  2. 使用PIL库中的ImageGrab,将剪贴板中的图片保存
  3. 使用qiniu库,生成token,并上传图片
  4. 将七牛云返回的URL拼接为MarkDown格式链接
  5. 使用clipboard库,将链接放到剪贴板中
  6. 使用os.system库,调用osascript发送系统通知,在屏幕右上角提示成功/失败
  7. CMD+V粘帖链接至编辑器

其中2-6步,是由qiniu-imgup来实现的。
可以用Automator工具,将shell脚本封装成一个APP,在系统设置中就可以指定一个快捷键了。

Linux版实现思路

  1. 使用shell脚本,调用第三方截图工具shutter,并将图片保存至临时目录。
  2. 使用qiniu库,生成token,并上传图片
  3. 将七牛云返回的URL拼接为MarkDown格式链接
  4. 直接使用print打印链接至console
  5. 调用libnotify-bin,发送系统通知,在屏幕右上角提示成功/失败
  6. 使用shell脚本,将Python输出结果传递给第三方工具xclip,复制到剪贴板
  7. 使用shell脚本,调用第三方工具xdotool,模拟键盘Ctrl+V操作,直接进行粘帖

其中2-5步,是由qiniu-imgup来实现的。
过程中使用到了第三方工具shutter、xclip及xdotool。
由于使用了xdotool,无须手工Ctrl+V粘帖了,节省了一个操作步骤。

安装与配置

Mac版安装与配置

  1. 安装依赖
    1
    sudo pip3 install -r requirement.txt
  2. 配置config.py,填入七牛云的AK、SK等参数
  3. 使用Automator将shell脚本uimg封装为APP
  4. 在系统设置中(System Preference->Keyboard->Shortcuts->App Shortcuts),为APP分配快捷键

Linux版安装与配置

  1. 依赖及工具安装
    1
    2
    3
    4
    5
    6
    sudo pip3 install qiniu
    sudo apt-get install shutter
    sudo apt-get install xclip
    sudo apt-get install parcellite
    sudo apt-get install xdotool
    sudo apt-get install libnotify-bin
  2. 将程序目录拷贝至/opt/qimg下
  3. 设置环境变量 export PATH=/opt/qimg:$PATH
  4. 在Shutter设置中,将图片自动保存位置设为/tmp/snap_shutter
  5. 在System Setting - Keyboard中,设置快捷键分别指向simg截图和uimg上传

源码

crontab

crontab并不陌生,在*nix的操作系统之中,使用它设置周期性被执行的指令.每个用户可以拥有自己的crontab文件;
同时,操作系统保存一个针对整个系统的crontab文件,该文件通常存放于/etc或者/etc之下的子目录中。

1
2
3
4
5
6
7
pi@raspberrypi:/etc $ ls -al|grep cron
drwxr-xr-x 2 root root 4096 Jan 1 1970 cron.d
drwxr-xr-x 2 root root 4096 Jan 1 1970 cron.daily
drwxr-xr-x 2 root root 4096 Jan 1 1970 cron.hourly
drwxr-xr-x 2 root root 4096 Jan 1 1970 cron.monthly
drwxr-xr-x 2 root root 4096 Jan 1 1970 cron.weekly
-rw-r--r-- 1 root root 722 Sep 5 2015 crontab

基本用法

  • -u user:用来设定某个用户的crontab服务;
  • file:file是命令文件的名字,表示将file做为crontab的任务列表文件并载入crontab。如果在命令行中没有指定这个文件,crontab命令将接受标准输入(键盘)上键入的命令,并将它们载入crontab。
  • -e:编辑某个用户的crontab文件内容。如果不指定用户,则表示编辑当前用户的crontab文件。
  • -l:显示某个用户的crontab文件内容,如果不指定用户,则表示显示当前用户的crontab文件内容。
  • -r:从/var/spool/cron目录中删除某个用户的crontab文件,如果不指定用户,则默认删除当前用户的crontab文件。
  • -i:在删除用户的crontab文件时给确认提示。

最常用的参数有-l 查询-e 编辑

配置格式

  • 第1列分钟0~59
  • 第2列小时0~23(0表示子夜)
  • 第3列日1~31
  • 第4列月1~12
  • 第5列星期0~7(0和7表示星期天)
  • 第6列要运行的命令

配置示例

每分钟执行一次:

1
* * * * * /path/to/your/app.sh

每半分钟执行一次:

1
*/2 * * * * /path/to/your/app.sh

每小时的第3和第15分钟执行:

1
3,15 * * * * /path/to/your/app.sh

在上午8点到11点的第3和第15分钟执行:

1
3,15 8-11 * * * /path/to/your/app.sh

每周六23点执行:

1
0 23 * * 6 /etc/init.d/smb restart

简单应用

检测并自动重启服务

1
2
crontab -e
*/2 * * * * isfound=$(ps | grep "redsocks" | grep -v "grep"); if [ -z "$isfound" ]; then echo "$(date): restart redsocks...">>/tmp/log/redsocks-mon.log && /etc/init.d/redsocks restart; fi

检测并自动重启tomcat

1
*/2 * * * * sh /path/to/tomcat_monitor.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
vi tomcat_monitor.sh
#!/bin/sh
source /home/user/.bash_profile
export PATH=$PATH:.:/bin:/sbin:/usr/bin:
pid_count=`ps aux|grep java|grep your-tomcat|grep -v grep|wc -l`
if [ $pid_count -ne 1 ]; then
echo "stop download-tomcat, time: `date`"
if [ $pid_count -gt 0 ]; then
ps aux|grep java|grep your-tomcat|grep -v grep|awk '{print $2}'|xargs kill
fi
sh /path/to/tomcat/bin/startup.sh
echo "start download-tomcat finished, time: `date`"
fi

清理30天前的tomcat日志

1
2
crontab -e
0 23 * * * sh /path/to/clean_log.sh
1
2
3
4
vi clean_log.sh
DATE=$(date -d "30 days ago" +%Y-%m-%d)
echo $DATE
rm /path/to/tomcat/logs/*$DATE*

备份并清理catalina.out

1
2
crontab -e
00 22 * * * sh /path/to/clean_catalina_out.sh
1
2
3
4
5
6
7
vi clean_catalina_out.sh
y=`date "+%Y"`
m=`date "+%m"`
d=`date "+%d"`
cp /path/to/tomcat/logs/catalina.out /path/to/tomcat/logs/catalina.out.$y-$m-$d
echo > /path/to/tomcat/logs/catalina.out
exit

注意设置环境变量

由于crontab执行任务时不加载任何环境变量,可以在脚本中加入必要的环境变量,甚至ulimit设置,以保证程序可以正常执行。

1
2
3
4
5
6
7
vi start.sh

!/bin/sh
source /etc/profile
export YOUR_ENV=value
ulimit -n 10240
/path/to/your/app/run

参考文档

引言

当修改一个Linux系统参数或限制,比如文件打开数时,之前用到过的方式有ulimit、limits.conf、sysctl和/proc文件系统。
对这几个东西一直比较困惑,翻了几篇文档,简单写一下它们之间的区别。

ulimit

什么是ulimit

ulimit是linux shell的内键命令,它具有一套参数集,用于对 shell进程 及其 子进程 进行 资源限制
例如用户同时运行了两个shell终端进程,只在其中一个环境中执行了ulimit – s 100,则该shell进程里创建文件的大小会有相应的限制,而另一个shell终端包括其上运行的子程序都不会受其影响。

ulimit的设定值是 per-process 的,也就是说,每个进程有自己的limits值。
使用ulimit进行修改,是 立即生效 的。
ulimit只影响shell进程及其子进程,用户登出后失效。
可以在profile中加入ulimit的设置,变相的做到永久生效。

查看ulimit的设定值

使用ulimit -a可以查看所有的设定值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pi@raspberrypi:~ $ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7336
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 65536
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 95
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 7336
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

ulimit的参数

  • -H 设置硬件资源限制.
  • -S 设置软件资源限制.
  • -a 显示当前所有的资源限制.
  • -c size:设置core文件的最大值.单位:blocks
  • -d size:设置数据段的最大值.单位:kbytes
  • -f size:设置创建文件的最大值.单位:blocks
  • -l size:设置在内存中锁定进程的最大值.单位:kbytes
  • -m size:设置可以使用的常驻内存的最大值.单位:kbytes
  • -n size:设置内核可以同时打开的文件描述符的最大值.单位:n
  • -p size:设置管道缓冲区的最大值.单位:kbytes
  • -s size:设置堆栈的最大值.单位:kbytes
  • -t size:设置CPU使用时间的最大上限.单位:seconds
  • -v size:设置虚拟内存的最大值.单位:kbytes
  • unlimited 是一个特殊值,用于表示不限制

注意:

  1. -n 限制文件描述符的最大值,在Linux下一切资源皆文件,所以该参数也限制了socket链接数
  2. 查询时,若不加H或S参数,默认显示的是软限制
  3. 修改时,若不加H或S参数,两个参数一起改变

设置ulimit的位置

可以在以下位置进行ulimit设置:

  • /etc/profile 所有用户有效,永久生效
  • ~/.bash_profile 当前用户有效,永久生效
  • 直接在控制台输入 当前用户有效,临时生效
  • 放在程序的启动脚本中

limit.conf

什么是limits.conf

limits.conf文件实际是Linux PAM中 pam_limits.so 的配置文件,pam_limits模块对 用户的会话 进行 资源限制

一个shell的初始limits就是由pam_limits设定的,用户登录后,pam_limits会给用户的shell设定在limits.conf定义的值。

pam_limits的设定值也是 per-process 的。
pam_limits的设置是 永久生效 的。

limits.conf的位置

1
/etc/security/limits.conf

配置limits.conf

示例:

1
2
3
4
5
6
*    soft    nofile    655360
* hard nofile 655360
* soft noproc 655360
* hard noproc 655355
* soft core 0
* hard core 0

4个字段的含义分别为: domain type item value

  • domain: username|@groupname
  • type: soft、hard、-
  • item:
    core - 限制内核文件的大小
    date - 最大数据大小
    fsize - 最大文件大小
    memlock - 最大锁定内存地址空间
    nofile - 打开文件的最大数目
    rss - 最大持久设置大小
    stack - 最大栈大小
    cpu - 以分钟为单位的最多 CPU 时间
    noproc - 进程的最大数目
    as - 地址空间限制
    maxlogins - 此用户允许登录的最大数目
  • value: 值的大小

sysctl

什么是sysctl

sysctl是一个允许改变正在运行中的Linux系统的接口,修改的是针对 整个系统内核参数
sysctl的修改是 立即临时 的(重启后失效)。
可以通过修改sysctl.conf配置文件,达到 永久 生效。

sysctl的选项

  • -n 打印值时不打印关键字
  • -e 忽略未知关键字错误
  • -N 仅打印名称
  • -w 当改变sysctl设置时使用此项
  • -p 从配置文件“/etc/sysctl.conf”加载内核参数设置
  • -a 打印当前所有可用的内核参数变量和值
  • -A 以表格方式打印当前所有可用的内核参数变量和值

查看某个内核参数

1
2
3
sysctl fs.file-max

fs.file-max = 93796

临时修改某个内核参数

1
sysctl -w fs.file-max=100000  # 设置文件打开数
1
sysctl -w net.ipv4.ip_forward=1  # 开启IP转发

sysctl.conf配置文件

1
2
/etc/sysctl.conf

修改sysctl.conf并使其生效

修改/etc/sysctl.conf可以做到永久生效:

1
2
3
vi /etc/sysctl.conf

fs.file-max = 100000

最后使用-p命令从配置文件中加载内核参数,使其立即生效:

1
sysctl -p

sysctl.conf配置示例

下面是一个摘抄的配置示例,出处:http://www.jianshu.com/p/9a8e383b5b49

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# Kernel sysctl configuration file for Red Hat Linux
#
# For binary values, 0 is disabled, 1 is enabled. See sysctl(8) and
# sysctl.conf(5) for more details.

# Controls IP packet forwarding
net.ipv4.ip_forward = 0

# Controls source route verification
net.ipv4.conf.default.rp_filter = 1

# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0

# Controls the System Request debugging functionality of the kernel

# Controls whether core dumps will append the PID to the core filename.
# Useful for debugging multi-threaded applications.
kernel.core_uses_pid = 1

# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1

# Disable netfilter on bridges.
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0

# Controls the default maxmimum size of a mesage queue
kernel.msgmnb = 65536

# Controls the maximum size of a message, in bytes
kernel.msgmax = 65536

# Controls the maximum shared segment size, in bytes
kernel.shmmax = 68719476736

# Controls the maximum number of shared memory segments, in pages
kernel.shmall = 4294967296
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.netfilter.nf_conntrack_max = 1000000
kernel.unknown_nmi_panic = 0
kernel.sysrq = 0
fs.file-max = 1000000
vm.swappiness = 10
fs.inotify.max_user_watches = 10000000
net.core.wmem_max = 327679
net.core.rmem_max = 327679
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0

/proc文件系统

什么是/proc文件系统

Linux内核提供了一种通过/proc文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。
proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口。
最初开发/proc文件系统是为了提供有关系统中进程的信息。但是由于这个文件系统非常有用,因此内核中的很多元素也开始使用它来报告信息,或启用动态运行时配置。

对/proc中内核文件的修改,针对的是 整个系统内核参数 ,修改后 立即生效 ,但修改是 临时 的(重启后失效)。

/proc文件系统与sysctl.conf的对应关系

/proc/sys下内核文件与配置文件sysctl.conf中变量的对应关系:

  1. 去掉前面部分/proc/sys
  2. 将文件名中的斜杠变为点

例如:

  • /proc/sys/net/ipv4/ip_forward -> net.ipv4.ip_forward
  • /proc/sys/kernel/hostname -> kernel.hostname

/proc文件系统中几个常用的内核文件

下面几个是经常会用到的文件:

  • /proc/meminfo 内存信息
  • /proc/cpuinfo CPU信息
  • /proc/sys/fs/file-max 文件打开数
  • /proc/sys/fs/file-nr 整个系统目前使用的文件句柄数量

/proc文件系统中文件的权限

proc 中的每个文件都有一组分配给它的非常特殊的文件许可权,并且每个文件属于特定的用户标识。

  • 只读:任何用户都不能更改该文件;它用于表示系统信息
  • root 写:如果 /proc 中的某个文件是可写的,则通常只能由 root 用户来写
  • root 读:有些文件对一般系统用户是不可见的,而只对 root 用户是可见的

对/proc进行读写

以开启IP转发为例:

1
2
3
4
5
cat /proc/sys/net/ipv4/ip_forward
0
echo "1" > /proc/sys/net/ipv4/ip_forward
cat /proc/sys/net/ipv4/ip_forward
1

当然,也可以使用sysctl来配置这些内核条目

内核文件详解

  • /proc/buddyinfo 每个内存区中的每个order有多少块可用,和内存碎片问题有关
  • /proc/cmdline 启动时传递给kernel的参数信息
  • /proc/cpuinfo cpu的信息
  • /proc/crypto 内核使用的所有已安装的加密密码及细节
  • /proc/devices 已经加载的设备并分类
  • /proc/dma 已注册使用的ISA DMA频道列表
  • /proc/execdomains Linux内核当前支持的execution domains
  • /proc/fb 帧缓冲设备列表,包括数量和控制它的驱动
  • /proc/filesystems 内核当前支持的文件系统类型
  • /proc/interrupts x86架构中的每个IRQ中断数
  • /proc/iomem 每个物理设备当前在系统内存中的映射
  • /proc/ioports 一个设备的输入输出所使用的注册端口范围
  • /proc/kcore 代表系统的物理内存,存储为核心文件格式,里边显示的是字节数,等于RAM大小加上4kb
  • /proc/kmsg 记录内核生成的信息,可以通过/sbin/klogd或/bin/dmesg来处理
  • /proc/loadavg 根据过去一段时间内CPU和IO的状态得出的负载状态,与uptime命令有关
  • /proc/locks 内核锁住的文件列表
  • /proc/mdstat 多硬盘,RAID配置信息(md=multiple disks)
  • /proc/meminfo RAM使用的相关信息
  • /proc/misc 其他的主要设备(设备号为10)上注册的驱动
  • /proc/modules 所有加载到内核的模块列表
  • /proc/mounts 系统中使用的所有挂载
  • /proc/mtrr 系统使用的Memory Type Range Registers (MTRRs)
  • /proc/partitions 分区中的块分配信息
  • /proc/pci 系统中的PCI设备列表
  • /proc/slabinfo 系统中所有活动的 slab 缓存信息
  • /proc/stat 所有的CPU活动信息
  • /proc/sysrq-trigger 使用echo命令来写这个文件的时候,远程root用户可以执行大多数的系统请求关键命令,就好- 像在本地终端执行一样。要写入这个文件,需要把/proc/sys/kernel/sysrq不能设置为0。这个文件对root也是不可- 读的
  • /proc/uptime 系统已经运行了多久
  • /proc/swaps 交换空间的使用情况
  • /proc/version Linux内核版本和gcc版本
  • /proc/bus 系统总线(Bus)信息,例如pci/usb等
  • /proc/driver 驱动信息
  • /proc/fs 文件系统信息
  • /proc/ide ide设备信息
  • /proc/irq 中断请求设备信息
  • /proc/net 网卡设备信息
  • /proc/scsi scsi设备信息
  • /proc/tty tty设备信息
  • /proc/net/dev 显示网络适配器及统计信息
  • /proc/vmstat 虚拟内存统计信息
  • /proc/vmcore 内核panic时的内存映像
  • /proc/diskstats 取得磁盘信息
  • /proc/schedstat kernel调度器的统计信息
  • /proc/zoneinfo 显示内存空间的统计信息,对分析虚拟内存行为很有用

以下是/proc目录中进程N的信息:

  • /proc/N pid为N的进程信息
  • /proc/N/cmdline 进程启动命令
  • /proc/N/cwd 链接到进程当前工作目录
  • /proc/N/environ 进程环境变量列表
  • /proc/N/exe 链接到进程的执行命令文件
  • /proc/N/fd 包含进程相关的所有的文件描述符
  • /proc/N/maps 与进程相关的内存映射信息
  • /proc/N/mem 指代进程持有的内存,不可读
  • /proc/N/root 链接到进程的根目录
  • /proc/N/stat 进程的状态
  • /proc/N/statm 进程使用的内存的状态
  • /proc/N/status 进程状态信息,比stat/statm更具可读性
  • /proc/self 链接到当前正在运行的进程

参考文档

peewee简介

peewee是Python一个ORM框架,相比于著名的SQLAlchemy,peewee更为轻量,且更加简单易上手。
peewee原生支持sqlite、mysql以及postgresql。

学习资源

peewee官网
GitHub页面

数据建模

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from peewee import *
import datetime
from playhouse.sqlite_ext import SqliteExtDatabase

db = MySQLDatabase(host='localhost', user='playground', passwd='playground', database='playground')
# db = SqliteExtDatabase('my_database.db')

class BaseModel(Model):
class Meta:
database = db

# 用户表
class User(BaseModel):
username = CharField(unique=True)

# Twitter表
class Tweet(BaseModel):
user = ForeignKeyField(User, related_name='tweets')
message = TextField()
created_date = DateTimeField(default=datetime.datetime.now)
is_published = BooleanField(default=True)

支持的字段类型

  • CharField varchar varchar varchar
  • FixedCharField char char char
  • TextField text text longtext
  • DateTimeField datetime timestamp datetime
  • IntegerField integer integer integer
  • BooleanField integer boolean bool
  • FloatField real real real
  • DoubleField real double precision double precision
  • BigIntegerField integer bigint bigint
  • SmallIntegerField integer smallint smallint
  • DecimalField decimal numeric numeric
  • PrimaryKeyField integer serial integer
  • ForeignKeyField integer integer integer
  • DateField date date date
  • TimeField time time time
  • TimestampField integer integer integer
  • BlobField blob bytea blob
  • UUIDField text uuid varchar(40)
  • BareField untyped not supported not supported

支持的参数

  • null = False – boolean indicating whether null values are allowed to be stored
  • index = False – boolean indicating whether to create an index on this column
  • unique = False – boolean indicating whether to create a unique index on this column. See - also adding composite indexes.
  • verbose_name = None – string representing the “user-friendly” name of this field
  • help_text = None – string representing any helpful text for this field
  • db_column = None – string representing the underlying column to use if different, useful - for legacy databases
  • default = None – any value to use as a default for uninitialized models
  • choices = None – an optional iterable containing 2-tuples of value, display
  • primary_key = False – whether this field is the primary key for the table
  • sequence = None – sequence to populate field (if backend supports it)
  • constraints = None - a list of one or more constraints, e.g. [Check(‘price > 0’)]
  • schema = None – optional name of the schema to use, if your db supports this.

    特殊的参数

  • CharField max_length
  • FixedCharField max_length
  • DateTimeField formats
  • DateField formats
  • TimeField formats
  • TimestampField resolution, utc
  • DecimalField max_digits, decimal_places, auto_round, rounding
  • ForeignKeyField rel_model, related_name, to_field, on_delete, on_update, extra
  • BareField coerce

连接数据库并生成表

1
2
3
def create_table():
db.connect()
db.create_tables([User, Tweet])

常用操作

插入记录

1
2
3
4
5
6
7
charlie = User.create(username='charlie')

huey = User(username='huey')
huey.save()

# 不需要设置 `is_published` 或 `created_date`,保存时会自动使用模型中指定的默认值
Tweet.create(user=charlie, message='My first tweet')

查询单条记录

1
user = User.get(User.id == 1)
1
user = User.get(User.username == 'charlie')

查询多条记录

1
2
for user in User.select():
print(user.username)

多条件查询

1
Tweet.select().where(Tweet.user == user, Tweet.is_published == True)

in查询,使用”<<”来代入多个条件

1
2
usernames = ['charlie', 'huey', 'mickey']
users = User.select().where(User.username << usernames)

join查询

1
2
3
4
tweets = (Tweet
.select()
.join(User)
.where(User.username << usernames))

count

1
Tweet.select().where(Tweet.id > 50).count()

count今天发布了几条Twitter

1
2
3
4
5
6
tweets_today = (Tweet
.select()
.where(
(Tweet.created_date >= datetime.date.today()) &
(Tweet.is_published == True))
.count())

排序及分页

1
2
User.select().order_by(User.username).paginate(3, 20)
Tweet.select().join(User).order_by(User.username, Tweet.created_date.desc())

join和gruopby,将用户按Twitter数排序

1
2
3
4
5
6
tweet_ct = fn.Count(Tweet.id)
users = (User
.select(User, tweet_ct.alias('ct'))
.join(Tweet, JOIN.LEFT_OUTER)
.group_by(User)
.order_by(tweet_ct.desc()))

更新

1
2
3
4
5
User.update(username='foo').where(User.id == 2).execute()

user = User.get(User.id == 1)
user.username='bar'
user.save()

删除

1
2
3
4
Tweet.delete().where(id==1).execute()

user = User.get(User.id == 8)
user.delete_instance()

什么是virtualenv

virtualenv是一个用于创建Python虚拟环境的工具。

虚拟环境又是什么呢?它是Python解释器的一个私有副本,在这个环境中可以安装私有包,而不会影响到系统中安装的全局Python解释器。
当一台主机上运行着多个Python应用时,使用虚拟环境可以有效的避免包的混乱和版本的冲突。

virtualenv官网

如果懒得看作者瞎BB,可以跳过下面的章节,直接访问官网:
https://virtualenv.pypa.io

安装

在Linux或Mac中,可以使用pipeasy_install来快速安装virturlenv:

1
sudo pip3 install virtualenv

或:

1
sudo easy_install virutalenv

测试安装是否成功:

1
2
virtualenv --version
15.1.0

创建虚拟环境

下面以macOS为例,创建一个python3的虚拟环境。
假设已经有一个工程目录pyapp,进入工程目录中,执行以下命令:

1
2
3
4
5
6
7
cd pyapp
virtualenv venv

Using base prefix '/Library/Frameworks/Python.framework/Versions/3.5'
New python executable in /Users/foobar/tmp/pyapp/venv/bin/python3.5
Also creating executable in /Users/foobar/tmp/pyapp/venv/bin/python
Installing setuptools, pip, wheel...done.

现在,virtualenv为我们在工程目录中,创建了一个名为venv的子目录,它里面保存了一个全新的虚拟环境,非常简单。

现在可以进入ven/bin目录下,看看里面都有些什么东西:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cd venv/bin
ls -al
total 160
drwxr-xr-x 16 foobar staff 544 Mar 13 09:44 .
drwxr-xr-x 7 foobar staff 238 Mar 13 09:44 ..
-rw-r--r-- 1 foobar staff 2089 Mar 13 09:44 activate
-rw-r--r-- 1 foobar staff 1031 Mar 13 09:44 activate.csh
-rw-r--r-- 1 foobar staff 2185 Mar 13 09:44 activate.fish
-rw-r--r-- 1 foobar staff 1137 Mar 13 09:44 activate_this.py
-rwxr-xr-x 1 foobar staff 262 Mar 13 09:44 easy_install
-rwxr-xr-x 1 foobar staff 262 Mar 13 09:44 easy_install-3.5
-rwxr-xr-x 1 foobar staff 234 Mar 13 09:44 pip
-rwxr-xr-x 1 foobar staff 234 Mar 13 09:44 pip3
-rwxr-xr-x 1 foobar staff 234 Mar 13 09:44 pip3.5
lrwxr-xr-x 1 foobar staff 9 Mar 13 09:43 python -> python3.5
-rwxr-xr-x 1 foobar staff 2348 Mar 13 09:44 python-config
lrwxr-xr-x 1 foobar staff 9 Mar 13 09:43 python3 -> python3.5
-rwxrwxr-x 1 foobar staff 25384 Mar 13 09:43 python3.5
-rwxr-xr-x 1 foobar staff 241 Mar 13 09:44 wheel

可以看到virtuanenv为我们创建了一个python3的虚拟环境。

但在Ubuntu16.04下,virtualenv默认会创建python2.7的虚拟环境。这时,只要在创建时加入-p python3参数即可解决。

1
virtualenv -p python3 venv

激活和退出虚拟环境

在使用虚拟环境之前,必须将其激活,命令如下:

1
2
3
source venv/bin/activate

. venv/bin/activate

这时,可以看到shell提示符前面加上了(venv)前缀,说明已经工作在虚拟环境之下了

1
(venv)➜pyapp

退出虚拟环境只要执行:

1
deactivate

在虚拟环境中安装依赖

在虚拟环境中,可以像平时一样使用pip安装依赖,操作完全没有区别:

1
2
3
4
5
6
7
pip3 install requests

Collecting requests
Downloading requests-2.13.0-py2.py3-none-any.whl (584kB)
100% |████████████████████████████████| 593kB 13kB/s
Installing collected packages: requests
Successfully installed requests-2.13.0

但依赖会安装到venv/lib/python3.5/site-packages目录下,可以进去看一下:

1
2
cd venv/lib/python3.5/site-packages
ls -al

当然还可以使用-r requirements.txt来批量安装依赖,也是没有问题的:

1
2
3
4
5
6
7
pip3 install -r requirements.txt

Collecting beautifulsoup4 (from -r requirements.txt (line 1))
Downloading beautifulsoup4-4.5.3-py3-none-any.whl (85kB)
100% |████████████████████████████████| 92kB 13kB/s
Installing collected packages: beautifulsoup4
Successfully installed beautifulsoup4-4.5.3

删除虚拟环境

1
rmvirtualenv venv

在PyCharm中使用virtualenv

PyCharm已经提供了对virtualenv的支持,详情可查看官方文档:
https://www.jetbrains.com/help/pycharm/2016.1/creating-virtual-environment.html

首先是设置virtualenv的路径,PyCharm应该会自动发现并配置上,查看一下即可。

位置: CMD+, –> Project –> Project Interpreter,点击右上角的齿轮图标,选择Create VirtualEnv

引子

SSH连接是我们与服务器交互的主要手段,每个程序员每天都会用到,就像喝白开水一样普通。
就是这样一个简单而又高频的动作,如果配置得当,或许能极大的提高我们工作的幸福感吧。

前不久一个同事刚从Windows切换到macOS平台,问我SecureCRT有没有mac下的版本,我说即然都用上了基于BSD的mac了,应该不再需要SecureCRT这样的东西了才对,SSH如果配置好了,体验应该完爆Windows。于是就有了写下这篇文章的念头,填一下之前的坑。

选择终端GUI工具

首先第一步是选择一个好用的GUI工具,毕竟大多数人都是在DE下工作,极少人会喜欢工作在tty1这样的文字介面下。

Windows平台

Windows平台下的工具比较多,下面捡几个主要的来说一说优缺点:

  • SecureCRT - 老牌的商业软件,同时也提供Mac和Linux版本,功能强大,费用昂贵,但貌似身边所有人都在用盗版,PASS
  • Xshell - 有免费的License,但只允许非商业场景下使用,这个也PASS
  • Putty - 好吧,只能是它了,免费,功能简单,但是也足够用了
  • Cygwin - 差点把这个忘了,严格来说它并不仅仅是一个SSH工具,也值得推荐

macOS平台

macOS平台的终端工具比较好选,公认的只有iTerm2一个:

  • 原生Terminal - 开箱即用,功能上也不过不失,但抛弃它,只是因为有更好的iTerm2。。。
  • iTerm2 - 免费,支持众多的自定义选项,可以完全替代原生Terminal,没得选,就是它了

Ubuntu平台

Ubuntu默认自带一个gnome-terminal,虽然不像iTerm2那样讨喜,但胜在简洁,个人认为是最优的选择吧:

  • Terminator - 支持窗口拆分,但界面丑,不能忍,PASS
  • Guake - 支持下拉式的呼出,但界面更丑,PASS
  • 原生Terminal - 界面简洁,功能够用,最终还是用回了它

iTerm2使用简介

Putty和gnome-terminal的配置都比较简单,记住几个快捷键就可以了,macOS下的iTerm2配置和使用都要麻烦些,这里单独拿出来写一下。

配置呼出快捷键

使用Cmd+,打开设置界面,切换到Keys一栏

在左下方可以设置 呼出/隐藏 iTerm2的快捷键,这里我设置成了Cmd+ESC,瞬间呼出,比Alfred/Spotlight还要方便。
另外还可以在Profile一栏中修改窗口为全屏+半透明,完美。

选中即复制

使用鼠标选中一段文字后,默认就已经复制到剪贴板了,直接用Cmd+V粘帖即可。

Profile设置

使用Cmd+,打开设置界面,切换到Profile一栏
在这里可以配置远程服务器的连接参数

配合sshpass这个命令,可以实现类似SecureCRT的Session管理的功能。
注意,sshpass直接使用明文保存密码(SecureCRT是加密后存在本地),已经不推荐使用,下面会介绍一个更好的方式。

分屏

分屏功能相当好用,例如我们可以在屏幕左侧查看日志,右侧进行常规操作
Cmd+D 垂直分割
Cmd+Shift+D 水平分割

自动完成

输入前几个关键字后,按Cmd+;,会有一个自动补全功能

命令历史记录

使用Cmd+shift+H可以打开命令历史记录

使用Tmux窗口管理工具

GUI工具有了,我们还缺一个通用的窗口管理工具–Tmux

Tmux是一个终端复用器,它可以激活多个终端或窗口, 还可以将屏幕水平或纵向切分成多个窗口。
类似于screen,它可以关闭窗口将程序放在后台运行,需要的时候再重新连接。

其实iTerm2等GUI工具也可以实现类似的功能,但Tmux的好处是:

  1. 它是一个字符终端软件,不需要任何GUI的支持,通用性更好
  2. tmux可以 保持多个会话 ,只要不关机,就可以随时恢复Session

macOS下的安装

1
brew install tmux

Ubuntu下的安装

1
sudo apt-get install tmux

tmux的主要元素分为三层:

  • Session 一组窗口的集合,通常用来概括同一个任务
  • Window 单个可见窗口,和ITerm2中的Tab类似
  • Pane 窗格,被划分成小块的窗口

tmux默认的前置操作是CTRL+b。例如,我们想要新建一个窗体,就需要先在键盘上摁下CTRL+b,松开后再摁下n键。
下面所有的prefix均代表CTRL+b

  • 查看/切换session prefix s
  • 离开Session prefix d
  • 重命名当前Session prefix $
  • 新建窗口 prefix c
  • 切换到上一个活动的窗口 prefix space
  • 关闭一个窗口 prefix &
  • 使用窗口号切换 prefix 窗口号
  • 切换到下一个窗格 prefix o
  • 查看所有窗格的编号 prefix q
  • 垂直拆分出一个新窗格 prefix “
  • 水平拆分出一个新窗格 prefix %
  • 暂时把一个窗体放到最大 prefix z

使用oh my zsh

工具已经齐全,但攘外必先安内,在连接远程服务器之前,我们先优化一下本机的Shell。

Linux系统中已经内置了几种shell,一般默认的是bash

zsh比bash更加好用,且完全兼容bash,但它配置繁琐。幸亏有了oh-my-zsh,让zsh的配置难度大大降低。

首先安装一下zsh,mac系统无需安装,Ubuntu可以通过apt安装

1
sudo apt install zsh

这里是oh my zsh官网

根据官网的介绍,安装相当的简单,只需要一行命令即可

1
2
$ sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

zsh的配置文件是~/.zshrc,各项配置都有对应的注释,非常清晰,在这里可以修改主题,其实默认的已经很好看了

以下是zsh的一些使用技巧,请尽量记住,因为都很常用:

  • 连按两次Tab会列出所有的补全列表并直接开始选择,补全项可以使用 ctrl+n/p/f/b上下左右切换
  • 命令选项补全。在zsh中只需要键入 tar - 就会列出所有的选项和帮助说明
  • 命令参数补全。键入 kill 就会列出所有的进程名和对应的进程号
  • 更智能的历史命令。在用或者方向上键查找历史命令时,zsh支持限制查找。比如,输入ls,然后再按方向上键,则只会查找用过的ls命令。而此时使用则会仍然按之前的方式查找,忽略 ls
  • 智能跳转,安装了 autojump 之后,zsh 会自动记录你访问过的目录,通过 j 目录名 可以直接进行目录跳转,而且目录名支持模糊匹配和自动补全,例如你访问过 hadoop-1.0.0 目录,输入j hado 即可正确跳转。j --stat 可以看你的历史路径库。
  • 目录浏览和跳转:输入 d,即可列出你在这个会话里访问的目录列表,输入列表前的序号,即可直接跳转。
  • 在当前目录下输入 ..... ,或直接输入当前目录名都可以跳转,你甚至不再需要输入 cd 命令了。在你知道路径的情况下,比如 /usr/local/bin 你可以输入 cd /u/l/b 然后按进行补全快速输入
  • 通配符搜索:ls -l **/*.sh,可以递归显示当前目录下的 shell 文件,文件少时可以代替 find。使用 **/ 来递归搜索
  • 扩展环境变量,输入环境变量然后按 就可以转换成表达的值

使用config记录远程连接

现在开始,我们再看一下如何连接远程服务器。

如果要管理几十台至上百台的主机,那么有没有什么方法能实现类似SecureCRT中Session管理那样的功能呢?

最简单的是使用iTerm2中的profile功能,它可以配置多台主机的连接,并可以使用tag进行归类。
但这种方式首先太依赖于GUI工具,离开了iTerm2就完全用不了。
其次是通用性不够好,配置文件不能跨平台,我们辛辛苦苦在Mac上配好了一份主机清单,但回家扔到Ubuntu下就没法用了。

有没有一种更为通用的方法呢?答案是直接使用openssh自带的config功能

配置文件的路径是:~/.ssh/config,如果不存在,可以新建一个

内容非常简单

1
2
3
4
Host demohost
HostName 192.168.1.1
User username
Port 10022

第一行Host后面,可以为这个连接起一个简单的名字
后面几行记得缩进,HostName后面是IP地址,User后面是用户名,这两项是必填的。如果端口不是标准的22,还可以用Port指定端口。

配置好后,我们只需要输入ssh demohost,即可快速打开SSH连接了。

如果记不清连接名也没有关系,利用zsh的自动补全功能,输入ssh 关键字,再按一下TAB键,会列出所有包含关键字的连接,使用方向键选择后,回车确认即可。

使用ssh-copy-id免密码登录

接着再看一下,如何实现免密码登录远程主机。

之前我们提到过使用sshpass这个工具,可以直接将密码写进命令行中,从而实现非交互式的免密码登录

1
sshpass -p password ssh demouser@92.168.1.1

但这种方式使用明文保存密码,非常不安全,不建议使用。

其实还有一种更好更直接的方式,那就是使用ssh-copy-id建立ssh信任关系,从而免密码登录。

  1. 首先,在本地机器上使用ssh-keygen产生公钥私钥对

    1
    ssh-keygen

    一路回车即可,会在~/.ssh目录下生成公钥私钥对。此命令只需执行一次即可。

  2. 然后,用ssh-copy-id将公钥复制到远程机器中

    1
    ssh-copy-id -i demouser@192.168.1.1

    按提示输入一次密码,ssh-copy-id就会自动将刚才生成的公钥id_rsa.pub追加到远程主机的~/.ssh/authorized_keys后面了,以后的 ssh 以及 sftp 连接,都不用输入密码了。

至此,我们只要输入ssh demousersftp demouser,回车,就可以直接登录远程主机了。

安利一个小工具

最后的最后,再介绍一个很恶搞,但相当有用的小工具,thefuck GitHub页面

当我们敲错了命令,比如忘记加sudo时,只需要输入fuck并大力敲下回车,它就会非常智能的帮助我们更正了,非常有趣。

1
2
3
4
5
6
7
8
9
➜ apt-get install vim
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?

➜ fuck
sudo apt-get install vim [enter/↑/↓/ctrl+c]
[sudo] password for nvbn:
Reading package lists... Done
...

参考文档

http://cenalulu.github.io/linux/tmux/
http://harttle.com/2015/11/06/tmux-startup.html
http://wulfric.me/2015/08/iterm2/
http://yijiebuyi.com/blog/e310fc437f32006eb6aa42cad1783587.html
http://wdxtub.com/2016/02/18/oh-my-zsh/

系统设置工具

raspi-config

设置root密码

sudo passwd root

修复ping权限

ls -lsa /bin/ping
sudo chmod 4711 /bin/ping

网络设置

vi /etc/network/interfaces
auto eth0
iface eth0 inet static
address xxx.xxx.xxx.xxx
netmask 255.255.248.0
gateway xxx.xxx.xxx.xxx
dns-nameservers xxx.xxx.xxx.xxx

启动网卡

sudo ifup eth0
sudo /etc/init.d/networking restart

代理设置

sudo vi /etc/environment
export http_proxy=”http://134.32.87.142:1080"
export http_proxy=”http://134.32.32.13:31315"

export http_proxy=”http://134.32.32.13:31081"

sudo vi /etc/apt/apt.conf.d/10proxy
Acquire::http::Proxy “http://134.32.87.142:8080/";
Acquire::http::Proxy “http://134.32.32.13:31315/";

apt-get使用阿里云镜像

sudo vi /etc/apt/sources.list
deb http://mirrors.aliyun.com/raspbian/raspbian/ wheezy main non-free contrib
deb-src http://mirrors.aliyun.com/raspbian/raspbian/ wheezy main non-free contrib

redsocks透明代理网关

开启IPV4转发:
sudo vi /etc/sysctl.conf
net.ipv4.ip_forward=1
sysctl -p /etc/sysctl.conf

源码编译Redsocks:
sudo apt install libevent-dev
make

redsocks配置文件:
sudo vi /etc/redsocks.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
base {
log_debug = off;
log_info = on;
log = "file:/home/pi/redsocks/logs/redsocks.log";
daemon = off;
redirector = iptables;
}
redsocks {
local_ip = xxx.xxx.xxx.xxx;
local_port = 3128;
ip = xxx.xxx.xxx.xxx;
port = 31080;
type = socks5;
}

iptables配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
iptables -F
iptables -X
iptables -Z

iptables -P INPUT DROP
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT

iptables -A INPUT -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp --dport 3128 -m state --state NEW,ESTABLISHED -j ACCEPT

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE
iptables -t nat -N REDSOCKS

iptables -t nat -A REDSOCKS -d 127.0.0.1 -j RETURN
iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 172.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 132.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 134.0.0.0/8 -j RETURN

iptables -t nat -A SS -p tcp -j REDIRECT --to-port 3128

iptables -t nat -A PREROUTING -p tcp -j SS
iptables -t nat -A OUTPUT -p tcp -j SS

dnsmasq架设DNS服务器

sudo apt install dnsmasq

shadowsocks

apt-get install python-pip
pip install shadowsocks

nginx配置端口

sudo vi /etc/nginx/sites-available/default
listen 30080;

设置时间

sudo raspi-config
ntpd -q -g
sudo date -s “2016-11-8 14:20:00”

什么是IntelliJ IDEA


简单来说,IntelliJ Idea是目前最好的Java集成开发环境,没有之一。

为什么要迁移到Intellij IDEA

Java应该是非常依赖IDE的一门语言了,恐怕也没有几个大牛能够直接用Vim/Emacs愉快的手撸代码,Java程序员离开了IDE基本上生活不能自理,IDE的重要性不言而喻。
最近在推行、部署各种自动化工具,但个人认为,相比于各种工具,一个好的IDE更是能 极大的提升 工作效率以及编码的爽快感。
目前团队中使用的开发工具主要还是Eclipse和NetBeans,所以就想借这篇文章安利一下,希望团队中更多的人能开始尝试并喜欢上IntelliJ IDEA。

目前常用的IDE主要有3个:

  • Eclipse
  • NetBeans
  • IntelliJ IDEA

其中,Eclipse及其衍生品是最为我们所熟知的,Eclipse开源,历史悠久,插件丰富,对一些老项目兼容性也比较好,另外有很多基于Eclipse的项目也很流行,比如STS、MyEclipse。

NetBeans使用的人稍微少一些,但它有很多比Eclipse更为优秀的地方,例如免费、Oracle自家出品,对于新标准的支持非常好、有中文语言包、界面布局更合理等。

但从目前的统计数据来看,IntelliJ Idea的市场份额已经超过了Eclipse。

IntelliJ IDEA作为一个商业化的IDE,而且是一个非常昂贵的商业化IDE(499刀/年),能够被如此多的开发人员认可,肯定有它非凡之处,简单罗列几点:

  • 黑色的Darcula主题,我想应该把这个放在第一位
  • 智能化的代码提示、自动补全、重复代码检查、快速修复
  • 更加智能的重构工具,支持跨语言的重构
  • 人性化的调试工具
  • 包含大量的内建工具,开箱即用的,无须配置大量的插件
  • 默认支持git/svn等多种版本控制工具
  • 默认支持Maven, Gradle, Ant等多种构建工具
  • 内建反编译工具,方便查看没有源码的老旧jar包
  • 内建数据库管理工具,可以抛弃toad/Navicat这些东西了
  • 内建REST API测试工具,可以抛弃Postman之类的测试工具了
  • 支持Tomcat、JBoss、WebLogic等主流应用服务器
  • Google的助攻,Android开发环境由最初基于Eclipse的ADT,迁移到了基于IDEA的Android Studio

导入一个工程

要想开始体验IntelliJ IDEA,首先要新建一个工程(Project)或导入已有的工程。这里我们选择从版本库中导入一个已有的工程。

在欢迎界面中点击最下方的 Check out from Version Control

可以看到,IntelliJ IDEA支持GitHub、CVS、Git、Svn等多种版本库。

这里我们尝试导入一个GitHub中的工程,填写自已的GitHub用户名、密码

在下拉列表中选择好一个工程后,点击 Clone

如果项目是用Gradle/Maven构建的,还会弹出一个构建工具配置界面

导入完成后,可以看到主界面了

项目结构

IntelliJ IDEA中的项目结构和Eclipse有很大的不同。

  • Eclipse中有workspace的概念,可以向workspace中添加多个工程。
  • IDEA没有workspace,一个窗口中只能打开一个工程(Project),但一个工程中可以包含多个模块(module),这种方式更符合多模块应用开发的需求。

界面左侧的Project栏,可以查看项目中的文件结构,通过Cmd+1快捷键调出/关闭。

使用Cmd+; 快捷键,可以打开项目设置界面,在这里配置模块、库、Facets、Artifacts等。

Facets

Facets可以认为是项目支持的特性,例如JPA、Spring、Hibernate等,当一个项目被IDEA扫描完毕之后,它会自动为每个模块添加相应用Facets,当然也可以手工进行添加

Artifacts

Artifacts是项目的打包部署设置。
例如,对于WEB工程而言,IDEA通过配置Artifacts,将编译输出的class文件,与jsp/html/css页面等静态文件,以特定的目录结构合并到一起。

目录图标

  • 蓝色 - 源码根目录
  • 绿色 - 测试代码目录
  • 红色 - 需要排除的目录,例如class/build等包含二进制文件的目录
  • 黄色 - 资源目录,application.yml等会放在这里面

点击Project栏中右上角齿轮图标,可以调整目录的展示方式,比如合并中间空目录等:

快捷键对比

下面是一份Eclipse与IntelliJ IDEA的快捷键比对表:

如果不想使用IDEA的默认快捷键,想沿用之前的一些习惯,IDEA也提供了几套其它的配置,使用 Ctrl+` 调出菜单

选择 3-Keymap 即可切换配置

但建议还是尽量适应IntelliJ IDEA的默认快捷键配置吧。

下面有几个有趣的与其它IDE的区别:

  • Cmd+D
    在Eclipse中,Cmd+D是删除一行,但在IntelliJ IDEA中,D是指duplicate,复制一行。
  • Cmd+S
    在其它编辑器中,我们通常会频繁使用Cmd+S进行保存,但在IDEA中,完全不需要这么做。IntelliJ IDEA的自动保存功能做的非常好,不用担心会丢失进度,Cmd+S只能给我们带来一些心理上的”安全感”。

界面布局

IntelliJ IDEA的默认布局非常的简洁,几乎只有一个编辑器界面,甚至还可以通过Ctrl+Cmd+F全屏显示,以获得更加沉浸式的体验。

点击界面最左下角的显示器形状的图标,可以用来切换布局模式,调出或隐藏周边的工具栏

在使用精简布局时,如果要进行文件定位、打开某个侧边栏等操作,就需要使用一些快捷建进行操作了。

一般是使用Cmd+数字来显示侧边栏,例如Cmd+1显示Project栏,Cmd+9显示版本控制栏,具体数字界面上会有提示。

另外,Cmd+E不但可以显示最近使用过的文件,还可以在左侧选择打开各个侧边栏,非常好用。

同样的,Ctrl+Tab快捷键可以实现类似的功能,并且效率更高

快速查找

使用Cmd+O可以弹出快速 查找类名 窗口,输入类名关键字筛选,可以快速打开类所在的源文件

使用Cmd+Shift+O可以弹出快速 查找文件名 窗口,输入文件名关键字,可以打开任意文件

还有一个更方便的方式,如果不确定要找什么,双击shift键,可以弹出”Search Everywhere”窗口,输入关键词搜索一切吧。

当然,还可以使用之前提到过的Cmd+E,查看曾经打开过的文件。

常用设置

缩进方式配置

使用空格与TAB键缩进,在码农界争论至今还没有定论,那就不妨根据自已的喜好手工设置一下吧。

首先使用Cmd+,打开全局设置界面,在Editor → Editor Tabs中可以找到相应的选项:

界面主题配置

Appearance & Behavior → Appearance中,可以设置喜欢的主题,字体、字号等

这里当然是首推Darcula主题。

代码编辑

首先要记忆的一个快捷键是Cmd+F12,可以打开 class outline 窗口,查看文件中的各个方法。

类似的也可以通过Ctrl+H打开 type hierarchy 侧边栏

另外,还可以使用Alt+F7,打开 Find Usages 底边栏,显示方法的使用者。

自动补全

使用Ctrl+Space,可以进行代码自动补全。

Ctrl+Shift+Space,是更加智能的代码补全,它会猜测你的意图,只展示最有用的结果

另外Alt+Enter也十分有用,当使用了一个类,但它还没有被导入时,可以用它来快速导入

代码生成

使用Cmd+N可以自动生成代码,比如Getter/Setter/toString()等等

代码重构

最简单的,可以通过右键菜单或Shift+F6进行重命名,可以是文件,也可以是类名、方法名、变量名等,点击确认后IntelliJ IDEA会跨语言检索全部代码(包括.html/.js),找到所有相关的地方一起修改。

插入模版

输入特定的关键字,按TAB后,可以直接在光标处插入模板代码。

例如,首先输入psvm

然后按下TAB键,就会自动插入一个main方法的模版,相当快捷

其它重要的快捷键

  • 格式化代码 - Cmd+Alt+L
  • 编译 - Cmd+F9
  • 关闭某个侧边栏 - Shift+ESC

查找快捷键的快捷键

到现在为止,已经接触了IntelliJ IDEA的不少快捷键了。
其实对于学习一个文本编辑器也好、IDE也好,要想用的得心应手,记忆大量的快捷键都是少不了的步骤。

但如果记不清快捷键怎么办,去哪里查呢?幸好IntelliJ IDEA为我们提供了一个终级快捷键 Cmd+Shift+A,这是一个用来 查找快捷键的快捷键 !其它所有的快捷键都忘了也没有关系,只要记得这一个。。。

配置Tomcat

对于Web应用,如果想在本机直接运行测试,除了使用Maven等构建工具内嵌的Application Server之外,还可以选择直接在IntelliJ中配置一个。

注意请提前配置好Artifacts,然后点击顶部右侧的 Run Configuration 按钮,在新窗口中点击左上角加号,选择Tomcat即可:

代码检查

在向版本库中提交时,可以在右侧选择进行一些提交前的处理,如代码检查、格式化等:

收藏夹

在Tab页上点击右键,可以选择Add to Favorites

然后在左下方的Favorites栏中就可以看到了

版本控制

在窗口左下方的 Version Control 栏中,可以查看到做过变更的文件

在文件上右键,可以进行代码差异比对,回滚等操作

在窗口右上方的工具栏中,可以快速Update/Commit

在窗口右下方的工具栏中,可以查看/新建/切换Git分支

内嵌工具

菜单栏中,Tools一项中,可以找到很多内嵌的工具,比如很常用的Rest测试工具

数据源配置

在右侧的Database工具栏中,可以配置常用的数据源

配置好之后,就可以使用内嵌的数据库查询管理工具了,另外在编写配置文件或SQL/JPQL时,也会有对应用智能提示

官方文档

以上介绍的,只是IntelliJ IDEA众多功能中的冰山一角,想要了解更多,请进一步参考官方文档:

另外官网上也提供了很多的视频教程,其中有不少小技巧。