Quantcast
Channel: mattintosh note
Viewing all articles
Browse latest Browse all 892

Raspberry Pi で Elasticsearch と Kibana

$
0
0

AWS Elasticsearch Service をお試してで使ってみたけど用途に対してコスパが悪いので、余ってる Raspberry Pi 3 Model B で運用することにした。Elasticsearch と Kibana を1台の Raspberry Pi 3 Model B で稼働させるのは重いので現在は ASUS Tinker Board や PINE64 Rock64 4GB を使ったり、Kibana だけ手元の Ubuntuで実行していたりする。

各種バージョン

Elasticsearch や Kibana は依存関係のバージョンが厳しいので(例えば Node.js のバージョンが 8.15.0 だと動かない、など)今回は下記の通りに合わせる。Javaは Elasticsearch、Node.js は Kibana で使用する。

  • Elasticsearch: 6.5.2
  • OpenJDK: 1.8.0
  • Kibana: 6.5.2
  • Node.js: 8.14.0
  • curator: 5.6.0

Elasticsearch のセットアップ

Debian系で Elasticsearch を使う場合は DEBパッケージを使うか、MACOS/LINUX用の TAR を解凍して使う方法がある。今回は保存用のストレージ等も分けるので TAR ファイルを使う方法にする。

Java Runtime Environment 8 をインストールする。特に Javaで開発する予定もないのでヘッドレス版。

※そのうち直るかもしれないが、openjdk-8-jre-headlessのインストール後処理でエラーが発生する。もう一度 openjdk-8-jre-headlessをインストールすれば正常に終了する。

sudo apt-get update
sudo apt-get install openjdk-8-jre-headless

Elasticsearch をダウンロードする。

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.2.tar.gz
tar xf elasticsearch-6.5.2.tar.gz

elasticsearch-6.5.2/config/jvm.optionsJVMのメモリ設定を変更する。Raspberry Pi 3 Model B はメモリが 1 GB なので 512 MB くらいにしておく。

#-Xms1g
#-Xmx1g
-Xms512m
-Xmx512m

Elasticsearch の設定を elasticsearch-6.5.2/config/elasticsearch.ymlで行う。xpack.ml.enabled: falseの設定が無いと起動しない。localhost以外からのアクセスも許可するので transport.hosttransport.tcp.portを設定する。

xpack.ml.enabled:falsenetwork.host: 0.0.0.0
http.port:9200transport.host: localhost
transport.tcp.port:9300

Elasticsearch を起動する。起動まで数分かかる。

elasticsearch-6.5.2/bin/elasticsearch

localhost:9200にアクセスして Elasticsearch が起動しているか確認する。Raspberry Piでは avahi-daemonが有効になっているのでクライアントが対応していれば raspberrypi.local:9200でもアクセスできる

curl localhost:9200
{"name" : "Z0Eokyo",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "NV6kGw3iQBiF7voqb6tIcA",
  "version" : {"number" : "6.5.2",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "9434bed",
    "build_date" : "2018-11-29T23:58:20.891072Z",
    "build_snapshot" : false,
    "lucene_version" : "7.5.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

Kibana のセットアップ

Kibana には ARM 版が無いので Linuxx86_64 版をダウンロードする。

wget https://artifacts.elastic.co/downloads/kibana/kibana-6.5.2-linux-x86_64.tar.gz
tar xf kibana-6.5.2-linux-x86_64.tar.gz

こちらもアクセス制限は設けないので kibana-6.5.2-linux-x86_64/config/kibana.ymlserver.host: 0.0.0.0を設定する。

server.host: 0.0.0.0

Raspberry Piなどの ARM デバイスで Kibana を使う場合、同梱されている Node.js が x86_64 用だったりするので Node.js を別途用意する必要がある。ネットで一通り見た感じ「node/bin/nodeをバックアップして…」とか書かれているが、あまり好きな方法ではないかな。

kibana-6.5.2-linux-x86_64/bin/kibanaを見てみると、自動で nodeファイルを探すようになっているが、実行できなければ whichで他の場所にある nodeファイルを探しに行くようになっている。

#!/bin/shSCRIPT=$0# SCRIPT may be an arbitrarily deep series of symlinks. Loop until we have the concrete path.while [-h"$SCRIPT"] ; dols=$(ls -ld "$SCRIPT")# Drop everything prior to ->link=$(expr"$ls" : '.*-> \(.*\)$')if expr"$link" : '/.*'> /dev/null; thenSCRIPT="$link"elseSCRIPT=$(dirname "$SCRIPT")/"$link"fidoneDIR="$(dirname "${SCRIPT}")/.."NODE="${DIR}/node/bin/node"test-x"$NODE" || NODE=$(which node)if [!-x"$NODE"]; thenecho"unable to find usable node.js executable."exit1fiNODE_ENV=production exec"${NODE}"$NODE_OPTIONS--no-warnings"${DIR}/src/cli"${@}

で、同梱されている node実行ファイルは ARM 上では実行できない。

$ node/bin/node
-bash: node/bin/node: cannot execute binary file: Exec format error

同梱されている nodeは使わないので実行権限を削除する。

chmod -x kibana-6.5.2-x86_64/node/bin/node

https://nodejs.org/dist/v8.14.0/からデバイスに合ったバイナリをダウンロードする。

wget https://nodejs.org/dist/v8.14.0/node-v8.14.0-linux-armv7l.tar.xz
tar xf node-v8.14.0-linux-armv7l.tar.xz

Node.js のインストールは下記のようなインストールスクリプトを使う方法もあるが、Kibana が Node.js のバージョンをチェックしているため、APT でアップデートが発生すると動かなくなってしまう可能性があり、Kibana との組み合わせではこの方法は向いていないと思われる。

curl -sL https://deb.nodesource.com/setup_8.x | bash -
apt-get install -y nodejs

nodeにパスを通して Kibana を起動する。

PATH=$HOME/node-v8.14.0-linux-armv7l/bin:$PATH kibana-6.5.2-x86_64/bin/kibana

Pythonでプログラムを書く

Python 3 用の PIP をインストールする。

sudo apt-get install python3-pip

今回はユーザ環境でしか使わないので ~/.config/pip/pip.confを下記のように設定しておく。「GPIO にアクセスするのに root 権限必要なんじゃ!」っていうデバイスの倍は sudo でどうぞ。

[global]
user = true

PIP をアップグレードする。

pip3 install -U pip

PATHを通しておく。

PATH=$HOME/.local/bin:$PATH

Python 3 用の elasticsearchモジュールをインストールする。

pip3 install elasticsearch

まずは簡単に CPU の温度を投げるだけのプログラムを書いてみる。Pythonタイムゾーンを扱う場合、datetime.now(timezone(timedelta(hours=+9)))と書くのが最初は少々面倒に感じるが、慣れれば定型文のように感じる。

とりあえずデータを投げる場合

#!/usr/bin/env python3from elasticsearch import Elasticsearch
from datetime import datetime, timedelta, timezone

es = Elasticsearch('localhost:9200')
withopen('/sys/class/thermal/thermal_zone0/temp') as f:
    timestamp, cpu_temp = datetime.now(timezone(timedelta(hours=+9))), int(f.read())
body = {
    '@timestamp': timestamp.isoformat(),
    'temperature': cpu_temp,
}
response = es.index(index='foo', doc_type='_doc', body=body)
print(response)
{'_version': 1, '_type': '_doc', 'result': 'created', '_seq_no': 0, '_index': 'foo', '_shards': {'failed': 0, 'total': 2, 'successful': 1}, '_id': 'RFfzK2gBykMjt7Ru8Nx9', '_primary_term': 1}

インデックスのセッティングとマッピングを追加する場合はこんな感じ。実際には毎回データを投げるわけではなく elasticsearch.helpersを使って1秒間隔で取得したデータを60秒間隔でまとめて Elasticsearch に投げるようにしている。

セッティングとマッピングを行う場合

#!/usr/bin/env python3from elasticsearch import Elasticsearch
from datetime import datetime, timedelta, timezone
import socket

hostname = socket.gethostname()
es = Elasticsearch('localhost:9200')

# CPU の温度を取得withopen('/sys/class/thermal/thermal_zone0/temp') as f:
    timestamp, cpu_temp = datetime.now(timezone(timedelta(hours=+9))), int(f.read())

# インデックス名の生成(logstash-%Y.%m.%d と同書式)
es_index = '-'.join([hostname, timestamp.strftime('%Y.%m.%d')])

# インデックス作成ifnot es.indices.exists(index=es_index):
    es_setting = {
        'settings': {
            'number_of_shards'  : 1,
            'number_of_replicas': 0,
        }
    }
    es_mapping = {
        '_doc': {
            '_all': {
                'enabled': False,
            }
        }
    }
    es.indices.create(index=es_index, body=es_setting)
    es.indices.put_mapping(index=es_index, doc_type='_doc', body=es_mapping)

# ポストデータ作成
es_body = {
    '@timestamp': timestamp.isoformat(),
    'hostname'  : hostname,
    'name'      : 'temperature',
    'value'     : cpu_temp,
}

# ポスト
response = es.index(index=es_index, doc_type='_doc', body=es_body)

print(response)

elasticsearch.helpers で Bulk API

適当に書いたので真似しない方がいいかもしれない。

#!/usr/bin/env python3from datetime import datetime, timedelta, timezone
from elasticsearch import Elasticsearch, helpers
from time import sleep
import socket

hostname = socket.gethostname()
es = Elasticsearch()

defgetCpuTemp():
    withopen('/sys/class/thermal/thermal_zone0/temp') as f:
        timestamp, temp = datetime.now(timezone(timedelta(hours=+9))), int(f.read())
    return timestamp, temp

data = []
whileTrue:
    timestamp, cpu_temp = getCpuTemp()
    es_index = '-'.join([hostname, timestamp.strftime('%Y.%m.%d')])
    ifnot es.indices.exists(index=es_index):
        es.indices.create(index=es_index, body={'settings':{'number_of_shards': 1, 'number_of_replicas': 0}})
        es.indices.put_mapping(index=es_index, doc_type='_doc', body={'_doc':{'_all':{'enabled': False}}})
    source = {
        '@timestamp' : timestamp.isoformat(),
        'hostname'   : hostname,
        'temperature': cpu_temp,
    }
    data.append({
        '_index' : es_index,
        '_type'  : '_doc',
        '_source': source,
    })
    iflen(data) >= 60:
        try:
            helpers.bulk(es, data)
            data = []
        except:
            pass
    sleep(1)

X-Pack Monitoring を無効にする

f:id:mattintosh4:20190108163654p:plain
Elasticsearch - X-Pack Monitoring

Monitoring を使うと細かくヘルスチェックデータを保存してくれるけど Raspberry Pi 3 Model B ではそれ自体が重い(CPU クロックが常に上がりっぱなし)。しかもインデックスのサイズが毎日 900 MB くらいになる。

クラスタを組んでいるわけでもないし、個人で使う分には必要ないので X-Pack Monitoring を無効にする。

elasticsearch-6.5.2/config/elasticsearch.yml

xpack.monitoring.enabled:false

家の外からのアクセス

家の中であればプライベート IP アドレスで問題ないんだけど、外でちょっと人に見せたりとかする場合に。めんどくさくて家には VPN入れてないので SSHでやっている。SSHのローカルフォワードで Elasticsearch と Kibana を動かしている Raspberry Piにそれぞれ接続している。

例えば Elasticsearch が入った Raspberry Pi192.168.1.1、Kibana が入った Raspberry Pi192.168.1.2であれば下記のように ssh_config を設定すればよい。

Host home-bastion
    Hostname XXX.XXX.XXX.XXX
    Port XXXXX
    LocalForward 9200 192.168.1.1:9200
    LocalForward 5601 192.168.1.2:5601

これで手元の Ubuntuからは curllocalhost:9200にアクセスすれば Elasticsearch に繋がるし、ブラウザで localhost:5601にアクセスすれば Kibana に繋がる。


Viewing all articles
Browse latest Browse all 892

Trending Articles