本文的结构
1. Ambari 的工作原理
2. 一个简单的自定义 service
3. 添加 mertrics 到service
4. 发送数据给 metrics
5. 添加 config 到 service
6. 添加 alert 到 service
7. 其他需要修改源码实现的部分
Ambari 的工作原理
先看两张图,下面有对应的说明
Ambari server 启动之后的的资源目录
-
当用 Ambari server 启动的时候,Ambari Server 传送三类文件到 Ambari Agent上,分别是
- Stack 配置文件
- Service 的配置文件
- Service 生命周期的控制脚本(安装,配置,启动,停止,查询状态)
Agent 拿到配置文件后,会下载安装软件包。
安装完成后,Ambari Server 会通知 Agent 去启动 Service。
Ambari Server 会定期发送命令到 Agent上, 来检查 Service 的状态; Agent 上报service数据给 Server,并呈现在 Ambari 的 GUI 上。
Ambari Server 支持 Rest API,这样可以很容易的扩展和定制 Ambari功能。
一个简单的自定义 Service
自定义service放在 /var/lib/ambari-server/resources/stacks/HDP/2.6/services目录下,这个目录下面有很多实例可以参考,还可以参考 公共service ,公共service的目录在/var/lib/ambari-server/resources/common-services
下面是我写的一个实例,先运行看一下,然后我们再分析配置的实现
这里先使用一个简单的实例---- HELLO_SERVICE(点开链接到 github上下载) ,将这个文件放在/var/lib/ambari-server/resources/stacks/HDP/2.6/services目录下。
sudo ambari-server restart
这个操作会将HELLO_SERVICE 传到agent上,至于传多少agent,就要看设置。
3.登录 ambari-server 界面,如图所示,添加service
4.选择 My Service test ,点击next,然后一路next 直到结束
5.添加自定义service 之后的效果
6.自定义service的配置分析
- 配置目录概览
dotheright@master:/var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVICE$ tree
├── metainfo.xml
└── package
├── archive.zip
└── scripts
├── master.py
└── slave.py
- metainfo.xml 分析 ,见原文注释部分
dotheright@master:/var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVICE$ cat metainfo.xml
<?xml version="1.0" encoding="utf-8"?>
<metainfo>
<schemaVersion>2.0</schemaVersion>
<services>
<service>
<name>TEST</name> <!---服务名 -->
<displayName>My service test</displayName>
<comment>My service test v1</comment>
<version>1.0</version>
<components>
<component>
<name>mymaster</name> <!-- 给timeline使用的名字,要唯一 -->
<displayName>my master</displayName>
<category>MASTER</category> <!--表示在master上安装-->
<cardinality>1</cardinality>
<commandScript>
<script>scripts/master.py</script> <!-- master上使用的脚本 -->
<scriptType>PYTHON</scriptType>
<timeout>3000</timeout>
</commandScript>
</component>
<component>
<name>myslave</name> <!-- 给timeline使用的名字,要唯一 -->
<displayName>my slave</displayName>
<category>SLAVE</category> <!--表示在slave上安装-->
<cardinality>1+</cardinality> <!--表示至少在一个slave上安装-->
<commandScript>
<script>scripts/slave.py</script>
<scriptType>PYTHON</scriptType>
<timeout>3000</timeout>
</commandScript>
</component>
</components>
<osSpecifics>
<osSpecific>
<osFamily>redhat6,debian7,ubuntu12,ubuntu14,ubuntu16</osFamily> <!-- 支持的 OS -->
</osSpecific>
</osSpecifics>
</service>
</services>
</metainfo>
- archive.zip 这个是发送前压缩的不用关注
- master.py 文件包含安装,配置,启动,停止,各个状态中的具体代码需要根据实际需求来写
import os
import sys
from resource_management import Script
class Slave(Script):
def install(self, env):
print 'Install the Sample Slave';
return 0;
def stop(self, env):
print 'Stop the Sample Slave';
return 0;
def start(self, env):
print 'Start the Sample Slave';
return 0;
def status(self, env):
print 'Status of the Sample Slave';
return 0;
def configure(self, env):
print 'Configure the Sample Slave';
return 0;
if __name__ == "__main__":
Slave().execute()
- slave.py 文件包含安装,配置,启动,停止,各个状态中的具体代码需要根据实际需求来写
import os
import sys
from resource_management import Script
class Master(Script):
def install(self, env):
print 'Install the Srv Master';
return 0;
def stop(self, env):
print 'Stop the Srv Master';
return 0;
def start(self, env):
print 'Start the Srv Master';
return 0;
def status(self, env):
print 'Status of the Srv Master';
return 0;
def configure(self, env):
print 'Configure the Srv Master';
return 0;
if __name__ == "__main__":
Master().execute()
添加 mertrics 到service
1 . 先看下目录结构
root@master:/var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVICE# tree
.
├── metainfo.xml
├── metrics.json
├── package
│ ├── archive.zip
│ └── scripts
│ ├── master.py
│ └── slave.py
├── send.sh
└── widgets.json
相对于一个service增加的是 widgets.json ,metrics.json两个文件,修改了 metainfo.xml,send.sh 脚本是发送数据使用的。
- widgets.json 解析
root@master:/var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVIroot@master:/var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVICE# cat widgets.json
{
"layouts": [
{
"layout_name": "default_test_dashboard",
"display_name": "Standard TEST Dashboard",
"section_name": "TEST_SUMMARY",
"widgetLayoutInfo": [
{
"widget_name": "test_widget",
"description": "test widget",
"widget_type": "GRAPH",
"is_visible": true,
"metrics": [
{
"name": "test1",
"metric_path": "metrics/test1",
"service_name": "TEST",
"component_name": "myslave"
}
],
"values": [
{
"name": "test1",
"value": "${test1}"
}
],
"properties": {
"graph_type": "LINE",
"time_range": "1"
}
}
]
}
]
}
widget_type 可以配置的有三种类型:
1. GRAPH 时间序列图。
2. NUMBER 显示一个数值
3.GAUGE 显示百分比
service_name: 和前面的service要对应
3.metrics.json 解析
root@master:/var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVICE# cat metrics.json
{
"myslave": {
"Component": [
{
"type": "ganglia",
"metrics": {
"default": {
"metrics/test1": {
"metric": "test1",
"pointInTime": true,
"temporal": true
},
"metrics/test2": {
"metric": "test2",
"pointInTime": true,
"temporal": true
},
"metrics/test3": {
"metric": "test3",
"pointInTime": true,
"temporal": true
},
"metrics/test4": {
"metric": "test4",
"pointInTime": true,
"temporal": true
}
}
}
}
]
}
}
4.metainfo.xml 上添加 timelineAppid
<cardinality>1</cardinality>
<timelineAppid>myTLappid</timelineAppid>
5.重启 ambari-server 能看到对应的wedgit 已经添加成功。
重启:# ambari-server restart
添加成功的wedgit,但是此时的wegit 没有数据。
发送数据给 metrics
这里使用 send.sh脚本,对应的脚本内容
#!/bin/sh
url=http://$1:6188/ws/v1/timeline/metrics
while [ 1 ]
do
millon_time=$(( $(date +%s%N) / 1000000 ))
random=$(( $(date +%s) % 1000 ))
json="{
\"metrics\": [
{
\"metricname\": \"$2\",
\"appid\": \"$3\",
\"hostname\": \"$1\",
\"timestamp\": ${millon_time},
\"starttime\": ${millon_time},
\"metrics\": {
\"${millon_time}\": ${random}
}
}
]
}"
echo $json
curl -i -X POST -H "Content-Type: application/json" -d "${json}" ${url}
sleep 5
done
# ./send.sh master test1 myTLappid
# cd /var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVICE
在 /var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVICE
目录下,执行 ./send.sh master test1 myTLappid 。这个三个参数分别是,master:主机名,test1:mertrics 名,myTLappid :timeline的appid名称。然后能在widgets上看到有数据的图形。
注意:
在发送数据到metrics上之前,一定要保证 Metrics Collector service 开启
添加 config 到 service
1.添加config之后的目录结构
root@master:/var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVICE# tree
.
├── configuration
│ └── ambari-server-env.xml
├── metainfo.xml
├── metrics.json
├── package
│ ├── archive.zip
│ └── scripts
│ ├── master.py
│ └── slave.py
├── send.sh
└── widgets.json
在service 目录下面增加了 configuration 目录,和配置文件ambari-server-env.xml
- config的配置文件
root@master:/var/lib/ambari-server/resources/stacks/HDP/2.6/services/HELLO_SERVICE# cat configuration/ambari-server-env.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration supports_final="false">
<property require-input="false">
<name>AMBARI_USER</name>
<value>admin</value>
<description>Ambari Server user name</description>
<on-ambari-upgrade add="true"/>
</property>
<property>
<name>AMBARI_USER_PASSWORD</name>
<value></value>
<description>Ambari Server user password</description>
<property-type>PASSWORD</property-type>
<on-ambari-upgrade add="true"/>
</property>
<property brequire-input="false">
<name>AMBARI_CLUSTER_NAME</name>
<value>mycluster</value>
<description>Ambari Cluster name</description>
<on-ambari-upgrade add="true"/>
</property>
<property require-input="false">
<name>AMBARI_SERVER_HOST</name>
<value>master</value>
<description>Ambari Server host name. Symphony will communicate with this host for integration</description>
<on-ambari-upgrade add="true"/>
</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>
<on-ambari-upgrade add="true"/>
</property>
</configuration>
require-input="false" 可以取默认值,默认是true ,上面配置中 AMBARI_USER_PASSWORD 就是必须配置的,在service添加的时候,会有提醒,见下面安装service配置的效果图。
- 配置文件之后对应的python脚本也需要修改
需要在启动的时候解析配置文件
def start(self, env): # analysis service config
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/guoqingyao"
os.system(cmd)
print "start the service"
def stop(self, env):
cmd ="rm -rf /var/run/guoqingyao"
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/guoqingyao"
result = os.system(cmd)
if result != 0:
print "The component is not runing"
- 。xml 文件也需要修改 在services 下面加入
<configuration-dependencies>
<config-type>ambari-server-env</config-type>
</configuration-dependencies>
再次安装自定义服务的时候就需要输入相关的配置了。
服务启动之后可以看到 配置文件
添加 alert 到 service
1.在service 目录下面添加 dotheright@master:~/mylovelycodes/ambari/Alert_SAMPLE$ cat alerts.json
{
"ALERT_TEST": {
"service": [],
"MyKubernetes": [
{
"name": "MyKubernetes",
"label": "My Kubernetes Alert",
"description": "This is my Kubernetes alert.",
"interval": 1,
"scope": "ANY",
"enabled": true,
"source": {
"type": "PORT",
"uri": "{{slave:18888}}",
"default_port": 18888,
"reporting": {
"ok": {
"text": "TCP OK - {0:.3f}s response on port {1}"
},
"warning": {
"text": "TCP OK -{0:.3f}s response on port {1}",
"value": 1.5
},
"critical": {
"text": "Connection failed: {0} to {1}:{2}",
"value": 5.0
}
}
}
}
]
}
}
- alert的效果
其他需要修改源码实现的部分
- dashbaord 里面添加metrics需要在源码中实现。
对应的代码目录是 ambari-web/app/views/main/dashboard/widgets/,里面有很多已经实现的实例,比如
hbase_average_load.js
hbase_links.js
hbase_master_heap.js
hdfs_capacity.js
hdfs_links.js
links_widget.js
metrics_cpu.js
- hosts的metrics需要修改源码实现。
hosts的metrics 是从dashbaord中指定的。