ZabbixからKafkaにデータ転送する

# 概要
Zabbixにて取得したデータをKafkaに転送するためのセットアップ手順を記載します。
本手順では、SNMPのポーリングで取得したデータを利用します。
SNMPエージェントやZabbixのインストール手順も含まれているので、既にそれらの環境が作成済みであれば、インストール部分はスキップしていただいて構いません。

# 環境
本記事で取り扱う内容は、次の環境にて確認しています。
* SNMPエージェント  
マシン：Amazon EC2  
OS：Ubuntu 24.04  

* Zabbix  
マシン：Amazon EC2  
OS：Ubuntu 24.04
Zabbix：7.0
※ZabbixとKafkaの連携を行うために、Zabbix versionが6.4以上である必要があります。

* Kafka Broker & Kafka Connector  
マシン：Amazon EC2  
OS：Ubuntu 24.04

# 前提条件
SNMPエージェント以外については、コンテナで構築するためマシンにDockerがインストール済みであること。  
インストール方法は[こちら](https://docs.docker.com/engine/install/ubuntu/)を参照下さい。

# SNMPエージェントセットアップ
※インバウンドルールにて、UDP 161 Portを許可して下さい。  SNMPポーリングにて利用するProtocol、Portになります。

以下でSNMPエージェントをインストールします。  
```sh
$ sudo apt-get update

$ sudo apt install snmpd

$ sudo apt install snmp 
```  
※snmp：マネージャ(net-snmp)及び、snmpwalkコマンドなどのツール  
※snmpd：エージェント  

次に、`/etc/snmp/snmpd.conf`を編集します。

```config
# コミュニティ名を任意の名前に変更します
rocommunity  <任意の名前> default -V systemonly
rocommunity6 <任意の名前> default -V systemonly

# 外部からSNMPの読み取りができるように以下をコメントアウトして下さい
# agentaddress  127.0.0.1,[::1]
```

snmpdを再起動し、設定を反映します。

```
$ sudo systemctl restart snmpd.service
```

SNMPにてデータが取得できることを確認して下さい。
```
$ snmpwalk -v2c localhost -c <コミュニティ名>
```
SNMPエージェントのセットアップは以上となります。


# Zabbixセットアップ
## Zabbixをコンテナとしてインストール
docker composeでZabbixをインストールします。

[公式サイト](https://www.zabbix.com/documentation/current/en/manual/installation/containers#docker-compose)の説明に従って設定します。

```
$ git clone https://github.com/zabbix/zabbix-docker.git

$ cd zabbix-docker/
```

Kafkaと連携するために、Zabbixの一部パラメータを変更します。  
次のコマンドを実行し、`ZBX_STARTCONNECTORS`という変数を0から1に変更して下さい。
```
$ vi env_vars/.env_srv
```

下記のコマンドにてコンテナを起動させますが、yamlファイルはご自身の環境に合ったものを選択してください。  
今回の手順では、OSがubuntuでありDBはmysqlを使おうと思うので、`docker-compose_v3_ubuntu_mysql_latest.yaml`を利用します。

```
$ docker compose -f ./docker-compose_v3_ubuntu_mysql_latest.yaml up -d
```

3つのコンテナが起動することを確認してください。
```
$ docker compose ps
NAME                                     IMAGE                                             COMMAND                  SERVICE                  CREATED              STATUS                         PORTS
zabbix-docker-mysql-server-1             mysql:8.0-oracle                                  "docker-entrypoint.s…"   mysql-server             About a minute ago   Up 39 seconds
zabbix-docker-zabbix-server-1            zabbix/zabbix-server-mysql:ubuntu-7.0-latest      "/usr/bin/docker-ent…"   zabbix-server            About a minute ago   Restarting (1) 7 seconds ago
zabbix-docker-zabbix-web-nginx-mysql-1   zabbix/zabbix-web-nginx-mysql:ubuntu-7.0-latest   "docker-entrypoint.sh"   zabbix-web-nginx-mysql   About a minute ago   Up 38 seconds (healthy)        0.0.0.0:80->8080/tcp, :::80->8080/tcp, 0.0.0.0:443->8443/tcp, :::443->8443/tcp
```

これでZabbixのWebUIにアクセス可能となります。
WebUIにアクセスすると、認証画面となり、次のデフォルトUser/PWでログイン可能です。
```
User：Admin
PW：zabbix
```

## SNMPポーリング設定
SNMPポーリングの設定を行います。  
Zabbix WebUIにて、`Data collection` > `Hosts` > `create host`を押下します。  

次のようなhostの作成画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510470/5c12c3c6-a932-b757-4a46-6aca8fed33f0.png)

下記の項目を入力してください。
* Hostname：任意
* Host groups：任意
* Interfaces：Type：SNMP
* Interfaces：IP address：SNMPエージェントマシンのIP
* Interfaces：Port：161


次に`Macros`タブを開きます。次のような画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510470/264bd3c7-55eb-dad9-7443-9bdd8646332f.png)

下記の項目を入力してください。 
* Macro：{$SNMP_COMMUNITY}
* Value：コミュニティ名

`item`タブを開き、`create item`を押下します。  
次のようなitemの作成画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510470/94a4e194-5127-db30-1d68-d2a4b3a03922.png)


下記の項目を入力してください。  
* Name：任意の名前(OIDを名前解決したときの名前にすると良いと思います)
* Type：SNMP agent
* Key：任意の名前
* Type of information：ポーリングで返ってきた値のデータ型
* Host interface：SNMPエージェントマシンのIP
* SNMP OID：取得したいOID  

入力後、`Test`タブを押下すると、指定したOIDの値が取得できるかテスト確認できるので便利です。  
これでポーリングの設定は完了し、SNMPエージェントからデータが取得できるようになりました。  
参考までに、左ペインから`Monitoring` > `Latest data` を押下すると、ポーリングのLast checkがいつ実施されたかが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510470/37e20099-745c-a7b3-2192-276e39c24f81.png)

また、`Grapf`を押下するとデータの取得状況が可視化されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510470/183e77c6-615d-6542-ab60-68ab8f4ba049.png)


ポーリングで問題なくデータが取得できているかどうかを確認することが出来ました。
Zabbixのセットアップは以上となります。

# Kafka セットアップ
Kafkaのセットアップでは、主に次の2つのコンポーネントをセットアップします
* Kafka Broker：Kakfa本体
* Kafka Connector： ZabbixとKakfaを接続するために利用

## Kafka Broker セットアップ

Kafka Brokerについても、docker composeでコンテナ作成します。
※コンテナではなく、Amazon MSK(Amazon Managed Streaming for Apache Kafka)を利用しても構いません。
次のcompose.yamlを用意し、compose.yamlが存在するディレクトリにて、`docker compose up -d`を実行して下さい。
`<Kakfa BrokerマシンのパブリックIP>`の箇所はご自身の環境のIPに置き換えて下さい。

```
services:
  zookeeper:
    image: docker.io/bitnami/zookeeper:3.9
    ports:
      - "2181:2181"
    volumes:
      - "zookeeper_data:/bitnami"
    environment:
      - ALLOW_ANONYMOUS_LOGIN=yes
  kafka:
    image: docker.io/bitnami/kafka:3.4
    ports:
      - "9092:9092"
      - "9094:9094"
    volumes:
      - "kafka_data:/bitnami"
    environment:
      - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181
      - KAFKA_CFG_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093,EXTERNAL://0.0.0.0:9094
      - KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,EXTERNAL://<Kakfa BrokerマシンのパブリックIP>:9094
      - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,EXTERNAL:PLAINTEXT,PLAINTEXT:PLAINTEXT
    depends_on:
      - zookeeper

volumes:
  zookeeper_data:
    driver: local
  kafka_data:
    driver: local
```

2つのコンテナが起動することを確認してください。  
```
$ docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED       STATUS       PORTS                                                                                  NAMES
9018cc887c1d   bitnami/kafka:3.4        "/opt/bitnami/script…"   7 hours ago   Up 7 hours   0.0.0.0:9092->9092/tcp, :::9092->9092/tcp, 0.0.0.0:9094->9094/tcp, :::9094->9094/tcp   kafka-kafka-1
489d311ac808   bitnami/zookeeper:3.9    "/opt/bitnami/script…"   7 hours ago   Up 7 hours   2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, :::2181->2181/tcp, 8080/tcp                kafka-zookeeper-1
```

Kafka Brokerコンテナにログインします。
```
$ docker exec -it <Kafka Broker コンテナID> /bin/bash
```

次のコマンドで`items`という名前のTopicを作成してください。  
この名前のTopicに対して、データが送信されることになります。

```
$ /opt/bitnami/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic items --partitions 1 replication-factor 1
```

`items`Topicが作成されたことを確認して下さい。

```
$ /opt/bitnami/kafka/bin/kafka-topics.sh --list --bootstrap-server localhost:9092
```

## Kafka Connector セットアップ
※Kafka Connectorは、Kafka Brokerと同じマシンでも、別のマシンで稼働させても構いません。  
Kafka Connectorについては、公式からはDockerImageが提供されていなかったので、
[公式サイト](https://git.zabbix.com/projects/ZT/repos/kafka-connector/browse)を参考に、自分でDockerImageを作成します。

まずはKafka Connector用の資材をダウンロードします。
```
$ git clone https://git.zabbix.com/scm/zt/kafka-connector.git
```

次の内容の`Dockerfile`を作成して下さい。
```
FROM golang:1.20 AS builder

WORKDIR /app
# COPY go.mod go.sum ./
# RUN go mod download
COPY . .
RUN make build

FROM golang:1.20
WORKDIR /app
COPY --from=builder /app/kafka-connector .
COPY --from=builder /app/kafka_connector.conf .
EXPOSE 8080
CMD ["./kafka-connector"]
```

`kafka_connector.conf`を次の内容に置き換えてください。
いくつかご自身の環境に合わせて設定する箇所があるのでご注意下さい。

```
# This is a configuration file for Zabbix Kafka connector
# To get more information about Zabbix, visit https://www.zabbix.com

############ KAFKA CONNECTOR (API SERVER) PARAMETERS #################

### Option: Connector.Port
#	Port for the kafka connector server.
#
# Mandatory: no
# Default: 80
Connector.Port=8080

### Option: Connector.LogType
#	Specifies where log messages are written to:
#		system  - syslog
#		file    - file specified with LogFile parameter
#		console - standard output
#
# Mandatory: no
# Default: file
Connector.LogType=console

### Option: Connector.LogFile
#	Specifies where log file is located.
#
# Mandatory: no
# Default: /tmp/kafka-connector.log
# Connector.LogFile=

### Option: Connector.LogFileSize
#	Maximum size of log file in MB.
#	0 - disable automatic log rotation.
#
# Mandatory: no
# Range: 0-1024
# Default: 1
# Connector.LogFileSize=

### Option: Connector.LogLevel
#	Specifies debug level:
#	0 - basic information about starting and stopping of Zabbix processes
#	1 - critical information
#	2 - error information
#	3 - warnings
#	4 - for debugging (produces lots of information)
#	5 - extended debugging (produces even more information)
#
# Mandatory: no
# Range: 0-5
# Default: 3
Connector.LogLevel=4

### Option: Connector.BearerToken
#	Authorization token for incoming connections.
#
# Mandatory: no
# Default:
# Connector.BearerToken=

### Option: Connector.AllowedIP
#	List of comma delimited IP addresses, optionally in CIDR notation, or DNS names.
#	Incoming connections will be accepted only from the hosts listed here.
#	If IPv6 support is enabled then '127.0.0.1', '::127.0.0.1', '::ffff:127.0.0.1' are treated equally
#	and '::/0' will allow any IPv4 or IPv6 address.
#	'0.0.0.0/0' can be used to allow any IPv4 address.
#	Example: Connector.AllowedIP=127.0.0.1,192.168.1.0/24,::1,2001:db8::/32,zabbix.example.com
#
# Mandatory: yes
# Default:
# Connector.AllowedIP=

# 10.0.0.0/16 cidr block of private subnet
Connector.AllowedIP=127.0.0.1,<ZabbixマシンのIP>

### Option: Connector.EnableTLS
#	Enable TLS check for incoming requests.
#
# Mandatory: no
# Default: false
# Connector.EnableTLS=

### Option: Connector.CertFile
#	Certificate file location for incoming request TLS verification.
#
# Mandatory: no
# Default:
# Connector.CertFile=

### Option: Connector.KeyFile
#	Key file location for incoming request TLS verification.
#
# Mandatory: no
# Default:
# Connector.KeyFile=

### Option: Connector.Timeout
#	Global Timeout (in seconds) used in Kafka connector.
#
# Mandatory: no
# Range: 1-30
# Default: 3
# Connector.Timeout=

############ KAFKA PRODUCER PARAMETERS #################

### Option: Kafka.URL
#	Kafka broker URL or DNS name.
#
# Mandatory: no
# Default: localhost
# Kafka.URL=
Kafka.URL=<Kafka BrokerのURL>

### Option: Kafka.Port
#	Kafka broker port.
#
# Mandatory: no
# Default: 9093
Kafka.Port=<Kafka BrokerがListenしているPort>

### Option: Kafka.Events
#	Kafka topic for events endpoint.
#
# Mandatory: no
# Default: events
Kafka.Events=events

### Option: Kafka.Items
#	Kafka topic for items endpoint.
#
# Mandatory: no
# Default: items
Kafka.Items=items

### Option: Kafka.Retry
#	Kafka producer retry amount on failed request.
#
# Mandatory: no
# Default: 0
# Kafka.Retry=

### Option: Kafka.Timeout
#	Kafka producer request timeout (in seconds).
#
# Mandatory: no
# Default: 1
# Kafka.Timeout=

### Option: Kafka.KeepAlive
#	Kafka producer connection keep alive duration (in seconds).
#
# Mandatory: no
# Range: 60-300
# Default: 300
# Kafka.KeepAlive=

### Option: Kafka.Username
#	SASL authorization username. Enables SASL authorization if provided.
#
# Mandatory: no
# Default:
# Kafka.Username=

### Option: Kafka.Password
#	SASL authorization password.
#
# Mandatory: no
# Default:
# Kafka.Password=

### Option: Kafka.EnableTLS
#	Enables kafka TLS authorization.
#
# Mandatory: no
# Default: false
# Kafka.EnableTLS=

### Option: Kafka.TLSAuth
#	Enables kafka TLS authorization.
#
# Mandatory: no
# Default: false
# Kafka.TLSAuth=

### Option: Kafka.CaFile
#	CA file location for outgoing request TLS verification.
#
# Mandatory: no
# Default:
# Kafka.CaFile=

### Option: Kafka.ClientCertFile
#	Client certificate file location for outgoing request TLS verification.
#
# Mandatory: no
# Default:
# Kafka.ClientCertFile=

### Option: Kafka.ClientKeyFile
#	Client key file location for outgoing request TLS verification.
#
# Mandatory: no
# Default:
# Kafka.ClientKeyFile=
```

DockerImageを作成します。
```
$ docker build -t kafka-connector .
```

コンテナを起動します。
```
$ docker run -d -p 8080:8080 kafka-connector:latest
```
※Kafka ConnectorをBrokerと同一マシンにて起動させる場合、docker runコマンドに、--netオプションを付与し、Kafka Brokerと同一ネットワークに所属させてください。  

Kafka Connectorが起動したことを確認して下さい。
```
$ docker ps
CONTAINER ID   IMAGE                    COMMAND                  CREATED              STATUS              PORTS                                                                                  NAMES
337b3990893c   kafka-connector:latest   "./kafka-connector"      About a minute ago   Up About a minute   0.0.0.0:8080->8080/tcp, :::8080->8080/tcp                                              nostalgic_cray
```

次に、Zabbix WebUI上でConnectorとの接続設定を行います。
Zabbix WebUIにて、`Administration` > `General` > `Connectors`を押下し、`create connector`を押下します。次のようなConnector作成画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3510470/57a2abdf-e8ab-0e9a-5147-2e6a1bd0f87b.png)


ここでは次のような設定にして下さい。
* name：任意の名前
* URL：http://[Kafka ConnectorのIP]:8080/api/v1/items

設定後、Zabbix コンテナにログインしてください。  

```
$ docker exec -it <Zabbix コンテナID> /bin/bash
```

次のコマンドを実行し、リロードして下さい。
```
$ zabbix_server -R config_cache_reload
```

Kafka Broker コンテナにログインします。
```
$ docker exec -it <Kafka Broker コンテナID> /bin/bash
```

Zabbixからのデータが`items`Topicにて受信できていることを確認してください。

```
$ /opt/bitnami/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic items
```
セットアップが出来ていれば、次のようにデータが受信できているはずです。  
次の例では、1行目のJSONはZabbixの情報で、2～4行目のJSONは登録したSNMPエージェントの情報を示しています。
```
{"clock":1721627016,"groups":["Zabbix servers"],"host":{"host":"Zabbix server","name":"Zabbix server"},"item_tags":[{"tag":"component","value":"internal-process"}],"itemid":28536,"name":"Utilization of LLD manager internal processes, in %","ns":66567525,"type":0,"value":0}
{"clock":1721627372,"groups":["Linux servers"],"host":{"host":"test","name":"test"},"item_tags":[],"itemid":47158,"name":"sysName","ns":13712042,"type":1,"value":"ip-10-0-0-97"}
{"clock":1721627372,"groups":["Linux servers"],"host":{"host":"test","name":"test"},"item_tags":[],"itemid":47159,"name":"sysServices","ns":13712042,"type":3,"value":72}
{"clock":1721627372,"groups":["Linux servers"],"host":{"host":"test","name":"test"},"item_tags":[],"itemid":47160,"name":"sysContact","ns":13712042,"type":1,"value":"Me \u003cme@example.org\u003e"}
```

ZabbixからKafkaへのデータ転送設定は以上となります。

# 2024/8/28 追記
本記事ではSNMPポーリングのデータのみを扱いましたが、次のデータに関してもKafkaに転送できることを確認しました。
* SNMPトラップ
* syslog

これらのデータをKafkaに転送するための手順は、[こちら](https://qiita.com/myama0827/items/31f34d2ad8c92fb818c0)を参照下さい。

# 参考
https://www.apresiatac.jp/blog/202309147751/
https://www.zabbix.com/documentation/current/en/manual/installation/containers#docker-compose
https://www.zabbix.com/documentation/current/en/manual/config/export/streaming
https://git.zabbix.com/projects/ZT/repos/kafka-connector/browse
https://qiita.com/myama0827/items/31f34d2ad8c92fb818c0