本系列会分析OpenStack 的高可用性(HA)概念和解决方案:
(1)OpenStack 高可用方案概述
(2)Neutron L3 Agent HA - VRRP (虚拟路由冗余协议)
(3)Neutron L3 Agent HA - DVR (分布式虚机路由器)
(4)Pacemaker 和 OpenStack Resource Agent (RA)
(5)RabbitMQ HA
(6)MySQL HA
(7)Pacemaker 和 OpenStack Resource Agent (RA)
Pacemaker 承担集群资源管理者(CRM - Cluster Resource Manager)的角色,它是一款开源的高可用资源管理软件,适合各种大小集群。Pacemaker 由 Novell 支持,SLES HAE 就是用 Pacemaker 来管理集群,并且 Pacemaker 得到了来自Redhat,Linbit等公司的支持。它用资源级别的监测和恢复来保证集群服务(aka. 资源)的最大可用性。它可以用基础组件(Corosync 或者是Heartbeat)来实现集群中各成员之间的通信和关系管理。它包含以下的关键特性:
Pacemaker 支持多种类型的集群,包括 Active/Active, Active/Passive, N+1, N+M, N-to-1 and N-to-N 等。
这里 有详细的 Pacemaker 安装方法。这是 中文版。这篇文章 提到了 Pacemaker 的一些问题和替代方案。
Corosync 用于高可用环境中提供通讯服务,位于高可用集群架构中的底层,扮演着为各节点(node)之间提供心跳信息传递这样的一个角色。Pacemaker 位于 HA 集群架构中资源管理、资源代理这么个层次,它本身不提供底层心跳信息传递的功能,它要想与对方节点通信就需要借助底层的心跳传递服务,将信息通告给对方。
关于心跳的基本概念:
这篇文章 详细介绍了其原理。
一个 Pacemaker 集群往往需要使用 Fencing agent。https://alteeve.ca/w/ANCluster_Tutorial_2#Concept.3B_Fencing 详细地阐述了Fencing的概念及其必要性。Fencing 是在一个节点不稳定或者无答复时将其关闭,使得它不会损坏集群的其它资源,其主要用途是消除脑裂。
通常有两种类型的 Fencing agent:power(电源)和 storage (存储)。Power 类型的 Agent 会将节点的电源断电,它通常连到物理的设备比如UPS;Storage 类型的Agent 会确保某个时刻只有一个节点会读写共享的存储。
一个 RA 是管理一个集群资源的可执行程序,没有固定其实现的编程语言,但是大部分RA都是用 shell 脚本实现的。Pacemaker 使用 RA 来和受管理资源进行交互,它既支持它自身实现的70多个RA,也支持第三方RA。Pacemaker 支持三种类型的 RA:
主流的 RA 都是 OCF 类型的。RA 支持的主要操作包括:
在一个 OpenStack Pacemaker 集群中,往往都包括这几种类型的 RA,比如:
在 OpenStack 控制节点Pacemaker集群中各组件:
要实现一个 RA, 需要遵守 OCF 的规范,其规范在 http://www.opencf.org/cgi-bin/viewcvs.cgi/specs/ra/resource-agent-api.txt?rev=HEAD
下面以OpenStack Glance-api RA 为例,说明其功能。其代码在 https://github.com/openstack/openstack-resource-agents/blob/master/ocf/glance-api,本身其实是一个 shell 脚本。
usage() { #RA 的功能,包括 start,stop,validate-all,meta-data,status 和 monitor glance-api 等,每个对应下面的一个函数 cat <<UEND usage: $0 (start|stop|validate-all|meta-data|status|monitor) $0 manages an OpenStack ImageService (glance-api) process as an HA resource The 'start' operation starts the imaging service. The 'stop' operation stops the imaging service. The 'validate-all' operation reports whether the parameters are valid The 'meta-data' operation reports this RA's meta-data information The 'status' operation reports whether the imaging service is running The 'monitor' operation reports whether the imaging service seems to be working UEND } meta_data() { #meta-data 功能,输出一段XML cat <<END ... END } ####################################################################### # Functions invoked by resource manager actions glance_api_validate() { #检查 glance-api,比如libaray是否存在,配置文件是否存在,RA 使用的用户是否存在 local rc check_binary $OCF_RESKEY_binary check_binary $OCF_RESKEY_client_binary # A config file on shared storage that is not available # during probes is OK. if [ ! -f $OCF_RESKEY_config ]; then if ! ocf_is_probe; then ocf_log err "Config $OCF_RESKEY_config doesn't exist" return $OCF_ERR_INSTALLED fi ocf_log_warn "Config $OCF_RESKEY_config not available during a probe" fi getent passwd $OCF_RESKEY_user >/dev/null 2>&1 rc=$? if [ $rc -ne 0 ]; then ocf_log err "User $OCF_RESKEY_user doesn't exist" return $OCF_ERR_INSTALLED fi true } glance_api_status() { #获取运行状态,通过检查 pid 文件来确认 glance-api 是否在运行 local pid local rc if [ ! -f $OCF_RESKEY_pid ]; then ocf_log info "OpenStack ImageService (glance-api) is not running" return $OCF_NOT_RUNNING else pid=`cat $OCF_RESKEY_pid` fi ocf_run -warn kill -s 0 $pid rc=$? if [ $rc -eq 0 ]; then return $OCF_SUCCESS else ocf_log info "Old PID file found, but OpenStack ImageService (glance-api) is not running" return $OCF_NOT_RUNNING fi } glance_api_monitor() { #监控 glance-api 服务的运行状态,通过运行 glance image-list 命令 local rc glance_api_status rc=$? # If status returned anything but success, return that immediately if [ $rc -ne $OCF_SUCCESS ]; then return $rc fi # Monitor the RA by retrieving the image list if [ -n "$OCF_RESKEY_os_username" ] && [ -n "$OCF_RESKEY_os_password" ] \ && [ -n "$OCF_RESKEY_os_tenant_name" ] && [ -n "$OCF_RESKEY_os_auth_url" ]; then ocf_run -q $OCF_RESKEY_client_binary \ --os_username "$OCF_RESKEY_os_username" \ --os_password "$OCF_RESKEY_os_password" \ --os_tenant_name "$OCF_RESKEY_os_tenant_name" \ --os_auth_url "$OCF_RESKEY_os_auth_url" \ index > /dev/null 2>&1 rc=$? if [ $rc -ne 0 ]; then ocf_log err "Failed to connect to the OpenStack ImageService (glance-api): $rc" return $OCF_NOT_RUNNING fi fi ocf_log debug "OpenStack ImageService (glance-api) monitor succeeded" return $OCF_SUCCESS } glance_api_start() { #启动 glance-api 服务 local rc glance_api_status rc=$? if [ $rc -eq $OCF_SUCCESS ]; then ocf_log info "OpenStack ImageService (glance-api) already running" return $OCF_SUCCESS fi # run the actual glance-api daemon. Don't use ocf_run as we're sending the tool's output # straight to /dev/null anyway and using ocf_run would break stdout-redirection here. su ${OCF_RESKEY_user} -s /bin/sh -c "${OCF_RESKEY_binary} --config-file $OCF_RESKEY_config \ $OCF_RESKEY_additional_parameters"' >> /dev/null 2>&1 & echo $!' > $OCF_RESKEY_pid # Spin waiting for the server to come up. # Let the CRM/LRM time us out if required while true; do glance_api_monitor rc=$? [ $rc -eq $OCF_SUCCESS ] && break if [ $rc -ne $OCF_NOT_RUNNING ]; then ocf_log err "OpenStack ImageService (glance-api) start failed" exit $OCF_ERR_GENERIC fi sleep 1 done ocf_log info "OpenStack ImageService (glance-api) started" return $OCF_SUCCESS } glance_api_stop() { #停止 glance-api 服务 local rc local pid glance_api_status rc=$? if [ $rc -eq $OCF_NOT_RUNNING ]; then ocf_log info "OpenStack ImageService (glance-api) already stopped" return $OCF_SUCCESS fi # Try SIGTERM pid=`cat $OCF_RESKEY_pid` ocf_run kill -s TERM $pid rc=$? if [ $rc -ne 0 ]; then ocf_log err "OpenStack ImageService (glance-api) couldn't be stopped" exit $OCF_ERR_GENERIC fi # stop waiting shutdown_timeout=15 if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5)) fi count=0 while [ $count -lt $shutdown_timeout ]; do glance_api_status rc=$? if [ $rc -eq $OCF_NOT_RUNNING ]; then break fi count=`expr $count + 1` sleep 1 ocf_log debug "OpenStack ImageService (glance-api) still hasn't stopped yet. Waiting ..." done glance_api_status rc=$? if [ $rc -ne $OCF_NOT_RUNNING ]; then # SIGTERM didn't help either, try SIGKILL ocf_log info "OpenStack ImageService (glance-api) failed to stop after ${shutdown_timeout}s \ using SIGTERM. Trying SIGKILL ..." ocf_run kill -s KILL $pid fi ocf_log info "OpenStack ImageService (glance-api) stopped" rm -f $OCF_RESKEY_pid return $OCF_SUCCESS } ####################################################################### case "$1" in meta-data) meta_data exit $OCF_SUCCESS;; usage|help) usage exit $OCF_SUCCESS;; esac # Anything except meta-data and help must pass validation glance_api_validate || exit $? # What kind of method was invoked? case "$1" in start) glance_api_start;; stop) glance_api_stop;; status) glance_api_status;; monitor) glance_api_monitor;; validate-all) ;; *) usage exit $OCF_ERR_UNIMPLEMENTED;; esac
(1)因为上述的 RA 是第三方的,因此需要将它下载到本地,RA 所在的文件夹是 /usr/lib/ocf/resource.d/provider,对 OpenStack 来说,就是 /usr/lib/ocf/resource.d/openstack。然后设置其权限为可运行。
(2)通过运行 crm configure,输入下面的配置,就可以创建一个 Pacemaker 资源来对 glance-api 服务进行 monitor:
primitive p_glance-api ocf:openstack:glance-api \ params config="/etc/glance/glance-api.conf" os_password="secretsecret" \ os_username="admin" os_tenant_name="admin" os_auth_url="http://192.168.42. 103:5000/v2.0/" \ op monitor interval="30s" timeout="30s"
该配置指定了:
(3)创建一个 service group
group g_services_api p_api-ip p_keystone p_glance-api p_cinder-api p_neutron-server p_glance-registry p_ceilometer-agent-central
Pacemaker group 的一些特性:
Pacemaker 根据 CIB 中对资源的 operation 的定义来执行相应的 RA 中的命令:
(1)monitor:Pacemaker 使用 monitor 接口来检查整个集群范围内该资源的状态,来避免重复启动一个资源。同时,重启已经崩溃的资源。
(2)restart:在被 monitored 的资源不在运行时,它会被重启(stop 再 start)。需要注意的是,Pacemaker 不一定在原来的节点上重启某服务,因此,需要通过更多的限制条件(group 和 colocation),来使得某服务在规定的节点上运行。
(3)failover:当 master 节点宕机时,Pacemaker 会启动failover 将它监管的服务切换到被节点上继续运行。这种切换,也许需要启动服务,也许只需要做上下文切换即可。
这篇文章 分析了用户在 CIB 中对 Pacemaker 所做的配置和 Pacemaker 的行为时间之间的关系。
CIB 针对重启服务的行为,做了两种规定:
各种配置项、值和结果:
这篇文章通过多种测试,得出如下基本的结论:
详细的结论可以直接阅读那论文。