7月 052018
 

错误信息:

查看卷列表时,dashboard提示: 无法获取连接信息 ; 英文提示应该是: Unable to retrieve attachment information.

 

查看日志:

发现一个卷是挂在某个实例上的,但是实例早被删掉了,所以“无法获取连接信息”;

实例ID: a95f316f-aeb7-40ce-8887-9145499518fc

卷ID: 7f75f270-17a9-4694-aff3-70c950f9c9b5

 

解决办法:

直接从cinder数据库中修改该卷的相关信息,然后删掉,相关表:

volume_attachment

volumes

 

sql 语句:

 

 

相关代码:

/usr/share/openstack-dashboard/openstack_dashboard/dashboards/project/volumes/tables.py  598 行

 Posted by at 上午 11:40
6月 052018
 

列出所有安全组:

 

列出所有名叫default的安全组的ID:

 

列出指定安全组下的所有规则: (–long 显示每条规则的方向,默认不显示方向)

可以通过–ingress   –egress  只显示指定方向上的规则; 通过 –protocol 显示指定协议相关的规则

 

实际应用:

检查是否所有的“default” 安全组都设置了允许所有tcp、udp都可以主动外出的规则:

结果输出:

如果输出了tcp和udp就意味着是正确的

 

添加安全组规则:

允许所有tcp主动外出访问:

 

 Posted by at 下午 2:43
5月 242018
 

如下图: 虚拟机管理器和计算主机中显示的主机的名字不同,为什么呢?

 

说明:

虚拟机管理器说的是hypervisor,具体来讲就是libvirtd

主机说的是虚拟机管理器所在的宿主机,就是我们所谓的计算节点

二者的信息都是记录在nova.compute_nodes 表中的,二者都没有唯一约束;

当然,host是不会重复的;特殊情况下hypervisor_hostname 重复是有可能的; 从dashboard来看,节点资源是hypervisor的,而不是host的。

而且也可以存在一个host上有多个虚拟机管理器的情况,一个nova-compute接到任务后,可以通过不同的虚拟机管理器来创建虚拟机

 

分析:

不同计算节点上使用相同hypervisor_hostname时,hypervisor将拥有了多个机器的资源,那么虚拟机调度时参考hypervisor_hostname的资源的话,虚拟机分配的任务最终会被分配到哪个host上呢?毕竟不同host上都有nova-compute进程的; 另,上报资源时使用的是node的uuid还是host还是hypervisor_hostname?

node的uuid又是如何生成的呢?

hypervisor_hostname 是如何获取到的呢?hypervisor_hostname是不是第一次注册的时候写入后来就不再修改了呢?

主机资源是记录在 nova_api.resource_providers 表中的:

当然,只有nova.compute_nodes 表中记录的uuid才是有效的resource_providers,才会被dashboard显示

 

为什么node节点的hostname已经修改了,虚拟机管理器中显示的还是以前的名字?

nova-compute.log 中会有错误信息:

 

问题: 谁和谁不一致?重启谁?

解决办法:

比较: hostname 和virsh hostname的结果:

二者是不同的,前者的信息是从libvirtd中获取到的,也就是说,libvirtd中显示的主机名和当前的主机名不一致,需要重启libvirtd, 相关逻辑:

 

 

问题:

  1. 重启libvirtd需要先关闭所有虚拟机吗?
    答案: 不需要的,直接重启就行
  2. 虽然我重启了libvirtd,但是virsh hostname 还是 和 hostname不一样,为什么?
    答案: 因为我在/etc/resolv.conf 中配置了search i.beebank.com, libvirtd会自动suffix上search domain的
  3. 虽然现在virsh hostname 和hostname一致了,但是dashboard中看到的还是原来的,为什么?
    答案: 重启一下openstack-nova-compute

 

总结:

  1. 确认一下 /etc/resolv.conf  的配置
  2. systemctl restart libvirtd && systemctl restart openstack-nova-compute

注意:

  1. 修改了libvirtd的hostname之后,需要去数据库中手动修改相关虚拟机(nova.instances表中)的hypervisor_hostname,否则,就找不到这些机器的hypervisor了,而新的hypervisor下也是没有虚拟机的

 

 

 Posted by at 上午 11:13
3月 122018
 

本人使用的owncloud版本号: 8.2.8

第一步:

使用admin账号在“管理”部分开启外部存储配置:

第二步:

在任意账号(也可以是管理员账号)配置外部存储:

 

注意:

  • 这里支持的keystone协议版本号只能是v2.0 的,不可配置,所以Identity URI 类似于: http://openstack-controller:5000/v2.0/
  • 其中的swift就是对象存储服务的名字,可以通过openstack endpoint list查到
  • 其中的test(bucket)就是openstack中对象存储部分创建的一个容器的名字,当然,如果没有预先创建的话,会自动创建的,所以,你可以随便写

 

问题:

  • 只要openstack对象存储中的容器被owncloud挂载过,容器根目录就会出现一个名字为 “.” 的文件,该文件在owncloud中看不见的,在openstack-dashboard中可以看见,但是删除总失败,而且,如果不删除该文件的话,容器也是删除不了的; 测试发现,openstack-dashboard中是创建不了一个名字叫做”.” 的目录的,相关issue: https://github.com/owncloud/core/issues/7191
    • 解决办法:
      • 通过openstack命令删除 “.” 文件:
      • end
    • 总结:这里似乎暴露了两个问题:
      • owncloud为什么要创建一个 “.” 文件,真的有必要吗?而且,就算是把 “.” 文件删除掉了,只要owncloud一访问,该文件就又出现了,暂且不太影响,pass
      • openstack-dashboard为什么就删除不了 “.” 文件,应该是个bug吧

 

owncloud + openstack 对象存储的好处:

  • 给owncloud找了一个可靠的存储
  • 给openstack对象存储找了一个比较好的前端
    • 可以通过浏览器直接访问
    • 也可以通过webdav的方式直接mount到各种操作系统和终端(windows、linux、手机端等)
      • linux 上mount,eg:

参考:

 Posted by at 下午 2:37
1月 112018
 

gnocchi-api 访问基本在10s +, why ?

gnocchi-api 使用了 wsgiref , wsgiref 使用了 :

/usr/bin/gnocchi-api:

/usr/lib64/python2.7/wsgiref/simple_server.py :

(这里提到了个REMOTE_HOST的环境变量,含义就是“REMOTE_ADDR 对应的域名”, 而 address_string() 的命名也是ip地址对应的域名的意思,因为绝大部分的ip地址是反解不到域名的,所以,这个逻辑基本可以注释掉,不过,直接修改人家的代码不大好)

然而上面的 WSGIRequestHandler 基本上会执行到get_environ() , 进而执行到 BaseHTTPServer.py 中的 self.address_string() ,如下:

address_string() 函数又调用了 /usr/lib64/python2.7/socket.py 中的 getfqdn(), 如下:

然后就肯定会执行到gethostbtaddr() 了,该函数的具体实现又是什么逻辑呢? socket.py import了 _socket 模块中的所有函数,而gethostbyaddr()正是_socket 模块实现的,_socket 模块的实现见: /usr/lib64/python2.7/lib-dynload/_socketmodule.so , 可见,这是一个c实现的so文件,稍后再看:

 

测试发现,该函数当遇到IP地址时,肯定会做一次反向地址解析,反向地址解析不是所有dns都能支持的很好的,有些能快速返回,有些却不能(具体原因,稍后再查),比如: 公网地址的反向地址解析可以很快返回,私网地址的反向地址解析就很慢

 

解决办法:

办法一: 在 dns 上给自己的IP地址添加反向地址解析,这样反向地址解析就可以很快; 给每个IP地址都添加反向地址解析的话,比较麻烦,最好能有一个更好的办法,让某一类IP地址能直接返回错误,或返回一个自定义的域名; 这个办法的优点是: 不需要修改程序 ; 如果搞不定dns,那就修改程序吧

办法二: 修改/usr/lib64/python2.7/BaseHTTPServer.py  ,在 address_string() 中直接返回host,而不进行socket.getfqdn(host) 的调用

办法三: 修改 /usr/lib64/python2.7/socket.py 中的 getfqdn() 函数,对于ip地址的情况,不再调用 gethostbyaddr()

办法四: 其实,不是特别有信心的话,不要修改的太底层,没准儿影响到别的程序的; 更好的办法是:

在 /usr/bin/gnocchi-api 中wss.make_server(…) 时,提供了三个参数,还有两个参数是可以定制的,我们可以自己在 /usr/bin/gnocchi-api  中实现一个 MyWSGIRequestHandler ,继承自./simple_server.py 中的WSGIRequestHandler , 然后覆盖其中的address_string() 方法即可

 

按照办法四 修改后的 /usr/bin/gnocchi-api 如下:

 

测试发现,访问确实快多了,不再感觉到延迟了

 Posted by at 上午 11:56
12月 142017
 

场景,用docker做开发用的虚拟机,每个docker都有一个可以公开访问的IP地址。

由于docker和宿主机共享内核,一不小心可能会把整个宿主机搞挂,而且,docker热迁移也是个难题,所以,尽管openstack马上可以支持docker,我也不想让docker直接部署在计算节点;我的思路是,将docker部署在openstack管理的kvm虚拟机上,这样还能通过热迁移kvm的方式将容器迁移到别的计算节点。

 

注意事项:

  1. 关闭openstack的端口安全,注意:
    1. 需要先从安全组中拿掉
    2. 在管理员界面操作
  2. 热迁移后容器的IP地址在交换机上的mac地址与端口的映射不能及时更新
    1. 如果容器频繁地和外部通信的话,mac地址与端口的映射会被及时刷新
    2. 如果没能及时刷新的话,可以在与容器IP同网段的机器上,先clear一下arp缓存,在ping 一下容器IP,就可以了;
    3. 如何自动处理呢?在kvm虚拟机上(就是容器的宿主机上),docker exec到容器内部,然后ping一下网关就行。

 Posted by at 下午 2:01
12月 042017
 

现象:

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 上?

 Posted by at 下午 6:30
12月 042017
 

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/

 Posted by at 上午 10:42
11月 232017
 

网络初始化:

/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. 结果:

 Posted by at 下午 3:58