tar打包时候的2个注意点

打包的时候千万要注意语句的次序

暂时先不说打包的命令,我们来说一下拷贝的命令,比如将 /tmp/ 下面的所有文件及文件夹拷贝到 /a/ 下面,如下:
cp -r /tmp/* /a/

再来看看,将/tmp/下面的所有文件及文件夹打包成 /tmp/a.tar.gz 文件,命令如下:
tar zcvf /tmp/a.tar.gz /tmp/*

注意这2个语句的次序,cp source dest,而 tar dest source

所以,对于 tar 来说是非常容易弄错的,要是弄错了,重新再来也无所谓,要命的是,tar也不知道是怎么个的脑洞打开,假如次序弄错了,会把 source 给弄丢了,这样会导致严重的问题。

有一次,我就这么弄错了,然后把source 日志文件给弄丢了,犯了一次错误后,我以后每次用 tar 命令,我就会想起那次错误教训,每次都会小心再小心的使用tar命令,那有没有当打错次序后不会把 source 给弄丢的方式方法呢?很可惜,有是有的,但是没有特别好的,比如有人用 alias 来解决这个问题,但是没有用的,比如针对上面的,用 alias 的方法就失效了:tar zcvf /tmp/a.tar.gz /tmp/*

所以,tar的作者在写这个命令的时候是不严谨的,有缺陷的。

打包文件时把隐藏文件加入

tar zcvf /tmp/a.tar.gz /tmp/*, 这样的写法是不包含打包隐藏文件的
tar zcvf /tmp/a.tar.gz .[!.]* *, 需要这样写才可以

linux cp 强制覆盖不生效的解决办法

在linux中,拷贝并覆盖文件,我们用 cp -f source dest 这个命令,其中 -f 表示就是强制覆盖而不用提示。

但是,你能发现提示是否覆盖还是弹出来了,这是为什么呢?

因为在linux在登录 login shell 的时候,会自动运行 ~/.bashrc 这个文件中的:
alias rm=’rm -i’
alias cp=’cp -i’
alias mv=’mv -i’
所以,仅仅用 cp -f,实际上是 cp -i -f, 而 i 和 f 两者是互斥的,默认linux就选择了 -i。

那么应该怎样才能强制覆盖而不会弹出提示呢?可以用下面的3种方法:
1,unaslias cp (这只是临时取消cp的别名,不是永久的),然后再 cp -f source dest 就可以了。
2,\cp -f source dest ,这个效果就等同于上面,反斜杠表示取消cp的别名。
3,yes|cp -fr source dest,使用管道自动输入yes。这个 yes 特别有意思,假如在控制台中直接输入yes,就可以发现很有趣的现象,不断地输出y。查看一下yes –help,能发现y是可以换成其他字符串的。

kvm在NAT模式下,虚拟机居然访问不了外网?

kvm在NAT模式下,发现虚拟机居然访问不了外网,这个不科学啊,从理论上讲,NAT中的虚拟机可以通过宿主机无防碍访问外网,怎么访问不了呢?

通过查找资料,网上都说设置net.ipv4.ip_forward = 1即可,但是这里我提醒一下,切记是在宿主机上修改!

过程如下:

在宿主机上(切记,是宿主机,不是虚拟机),修改 /etc/sysctl.conf 文件,在最后加上下面一行:
net.ipv4.ip_forward = 1

保存退出后,执行:sysctl -p /etc/sysctl.conf 即可。

假如这个时候,虚拟机还是不能访问外网,则将虚拟机重新启动一遍即可。

Makefile疑难解答和技巧合集

Makefile文档

Makefile是GNU make中最重要的一个文件,官方的文档:GNU make,当然也是比较复杂和难懂的。

Makefile教程

很早以前,咱们国人写过这么一篇《跟我一起写 Makefile》,这篇文章写得是比较不错的,通过通俗易懂的例子教你怎么写Makefile,但是是一页一页的html,看起来累死,你也可以到网上去搜索相应的pdf,下载下来后,在写作和分析别人写得Makefile的时候,可以作为参考手册。

Makefile基础

Makefile的大致框架如下:

target(目标) ... : prerequisites(依赖目标) ...
    <TAB>command(命令)

上述的翻译:目标、依赖目标、命令 是来自《跟我一起写 Makefile》,大家在看这本书的时候,一定要记住,千万要看清目标和依赖目标,千万别看错了。我个人觉得prerequisites还是翻译成“前置条件”比较好,尽管从意义上来看在这里的prerequisites确实是依赖的目标,但是翻译成了“前置条件”不至于把读者给看晕和看错。

Makefile的调试

Makefile挺难的,更难的是那些变量值、那些调用过程,一个复杂点的Makefile会把你给完全绕晕。这个时候,对于Makefile的调试就非常重要了。对于Makefile的调试,主要看这篇文章,写得相当不错:Makefile常用调试方法
我调试的时候,常用下面的技巧:
1. make的时候,用参数 “-n” “--just-print” “--dry-run” “--recon”,这4个参数是完全一样的。比如 make -n
2. 但是上面只能看到具体执行了哪个命令,假如Makefile相当庞大和复杂,那么就不知道这个命令是由哪个规则调用的,这个时候就需要用下面的参数: --debug=basic,也就是完整的命令是:make -n --debug=basic,出来的结果非常不错,强烈推荐这个。
3. 对于某个变量的值是多少,可以用$(error, ….) $(warning, ….)这2个函数来打印。

Mafefile的函数参考

《跟我一起写 Makefile》这本书写得比较早,有些函数在它上面找不到了,需要在官网http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions参考,官网是全面的。

Makefile的模式规则

其实挺简单的,就是类似正则表达式,比如下面的:

all: bin/a bin/b
bin/%: ...

那么 bin/a 就会匹配 bin/%,bin/b 也会匹配 bin/%

再比如:

all: bin/a/image bin/b/image
bin/%/image: ...

那么 bin/a/image 就会匹配 bin/%/image,bin/b 也会匹配 bin/%/image

再来一个例子:

all: bin/a/image bin/b/image

bin/a/image: ...

bin/%/image: ...

那么 bin/a/image 会匹配 bin/a/image 和 bin/%/image 这2个目标,这2个目标都执行!

Makefile的中间规则文件

隐含规则,可以参见《跟我一起写 Makefile》,其中上面所说到的模式规则也是属于隐含规则。那么上面所提到的bin/a,bin/a/image所匹配的bin/%, bin/%/image这些就是属于中间规则,假如这些中间规则结果是个文件,那么就叫做中间规则文件。正常情况下,中间规则文件是在规则执行完后要被删除的,比如:

%.txt: foo.log
    # pass

%.log:
    # pass

执行结果如下:

$ make a.txt -n
# pass
# pass
rm foo.log

上面的foo.log这个就是中间规则文件,所以要被删除的。为了防止中间规则文件被删除,那么用下面的来定义,这样就不会删除该中间规则文件了:
.PRECIOUS: foo.log
或者
.SECONDARY: foo.log

Centos7下升级GCC

centos7自带的GCC是比较老的,gcc -v可以看到版本是4.8.5,在yum中也能看到最高版本也是这个版本4.8.5:yum list gcc。

用这个比较老的GCC版本,在运行一些软件的时候,常会报错:
CXXABI_1.3.8 not found
GLIBCXX_3.4.20 not found

用下面2个命令可以看到上述这2个确实不存在
strings /usr/lib64/libstdc++.so.6 | grep GLIBC
strings /usr/lib64/libstdc++.so.6 | grep CXXABI

解决这个问题,只有一条路可以走,那就是升级GCC到更高的版本,GCC官网上的版本已经到了很高的版本9了,我个人觉得没有必要用这么高的版本,折衷一下,选个GCC 6.5.0 这个版本即可。

下面是GCC的升级之路,整个过程大概耗时3个小时,要有心理准备:
1,下载GCC 6.5.0:http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-6.5.0/gcc-6.5.0.tar.gz,或者到官网找更好的mirror下载,https://gcc.gnu.org/mirrors.html,我选了个日本的镜像,很遗憾没有国内的。
2,假设 gcc-6.5.0.tar.gz 在 /opt 下面,tar xzvf gcc-6.5.0.tar.gz && cd gcc-6.5.0
3,升级之前,需要做好下面2个准备工作:
3.a:yum -y install gcc-c++ , 否则在升级的时候会报错:error: C++ preprocessor “/lib/cpp” fails sanity check
3.b:cd /opt/gcc-6.5.0,然后运行 sh contrib/download_prerequisites,必须在/opt/gcc-6.5.0下面,否则运行download_prerequisites的时候就会报错;这个脚本将会下载4个小文件(每个文件1M左右),但是因为网络的因素,下载了半天才下载完。这个必须要运行,否则在GCC升级的时候就会报错什么:GMP 4.2+, MPFR 2.4.0+ and MPC 0.8.0+这些找不到。
4,准备工作做好了,开始吧:./configure –disable-multilib,disable-multilib表示仅仅需要64位的GCC,不需要32位的GCC,假如在centos7安装的时候没有选上32位的GCC,那么在这里必须要 –disable-multilib,否则就会报错。
5,make,这个过程最长了,估计要1个多小时。
6,make install,非常快
7,装好后,gcc -v,确实已经升级到了 6.5.0 版本,但是假如运行前面报错的软件的话,还是会报以前的错误,用刚才的strings命令去看,也是缺少那2个,这是什么原因呢?
8,这是因为,gcc升级安装在了 /usr/local/lib64下面,而运行的软件只认 /usr/lib64 这个位置,所以最后还需要 cp /usr/local/lib64/libstdc++.so.6 /usr/lib64/,这样就全部搞定了

最后说一下,GCC的升级就是比较耗时点,但是难度不大,严格按照我上面的步骤,很容易搞定的。

ssh登录的时候很慢

在ssh登录的时候很慢,网上查找问题的时候,基本上都是前篇一律的,按照网上的来解决:

vi /etc/ssh/sshd_config      (编辑配置文件) 
输入 / ,查找GSSAPIAuthentication 赋值为no 
输入 /,查找UseDNS,赋值为 no(该项默认不启用的,要把前面的#删除掉) 
最后输入!wq保存文件并退出 
重启systemctl restart sshd

但是用上面的方法修改后,发现有些起效,有些还是不起效。继续查找这个问题,参照这篇文章 linux下ssh连接慢的原因调查及解决方案

systemctl restart systemd-logind

问题解决。

总结一下:除了需要设置 UseDNS 和 GSSAPIAuthentication 以外,最好 systemctl restart systemd-logind,这样就可以彻底解决这个问题了。

云服务器的centos7镜像安装gnome以及vnc

这篇文章也适用于其他的云服务器。

有个别场景需要用图形的方式连接linode,linode最便宜的vps就是1GRAM,所以完全可以用来支持图形界面了,网上有不少关于linode vps安装图形界面的教程,但是那些都有些老了,最新的linode vps在centos7下安装图形界面非常简单,过程大致如下:

1,首先看一下centos7是否有 GNOME Desktop 这个安装组:yum grouplist
2,yum groupinstall GNOME Desktop
3,yum install vnc vnc-server
4,vncpasswd //设置vncserver的登录密码
5,vncserver -depth 24 //无需vncserver那些很复杂的加入启动服务中的那些过程
如上,就启动默认 :1 号vncserver,监听端口是 5901,有可能5901已经被其他进程占用了,那么vncserver就会启用 :2号,监听端口是5902,同样的道理假如5902也被占用,那么继续顺延,我就遇到了这样的极端情况 5901到5903都被占用了,结果就启用了:4号,监听端口是5904。
vncserver -kill :1 //这个命令是杀掉vncserver进程
6,客户端下载 realvnc,然后连接 ip:1 就可以连接上图形界面了

是不是很简单:)

代理那些事

本文只涉及代理的一些技术性原理和术语解释。

我在工作中经常用到代理:比如nginx的反向代理,使用littleproxy来作为程序可控的正向代理,公司内作为正向代理访问外网一些资料。

什么是代理

那么什么是代理,其实看下面的图,很简单,不需要用过多的文字来描述:

用户要访问app,因为各种原因直接不可达,那么在用户和app之间放一层代理:
1. 用户传入的请求流到代理
2. 代理将流转到目标app
3. app的响应流到代理
4. 代理将响应流转给用户
说白了,代理的作用就是你给我什么流,我转就是了。

那么假如让你来写一个代理软件,是不是很简单,只需要一个socket接收,另一个socket转发就可以了?理论上是这样的,比如HAPROXY就是这样的。但是实际上还是有很多地方需要考虑的,更多的是协议!

代理和协议转换

假如代理实现的是http/https的协议,那么用户传入的请求必须是http/https;假如代理实现的是mysql的协议,那么用户传入的请求必须是mysql协议;假如代理实现的是socks的协议,那么用户传入的请求必须是socks协议。

下面以socks代理服务器来举例说明:

等一下,有几个情况先看一下:
1. firefox中设置好了socks代理服务器后,居然能够使得socks代理http协议的流量?也就是说上面图中,发出http协议的请求,居然socks代理能够接受?原因是:firefox事先将http转换成了socks协议然后再发送,同理在响应的时候将socks协议转成了http协议了。
2. curl中,通过 --socks 来访问socks代理,那么curl的收发代码中肯定有对 http 互转 socks 的代码。
3. 在git中,我们可以设置如下来进行git的代理访问:

git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'

但是在git中,非常奇怪的能看到 http.proxy 中,居然可以设置 socks的协议。这个不像上2个情况,比如第1个firefox是对http和socks进行分别设置,然后由firefox来转换协议;第2个的curl通过--socks和-x来区分,由curl来转换协议。那么git怎么弄了个在 http 中设置成 socks 的协议呢?
这是因为只有HTTP_PROXY这种约定俗成的环境变量定义,而没有SOCKS_PROXY这个环境变量。git采用了一个取巧的办法(尽管我没有查git的源代码,但是根据原理肯定能猜出来),就是判断HTTP_PROXY的内容假如是socks协议的就转socks。

上面3个情况,都可以通过设置环境变量进行全局代理,详见HTTP_PROXY,HTTPS_PROXY,NO_PROXY,ALL_PROXY来自什么协议?

通过上面3个情况可以看到,对于 http互转socks这个过程,都是在客户端本身内部完成的,而和socks代理没有任何关系。

根据上面的理论,再来看一个现象,分析一下为什么会出现这样的情况:
minikube start
然后会去下载一些文件,因为一些原因下载不下来就会卡在那里,这个时候,假如用HTTP_PROXY=socks://127.0.0.1:1080,那么也还是下载不下来,为什么原因呢?因为minikube start会调用curl去下载文件,而curl不同于git,curl是http_proxy和socks是分开的。问题就出在这里。那怎么办呢?有几种解决办法:1,采用privoxy对http和socks进行互换;2,直接用nginx来作为http的代理,详见我的另一篇博文玩转nginx:用nginx搭建正向代理,支持http和https,当然假如就minikube这个来说,建议采用阿里修改的minikube,非常好用,阿里minikube

正向代理和认证

从我的那篇关于nginx代理的文章中知道,nginx或者tinyproxy从http的原理上来说,因为是短连接,所以天生对于认证不方便或者实现不了(注意,这里的认证不是说nginx带的安全认证,那个安全认证在代理中没有用,你总不可能让你所访问的网站上带上你的认证信息吧)。

所以,对于socks来说,在用户和代理之间再加一个代理客户端,这个代理客户端就是和代理进行长连接,当然也具有认证的功能。

反向代理和正向代理


反向代理:关键点是用户在外网,代理在内网。

正向代理:关键点是用户和代理都在内网中。

玩转nginx:用nginx搭建正向代理,支持http和https

什么是代理,什么是正向代理,什么是反向代理,详见代理那些事

用nginx搭建反向代理,这个是nginx最大的功能,网上资料一大堆,这里不再复述。

用nginx搭建正向代理,假如只是http的代理,那么网上也是一大堆,也都是正确的;但是https的代理,网上所讲得一大堆,绝大部分是错误的。(吐槽一下,明明是很明显错误的内容,难道作者都没有验证一下就发出来吗?)希望读者能通过搜索引擎找到我这一篇文章,而不是先找到那些错误的文章,耗时耗精力。

nginx的正向代理支持https,其实也是很简单,只要 nginx 加入 ngx_http_proxy_connect_module 这个模块即可。(所以网上的文章假如说支持https的nginx正向代理没有提到 ngx_http_proxy_connect_module 这个模块,看都不用看,是错误的)

下面是安装步骤:
#所有操作在 /opt 目录下
cd /opt
git clone https://github.com/chobits/ngx_http_proxy_connect_module.git
wget http://nginx.org/download/nginx-1.14.2.tar.gz
tar xzvf nginx-1.14.2.tar.gz
cd nginx-1.14.2
patch -p1 < /opt/ngx_http_proxy_connect_module/patch/proxy_connect_xxxx.patch
#注意这里选用的补丁文件proxy_connect_xxxx.patch需要参照 https://github.com/chobits/ngx_http_proxy_connect_module 中的nginx不同版本来决定,如下所示:

因为我们的nginx是1.14版本,参照上面,所以上面的命令应该是:
patch -p1 < /opt/ngx_http_proxy_connect_module/patch/proxy_connect_1014.patch
假如不成功,会显示错误信息。成功后,进行编译nginx
./configure --add-module=/path/to/ngx_http_proxy_connect_module
make && make install

然后nginx的配置如下:

server {
        listen 6281;
        resolver 114.114.114.114;

        proxy_connect;
        proxy_connect_allow            443 563;
        proxy_connect_connect_timeout  10s;
        proxy_connect_read_timeout     10s;
        proxy_connect_send_timeout     10s;

        location / {
                #下面的居然是 http 而不是 https,很奇怪的设置,但是事后验证确实没有问题
                proxy_pass      http://$host;
                proxy_set_header        Host $host;
        }
}

然后启动nginx,这样即可支持 https 的正向代理。

另外多说两句:
1. 一定要知道这样一件很重要的事情,nginx的 http/https的代理,是不支持认证的(不是说nginx不支持认证,而是这种机制下认证是没有用的),所以该代理只能放在内网里,否则你就等着哪一天突然你的外网nginx被别人使用了。
2. 支持 http/https 的代理,还可以用 tinyproxy。

linux中dns的设置

linux查看dns的顺序是依照:
1. /etc/hosts
2. /etc/sysconfig/network-scripts/ifcfg-eth0
3. /etc/resolve.conf

  1. /etc/hosts:仅在特定情况下使用,这个如何使用大家都知道。
  2. /etc/sysconfig/network-scripts/ifcfg-eth0,(ifcfg-eth0 这个每个人的网卡接口不一样,名字也不一样):在其中写上比如:
    DNS1=114.114.114.114
    DNS2=8.8.8.8
    DNS3=xxx.xxx.xxx.xxx

    按照顺序往下进行解析。
  3. /etc/resove.conf:上面2个都没有设定,则最后找到这个文件,这个文件中的内容如下:
    nameserver 114.114.114.114
    nameserver 8.8.8.8
    nameserver xxx.xxx.xxx.xxx

在国内,最好用 114.114.114.114
在国外,最好用8.8.8.8或者8.8.4.4