Zabbix 5.0 (MariaDB + Apache) → 7.0 (PostgreSQL + nginx) 移行メモ

Raspberry Pi 4BにUbuntu 20.04 LTSをインストールして、Zabbix 5.0 (Apache + MySQL (MariaDB))を動かしていましたが、Ubuntu 20.04 LTSがEOLを迎えたこともあり、環境を再構築したくなったのでその移行メモとなります。
なお、移行先も別のRaspberry Pi 4Bです。

大まかな手順は以下の通りです。

1. 移行先の環境でZabbix 7.0のインストール
2. 移行元からDBのお引越し
    1. 移行元の環境にPostgreSQLを入れる(user&db作成)
    2. `pgloader`でPostgreSQLにデータを移行
    3. `pg_dump`で生SQLダンプを生成
    4. ダンプを移行先に持っていってDBに突っ込む
3. 移行先で設定ファイルを編集
4. ZabbixサーバーのDB migrationエラーを解消
5. ブラウザでGUIにアクセス(&初期設定)

# 環境

|     | 移行前 | 移行後 |
| :-- | :---- | :---- |
| OS  | Ubuntu 20.04 LTS<br>(20.04.6 LTS) | Ubuntu 24.04 LTS<br>(24.04.2 LTS) |
| Zabbix | 5.0.47 | 7.0.13 |
| Webサーバー | Apache2<br>`2.4.41-4ubuntu3.23` | nginx<br>`1.24.0-2ubuntu7.3` |
| DB | MariaDB<br>`1:10.3.39-0ubuntu0.20.04.2` | PostgreSQL<br>`17.5-1.pgdg24.04+1`<br>(移行元): `12.22-0ubuntu0.20.04.4` |

# 移行先の環境に Zabbix 7.0 (nginx + PostgreSQL) をインストール

## PostgreSQLのインストール

今回は17を使います。

```sh
sudo apt install postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
sudo apt install postgresql-17
sudo systemctl enable postgresql@17-main.service
```

## Zabbix 7.0のインストール

公式の手順に従ってインストールします。
**d. Create initial database**までやります。 

```shell
# b. Install Zabbix repository
wget https://repo.zabbix.com/zabbix/7.0/ubuntu-arm64/pool/main/z/zabbix-release/zabbix-release_latest_7.0+ubuntu24.04_all.deb
sudo dpkg -i zabbix-release_latest_7.0+ubuntu24.04_all.deb
sudo apt update
# c. Install Zabbix server, frontend, agent
sudo apt install zabbix-server-pgsql zabbix-frontend-php php8.3-pgsql zabbix-nginx-conf zabbix-sql-scripts zabbix-agent
# d. Create initial database
sudo -u postgres createuser --pwprompt zabbix
sudo -u postgres createdb -O zabbix zabbix
```

後で使うので、zabbixユーザーを作成する際に入力するパスワードはメモっておきます。

# DBのお引越し

移行元のMariaDBはリモートアクセスを制限していたので、
移行元の環境にPostgreSQLをインストールして`pgloader`で変換し、ダンプファイルを出力して移行先に持っていき、ダンプを移行先DBに突っ込むことでお引越しをすることにしました。
多分リモートアクセスできるようにしたりすれば、こんな面倒なことはしなくて良いはずです。

## (移行元) PostgreSQLのインストールとDB初期設定

後で使うので`pgloader`もインストールしておきます。

```sh
sudo apt install postgresql pgloader
# DB内にzabbixユーザーとzabbix DBを生成
sudo -u postgres createuser --pwprompt zabbix
sudo -u postgres createdb -O zabbix zabbix
```

全部の作業を終えてから気がついたのですが、この時点でPostgreSQLのバージョンを合わせておくべきでしたね…。

## `pgloader`でMariaDB → PostgreSQLにデータ移行

```sh
pgloader -v mysql://zabbix:PASSWORD@localhost/zabbix postgresql://zabbix:PASSWORD@localhost/zabbix
```

どちらのDBでもzabbixユーザーのパスワードに記号(`@`など)が入っていると上手く動かないようです。
その場合は`''`で囲ったり、URLエンコードした文字列を渡したりすると良いようです。

## ダンプ経由でデータの移動

(移行元)

```sh
sudo -u zabbix pg_dump -U zabbix > zabbix_db_dump.sql
```

(移行先)

```sh
sudo -u zabbix psql -d zabbix -f zabbix_db_dump.sql
```

# 設定ファイルの編集、zabbix-serverの再起動

公式の手順e.〜g.を実行します。

`/etc/zabbix/nginx.conf`の2〜3行目をアンコメントし、適宜編集します。

```/etc/zabbix/nginx.conf
server {
        listen          8080;
        server_name     SERVER_NAME;

        ...
}
```

`/etc/zabbix/zabbix_server.conf`を編集し、`DBPassword`(と`DBSchema`)を設定します。

```/etc/zabbix/zabbix_server.conf
...

### Option: DBSchema
#       Schema name. Used for PostgreSQL.
#
# Mandatory: no
# Default:
# DBSchema=
DBSchema=zabbix

...

### Option: DBPassword
#       Database password.
#       Comment this line if no password is used.
#
# Mandatory: no
# Default:
# DBPassword=
DBPassword=PASSWORD

...
```

サービスをリスタートさせます。

```sh
sudo systemctl restart zabbix-server zabbix-agent nginx php8.3-fpm
# (どこかのタイミングでenableもしておく)
sudo systemctl enable zabbix-server zabbix-agent nginx php8.3-fpm
```

# DBエラーの解消

`/var/log/zabbix/zabbix_server.log`を確認すると、Zabbix 5.0から7.0へアップグレードしたことで自動的にデータベースの更新が行われますが、そこでエラーが生じていたので各々解消させます。
以下はエラーのログ(抜粋)とそれを解消するために実行したコマンドです。
(このあたりはエラーメッセージをClaudeに読ませたりして作業していました)

```/var/log/zabbix/zabbix_server.log

 57081:20250603:024051.825 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  foreign key constraint "c_items_3" cannot be implemented
 DETAIL:  Key columns "valuemapid" and "valuemapid" are of incompatible types: numeric and bigint.
 [alter table items add constraint c_items_3 foreign key (valuemapid) references valuemap (valuemapid)]

 57183:20250603:024908.085 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  constraint "c_items_3" for relation "items" already exists
 [alter table items add constraint c_items_3 foreign key (valuemapid) references valuemap (valuemapid)]
 57183:20250603:024908.086 database upgrade failed on patch 05030047, exiting in 10 seconds

 57286:20250603:025410.074 starting automatic database upgrade
 57286:20250603:025410.076 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  index "users_1" does not exist
 [drop index users_1]
 57286:20250603:025410.076 database upgrade failed on patch 05030052, exiting in 10 seconds

 57344:20250603:025748.129 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  index "httptest_1" does not exist
 [drop index httptest_1]
 57344:20250603:025748.130 database upgrade failed on patch 05030134, exiting in 10 seconds

 57618:20250603:031219.878 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  index "escalations_1" does not exist
 [drop index escalations_1]
 57618:20250603:031219.879 database upgrade failed on patch 05050019, exiting in 10 seconds

 57683:20250603:031614.213 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  index "hstgrp_1" does not exist
 [drop index hstgrp_1]
 57683:20250603:031614.213 database upgrade failed on patch 06010031, exiting in 10 seconds

 57716:20250603:031915.406 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  index "scripts_3" does not exist
 [drop index scripts_3]
 57716:20250603:031915.406 database upgrade failed on patch 06030192, exiting in 10 seconds

 57745:20250603:032059.195 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  foreign key constraint "c_hosts_1" cannot be implemented
DETAIL:  Key columns "proxyid" and "proxyid" are of incompatible types: numeric and bigint.
 [alter table hosts add constraint c_hosts_1 foreign key (proxyid) references proxy (proxyid)]

 57792:20250603:032613.957 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  foreign key constraint "c_drules_1" cannot be implemented
DETAIL:  Key columns "proxyid" and "proxyid" are of incompatible types: numeric and bigint.
 [alter table drules add constraint c_drules_1 foreign key (proxyid) references proxy (proxyid)]

 57821:20250603:032801.870 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  foreign key constraint "c_autoreg_host_1" cannot be implemented
DETAIL:  Key columns "proxyid" and "proxyid" are of incompatible types: numeric and bigint.
 [alter table autoreg_host add constraint c_autoreg_host_1 foreign key (proxyid) references proxy (proxyid) on delete cascade]

 57847:20250603:032931.780 [Z3005] query failed: [0] PGRES_FATAL_ERROR:ERROR:  foreign key constraint "c_task_1" cannot be implemented
DETAIL:  Key columns "proxyid" and "proxyid" are of incompatible types: numeric and bigint.
 [alter table task add constraint c_task_1 foreign key (proxyid) references proxy (proxyid) on delete cascade]
```

```sh
sudo systemctl stop zabbix-server
sudo -u zabbix psql -U zabbix
zabbix=> ALTER TABLE items ALTER COLUMN valuemapid TYPE bigint;
zabbix=> ALTER TABLE items ADD CONSTRAINT c_items_3
FOREIGN KEY (valuemapid) REFERENCES valuemap (valuemapid);
zabbix=> quit;
sudo -u zabbix psql -U zabbix
sudo systemctl start zabbix-server

sudo systemctl stop zabbix-server
sudo -u zabbix psql -U zabbix
zabbix=> ALTER TABLE items DROP CONSTRAINT IF EXISTS c_items_3;
zabbix=> quit;
sudo systemctl start zabbix-server

sudo systemctl stop zabbix-server
sudo -u zabbix psql -U zabbix
zabbix=> SELECT * FROM pg_indexes WHERE indexname = 'users_1';
 schemaname | tablename | indexname | tablespace | indexdef
------------+-----------+-----------+------------+----------
(0 rows)
zabbix=> CREATE INDEX users_1 ON users (userid);
zabbix=> quit;
sudo systemctl start zabbix-server
# このあたりはひたすらzabbix-server起動→ログチェック→zabbix-server止める→SQL実行する の流れを繰り返しました
sudo systemctl stop zabbix-server
sudo -u zabbix psql -U zabbix
zabbix=> CREATE INDEX IF NOT EXISTS httptest_1 ON httptest (httptestid);
zabbix=> CREATE INDEX IF NOT EXISTS escalations_1 ON escalations (escalationid);
zabbix=> CREATE INDEX IF NOT EXISTS hstgrp_1 ON hstgrp (groupid);
zabbix=> CREATE INDEX IF NOT EXISTS scripts_3 ON scripts (scriptid);
zabbix=> ALTER TABLE hosts ALTER COLUMN proxyid TYPE bigint;
zabbix=> ALTER TABLE drules ALTER COLUMN proxyid TYPE bigint;
zabbix=> ALTER TABLE autoreg_host ALTER COLUMN proxyid TYPE bigint;
zabbix=> ALTER TABLE task ALTER COLUMN proxyid TYPE bigint;
# ここまでやってDB migrationのエラーが出なくなりました
zabbix=> quit;
sudo systemctl start zabbix-server
```

# ブラウザでアクセス&GUI上で設定

省略します。

初期設定が終わりDashboardに到達すると以下のようなlocale関連のエラーが出ていました。

```text
Locale for language "en_GB" is not found on the web server. Tried to set: en_GB, en_GB.utf8, en_GB.UTF-8, en_GB.iso885915, en_GB.ISO8859-1, en_GB.ISO8859-2, en_GB.ISO8859-4, en_GB.ISO8859-5, en_GB.ISO8859-15, en_GB.ISO8859-13, en_GB.CP1131, en_GB.CP1251, en_GB.CP1251, en_GB.CP949, en_GB.KOI8-U, en_GB.US-ASCII, en_GB.eucKR, en_GB.eucJP, en_GB.SJIS, en_GB.GB18030, en_GB.GB2312, en_GB.GBK, en_GB.eucCN, en_GB.Big5HKSCS, en_GB.Big5, en_GB.armscii8, en_GB.cp1251, en_GB.eucjp, en_GB.euckr, en_GB.euctw, en_GB.gb18030, en_GB.gbk, en_GB.koi8r, en_GB.tcvn. Unable to translate Zabbix interface.
```

どうやらシステムに`en_GB.UTF-8`がインストールされていないことに起因するエラーのようですので、`en_GB.UTF-8`を生成しておきます。

```sh
# locales パッケージがインストールされていなければしておく
sudo apt update
sudo apt install locales
# 生成 (TUI上で `en_GB.UTF-8 UTF-8` にチェックを入れる)
sudo dpkg-reconfigure locales
# 関連サービスを再起動
sudo systemctl restart zabbix-server zabbix-agent nginx php8.3-fpm
```

加えてGUIの設定も変えておきます。
(これをするならlocaleの生成はいらないかもしれないです)
⚙ Administration > General > GUIのDefault languageを`English (en_US)`にしてUpdateボタンを押して適用します。

あとは適宜Hostの設定などを必要であれば修正してください。
お疲れ様でした。

# 参考

- [Zabbixのダウンロードページ](https://www.zabbix.com/download?zabbix=7.0&os_distribution=ubuntu_arm64&os_version=24.04&components=server_frontend_agent&db=pgsql&ws=nginx)
- [Zabbix5.0 のDB移行（MariaDB→TimescaleDB）](https://qiita.com/xotaki/items/2bf03752bc00b84fef47)
- [postgresql - Escape password containing @ when using postgres pg_dump command - Stack Overflow](https://stackoverflow.com/questions/44561378/escape-password-containing-when-using-postgres-pg-dump-command)