自分のBeatで、Elasticsearch や Logstash にデータを送りたい！Custom Beat を作ってみた。メモ。

みなさん、Elasticsearch や Elastic Cloud はご存じでしょうか？ 

https://www.elastic.co/jp/elasticsearch

Elasticsearchは、分散型検索および分析エンジンとして主に大規模なデータセットから迅速に情報を検索するために使用されます。以下は、主な特徴です。

1. **全文検索**: Elasticsearchは、テキストデータの全文検索に優れています。指定したキーワードを含むドキュメントを高速で検索できます。
2. **スケーラビリティ**: 数百台のサーバーにまたがるクラスタ構成が可能で、ペタバイト級のデータにも対応できます。
3. **リアルタイム分析**: データの取り込みから検索、分析までをほぼリアルタイムで行うことができます。
4. **柔軟なデータモデル**: 様々なデータ型やスキーマに対応し、スキーマレスでデータを投入することも可能です。
5. **高可用性**: 分散環境での運用を前提として設計されており、障害が発生してもデータを安全に保持し続けることができます。

Elasticsearchは、ログの監視、インフラの監視、アプリケーションのパフォーマンス管理など、様々なユースケースに対応しています。また、Kibanaという可視化ツールと連携することで、データの視覚化やインタラクティブなダッシュボードの構築も可能です。

Microsoft Azure でも Elastic Cloud として Kibana とともに提供されています！

https://learn.microsoft.com/ja-jp/azure/partner-solutions/elastic/

# Custome Beat を作ってみる

今回は、Elastic Cloud に、独自のデータでデータを送るための Beat 7.17 を作成する方法を紹介します。以下の、Beats Developer Guide サイトを参考にしています。

https://www.elastic.co/guide/en/beats/devguide/7.17/new-beat.html

## 開発環境を整える

ビルドに必要なgoとmakeをインストールします。

```sh
sudo apt install golang-go make
```

goの環境変数とパスの設定します。必要な方は、~/.bashrc あたりに追加しておいたほうが便利かもしれません。

```sh
export GOPATH=~/go
export GOBIN=$GOPATH/bin
export GOMODCACHE=$GOPATH/pkg/mod
export PATH=$GOBIN:$PATH
```

goのバージョンは以下になります。

```sh
$ go version
go version go1.22.2 linux/amd64
```

## beat のgitリポジトリを取得する

libbeat を含む beat のリポジトリを github.com から取得して、7.17 をチェックアウトします。

```sh
mkdir -p ${GOPATH}/src/github.com/elastic
git clone https://github.com/elastic/beats.git ${GOPATH}/src/github.com/elastic/beats
cd ${GOPATH}/src/github.com/elastic/beats
git checkout 7.17
```

## カスタムBeatを作成する

beats のディレクトリで make した後に、mage で カスタムBeat を作成します。

```sh
cd ${GOPATH}/src/github.com/elastic/beats
make update
```

mage generateCustomBeatを実行すると、カスタムBeat 作成に名前などの入力を求められます。your github name などはご自身のgithubアカウントを設定してください。このコマンドにより、${GOPATH}/src/github.com/your_name/testbeat のディレクトリにテンプレートの beat が作成されます。

```sh
$ mage generateCustomBeat
Generating custom Beats are going to be removed in 8.0.0.
Enter the beat name [examplebeat]: testbeat
Enter your github name [your-github-name]: your_name
Enter the beat path [github.com/your_name/testbeat]:
Enter your full name [Firstname Lastname]:  
```

## カスタムBeat のビルドに向けた準備

作成された カスタムBeat のディレクトリでビルドするためのモジュールを取得します。

```sh
cd ${GOPATH}/src/github.com/your_name/testbeat
go mod tidy
go get github.com/elastic/beats/v7/dev-tools/mage/target/build
go get github.com/elastic/beats/v7/libbeat/publisher/queue/spool
go get github.com/elastic/beats/v7/libbeat/cmd/platformcheck
go get github.com/elastic/beats/v7/libbeat/cmd
```

現在のgoに合わせるため Makefile を編集します。
```sh
cd ${GOPATH}/src/github.com/your_name/testbeat
vi Makefile
```
変更内容は、GOBUILD_FLAGS の "-i"オプションを削除します。Makefileの中身は以下の通り。
```sh
$ cat Makefile
BEAT_NAME=testbeat
BEAT_PATH=github.com/your_name/testbeat
BEAT_GOPATH=$(firstword $(subst :, ,${GOPATH}))
SYSTEM_TESTS=false
TEST_ENVIRONMENT=false
ES_BEATS_IMPORT_PATH=github.com/elastic/beats/v7
ES_BEATS?=$(shell go list -m -f '{{.Dir}}' ${ES_BEATS_IMPORT_PATH})
LIBBEAT_MAKEFILE=$(ES_BEATS)/libbeat/scripts/Makefile
GOPACKAGES=$(shell go list ${BEAT_PATH}/... | grep -v /tools)
GOBUILD_FLAGS=-ldflags "-X ${ES_BEATS_IMPORT_PATH}/libbeat/version.buildTime=$(NOW) -X ${ES_BEATS_IMPORT_PATH}/libbeat/version.commit=$(COMMIT_ID)"
MAGE_IMPORT_PATH=github.com/magefile/mage
NO_COLLECT=true
CHECK_HEADERS_DISABLED=true

# Path to the libbeat Makefile
-include $(LIBBEAT_MAKEFILE)

.PHONY: copy-vendor
copy-vendor:
        mage vendorUpdate
```

最後にビルドします。ビルド後、testbeat が作成されていることを確認します。

```sh
cd ${GOPATH}/src/github.com/your_name/testbeat
make
```

fileコマンドで確認します。

```sh
$ file testbeat
testbeat: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f73b93cdb472dd8b1295ef09f2b158b1f229e04c, for GNU/Linux 3.2.0, with debug_info, not stripped
```

# テンプレートの カスタムBeat を動かしてみる

Elasticsearchを構築した後に、testbeatのデータを送ってみます。

## Elasticsearch環境の作成

Elasticsearch は Azure の Elastic Cloud で作成することができます。プロダクション環境を検討の場合はこちらをご利用ください。

https://learn.microsoft.com/ja-jp/azure/partner-solutions/elastic/

ただ、今回は Azure のアカウントを持っていない人もいると思いますので、Docker 環境を使用して、Elasticsearch を構築します。今回は１台ですが今後のためにもネットワークを作っておきます。

```sh
sudo docker network create elastic
sudo docker run --name es01 --net elastic -p 9200:9200 -it -m 1GB docker.elastic.co/elasticsearch/elasticsearch:8.17.0
```

## Elasticsearch のパスワードを初期化とSSL証明書の取得

作成した Elasticsearchコンテナ のユーザー「elastic」のパスワードを初期化します。

```sh
sudo docker exec -it es01 /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic
```

表示されたパスワードを環境変数に設定します。

```sh
export ELASTIC_PASSWORD="your_password"
```

SSL certificate を Elasticsearch のコンテナからtestbeatのディレクトリにコピーします。（本記事で説明しやすいようにtestbeatのディレクトリにコピーしていますが、適切なディレクトリに保存することをお勧めします）

```sh
cd ${GOPATH}/src/github.com/your_name/testbeat
sudo docker cp es01:/usr/share/elasticsearch/config/certs/http_ca.crt .
```

## testbeat.yml を作成する

testbeat の設定用の yml を作成します。カスタムBeat のテンプレートでは、動作間隔を設定ファイルから読み込むように作成されているため、periodで5秒を設定しています。また、passwordには、先ほど初期化したパスワードを、ssl.certificate_authoritiesには、コンテナからコピーして取得した SSL certificate のパスを設定します。

```sh
cd ${GOPATH}/src/github.com/your_name/testbeat
vi testbeat.yml
```

```testbeat.yml
testbeat:
  period: 5s

# ================================== Outputs ===================================

# Configure what output to use when sending the data collected by the beat.

# ---------------------------- Elasticsearch Output ----------------------------
output.elasticsearch:
  # Array of hosts to connect to.
  hosts: ["localhost:9200"]

  # Protocol - either `http` (default) or `https`.
  protocol: "https"

  # Authentication credentials - either API key or username/password.
  #api_key: "id:api_key"
  username: "elastic"
  password: "${ELASTIC_PASSWORD}"
  ssl.certificate_authorities: ["${GOPATH}/src/github.com/your_name/testbeat/http_ca.crt"]
```

## 実行してみる
準備が整ったら testbeat を実行してみます。終了するときは Ctl-C です。

```sh
cd ${GOPATH}/src/github.com/your_name/testbeat
./testbeat -c testbeat.yml -e -d "*"
```

1. **`-c testbeat.yml`**: このオプションは、使用する設定ファイルを指定します。ここでは、`testbeat.yml`という設定ファイルを使用しています。設定ファイルには、Beatの動作に関する詳細な設定が含まれています。

2. **`-e`**: このオプションは、ログを標準出力（コンソール）に出力するためのものです。通常、ログはファイルに書き込まれますが、このオプションを使用すると、リアルタイムでログを確認できます。

3. **`-d "*"`**: このオプションは、デバッグログを有効にします。`"*"`はすべてのデバッグモジュールを意味し、詳細なデバッグ情報を出力します。特定のモジュールのみをデバッグしたい場合は、`"*"`の代わりにモジュール名を指定します。

## インデックスの確認
Elasticsearch の API を使用してインデックスが作成されていることを確認します。

```sh
curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -X GET "https://localhost:9200/_cat/indices?v"
```

作成されてますね。

```
health status index                              uuid                   pri rep docs.count docs.deleted store.size pri.store.size dataset.size
yellow open   testbeat-7.17.26-2024.12.30-000001 _fNwyKLmSBq5nrFN6E9bVg   1   1          6            0     64.8kb         64.8kb       64.8kb
```

Elasticsearch の testbeat インデックスに入っているデータを全部出力してみます。

```sh
curl --cacert http_ca.crt -u elastic:$ELASTIC_PASSWORD -X GET "https://localhost:9200/testbeat-*/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "match_all": {}
  }
}
'
```

testbeat のデータが入っていることを確認することができますね。（記事の関係で、hitsは1つだけ残して、他は削除しています）

```json
{
    "took": 17,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 225,
            "relation": "eq"
        },
        "max_score": 1.0,
        "hits": [
            {
                "_index": "testbeat-7.17.26-2024.12.30-000001",
                "_id": "QhiuF5QBYWpJQmJQtJoy",
                "_score": 1.0,
                "_source": {
                    "@timestamp": "2024-12-30T13:08:31.938Z",
                    "ecs": {
                        "version": "1.12.0"
                    },
                    "host": {
                        "name": "ubuntu24"
                    },
                    "type": "ubuntu24",
                    "counter": 28,
                    "agent": {
                        "id": "49420ea5-c054-4ec9-bdfd-8aa0a9d75ce9",
                        "name": "ubuntu24",
                        "type": "testbeat",
                        "version": "7.17.26",
                        "hostname": "ubuntu24",
                        "ephemeral_id": "bb9f83ec-364c-46fe-b252-769f32cca581"
                    }
                }
            }
        ]
    }
}
```

# さいごに
時間があれば、テンプレートからのカスタマイズ方法を記事にできればと思います。