2016-01-07 zhangjinnan SOHU-DBA
有效定位和解决 OpenStack 问题
对 OpenStack 这样一个庞大的系统来说,遇到问题很正常,如何对遇到的问题进行精确的定位和解决才是关键?但在很多时候,从用户表象上看到的现象和后端真正的错误往往会有一些偏差。本文以 OpenStack 虚拟机启动工作流为基础,对 OpenStack troubleshooting 做一个介绍。从了解整个 OpenStack 中最核心的虚拟机管理,来对整个 OpenStack 的设计架构有个了解,为今后更复杂的问题提供一些参考。
从启动虚拟机说起
在开始之前,如果你曾经使用过 OpenStack,那请你花几分钟时间回忆一下,你所了解的虚拟机创建过程是怎么样的?如果你还没来得及安装 OpenStack,那我建议你先用 RDO 安装一个,这样以便于让你能更好的对下面的内容进行学习。
启动一个虚拟机需要涉及的组件
- CLI:OpenStack 命令行工具,可以通过命令来创建虚拟机。
- Horizon:OpenStack 图形化界面,可以更友好的通过图形化来操作虚拟机。
- Nova:OpenStack 计算核心组件,调用后端的虚拟化平台 API 接口来最终通过镜像创建虚拟机。
- Glance:OpenStack 镜像管理组件,虚拟机创建过程中需要从这个组件获取虚拟机镜像。
- Cinder:OpenStack 存储管理组件,管理后端存储资源,并为虚拟机提供持久化存储的能力。
- Neutron:OpenStack 网络管理组件,虚拟机创建过程中需要通过此组件获取网络信息。
- Keystone:OpenStack 认证组件,虚拟机创建过程中用户和服务认证需要此服务支撑。
- MQ(RabbitMQ):消息中间件,支持 OpenStack 组件内通讯。
Nova 组件架构和通讯方式
Nova 组件是整个虚拟机启动过程中最重要的组件,Nova 的整个设计如下图所示:
整个 Nova 的设计可以总结如下几点:
- Nova 组件内部模块之前通讯采用 AMQP
- Nova 组件和其它组件之间通讯采用 RESTful API
- Nova 组件有本身数据库存储持久化数据
可以通过 Nova 的架构图回味一下 Cinder、Neutron、Ceilometer 的结构,会发现 OpenStack 设计上都有类似的地方。当了解了 Nova 组件内和组件间的交互形式,就可以更好的把之前说到的整个虚拟机创建过程中涉及到的所有组件串起来,下面用一个虚拟机创建的流程想想说明这个过程。
启动虚拟机流程
在 OpenStack 中,启动虚拟机整个过程看似几秒钟完成的工作,其涉及的相关知识还是相当丰富。曾近有人统计了所涉及的技术,应该在 100 个知识点以上,这里就不拿出来吓唬大家。重点把整个虚拟机启动过程的图就我的理解进行了整理,如下(有部分是盗用):
虚拟机启动过程如下:
- 界面或命令行通过 RESTful API 向 keystone 获取认证信息。
- keystone 通过用户请求认证信息,并生成 auth-token 返回给对应的认证请求。
- 界面或命令行通过 RESTful API 向 nova-api 发送一个 boot instance 的请求(携带 auth-token)。
- nova-api 接受请求后向 keystone 发送认证请求,查看 token 是否为有效用户和 token。
- keystone 验证 token 是否有效,如有效则返回有效的认证和对应的角色(注:有些操作需要有角色权限才能操作)。
- 通过认证后 nova-api 和数据库通讯。
- 初始化新建虚拟机的数据库记录。
- nova-api 通过 rpc.call 向 nova-scheduler 请求是否有创建虚拟机的资源 (Host ID)。
- nova-scheduler 进程侦听消息队列,获取 nova-api 的请求。
- nova-scheduler 通过查询 nova 数据库中计算资源的情况,并通过调度算法计算符合虚拟机创建需要的主机。
- 对于有符合虚拟机创建的主机,nova-scheduler 更新数据库中虚拟机对应的物理主机信息。
- nova-scheduler 通过 rpc.cast 向 nova-compute 发送对应的创建虚拟机请求的消息。
- nova-compute 会从对应的消息队列中获取创建虚拟机请求的消息。
- nova-compute 通过 rpc.call 向 nova-conductor 请求获取虚拟机消息。(Flavor)
- nova-conductor 从消息队队列中拿到 nova-compute 请求消息。
- nova-conductor 根据消息查询虚拟机对应的信息。
- nova-conductor 从数据库中获得虚拟机对应信息。
- nova-conductor 把虚拟机信息通过消息的方式发送到消息队列中。
- nova-compute 从对应的消息队列中获取虚拟机信息消息。
- nova-compute 通过 keystone 的 RESTfull API 拿到认证的 token,并通过 HTTP 请求 glance-api 获取创建虚拟机所需要镜像。
- glance-api 向 keystone 认证 token 是否有效,并返回验证结果。
- token 验证通过,nova-compute 获得虚拟机镜像信息 (URL)。
- nova-compute 通过 keystone 的 RESTfull API 拿到认证 k 的 token,并通过 HTTP 请求 neutron-server 获取创建虚拟机所需要的网络信息。
- neutron-server 向 keystone 认证 token 是否有效,并返回验证结果。
- token 验证通过,nova-compute 获得虚拟机网络信息。
- nova-compute 通过 keystone 的 RESTfull API 拿到认证的 token,并通过 HTTP 请求 cinder-api 获取创建虚拟机所需要的持久化存储信息。
- cinder-api 向 keystone 认证 token 是否有效,并返回验证结果。
- token 验证通过,nova-compute 获得虚拟机持久化存储信息。
- nova-compute 根据 instance 的信息调用配置的虚拟化驱动来创建虚拟机。
在虚拟机创建过程中,可以看到一个任务状态(Task),可以通过这个状态初步判断虚拟机处于哪个步骤:
- scheduling(3~12)
- networking(23~25)
- block_device_mapping(26~28)
- spawing(29)
- none(虚拟机创建成功)
记住这些状态,这个是在整个排错过程中最重要的一个状态。可以通过这个状态初步判断整个过程处于什么位置,可以很快的把问题缩小在一个比较小的范围。
永远的日志
看到这里估计在排错的时候心里就有底气多了,不会满世界的去找问题。但还是需要提醒大家,有问题——> 找日志。别看这个大家都懂的事情,往往在操作起来,大家跟愿意直接找个人问出了什么问题。大概的归类了一下 OpenStack 的日志:
- nova
- /var/log/nova/*(api.log/compute.log)
- neutron
/var/log/neutron/*
glance
/var/log/glance/*
cinder
/var/log/cinder/*
keystone
/var/log/keystone/*
libvirtd
/var/log/libvirt/*(qemu 里的日志很重要!!)
虚拟机涉及文件
一个虚拟机默认情况下启动过程、或者启动后会在其调度的 nova-compute 节点的 / var/lib/nova/instances 目录下会生成如下的文件:
- base 目录下一个 base 镜像
- libvirt.xml
- disk
- disk-raw
- kernel
- ramdisk
- console.log
辅助的工具
工具千千万只是能提升效率的一个点,关键还是在于对整个过程的理解。在 OpenStack 使用过程中会用到一些工具辅助排除错误,常用工具如下:
工具名称 | 工具用途 | 说明 |
strace | 系统调用跟踪 | 一个简易且十分好用的系统调研跟踪工具 |
lsof | 查看打开文件 | 可以很容易的对打开的文件进行查看 |
tcpdump | 网络抓包分析 | 可以通过抓发分析网络不通 |
kill | kill -USR1 | 最近发现的牛掰用法 |
strace 用法
- strace -e open ping
- strace -p process_id
- strace -c ping
- strace -e trace=network nc 127.0.0.1 22
lsof 用法
- lsof -p process_id
- lsof -i :22 -n
tcpdump 用法
- tcpdump -i interface icmp(其它更多参考 tcpdump 命令)
- 建议配合 wireshark 来分析报文
kill -USR1 用法
OpenStack 提供 SIGUSR1 用户定义的信号生成 Guru Meditation 报告,报告包含如下服务的完整信息和状态,这些状态会输出到标准错误输出中,可以在错误日志中查看。
[kevin@stack ~]$ ps -ef|grep nova-api
kevin 4320 3116 30 11:06 pts/7 00:00:03 /usr/bin/python /usr/bin/nova-api
kevin 4335 4320 2 11:06 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
kevin 4336 4320 2 11:06 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
kevin 4339 4320 4 11:06 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
kevin 4340 4320 4 11:06 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
kevin 4349 4320 9 11:06 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
kevin 4350 4320 11 11:06 pts/7 00:00:00 /usr/bin/python /usr/bin/nova-api
kevin 4360 4205 0 11:07 pts/23 00:00:00 grep --color=auto nova-api[kevin@stack ~]$ kill -USR1 4320
报告包含如下章节:
- 软件包信息
- Threads
- Green Threads
- 配置文件
============================================================================ Guru Meditation ============================================================================||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||============================================================================ Package ============================================================================product = OpenStack Novavendor = OpenStack Foundationversion = 13.0.0============================================================================ Threads ============================================================================------ Thread #139957736490816 ------/usr/lib/python2.7/site-packages/eventlet/hubs/hub.py:346 in run `self.wait(sleep_time)`/usr/lib/python2.7/site-packages/eventlet/hubs/poll.py:82 in wait
`sleep(seconds)`============================================================================ Green Threads ============================================================================------ Green Thread ------
/usr/bin/nova-api:10 in <module> `sys.exit(main())`/home/kevin/openstack/nova/nova/cmd/api.py:53 in main `launcher.wait()`/usr/lib/python2.7/site-packages/oslo_service/service.py:520 in wait
`self._respawn_children()`/usr/lib/python2.7/site-packages/oslo_service/service.py:504 in _respawn_children `eventlet.greenthread.sleep(self.wait_interval)`/usr/lib/python2.7/site-packages/eventlet/greenthread.py:34 in sleep `hub.switch()`/usr/lib/python2.7/site-packages/eventlet/hubs/hub.py:294 in switch `return self.greenlet.switch()`------ Green Thread ------
No Traceback!============================================================================ Processes ============================================================================Process 4320 (under 3116) [ run by: kevin (1000), state: running ]
Process 4335 (under 4320) [ run by: kevin (1000), state: sleeping ]
Process 4336 (under 4320) [ run by: kevin (1000), state: sleeping ]
Process 4339 (under 4320) [ run by: kevin (1000), state: sleeping ]
Process 4340 (under 4320) [ run by: kevin (1000), state: sleeping ]
Process 4349 (under 4320) [ run by: kevin (1000), state: sleeping ]
Process 4350 (under 4320) [ run by: kevin (1000), state: sleeping ]============================================================================ Configuration ============================================================================api_database: connection = *** connection_debug = 0 connection_trace = False idle_timeout = 3600 max_overflow = None max_pool_size = None max_retries = 10 mysql_sql_mode = TRADITIONAL pool_timeout = None retry_interval = 10 slave_connection = *** sqlite_synchronous = True
……此处省略其它配置
总结
OpenStack troubleshooting 的过程中,最重要的是梳理 OpenStack 的流程。在梳理流程的基础上,配合一些工具可以解决大部分在运行过程中遇到的问题。另外一方面,由于 OpenStack 本身是一个云管理框架,在排错的过程当中,你往往会遇到很多 KVM、存储、OVS、iptables 这块的问题,对于这块的问题的解决,还是需要对其原理有一个深刻的理解才行。
几个课后练习
- nova-api 服务停止的情况下,nova-list 可以列出虚拟机吗?为什么?
- 用 kill 命令尝试终止 nova-conductor 进程,会有什么报错?(提示先从日志开始)
- 用 strace 跟踪一下某个进程的系统调用。
http://prajnagarden.com/openstack/2015/12/18/instance-boot-workflow-troubleshooting/