因工作原因,我需要使用 ubuntu 通过 vpn 连接 到国外的网络。 使用 windows 设置 vpn client 非常容易就成功了,但是在ubuntu下, 按照教程反复试了很多次也没有成功, 最终使用命令行的方式连接成功了。

因为涉及到许多网络操作, 感觉还是比较有价值, 特此记录一下:

第一步:安装 ubuntu 客户端软件

~ sudo apt-get install pptp-linux

正常情况下, 该软件应该是已经安装好了的。

第二步: 查看网络配置

~ ifconfig

结果大致如下:

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:255 errors:0 dropped:0 overruns:0 frame:0
          TX packets:255 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:52525 (52.5 KB)  TX bytes:52525 (52.5 KB)

p3p1      Link encap:Ethernet  HWaddr b0:83:fe:84:2e:60  
          inet addr:192.168.2.182  Bcast:192.168.2.255  Mask:255.255.255.0
          inet6 addr: fe80::b283:feff:fe84:2e60/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:998 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1023 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:389146 (389.1 KB)  TX bytes:207345 (207.3 KB)

查看路由信息

~ route -n

信息如下:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.1     0.0.0.0         UG    0      0        0 p3p1
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 p3p1
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 p3p1

列出路由表条目

~ ip route show

结果如下:

169.254.0.0/16 dev p3p1  scope link  metric 1000 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 linkdown 
192.168.2.0/24 dev p3p1  proto kernel  scope link  src 192.168.2.182 

建立 vpn 链接

现在, 让我们建立一个名为 myvpn 的连接

~ sudo pptpsetup --create myvpn --server xxx.xxx.xxx.xxx --username xx1--password xx2 --encrypt --start

返回结果如下, 显示成功连接

Using interface ppp0
Connect: ppp0 <--> /dev/pts/2
CHAP authentication succeeded
local  IP address 192.168.1.211
remote IP address 192.168.1.2

成功连接到远程VPN服务器。

刚才的命令, 会在 /etc/ppp/peers 目录下, 会生成一个叫myvpn的文件。
在/etc/ppp目录下面,用户名和密码会写在chap-secrets文件中。

测试测试VPN

安装traceroute

~ sudo apt-get install traceroute 

查看路由细节

~ traceroute www.163.com

返回结果如下:

traceroute to www.google.com (8.7.198.45), 30 hops max, 60 byte packets
 1  192.168.2.1 (192.168.2.1)  0.367 ms  0.363 ms  0.368 ms
 2  111.204.38.33 (111.204.38.33)  3.002 ms  3.789 ms  4.499 ms
 3  * * *
 4  124.65.63.249 (124.65.63.249)  1.476 ms  1.952 ms  1.972 ms
 5  123.126.8.169 (123.126.8.169)  2.234 ms 124.65.57.113 (124.65.57.113)  3.730 ms  3.731 ms
 6  * * *
 7  * 219.158.112.46 (219.158.112.46)  42.740 ms *
 8  219.158.103.42 (219.158.103.42)  42.498 ms 219.158.24.126 (219.158.24.126)  40.778 ms  40.793 ms
 9  219.158.24.134 (219.158.24.134)  40.229 ms  40.226 ms  40.200 ms
10  219.158.96.30 (219.158.96.30)  196.130 ms  195.833 ms  195.793 ms
11  * * *

我们发现虽然VPN已经连接成功,但是路由没有通过VPN上网,第1跳还是localhost (192.168.2.1)

再查看网络连接配置

~ ifconfig

返回结果如下:

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:405 errors:0 dropped:0 overruns:0 frame:0
          TX packets:405 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:104287 (104.2 KB)  TX bytes:104287 (104.2 KB)

p3p1      Link encap:Ethernet  HWaddr b0:83:fe:84:2e:60  
          inet addr:192.168.2.182  Bcast:192.168.2.255  Mask:255.255.255.0
          inet6 addr: fe80::b283:feff:fe84:2e60/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8762 errors:0 dropped:0 overruns:0 frame:0
          TX packets:7325 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:3815784 (3.8 MB)  TX bytes:1856716 (1.8 MB)

ppp0      Link encap:Point-to-Point Protocol  
          inet addr:192.168.1.211  P-t-P:192.168.1.2  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1460  Metric:1
          RX packets:7 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:3 
          RX bytes:342 (342.0 B)  TX bytes:46 (46.0 B)

查看 路由表

~ route -n

返回

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.1     0.0.0.0         UG    0      0        0 p3p1
124.205.150.18  192.168.2.1     255.255.255.255 UGH   0      0        0 p3p1
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 p3p1
192.168.1.2     0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 p3p1

列出路由表条目

ip route show
default via 192.168.2.1 dev p3p1 
124.205.150.18 via 192.168.2.1 dev p3p1  src 192.168.2.182 
169.254.0.0/16 dev p3p1  scope link  metric 1000 
192.168.1.2 dev ppp0  proto kernel  scope link  src 192.168.1.211 
192.168.2.0/24 dev p3p1  proto kernel  scope link  src 192.168.2.182 

我们发现默认路由是指向eth0, 我们要修改路由配置, 使其指向ppp0

修改路由配置

修改路由命令

~ sudo ip route del default
~ sudo ip route add default dev ppp0

再看看路由信息

~ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         0.0.0.0         0.0.0.0         U     0      0        0 ppp0
124.205.150.18  192.168.2.1     255.255.255.255 UGH   0      0        0 p3p1
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 p3p1
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.1.2     0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 p3p1
~ ip route
default dev ppp0  scope link 
124.205.150.18 via 192.168.2.1 dev p3p1  src 192.168.2.182 
169.254.0.0/16 dev p3p1  scope link  metric 1000 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 linkdown 
192.168.1.2 dev ppp0  proto kernel  scope link  src 192.168.1.211 
192.168.2.0/24 dev p3p1  proto kernel  scope link  src 192.168.2.182 

~ traceroute www.google.com

traceroute to www.google.com (4.35.153.251), 30 hops max, 60 byte packets
traceroute to www.google.com (4.35.153.251), 30 hops max, 60 byte packets
 1  192.168.1.2 (192.168.1.2)  79.715 ms  80.120 ms  80.113 ms
 2  67.203.7.193.rdns.ColocationAmerica.com (67.203.7.193)  82.697 ms  82.829 ms  83.315 ms
 3  * * *
 4  67.203.3.161.rdns.ColocationAmerica.com (67.203.3.161)  232.638 ms  232.631 ms  232.624 ms
 5  * * *
 6  tge4-1.cr2.lax.multacom.com (208.64.231.6)  265.099 ms  256.633 ms  242.120 ms
 7  los-edge-07.inet.qwest.net (65.153.29.221)  246.835 ms  246.829 ms  246.823 ms
 8  los-brdr-01.inet.qwest.net (67.14.102.110)  233.854 ms los-brdr-01.inet.qwest.net (67.14.102.114)  233.992 ms  233.986 ms

查看第一跳, 已经通过VPN实现路由。

这个时候, 你如果使用浏览器访问 google 的话, 可以发现已经成功翻墙了。

停止VPN

~ poff myvpn

再ping网站, 发现网络出现问题。

ping: unknown host www.google.com
~ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
124.205.150.18  192.168.2.1     255.255.255.255 UGH   0      0        0 p3p1
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 p3p1
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.2.0     0.0.0.0         255.255.255.0   U     0      0        0 p3p1
~ ip route
124.205.150.18 via 192.168.2.1 dev p3p1  src 192.168.2.182 
169.254.0.0/16 dev p3p1  scope link  metric 1000 
192.168.2.0/24 dev p3p1  proto kernel  scope link  src 192.168.2.182

重置路由

~ sudo ip route add default via 192.168.1.1

这样, 就有可以上网了。

通过ip-up, ip-down 配置路由

~ sudo vi /etc/ppp/ip-up.d/route-traffic
#!/bin/bash
/sbin/ip route add 50.116.27.194 via 192.168.1.1
/sbin/ip route del default
/sbin/ip route add default dev ppp0
~ sudo vi /etc/ppp/ip-down.d/disableroute
#!/bin/bash
/sbin/ip route add default via 192.168.1.1

重启VPN连接

~ sudo pon myvpn

正常退出

~ sudo poff myvpn

这里总结一下运维工作范畴

要让一切变得清晰, 可见, 高效

一、 资源管理

  • 域名管理: 域名购买, 续费, 解析等
  • 主机管理: 主机购买, 续费, 迁移, 注销等
  • 账号管理:
    • 域名服务商账号
    • 主机服务商账号
    • 主机账号
    • webmaster账号
    • 工具站点账号

二、 服务监控

  • 网站是否正常运行: 网站是否能正常提供服务
  • 服务是否正常运行: 电子邮件系统是否正常
  • 服务器健康状况: 负载情况, 内存状况, 磁盘状况, cpu状况

三、 安全防护

  • 网站防火墙的规则, 以及定期的检查
  • 使用工具定期对网站进行安全扫描
  • 合理配置权限

四、 日志分析

  • 合理的采集和切分网站日志
  • 通过 ELK 分析网站日志
  • 检查防火墙规则, 观察 client 被 ban 的情况
  • 安装 pwiki 日志工具, 可视化的分析网站的访问情况

五、 服务部署

  • 目前人工安装所有服务, 比较低效, 希望能够尽可能实现自动化,尤其是对于通用环境。
  • 探索 docker 对于我们的业务部署是否有价值和意义,多看一些相关的资料
  • 探索 jenkins 工具, 对于我们的业务部署,日常代码上线是否有价值和意义,多看一些相关的资料

六、 脚本分发

  • 熟练使用 ansible , 便于通过一台机器管理多台机器
  • crontab 的管理, 日志的分析: 脚本要有输出, 输出要有采集, 采集要易于查看
  • 数据备份日志分析: 脚本要有输出, 输出要有采集, 采集要易于查看

七、 SEO工作

  • 理清 SEO 工作范畴: 制作网站, 制作页面, 上线网站, 更新网站, 提交 sitemap
  • 理清 SEO 工作流程, 脚本, 工具, 部署的要求。
  • 理清 SEO 工作标准, 如何测试, 检查。

八、 做好总结工作

  • 每次对服务器做了变动和修改, 需要记录日志: 某月某日, 做了什么事情
  • 每次服务器出现异常, 需要分析清楚原因, 并提出改善的方案
  • 尽量避免误操作, 一旦发现误操作, 应当总结反思, 避免重蹈覆辙

概述

如何做好运维工作呢? 首先需要对运维工作做一个全面的分析和理解。 只有这样,才能站在一定的高度,站在全局来管理这部分工作,从而使得方方面面的事情得以完整的展开,而不出问题。

运维工作的作用: 运维工作在所有工作中是什么样的地位, 它与其他工作是一个怎样的关系, 站在运维的角度上来说, 需要怎样做才算是到位。

运维工作的性质:

运维工作的重点:

总的工作方针

事情需要靠人来推动, 在工作的过程中, 人是事情的核心, 因此管理工作非常重要, 人的组织和安排, 培训和培养, 需要重视。

一、目标与任务

1、 快速部署: 新的设备,新的服务部署
2、 性能监控: 性能监控,报警
3、 异常处理: 异常问题的分析处理经验,流程
4、 日志分析: 日志是正常采集的, 可以被分析的
5、 数据备份: 数据是有备份的
6、 安全防护: 服务器是安全的

二、计划与安排

战略上, 需要做好整体的架构与安排
战略上, 有哪些新的工具可以为我所用
战略上, 整个系统有哪些地方可以进行优化
战略上, 有哪些新的技术需要学习

战术上, 一个任务,应该怎样完成, 需要分析
战术上, 需要完善文档, 如作业指导书, 资源地图...
战术上, 需要指定具体的计划与安排
战术上, 需要有服务器操作规范: 重要的操作,双重确认。 经常需要修改的配置文件要进行版本管理

三、落实,反馈,检查

  • 做什么事情, 怎样算完成, 需要有标准
  • 事情完成, 需要上级检查, 需要有反馈
  • 遇到问题, 需要及时汇报

四、 总结与反思

  • 定期总结自己的工作, 修正错误, 提高管理的效果。
  • 对于错误要认真总结反思, 避免再次犯错。

思想延伸

发现可以使用工业生产中 全面质量管理 的做法,

人们不应仅仅把TQC看作是控制质量的活动, 它还可以通过不断改善各个方面的工作,而被作为企业提升竞争力和赢利潜能的发展战略。 TQC 中的“Q”意味着质量——优先权,同时也包含了成本和交货期的控制目标。 “T”代表“全面、全员”,也就是说企业内的全部员工包括自上而下从企业最高领导到中层领导,直至生产线操作工人都要参与进来。另外,供应商、代理商和销售商也都加入。“T”还表示高质量的管理(Top—management),它要求企业的高层领导对企业内实施 TQC 的成功负有管理的责任和义务。 “C”代表控制(Control),也就是对过程的控制。借助于TQC人们可以弄清过程的本质,监控并不断完善它,这样以取得成功的改善。

持续改进思想的特点:

1、长远的和持续的,平和的,但不显著
2、许多的小幅度
3、连续的和增量的
4、逐步的和稳定的
5、涉及每一个人
6、集体主义、团队奋斗和系统方法
7、传统的诀窍和达到最新的技术发展水平的目标
8、维护和改进
9、强调较小的投资,但非常努力维持
10、向人员倾斜
11、争取更好结果(能力)的过程
12、对慢速增长的经济有效

原则

  • 丢掉对工艺原有的僵化的看法
  • 考虑怎样可以做事情,而不是找出不做的理由
  • 不找借口,对现有方法质疑
  • 不要追求完美,马上付诸实施,尽管只达到约定目标的5%
  • 立即纠正错误
  • 排除障碍,寻找解决方法
  • 问上五次“为什么?”,并寻找真正的原因
  • 集合大家的意见而不仅仅是个别人的主意

爬虫是数据搜集系统中的一个重要工具,主要用于从Web上搜集数据。一般一个爬虫的流程如下:

func Crawler(seed_url):
Q = Queue()
Q.append(seed_url)
while !Q.empty() :
link = Q.pop()
html = download(link)
sub_links = extract_links(html)
for link in sub_links:
Q.append(link)

如果我们要设计一个分布式爬虫,可以将上述程序分成3个部分:

downloader : 输入一个url,返回这个url对应的HTML
link extractor : 输入一个HTML,返回这个HTML中的链接
redirector : 负责接收link extractor提取的链接,并且将这些链接转发给downloader

不过,因为downloader主要消耗网络资源,而link extractor主要消耗CPU资源,因此我们可以将1,2部分合并在一个程序中。我们把合并后的程序也称为downloader。downloader集群通过nginx做负载均衡和外面通信。而downloader集群的鲁棒性可以通过nginx的health check实现。
Downloader

downloader的任务就是 1. 给定一个url,将他对应的HTML下载下来,写到磁盘上 2. 从HTML中提取链接,并将提取出来的链接发送给redirector

下载网页这一步是需要解决一下的问题: 1. 如何通过HTTP GET下载网页(这个是最简单的) 2. 如何使用HTTP 代理 3. 如何通过HTTP POST下载网页,这个涉及到表单的自动post 4. 如何处理页面的Javascript,获得Ajax的调用内容 5. 如何处理非HTML网页,比如PDF,Excel等等
Redirector

redirector的任务是 1. 控制每个不同网站的爬取速率 2. 控制网站爬取的优先级 3. 控制网页的更新速率(同一个网页,什么时候再爬一次)

所以,redirector从downloader接受到新的链接后,要对链接进行排序,整理,再发送给downloader下载。从而redirector和downloader之间形成闭环。
Golang

golang在实现上述逻辑时,可以充分发挥它强大的channel特性。

比如,如何控制不同网站的爬取速率?

可以给每个域名建立一个channel,每个域名的网页都进入到各自的channel。然后channel的消费者按照一定的速率从channel中取出链接进行消费。

不过使用channel也有一个问题。就是channel是阻塞的,如果channel满了,一定要消费者消费一个才能往里面放东西。而因为我们整个系统是一个环状系统:

downloader 有一个input的queue A
redirector 有一个input的queue B
redirector将B中的链接放入A
download消费A中的链接,得到新链接,放入到B

这时候,如果A,B都满了,redirector和downloader就会出现死锁,因为他们都需要别人先动一下,自己才能动。

因此,我们就需要设计一个逻辑,让所有的queue都不可能满。这样就只能利用文件系统了。

如果queue满了,将链接写文件
如果queue没有满,将链接写入queue中
如果queue空闲了,将文件中的链接写入queue

管道(Channel)是Go语言中比较重要的部分,经常在Go中的并发中使用。今天尝试对Go语言的管道来做以下总结。总结的形式采用问答式的方法,让答案更有目的性。

Q1.管道是什么?
管道是Go语言在语言级别上提供的goroutine间的通讯方式,我们可以使用channel在多个goroutine之间传递消息。channel是进程内的通讯方式,是不支持跨进程通信的,如果需要进程间通讯的话,可以使用Socket等网络方式。

以上是管道的概念,下面我们就看下管道的语法。

Q2.管道的语法?

整个Go语言的语法都比较简洁,管道也不例外,其语法如下所示:

在此应当注意,管道是类型相关的,即一个管道只能传递一种类型的值。管道中的数据是先进先出的。

 1 // 声明方式,在此ElemType是指此管道所传递的类型
 2 var chanName chan ElemType
 3 // 声明一个传递类型为int的管道
 4 var ch chan int
 5 // 声明一个map,元素是bool型的channel
 6 var m map[string] chan bool
 7 
 8 // 定义语法,定义需要使用内置函数make()即可,下面这行代码是声明+定义一个整型管道
 9 ch := make(chan int)
10 // 事先定义好管道的size,下面这行代码定义管道的size为100
11 ch := make(chan int, 100)
12 
13 // 由管道中读写数据,<-操作符是与最左边的chan优先结合的
14 // 向管道中写入一个数据,在此需要注意:向管道中写入数据通常会导致程序阻塞,直到有
15 // 其他goroutine从这个管道中读取数据
16 ch<- value
17 // 读取数据,注意:如果管道中没有数据,那么从管道中读取数据会导致程序阻塞,直到有数据
18 value := <-ch
19 
20 // 单向管道
21 var ch1 chan<- float64     // 只能向里面写入float64的数据,不能读取
22 var ch2 <-chan int         // 只能读取int型数据
23 
24 // 关闭channel,直接调用close()即可
25 close(ch)
26 // 判断ch是否关闭,判断ok的值,如果是false,则说明已经关闭(关闭的话读取是不会阻塞的)
27 x, ok := <-ch

Q3.管道的使用场景?

在第一个问题中,我们已经知道管道可以做进程间通讯,Go中自带了对协程的支持(关键字go),而管道就是各个协程间通讯的一个方法。这里我们举些简单的小例子来说明一下管道如何在协程中使用。

 1 package main
 2 import "fmt"
 3 
 4 func print() {
 5     fmt.Println("Hello world")
 6 }
 7 
 8 func main() {
 9     for i := 0; i < 10; i++ {
10         go print()
11     }
12 }

上面的代码意思大致是:使用协程来并行输出10次 "Hello world", 但是大家运行上面代码的时候,会发现不会有输出。这是因为虽然使用go关键字进行了协程的创建,但是还没有等到执行的时候,main函数已经退出来了,进程已经关闭,所以起来的协程也不会被执行。

如果你有C相关的多线程经验时,可已经将协程改为线程,之后调用线程的join方法,让主线程等待子线程执行完毕后再退出。而在Go语言中,我们可以利用管道的写入阻塞和读取阻塞来完成类似线程join的行为。代码如下所示:

 1 package main
 2 import "fmt"
 3 
 4 func print(ch chan int) {
 5     fmt.Println("Hello world")
 6     ch<- 1
 7 }
 8 
 9 func main() {
10     chs := make([]chan int)
11     for i := 0; i < 10; i++ {
12         chs[i] = make(chan int)
13         go print(chs[i])
14     }
15     
16     for _, ch := range(chs){
17         <-ch
18     }
19 }

通过以上代码,我们就可以完成了并行输出10此Hello world 的效果。

有一个问题留给大家,如果将 print改为

func print(ch chan int){
     ch<- 1
     fmt.Println("Hello world")
}

会打印出什么呢?

由于水平有限,难免会有错误,请大家指正。
谢谢。