当while read 遇上ssh

为什么第二条命令输出的不是a b c三行?

改进:

这里把ssh的标准输入关闭了,结果就正常了,可见,原来不能输出三行是有ssh的标准输入导致的

再次验证如下:

这里比较清晰地说明了b、c被ssh给读走了

如果不想费这心思,完全可以别走管道:

 

有时候就是这样,能用简单明了的写法,最好别摆酷

 

非图片版:

 

vxlan 问题排查

现象:

openstack中创建的vpc网络中,虚拟机不能dhcp到IP地址,抓包分析如下:

这是openstack控制节点的网络相关信息,问题是: vxlan-60中一个虚机想要通过dhcp获取IP地址,现在dhcp的数据包可以通过eth0到达brqce4d2a54-44,抓包可以验证 :

但是vxlan-60上却抓不到dhcp数据包:

我觉得,到达了 brqce4d2a54-44 的vxlan数据包,如果vxlan id是60就直接转给vxlan-60 就是了,还可能被哪里的规则给拦截?问题都定位了这地步了,应该问题就出现在openstack-controller身上吧?不应该和其它机器有关系吧?(我不断祭出bridge fdb、brctl、ip等工具,浪费了有半天的时间)

后来,在我都试图想重启openstack-controller的时候,我决定分别在两个compute上创建两个机器,如果两个机器之间能够通信,则说明openstack-controller 的问题,否则,就不是openstack-controller的问题; 测试发现,两个机器不能通信,我才把重点放在了compute节点;

compute节点网络架构:

话说,这个网络和官方指导架构或者书本上指导的架构都不一样; 正常来讲,把bond0 添加到 /etc/neutron/plugins/ml2/linuxbridge_agent.ini 中就可以了,也不会出现今天的问题,因为最初是这样的,我测试vpc功能都是OK的;

加入我把bond0给了neutron,则neutron会将bond0的IP转移给brqce4d2a54-44 , 由于机器有限,我需要在这些compute节点上起ceph node,ceph node也通过虚拟机提供存储服务(如上图的vnet0),如果让vnet0桥接到brqce4d2a54-44 上,总感觉不大好,于是,便有了上述的网络架构;

既然  /etc/neutron/plugins/ml2/linuxbridge_agent.ini  里面配置成了veth_neutron ,那么 /etc/neutron/plugins/ml2/linuxbridge_agent.ini 里面的 local_ip 也应该修改为 veth_neutron 的IP,不是吗?(当然不是,错就错在这儿了),于是我就这么改了

 

 

因为vxlan-60 的 dev 是brqce4d2a54-44 ,数据只有先到达brqce4d2a54-44  才可能进入vxlan-60 ;

我发现,进入的vxlan数据包首先是要走到bond0的,然后走到br0,我期望能通过veth_br0 到 veth_neutron , 再到 brqce4d2a54-44 ,然后再到vxlan-60, 然而,实际情况是,vxlan数据包根本不进入veth_br0; 我猜测,很可能内核已经在分析vxlan数据包了,该给谁给谁,没人要就丢掉呗; 然而,vxlan-60是base在brqce4d2a54-44  上的,没有base在br0上; 如果让vxlan-60 base在br0上是不是就可以了呢?

关于vxlan-60 base在哪个设备是通过/etc/neutron/plugins/ml2/linuxbridge_agent.ini  里面的local_ip 来决定的,和 physical_interface_mappings 是不必相同的。

修改后,重启 neutron-linuxbridge-agent.service , 重新创建vpc, 问题解决。

 

思考:

为什么vxlan的目的IP是brqce4d2a54-44, 而实际却不能真正落到brqce4d2a54-44 上?

vxlan实践

vxlan 也能在单台机器上演示:

网络拓扑:

pic

执行命令:

  1. 创建两个网络名字空间:(相当于做了两个虚拟机)

     
  2. 创建一个设备对儿:

     
  3. 将设备对分别添加到两个名字空间:

     
  4.  进入名字空间进行配置:

     
  5. 进入另外一个名字空间进行类似配置:

     
  6. 通过ip link show veth01   和ip link show veth10, 查到:
    veth01 Mac: fe:ea:f2:aa:1f:fc
    veth0 Mac: ee:b4:c4:3f:b3:2b
  7. 添加转发表:
  8. 验证:

     
  9. 注意:我们在各自的名字空间内ping不到自己的IP,因为我们没有启动lo,启动lo就可以ping到自己了

 

参考: http://tech.mytrix.me/2017/04/vxlan-overlay-in-linux-bridge/

watch + ssh 远程top

通过ssh远程top一次ceph用户的所有进程:

如果想查看多次(3次):

如果想以本机的top效果查看,则可以:

其实,根本不用watch :

但是如果想在一个机器上查看2个机器的top呢?

如果如果想在一个机器上查看4个机器的top呢?写4遍ssh好繁琐:

分割线的打印,参考: https://stackoverflow.com/questions/5349718/how-can-i-repeat-a-character-in-bash

 

cloud-init 源码阅读

网络初始化:

/usr/lib/python2.7/site-packages/cloudinit/stages.py:

 

分析:

  1. 每次都查找网络配置
  2. 如果找到配置,则 self.distro.apply_network_config_names(netcfg)
    1. 对于新机器,则 self.distro.apply_network_config(netcfg, bring_up=bring_up)  ,包括
      1.  写 ifcfg-eth0 配置文件
      2. if bring_up ,则,启动该网络设备

 

/usr/lib/python2.7/site-packages/cloudinit/stages.py:

分析:

先尝试从三个不同的地方获取网络配置(注意,这里是有优先级的):cmdline、system_cfg、datasource中的network_config; 只要其中一个地方明确禁用网络或存在配置则返回;

如果没有找到任何配置,则进入预定义的配置逻辑net/__init__.py: net.generate_fallback_config() :

 

分析:

  1. lo 排除在外
  2. list目录 SYS_CLASS_NET = “/sys/class/net/”  ,可以找到多个网络设备,如:
  3. 分析现有的网络设备,看看哪个最适合连网
    “””Determine which attached net dev is most likely to have a connection and
    generate network state to run dhcp on that interface”””

    1. 如果是veth开头的,认为是设备对,不考虑
    2. 如果存在 /sys/class/net/{$name}/bridge  则认为是(肯定是)网桥, 也不考虑
    3. 如果是插着线(carrier)的,则加入可以考虑的接口列表,如何判断是否插着线呢?
      参考:

       

      简单说就是: cat /sys/class/net/{$name}/carrier    如果结果是整数,则是插着线呢,否则就没插线,如下:

      注意:
      插着线的意思是,线的两端都是加了电的网络设备,即: 数据链路层是UP的;
      有些网络设备的该文件是不能cat的,如:

    4. 如果cat /sys/class/net/{$name}/dormant  是一个大于0的整型值,也可以考虑
    5. 参考文件 /sys/class/net/{$name}/operstate  ,这里记录了设备的状态,如果状态是: ‘dormant’, ‘down’, ‘lowerlayerdown’, ‘unknown’, 也可以考虑
    6. 最后,对可以考虑的列表进行排序;排在前面的优先考虑; 不过还有个例外,程序里面定义了一个默认的网络设备 DEFAULT_PRIMARY_INTERFACE,就是 eth0, 排序后被特意添加到了列表的最前面; 不出意外的话,后续胜出的基本就是eth0了
  4. 根据上面得到的列表,查找设备的mac地址,只要有一个设备有mac地址,该设备就胜出了,后面的就没戏了
  5. 最后,返回网络配置

     

总结:

分析可知,如果不对网络进行特殊配置的话,cloud-init只能帮我们配置一个网卡; 一般来讲,大部分需求已经满足了。

我们如果看 cloud-init ( /var/log/cloud-init.log )的日志的话,会发现,在多个网卡的时候,虽然其他网卡的信息也被read了,但是最终却没有得到和eth0相同的待遇,现在也就真相大白了

 

 

 

堆栈:

关于cmdline的获取方法: (util.py)

  1. 容器的话,cat /proc/1/cmdline
  2. 非容器的话, cat /proc/cmdline
  3. 结果:

变化的mac地址

 

一个bridge诞生时,会有一个mac地址;当向bridge上addif  veth2时,bridge的mac地址就跟随了veth2的mac地址,难道br0就不能固定一个mac地址吗?

可以的:

默认情况下,bridge总是跟随port中mac地址最小的那个port的mac地址,如果不想让mac地址总是变化,则可以设置bridge的首选mac地址,方法就是显式地给bridge设置mac地址:

参考:

http://blog.csdn.net/fanwenbo/article/details/2131193

查找网线在交换机哪个口的方法

已知:

  1. 我可以登录服务器
  2. 我可以登录交换机
  3. 服务器上有多块网卡,当前登录走网卡em1

任务:

  1. 要给em4配置ip地址

步骤:

  1. 首先找到em4在交换机的哪个口
    1. 在服务器上:
    2. 在服务器上:
    3. 在交换机上
    4. 啥?没有?有可能,继续
    5. 在交换机上
    6. 在服务器上
    7. 在交换机上
    8. 把网卡重新设置为自动协商模式:
  2. 然后配置交换机上该端口
  3. 配置服务器IP

 

参考:

http://blog.csdn.net/ggxiaobai/article/details/53583290

fuser or lsof

如果要卸载一个目录,那么目录下任何一个文件被占用都是不能卸载的,但是通常会不假思索地使用fuser 挂载目录,如 挂载目录为 /data :

我们发现,fuser 并没有觉得谁在占用 /data ,然而lsof 却能知道; 实际上fuser仅仅查看当前的inode有没有被占用,还是lsof更适合此场景

其实,fuser -m 选项是可以的;  而且还可以fuser -k 直接杀掉相关的进程;

注意fuser 选项-m与-M的区别:

-m 会根据指定的位置计算该位置所在的挂载点,然后列出该挂载点文件系统相关的进程

-M 必须指定一个确切的挂载点,对于目录可以没有’ / ‘; 这个有时更加安全,有时候,对于已经卸载了的挂载点,就已经属于别的文件系统了

 

gops 工作原理

gops用来查看系统中存在的go进程。

注意事项:

gops有可能没发现你的go进程:

一方面可能进程是藏在容器中的,在宿主机上gops就发现不了

另一种情况,就是gops参考的是进程文件的特征,该特征在不同go版本可能不一样,比如,我的gops能发现go 1.11的go进程,就发现不了go 1.14的go进程

如下:

gops能list出来系统中的go进程,如果内置了agent的话,还能添加个星号,带星号的进程可以进行深度的分析(因为有agent呀)

那么,gops是如何找到所有go进程,又是如何识别出来agent的呢?

关键代码是这么写的:

 

  1. 拿到所有的系统进程
  2. 分析进程文件可以检测是否go进程
  3. 在进程的用户目录下查找 .config/gops/{$pid}  文件,如果存在,就认为是有内置了agent了,该文件中存放的是agentlisten的端口号

如下: