ZabbixでAWS ALBの監視をする

ZabbixでAWS ALBの監視をする:


前提

  • zabbix3.4
  • ALBに紐づいているTargetGroupのヘルスチェックが通っているかを確認したい


構成

AWS ALBはHealthyHostCountという情報をCloud watchに保存しています。

Cloud Watchからの情報はAPIを経由して取得する必要があります。

なので今回は

1. external scriptsにAPIを打ってzabbix senderでcloud watchの情報を送るスクリプトを配置する

2. zabbix server側でzabbix trapperを使ってzabbix senderで送られた情報をキャッチする

3. そのitemでアラートを出すようにする

zabbix trapper等の情報は以下が詳しいです。
https://www.zabbix.com/documentation/3.0/manual/config/items/itemtypes/trapper


zabbix senderでcloud watchの情報を送る

基本pythonで以下の感じで実装をしました。

  1. シェルスクリプトでpythonを叩く
  2. zabbixで設定されているHost情報から target groupの情報を抜く(ZabbixのMacroとかにTarget情報をいれてもOK)
  3. cloud watchから情報を抜く(今回はメトリクス情報もAPIから毎回引っこ抜いています。)

  4. alb.metrics_nameという形に生成
  5. subprocessでzabbix senderを実行。
aws_monitoring.py

#!/usr/bin/python 
# -*- coding: utf-8 -*- 
import sys, subprocess, datetime 
from boto3.session import Session 
 
def _exponential_backoff(func, trial_count=5): 
  last_raised = None 
  for x in xrange(trial_count): 
    try: 
      results = func() 
      return results 
    except Exception as e: 
      print('[{0}/{1}] Exponential Backoff Failed'.format(x + 1, trial_count)) 
      last_raised = e 
      time.sleep(2 ** x) 
  raise last_raised 
 
def get_client(akey, sakey, region, SERVICE='ec2'): 
  client = Session( 
    aws_access_key_id     = akey, 
    aws_secret_access_key = sakey, 
    region_name           = region 
  ).client(SERVICE) 
  return client 
 
def send_data(hostname, key, value): 
  cmd =['zabbix_sender', '-z','127.0.0.1', '-s', str(hostname), '-k', str(key), '-o', str(value), '-vv'] 
  result = subprocess.call( cmd, shell=False ) 
 
def get_cw_columnlist(client, TARGET_GROUP): 
  metricslist = _exponential_backoff(lambda: client.list_metrics( 
      Namespace  = 'AWS/ApplicationELB', 
      Dimensions = [{ 
        'Name'  : 'TargetGroup', 
        'Value' : TARGET_GROUP, 
      }], 
    ) 
  )  
  columnlist = []  
  for metrics in metricslist['Metrics']: 
    columnlist.append(metrics['MetricName']) 
 
  columnlist_unique = list(set(columnlist)) 
 
  return columnlist_unique 
 
def send_items(cw_client, alb_client, ELB_NAME): 
  alb_info = _exponential_backoff(lambda: alb_client.describe_target_groups(Names=[ELB_NAME])) 
  TARGET_GROUP = alb_info['TargetGroups'][0]['TargetGroupArn'].rsplit(':',1)[1]  
  for column in get_cw_columnlist(cw_client, TARGET_GROUP): 
 
    unit = _select_unit(column) 
 
    cw_values = _exponential_backoff(lambda: cw_client.get_metric_statistics( 
        Namespace  = 'AWS/ApplicationELB', 
        MetricName = column, 
        Dimensions = [{ 
          'Name'  : 'TargetGroup', 
          'Value' : TARGET_GROUP, 
        }], 
        StartTime  = get_nowtime_utc() - datetime.timedelta(minutes=9), 
        EndTime    = get_nowtime_utc(), 
        Period     = 300, 
        Statistics = [unit], 
      ) 
    )['Datapoints'] 
 
    key   = 'alb.' + column  
    value = 0 
 
    if cw_values != []: 
      value = sorted(cw_values,key=lambda x:x['Timestamp'],reverse=True)[0][unit] 
    print(key, value) 
    send_data(ELB_NAME, key, value) 
 
def _select_unit(column): 
  unitlist = { 
    'HTTPCode_Backend_2XX':'Sum', 
    'HTTPCode_Backend_4XX':'Sum', 
    'HTTPCode_Backend_5XX':'Sum', 
    'RequestCount':'Sum', 
    'HealthyHostCount':'Maximum', 
    'UnhealthyHostCount':'Maximum', 
    'TargetResponseTime': 'Average', 
    'RequestCountPerTarget': 'Sum' 
  } 
  if column not in unitlist: 
    return 'Average' 
  else: 
    return unitlist[column] 
 
if __name__ == '__main__': 
  main() 
 
def main(): 
  AKEY     = sys.argv[1] 
  SAKEY    = sys.argv[2] 
  HOSTNAME = sys.argv[3] 
  REGION   = 'ap-northeast-1' 
  ELB_NAME = HOSTNAME 
  cw_client = get_client(AKEY, SAKEY, REGION, SERVICE='cloudwatch') 
  alb_client = get_client(AKEY, SAKEY, REGION, SERVICE='elbv2') 
  send_items(cw_client, alb_client, ELB_NAME) 
aws_monitoring.sh (アクセスキーはインスタンスプロファイル/credential等使用していれば不必要です)

AWS_KEY=hoge 
AWS_SAKEY=fuga 
python aws_monitoring.py $AWS_KEY $AWS_SAKEY $1 


senderするスクリプトを定期実行する

定期実行するには

- cronとして仕込む

- zabbix itemのExternal checkで定期実行させる。

今回はExternal checkを使って実装します(以下が詳しいです)

https://www.zabbix.com/documentation/3.4/manual/config/items/itemtypes/external
https://www.zabbix.com/documentation/3.4/manual/appendix/command_execution


  1. zabbix_server.cfgExternalScriptsに上記のスクリプトを配置します
  2. zabbix itemを設定します

    • type: External check
    • key: aws_monitoring.sh[{HOST.HOST} (ここの引数は適宜変えてください)
    • Update interval: 300 (監視間隔なので適宜変えてください)


zabbix trapperを配置する

  1. zabbix itemを設定します (HealthyHostCountの場合)

    • type: Zabbix Trapper
    • key: alb.HealthyHostCount
    • Type of information: Numeric(float)
配置すれば終了。あとはLatest Dataでデータが反映されているか確認しましょう。


結論

この辺りを応用するとcloud watchの情報を使ってzabbixで監視ができる。

cloud watchのAPIは有料なので長い期間を連続して取得しないようにする。
https://aws.amazon.com/jp/cloudwatch/pricing/

コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)