摘自Ambari 服务配置以及 Alert 详解
http://www.ibm.com/developerworks/cn/opensource/os-cn-bigdata-ambari3/index.html
Ambari 作为一个开放的平台,可以让用户很方便的维护管理集群。除此之外,本文将从另一方面介绍它是如何支持客户自定义 Service,使得用户方便进行 Service 管理维护。
Ambari 最新动态2015 年,Ambari 发展的比较快,最新的发布版本已经是 2.1.1,而且马上将要发布 2.1.2 版本。与之前版本相比较,Ambari 增加了对一些最新版本操作系统的支持,同时也不再支持一些过时版本的操作系统。例如不再支持 RHEL/CentOS/OEL 5,增加了对 RHEL/CentOS/OEL 7 的支持。Ambari 在 2.1 中也更新了 JDK 的支持版本。目前已经支持了 OpenJDK 和 Oracle JDK 的 1.8 版本,去掉了对 Oracle JDK 1.6 的支持。相信在众多越来越多贡献者的推动下,Ambari 可以变得更加稳定和健壮。
Ambari 自定义 Service 的配置Ambari 在每次启动的时候,会扫描 resource 目录下 Stack 下面的 service 配置。也就是每个 Service 的 metainfo.xml,同时会将这些配置信息放在自己的数据库中。当用户在 WEB 上面点击 “Add Service”的时候,WEB 就会加载这些配置信息到具体的页面里。
关于最基本的自定义 Service 配置项,以及如何在 Ambari 中增加一个自定义的 Service,已经在《Ambari——大数据平台的搭建利器》中有过介绍。这里我只做一些补充的配置说明。
增加 Service Check 逻辑在 Service 的 metainfo.xml 中,commandScript 字段就是用来配置 service check 脚本入口。如果一个 Service 的 metainfo.xml 有该字段,那么在 Service 的 Action 列表中就会出现“Run Service Check”这个命令。相比较之前文章介绍的自定义命令(Customcommand),Service Check 是没有 name 属性的,所以它才是固定的“Run Service Check”。不过关于 Ambari 如何分发执行自定义命令和 Service Check 是一样的。
commandScript 段示例代码(完整的示例代码,可以在任一个 Ambari 的 common Service 目录中找到):
<commandScript>
<script>scripts/master/my_check.py</script>
<scriptType>PYTHON</scriptType> <timeout>300</timeout>
</commandScript>
当用户在 WEB 中点击“Run Service Check”时,Ambari Server 会随机通知一个该 Service 所在机器上的 Agent 进程,然后由 Agent 执行该 Service check 脚本。
增加 Service 的配置项在 Ambari 上安装过 Service 的用户,肯定经历过 Custom Service 这一步。在这一步中,用户必须输入很多必要的输入项,才可以继续下一步。当一个 Service 安装完成后,在 Dashboard 上点击该 Service,可以看到一个 config 页面。这个页面是为了给用户提供一个更新 Service 配置的入口。如果更新了相关数据,Ambari 就会存入它的数据库(postgres)中。
对于自定义的 Service,默认是没有这些配置项的。如果一个自定义的 Service 需要某些必须的参数时,就必须创建 Service 的配置目录(configuration)和对应的配置文件,让用户安装的时候输入。
这里需要在 Service 的 metainfo.xml 中增加<configuration-dependencies>字段。该字段就是用来关联一个 Service 与配置项文件入口。Ambari 支持 xml 和 json 格式的配置文件。
示例代码如下:
<configuration-dependencies>
<config-type>ambari-server-env</config-type> </configuration-dependencies>
示例代码中每一行<config-type>字段,用来指定一个配置文件。一个 Service 可以同时指定多个配置文件。不过所有的配置文件必须放在 Service 的 configuration 目录中。
SAMPLE_EXT
----alert.json
----configuration
-------ambari-server-env.xml
----metainfo.xml
----package
-------scripts
--------master
----------master.py
--------slave
----------slave.py
示例配置文件:
[root@zwshen71 configuration]# cat ambari-server-env.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>AMBARI_USER</name>
<value>admin</value>
<description>Ambari Server user name</description>
</property>
<property>
<name>AMBARI_USER_PASSWORD</name>
<value></value>
<description>Ambari Server user password</description>
<property-type>PASSWORD</property-type>
</property>
<property>
<name>AMBARI_CLUSTER_NAME</name>
<value></value>
<description>Ambari Cluster name</description>
</property>
<property>
<name>AMBARI_SERVER_HOST</name>
<value></value>
<description>Ambari Server host name. Symphony will communicate with this host for
integration</description>
</property>
<property>
<name>AMBARI_WEB_LISTEN_PORT</name>
<value>8080</value>
<description>Ambari WEB Server listen port. Symphony uses this port for communication
with Ambari</description>
</property>
</configuration>
配置文件中,其实就是指定了一些键值对的属性,以及一个描述。当在 Ambari 的 WEB 中增加这个 Service 时,Ambari Server 会读取这些信息,并显示到该 service 的配置页面中(Customize Service 和 config 页面)。默认情况下,如果一个配置项没有配置默认值,用户则必须输入。如果一个项允许为空,则需要在<property>中增加 require-input="false“的属性。例如下面的配置项。
require-input 示例配置:
<property require-input="false">
<name>AMBARI_CLUSTER_NAME</name> <value></value>
<description>Ambari Cluster name</description> </property>
Ambari 会在安装这个 service 的时候,将用户的输入项存入 Ambari 的数据库中。当 Agent 方需要访问这些数据的时候,Server 会读取数据库并以 Json 格式传送给 Agent。
如何在 Agent 方读取 WEB 中的输入参数
对 Service 添加了参数项之后,就是读的问题了。Ambari 的 Server 会以 Json 格式将数据传送给 Ambari Agent。在 Agent 的实现中,其实已经提供了访问配置数据的接口。因此很容易就可以获取这些输入项了。
在 Ambari 的 Agent 中有实现了叫做 Script 的类,每个 Service 的生命周期脚本都必须继承这个 Script 类。Script 提供了很多简单易用的函数供 Service 使用,其中 def get_config() 这个函数就是用于获取该 Service 配置信息。由于 Service 的配置文件可以是多个,get_config 返回的也就是一个合集,需要 Service 对应的脚本代码去解析。这里直接给一个简单的示例代码。
Service Master 模块的示例代码:
import sys, os
import json
import logging
import platform from resource_management
import * from resource_management.core.exceptions
import ComponentIsNotRunning from resource_management.core.environment
import Environment from resource_management.core.logger
import Logger
class Master(Script):
def install(self, env):
print "install my master"
def configure(self, env):
print "configure this service here"
def start(self, env): # 解析 service 的配置参数
config = Script.get_config()
AMBARI_USER = config['configurations']['ambari-server-env']['AMBARI_USER']
AMBARI_USER_PWD = config['configurations']['ambari-server-env']['AMBARI_USER_PASSWORD']
AMBARI_SERVER_HOST = config['configurations']['ambari-server-env']['AMBARI_SERVER_HOST']
AMBARI_WEB_LISTEN_PORT = config['configurations']['ambari-server-env']['AMBARI_WEB_LISTEN_PORT']
print "Ambari User: " + AMBARI_USER + " \nAmbari user password: " + AMBARI_USER_PWD + "\nServer: " +
AMBARI_SERVER_HOST + "\nLinsten port " + str(AMBARI_WEB_LISTEN_PORT)
cmd = "mkdir -p /var/run/shenzhaowei"
os.system(cmd)
print "start the service"
def stop(self, env):
cmd = "rm -rf /var/run/shenzhaowei"
os.system(cmd)
print "stop the service"
def status(self, env):
cmd = "echo 'check one time' > /tmp/my.log"
os.system(cmd)
cmd = "ls /var/run/shenzhaowei"
result = os.system(cmd)
if result != 0:
raise ComponentIsNotRunning()
if __name__ == "__main__":
Master().execute()
在上面的示例代码中,start 的控制函数中引入了简要的输入参数解析逻辑。读者可以参考实现。这里需要延伸多说下 Script 这个类。在 Ambari 的环境中可以在路径“/usr/lib/python2.6/site-packages/resource_management/libraries/script”中找到 Script.py(有兴趣的读者也可以在 Ambari 的 git 库中找到最新的代码),也就是 Script 类的实现。在 Service 的控制脚本中 install、start、stop 等控制函数,其实都继承于 Script 类,并被重新实现。Script 提供很多常用的功能,因为当需要在控制脚本中实现一个相关的控制函数时,可以先看看 Script 是否已经有实现。有的话,直接用就好了。例如需要执行一个 shell 脚本的时候,可以用 os.system(),也可以用 Script 的 Execute 函数,而且更加简单。