Webページの更新チェッカー on Zabbix@Docker


概要

※初Qiita投稿です。至らない点があれば、コメントにて教えていただけると幸いです。

ボカロ好きな私が、ニコニコ動画上で特定のタグに更新があった場合に、Zabbixからお知らせ出来ないかと思い、試行錯誤してみました。

参考にさせて頂いたページ「Zabbixで更新チェッカーを作ってみる

現在の状態

Ubuntu上にDocker-composerを利用してZabbixサーバーを構築しています。

docker-compose.yml_抜粋
version: '2'

services:
  zabbix_db:
    container_name: zabbix_db
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    restart: always
    image: mysql:5.7
    volumes:
      - "./data/db:/var/lib/mysql"
    environment:

  zabbix_server:
    container_name: zabbix_server
    image: zabbix/zabbix-server-mysql:alpine-4.2-latest
    depends_on:
      - zabbix_db
    links:
      - zabbix_db
    volumes:
      - ./scripts:/usr/lib/zabbix/externalscripts
      - ./data/zabbix:/var/lib/zabbix
    ports:
      - "30051:10051"
      - "30050:10050"
    environment:
      DB_SERVER_HOST: zabbix_db

  zabbix_web:
    container_name: zabbix_web
    #image: zabbix/zabbix-web-nginx-mysql:alpine-4.2-latest
    build: 
      context: ./
      dockerfile: zabbix_web
    restart: always
    volumes:
      - /etc/localtime:/etc/localtime:ro
    links:
      - zabbix_db
    ports:
      - "7998:80"
    environment:
      DB_SERVER_HOST: zabbix_db
      ZBX_SERVER_HOST: zabbix_server
      PHP_TZ: Asia/Tokyo
    depends_on:
      - zabbix_db
      - zabbix_server

  zabbix_agent:
    container_name: zabbix_agent
    image: zabbix/zabbix-agent:alpine-latest
    restart: always
    environment:
      ZBX_SERVER_HOST: zabbix_server
      ZBX_ENABLEREMOTECOMMANDS: 1
    links:
      - zabbix_server
    depends_on:
      - zabbix_server

参考にしたページを元につくってみる

スクリプトの用意

/script/urlcheck.sh
#!/bin/bash

URL="$1"
# URLに含まれる文字でファイル名に使えない"/"は置換する
URL_PATH=${URL//\//-}
STORE_PATH="/tmp/urlcheck/url_${URL_PATH}"

mkdir -p /tmp/urlcheck

if [ -e "${STORE_PATH}_after" ]; then
  # afterが存在すればbeforeとしてコピー
  cp -f "${STORE_PATH}_after" "${STORE_PATH}_before"
else
  # afterが存在しなければbeforeとしてコンテンツ取得
  curl -s -g "$URL" -o "${STORE_PATH}_before"
fi

# コンテンツ取得
curl -s -g "$URL" -o "${STORE_PATH}_after"

# 差分確認
diff "${STORE_PATH}_before" "${STORE_PATH}_after" >/dev/null
echo $?

元のページのままだと取得時にエラーが出ることがあったため、一部改変しています。
実行権限を付与し、docker-composeに下記を追記します。

docker-compose.yml
  zabbix_server:
    volumes:
      - ./scripts:/usr/lib/zabbix/externalscripts

docker内に入り、スクリプトをテストします。

# /usr/lib/zabbix/externalscripts/urlcheck.sh http://google.com/
0

正常終了なら、0が戻ります。
ページが更新された場合、1が戻る仕様になっているので、これをZabbixで監視します。

Zabbixにアイテム登録

上記の通り登録します。

  • 名前:URL定期更新テスト
  • タイプ:外部チェック
  • キー:urlcheck.sh["https://google.com/"]
  • 更新間隔:60m

Zabbixにアクション登録

上記通り登録します。

  • 名前:定期更新アクション
  • 条件式:{localhost:urlcheck.sh["https://google.com/"].last()}<>0
  • 説明:{ACTION.NAME} is changed.

問題点:単一ページでは動くが、RSSなどの動的ページでは想定通りに動作しない

原因を調べてみる

上記のニコニコ動画のRSSをよーく眺めてみると、/rss/channel/lastBuildDateのところに更新日時が入ってしまっている。
この文字列が毎回変更されるため、取得しに行くたびに変更した扱いになるため、想定の動作しませんでした。

なので、XMLを簡易解析し、/rss/channel/item[n]/titleをテキスト出力し、それを比較することにします。

Dockerfileの作成とdocker-composeの修正

現在の設定ではZabbixServer内でXMLの解析が行えないため、Dockerイメージを作り直すことにしました。

FROM zabbix/zabbix-server-mysql:alpine-4.2-latest

RUN apk add --update curl xmlstarlet && \
    rm -rf /var/cache/apk/*
  • curl
  • xmlstarlet

を有効にしたDockerfileを作成し、docker-composeに追記します。

cocker-compose.yml
  zabbix_server:
    #image: zabbix/zabbix-server-mysql:alpine-4.2-latest
    build:
      context: ./zabbix_server
      dockerfile: Dockerfile

シェルスクリプトの追加

rsscheck.sh
#!/bin/bash

URL="$1"
# URLに含まれる文字でファイル名に使えない"/"は置換する
URL_PATH=${URL//\//-}
STORE_PATH="/tmp/urlcheck/rss_${URL_PATH}"

mkdir -p /tmp/urlcheck

if [ -e "${STORE_PATH}_after" ]; then
  # afterが存在すればbeforeとしてコピー
  cp -f "${STORE_PATH}_after" "${STORE_PATH}_before"
else
  # afterが存在しなければbeforeとしてコンテンツ取得
  curl -s -g "$URL" | xmlstarlet sel -t -m "/rss/channel/item" -v "title " -o " / " -v "pubDate" -n > "${STORE_PATH}_before"
fi

# コンテンツ取得
curl -s -g "$URL" | xmlstarlet sel -t -m "/rss/channel/item" -v "title " -o " / " -v "pubDate" -n > "${STORE_PATH}_after"

# 差分確認
diff "${STORE_PATH}_before" "${STORE_PATH}_after" >/dev/null
echo $?

RSS用のシェルスクリプトを作成し、同様に実行権限を付与し、テストします。
やってることは単純で、CURLで取得したデータをXmlstarletを通して、下記の通り整形しています。

  • タイトル / 動画の更新日
  • タイトル / 動画の更新日
  • ・・・
# /usr/lib/zabbix/externalscripts/rsscheck.sh https://www.nicovideo.jp/tag/%E9%9A%A0%E3%82%8C%E3%81%9F%E3%83%9C%E3%82%AB%E3%83%AD%E5%90%8D%E6%9B%B2?rss=2.0
0

あとは、既に記載したように、Zabbixにアイテム登録すれば動きます。
お盆休みで田舎に帰って暇だったので、思いつきで作ってみました。

2019/08/14 追記

RSSチェックが、時々更新判定を失敗しているので、よくよく確認してたところ、オプションフラグをつけないと毎回最新順にソートされているとは限らないようでした。
現在は下記の通りの設定でうごいています。