この記事について
golangのechoが吐き出すログをvectorで収集し、opendistro版 Elasticsearchに収集、可視化する方法についてメモ
- この記事について
- vectorについて
- opendistro Elasticsearchについて
- elasticsearch + kibanaの構築
- vectorの作成
- アプリケーションからのログ送信
- kibanaでの確認と可視化
- 終わりに
vectorについて
Rust製のデータ収集、変換ツールです。この分野で有名なものにtd-agent(fluentd)がありますが、vectorは高パフォーマンス、軽量を売りにしています。
opendistro Elasticsearchについて
OSSのElasticsearchにいろいろなプラグインを同包したものです。elastic版Elasticsearchとは異なり、elastic社が有料プランで提供しているアラートなどの機能を無料で使うことができます。
elasticsearch + kibanaの構築
docker-composeを利用して構築します。無駄にクラスタを組んでますが1ノードでも問題なく動きます。
docker-compose.yml
version: "3" services: server: build: ./server ports: - 8888:8888 odfe-node1: image: amazon/opendistro-for-elasticsearch:1.12.0 container_name: odfe-node1 environment: - cluster.name=odfe-cluster - node.name=odfe-node1 - discovery.seed_hosts=odfe-node1,odfe-node2 - cluster.initial_master_nodes=odfe-node1,odfe-node2 - bootstrap.memory_lock=true # along with the memlock settings below, disables swapping - opendistro_security.disabled=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" # minimum and maximum Java heap size, recommend setting both to 50% of system RAM ulimits: memlock: soft: -1 hard: -1 nofile: soft: 65536 # maximum number of open files for the Elasticsearch user, set to at least 65536 on modern systems hard: 65536 volumes: - odfe-data1:/usr/share/elasticsearch/data ports: - 9200:9200 - 9600:9600 # required for Performance Analyzer networks: - odfe-net odfe-node2: image: amazon/opendistro-for-elasticsearch:1.12.0 container_name: odfe-node2 environment: - cluster.name=odfe-cluster - node.name=odfe-node2 - discovery.seed_hosts=odfe-node1,odfe-node2 - cluster.initial_master_nodes=odfe-node1,odfe-node2 - bootstrap.memory_lock=true - opendistro_security.disabled=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" ulimits: memlock: soft: -1 hard: -1 nofile: soft: 65536 hard: 65536 volumes: - odfe-data2:/usr/share/elasticsearch/data networks: - odfe-net kibana: build: ./kibana container_name: odfe-kibana ports: - 5601:5601 environment: ELASTICSEARCH_URL: http://odfe-node1:9200 ELASTICSEARCH_HOSTS: http://odfe-node1:9200 networks: - odfe-net volumes: odfe-data1: odfe-data2: networks: odfe-net:
elasticsearchのセキュリティ機能をオフにしたので、kibanaのセキュリティプラグインも削除します。
kibana/Dockerfile
FROM amazon/opendistro-for-elasticsearch-kibana:1.12.0 RUN /usr/share/kibana/bin/kibana-plugin remove opendistroSecurityKibana COPY --chown=kibana:kibana kibana.yml /usr/share/kibana/config/
kibana/kibama.yml
server.name: kibana server.host: "0"
./server
にはechoアプリケーションが入ります。開発環境なのでfreshでオートビルドされるようにしてあります。
./server/Dockerfile
FROM golang:1.15.6-alpine3.12 WORKDIR /go/src/app RUN apk add --no-cache \ alpine-sdk \ git \ && go get github.com/pilu/fresh CMD [ "fresh" ]
ビルドしていい感じにkibanaにログインできたらOK
vectorの作成
こちらもDockerで立てます。ネットワークはアプリケーションがあるdefault
とelasticsearchがあるodfe-net
の両方に属している必要があります。
docker-compose.yml
vector-server: image: timberio/vector:0.11.X-alpine volumes: - ./vector/vector.toml:/etc/vector/vector.toml:ro depends_on: - odfe-node1 networks: - default - odfe-net
vectorでは次の3つを指定します。
sources
: データの発生元transforms
:sources
で受け取ったデータの変換規則(オプション)sinks
: 最終的なデータの受け渡し先
sources
ではファイルやOSのメトリックの他、サーバを立ててそこに投げられるデータを扱うことも可能です。今回はsocket source
を利用してechoアプリケーションのログをUDPで受けるようにします。
https://vector.dev/docs/reference/sources/socket/#outputにあるように、socket source
で受けたデータはmessage
フィールドにコンテンツが格納されるので、transforms
でそれを抽出し、elasticsearch sink
に渡します。
./vector/vector.toml
[sources.origin] type = "socket" # required address = "0.0.0.0:50000" # required, required when mode = `tcp` or `udp` mode = "udp" # required [transforms.extract_message] type = "json_parser" # required inputs = ["origin"] # required field = "message" # optional, default [sinks.elastic] type = "elasticsearch" # required inputs = ["extract_message"] # required endpoint = "http://odfe-node1:9200" # required index = "echo-log-%F" # optional, default
アプリケーションからのログ送信
echoにはロギング用のミドルウェアが備わっているのでそれを使い、UDPのエンドポイントとstdoutに同時に出力するようにしています。
$VECTOR_SERVER
には先ほどvector.toml
のsocket source
で指定したアドレスがセットされるようにする必要があります(省略)。
main.go
e := echo.New() api := e.Group("/api") var output io.Writer = os.Stdout raddr, err := net.ResolveUDPAddr("udp", os.Getenv("VECTOR_SERVER")) if err == nil { conn, err := net.DialUDP("udp", nil, raddr) if err == nil { output = io.MultiWriter(output, conn) } } api.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{ Output: output, }))
ここまでできれば、アプリケーションのログがvectorを通してelasticsearchに蓄積されるようになります。
$ curl localhost:9200/_cat/indices?v health status index uuid pri rep docs.count docs.deleted store.size pri.store.size green open echo-log-2021-01-17 i8CpjKbuSAGEX3J5Ez6dmg 1 1 5 0 27.5kb 13.7kb
kibanaでの確認と可視化
ログインし、右のメニューからStack Management > Index Patterns > Newを選択しecho-log-*
でインデックスパターンを作成します。これでVisualizationが利用できます。
Visualizeタブからグラフを作成しました。Buckets
がX軸、Metrics
がY軸になります。X軸方向にはタイムスタンプによる時間、Y軸にはログのカウントを取っています。ログのフィールドからHTTPのステータスコードやレスポンスタイムを可視化することも可能です。
終わりに
golang echo + vector + elasticsearch + kibanaによるログ可視化について記述しました。ログが収集できたので、この値を元にアラートを飛ばすことも可能です(これが無料でできるのがopendistro版ESの良いところ)。次回はアラートについて書きたいと思います。