DockerでZabbix ServerとZabbix Proxyを構築してみた

# 背景

Dockerコンテナ環境でZabbix Serverを構築していますのでメモ書きしてみました。
[2022/05/10] Zabbix Proxyを追記した。
[2022/12/01] Zabbix Server 6.0.11の対応を追加

# 動作環境

## ホスト側

- OS:Ubuntu Server 22.04LTS
- Docker CE version 20.10.17
- docker compose version v2.8.0


## コンテナ側

公式のDockerコンテナを使用します。

- [GitHub - zabbix/zabbix-docker: Official Zabbix Dockerfiles](https://github.com/zabbix/zabbix-docker)

ベースには以下のLinuxディストリビューションが用意されています。

- Alpine
- CentOS
- Oracle Linux
- Ubuntu

今回は例によって軽量のAlpine Linux版を使用します。
なおCentOS 8はOracle Linux 8に置き換わった様子です。

- [zabbix's Profile | Docker Hub](https://hub.docker.com/u/zabbix/)


# Docker環境の準備

以下のページにて紹介していますので参考にしてみて下さい。

- [Linuxサーバー環境のDockerインストールメモ - Qiita ](https://qiita.com/ohhara_shiojiri/items/486a54ad895d6bb3144e)


# Zabbix 6.0構築の方針

Zabbixには状況に応じて複数のサービスがあります。

- Zabbix Agent
- Zabbix Server
- Zabbix Web interface(Apache2 or Nginx)
- Zabbix Proxy
- Zabbix Java Gateway
- Zabbix SNMPtraps

またデータベースも以下が利用出来ます。

- MySQL
- PostgreSQL
- SQLite3

今回は通常のZabbix Serverを構築する事として以下の必要なサービスを選択します。

- Zabbix Agent
- Zabbix Server
- Zabbix Web interface(Nginx)
- Zabbix SNMPtraps
- MySQL

# Zabbix 6.0のシステム構築

公式ドキュメントを参考にdocker composeでシステム全体を作成します。

- [Zabbix Documentation 6.0
 5 コンテナでのインストール](https://www.zabbix.com/documentation/6.0/jp/manual/installation/containers)

## gitリポジトリの取得

GitHubからZabbix公式のgitリポジトリを取得します。

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

## gitブランチの変更

標準のブランチは最新版の6.2になりますが状況に応じてLTSの6.0に変更します。
ここでは安定長期サポートLTSの6.0に変更します。

```
$ git branch
* 6.2
$ git checkout 6.0
$ git branch
* 6.0
  6.2
$ git branch --set-upstream-to=6.0
$ git pull
```

## docker compose設定

サンプルの「compose.yaml」ファイルが複数用意されているので適当にコピーします。
今回はAlpine-MySQL版を選択します。

```
$ cp docker-compose_v3_alpine_mysql_latest.yaml compose.yaml
```

### リソースオプションの警告

docker compose起動時にswarmのリソースオプションのエラーがでます。
「WARNING: The following deploy sub-keys are not supported and have been ignored: resources.reservations.cpus」
該当項目(reservations:)を複数箇所コメントアウトします。

```:compose.yaml
#    reservations:
#      cpus: '0.5'
#      memory: 512M
```

### Zabbix Agent

Zabbix-Agentのコンテナは「compose.yaml」ファイル設定のprofilesでオプション扱いなので外して有効化します。
これでホスト側が監視出来ます。

```:compose.yaml
 zabbix-agent:
  image: zabbix/zabbix-agent:alpine-6.0-latest
  #profiles:
  # - full
  # - all
```

### Zabbix SNMPtraps

主にネットワーク機器の監視で利用されるSNMPの監視をZabbixで行う場合に有効化します。
「compose.yaml」ファイル設定のprofilesでオプション扱いなので外して有効化します。
これでSNMP機器の監視出来ます。

```:compose.yaml
 zabbix-snmptraps:
  image: zabbix/zabbix-snmptraps:alpine-6.0-latest
  #profiles:
  # - full
  # - all
```

#### MIB設定

SNMPのMIB設定ファイルは「zbx_env/var/lib/zabbix/mibs」以下に配置すると利用出来ます。
以下は例としてYAMAHAのRTXルーターのMIBテンプレートファイルを配置する方法です。

```
$ cd zabbix-docker
$ wget http://www.rtpro.yamaha.co.jp/RT/docs/mib/yamaha-private-mib.tar.gz
$ tar xvzf yamaha-private-mib.tar.gz
$ sudo cp yamaha-private-mib/* zbx_env/var/lib/zabbix/mibs
```

## PHPのタイムゾーン設定

```:env_vars/.env_web
PHP_TZ=Asia/Tokyo
```

## docker composeの起動

```
$ docker compose up -d
```

問題がなければ以下のように起動しています。

```
$ docker compose ps
NAME                                     COMMAND                  SERVICE                  STATUS               PORTS
zabbix-docker-db_data_mysql-1            "sh"                     db_data_mysql            exited (0)           
zabbix-docker-mysql-server-1             "docker-entrypoint.s…"   mysql-server             running              
zabbix-docker-zabbix-agent-1             "/sbin/tini -- /usr/…"   zabbix-agent             running              
zabbix-docker-zabbix-server-1            "/sbin/tini -- /usr/…"   zabbix-server            running              0.0.0.0:10051->10051/tcp
zabbix-docker-zabbix-snmptraps-1         "/usr/sbin/snmptrapd…"   zabbix-snmptraps         running             0.0.0.0:162->1162/udp, :::162->1162/udp
zabbix-docker-zabbix-web-nginx-mysql-1   "docker-entrypoint.sh"   zabbix-web-nginx-mysql   running (starting)   0.0.0.0:80->8080/tcp, 0.0.0.0:443->8443/tcp
```

一つ停止しているコンテナ「zabbix-docker-db_data_mysql-1」はMySQLのデータ格納コンテナを作成するプロセスです。このままで問題ありません。

初回起動時はデータベースが空なので順次基本データを取得して作成されます。
その為ログイン画面が正常に表示されるまではしばらく時間がかかります。
お茶でも飲みながらしばらく休憩して待ちましょう。

# グラフの日本語の文字化け

Web設定でユーザー言語を「日本語(ja_JP)」を選択しても、グラフ表示のキャプションが豆腐文字で文字化けするので修正します。
以下のページで紹介しているので参考にしてください。

- [DockerでAlpine LinuxのZabbix 5.0グラフが豆腐になる日本語表示を修正するメモ - Qiita ](https://qiita.com/ohhara_shiojiri/items/acf995bb70f64ec757f9)

# 通知メールの日本語の文字化け

アラート通知設定のメディアタイプにメールを使用している場合、ホスト表示名などの日本語が文字化けする事があります。
これはデータベースのMySQLに対しての文字セットの扱いに起因します。
詳しくは以下の「MySQL 8.0 リファレンスマニュアル」を参考にしてください。

・ [MySQL 8.0 にアップグレードしました。 文字セットに関して、MySQL 4.0 の動作に戻すにはどうすればよいですか。](https://dev.mysql.com/doc/refman/8.0/ja/faqs-cjk.html#faq-cjk-how-use-4-0-charset)

この場合MySQLがサーバー側でクライアント側がZabbixになるのでMySQLサーバーのDockerコンテナ設定にオプション「--skip-character-set-client-handshake」を設定してMySQLコンテナを再起動させます。

```:compose.yaml
 mysql-server:
  image: mysql:8.0
  command:
   - mysqld
   - --character-set-server=utf8
   - --collation-server=utf8_bin
   - --skip-character-set-client-handshake # 設定追加
```

# Zabbix Server「sda: Disk read/write request responses are too high (read > 20 ms for 15m or write > 20 ms for 15m)」

監視ホストとアイテムが増えてくるとZabbix Serverで「sda: Disk read/write request responses are too high (read > 20 ms for 15m or write > 20 ms for 15m)」のアラートが継続するようになります。
この状態ではCPUやストレージへ負荷が掛かりパフォーマンスに影響します。
MySQLのデータベースを適切に最適化する必要があります。
ホストの性能やリソース状況とZabbix監視内容によってMySQLの設定値は変わってきますので「MYSQL Tuner」等で実際に調査して最適値を探る方法もあります。

Zabbixの場合に主に影響する値は「innodb_buffer_pool_size」と「innodb_log_file_size」です。以下が規定値です。
- innodb_buffer_pool_size = 128M
- innodb_log_file_size = 48M

「innodb_log_file_size」は「innodb_buffer_pool_size」の25%程度が目安とされます。またファイル数は規定値で2なので設定はその半分になります。

値を変更する場合は「compose.yaml」ファイルに記述します。

```:compose.yaml
 mysql-server:
  image: mysql:8.0
  command:
   - mysqld
   - --character-set-server=utf8
   - --collation-server=utf8_bin
   - --default-authentication-plugin=mysql_native_password
   - --join_buffer_size=128M
   - --key_buffer_size=0
   - --innodb_buffer_pool_size=1G
   - --innodb_log_file_size=128M
   - --innodb_buffer_pool_instances=1
```

各設定値は少なくても大きくても駄目で状況にもよりますがとりあえず1G辺りまで徐々に各設定値を増やして調整してみます。
無闇やたらと各設定値を大きくしても逆にパフォーマンスが低下して悪化しますので注意です。

# You do not have the SUPER privilege and binary logging is enabled

Zabbix Serverを6.0.11にバージョンアップしたら起動しなくなったので対応方法
ログを確認すると「[Z3005] query failed: [1419] You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) [create trigger hosts_name_upper_insert」と記録されていました。
これはMySQLのバイナリログ機能がデフォルトで有効になっている為でオプションで無効化します。

```:compose.yaml
 mysql-server:
  image: mysql:8.0
  command:
   - mysqld
   - --skip-log-bin
```

MySQLとZabbix Severのコンテナを再構成すれば起動出来ました。

```
$ docker compose up -d mysql-server
$ docker compose up -d zabbix-server
```

# バージョンアップ方法

## マイナーバージョンアップ

- 「5.0.XX」→「5.0.XX」
- 「5.4.XX」→「5.4.XX」
- 「6.0.XX」→「6.0.XX」

Zabbixのマイナーバージョンアップする方法は、オリジナルのDocker Imageを更新する必要があります。
Dockerコンテナ内のパッケージを更新してもZabbix自体は更新されません。
必要とするDocker ImageだけpullしてDocker Composeで再起動させます。

```
$ docker pull zabbix/zabbix-web-nginx-mysql:alpine-6.0-latest
$ docker pull zabbix/zabbix-server-mysql:alpine-6.0-latest
$ docker pull zabbix/zabbix-agent:alpine-6.0-latest
$ docker compose up -d
```

## データベースのバージョンアップ

データベースにMySQLを使用している場合にバージョンアップする方法も同様にオリジナルのDocker Imageを更新する必要があります。

```
$ docker pull mysql:8.0
```

基本的にはZabbixコンテナ群を停止させてからバージョンアップ作業を行います。

```
$ docker compose stop
```

docker composeコマンで一括停止した際にMySQLコンテナも停止するのですが場合によっては正常終了(0)していない時があります。そのままではバージョンアップ出来ないのでdockerコマンドで再度停止処理します。

```
$ docker start zabbix-docker-mysql-server-1
$ docker stop zabbix-docker-mysql-server-1
```


## メジャーバージョンアップ

- 「5.0.XX」→「6.0.XX」

Zabbixのメジャーバージョンアップの場合はgitのリポジトリブランチを変更する必要があります。
以下は「5.0.26」から「6.0.7」にメジャーバージョンアップした例です。

### 既存のDockerコンテナを停止して削除します。

この段階では設定ファイルやMySQLのデータベースのデータは残ります。

```
$ docker compose stop
$ docker compose rm
```

### gitブランチの確認

```
$ git branch
* 5.0
```

### gitステータスの確認

```
$ git status
On branch 5.0
Your branch is up to date with 'origin/5.0'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   compose.yaml

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
        added by us:     env_vars/.env_srv
        added by us:     env_vars/.env_web

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   compose.yaml
        modified:   env_vars/.env_agent

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        env_vars/.env_srv~Updated upstream
        env_vars/.env_web~Updated upstream
```

### 追加修正ファイルの保存と待避

```
$ git add .
$ git status
On branch 5.0
Your branch is up to date with 'origin/5.0'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   compose.yaml
        modified:   env_vars/.env_agent
        modified:   env_vars/.env_srv
        new file:   env_vars/.env_srv~Updated upstream
        modified:   env_vars/.env_web
        new file:   env_vars/.env_web~Updated upstream
$ git stash
```

### 最新のgitリポジトリブランチに更新

```
$ git pull
```

### gitブランチの変更

```
$ git checkout 6.0
Switched to branch '6.0'
Your branch is up to date with 'origin/6.0'.
$ git branch
  5.0
* 6.0
```

### 待避した追加修正ファイルを復元

```
$ git stash apply
Auto-merging env_vars/.env_web
Auto-merging env_vars/.env_srv
On branch 6.0
Your branch is up to date with 'origin/6.0'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   compose.yaml
        new file:   env_vars/.env_srv~Updated upstream
        new file:   env_vars/.env_web~Updated upstream

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   env_vars/.env_agent
        modified:   env_vars/.env_srv
        modified:   env_vars/.env_web
```

復元した「compose.yaml」ファイルは5.0ベースで作成されたものなので、サンプルの6.0ベースに変更して修正する必要があります。
「env_vars」以下の各設定ファイルは流用可能です。

# Zabbix Proxy構築の方針

Zabbix Proxyにはデータベースに応じてサービスがあります。
今回はSqlite3版を使用し以下の必要なサービスを選択します。

- Zabbix Proxy Sqlite3
- Zabbix Java Gateway
- Zabbix SNMPtraps

## Docker Compose 設定

基本的な設定方法はZabbix Serverと同様に行いますが、Zabbix Proxyに対応したDocker Compose 設定ファイルの修正を行います。

### Zabbix Server

「compose.yaml」ファイル設定のprofilesでオプションに設定して無効化します。

```:compose.yaml
 zabbix-server:
  image: zabbix/zabbix-server-mysql:alpine-6.0-latest
  profiles:
   - all
```

### Zabbix Proxy Sqlite3

「compose.yaml」ファイル設定のprofilesでオプション扱いなので外して有効化します。

```:compose.yaml
 zabbix-proxy-sqlite3:
  image: zabbix/zabbix-proxy-sqlite3:alpine-6.0-latest
#  profiles:
#   - all
```

### Zabbix Web interface(Nginx)

「compose.yaml」ファイル設定のprofilesでオプションに設定して無効化します。

```:compose.yaml
 zabbix-web-nginx-mysql:
  image: zabbix/zabbix-web-nginx-mysql:alpine-6.0-latest
  profiles:
   - all
```

### Zabbix Java Gateway

「compose.yaml」ファイル設定のprofilesでオプション扱いなので外して有効化します。

```:compose.yaml
 zabbix-java-gateway:
  image: zabbix/zabbix-java-gateway:alpine-6.0-latest
#  profiles:
#   - full
#   - all
```

### Zabbix SNMPtraps

「compose.yaml」ファイル設定のprofilesでオプション扱いなので外して有効化します。

```:compose.yaml
 zabbix-snmptraps:
  image: zabbix/zabbix-snmptraps:alpine-6.0-latest
#  profiles:
#   - full
#   - all
```

### MySQL

「compose.yaml」ファイル設定のprofilesでオプションに設定して無効化します。

```:compose.yaml
 mysql-server:
  image: mysql:8.0
  profiles:
   - all
```

## パッシブのIPアドレス指定に設定

Zabbix Server側に設定するProxy設定項目では、パッシブモードでIPアドレスとポート番号を指定します。
また、Config設定同期時間が標準では3600秒なので適切に変更します。Server側も調整して合わせます。

```:env_vars/.env_prx
ZBX_PROXYMODE=1
ZBX_SERVER_HOST=[Zabbix Server側のIPアドレス番号]
ZBX_CONFIGFREQUENCY=60
```

このZabbix Proxy設定はDocker Composeコマンド実行時に更新されますので内容を変更した場合は再度Docker composeで再起動させます。

## docker composeの起動

```
$ docker compose up -d
```

問題がなければ以下のように起動しています。

```
$ docker compose ps
zabbix-docker-db_data_mysql-1          "sh"                     db_data_mysql          exited (0)          
zabbix-docker-zabbix-java-gateway-1    "docker-entrypoint.s…"   zabbix-java-gateway    running             
zabbix-docker-zabbix-proxy-sqlite3-1   "/sbin/tini -- /usr/…"   zabbix-proxy-sqlite3   running             0.0.0.0:10061->10051/tcp, :::10061->10051/tcp
zabbix-docker-zabbix-snmptraps-1       "/usr/sbin/snmptrapd…"   zabbix-snmptraps       running             0.0.0.0:162->1162/udp, :::162->1162/udp
```

Zabbix Proxyのサービスポート番号は、コンテナ内部側で「10061」から「10051」で変換されている。
ちなみにデータベースをMySQL版にした場合は「10071」になります。

Zabbix ServerのProxy設定では、パッシブモードでIPアドレスを指定してポート番号を「10061」に設定します。