Mackerelでは、RDBのMySQLやPostgreSQLのメトリック監視のプラグインは公式提供(PostgreSQLを含むプラグイン集およびmackerel-plugin-mysql)しているのですが、Oracle DBについては(意外なことに?)公式では提供がありません。
Oracle DBのメトリックを取得するサードパーティープラグインとしては、mattnさんが作られたmackerel-plugin-oracleというものがあります。最近にこの利用実験をしてちまちまと落とし穴にハマったので、後世のためにまとめておきます。
ビルドと設定の結論
グダグダ書いていると「ビジネスのスピードじゃない」と言われそうなので、プラグインのビルドと設定を最初に書いておきます。
Oracle Linux 8 + Oracle 19cの組み合わせで動作するプラグインを、Docker環境で構築します。元のコードからforkしてビルド支援をいくつか追加しています。
$ git clone https://github.com/kmuto/mackerel-plugin-oracle.git $ cd mackerel-plugin-oracle $ git checkout oracle19.20 $ (https://www.oracle.com/jp/database/technologies/instant-client/linux-x86-64-downloads から19.20用のBasicとSDKのzipファイルをダウンロードし、ここに展開) $ docker compose run --rm builder
これで、mporacle
というプラグインバイナリができます。これをOracle DBホストにMackerelエージェントとともに配置し、/etc/mackerel-agent/mackerel-agent.conf
を設定します。
[plugin.metrics.oracle] command = ["/home/oracle/mporacle", "-dsn=sys/パスワード@?as=SYSDBA"] env = { LD_LIBRARY_PATH="/u01/app/oracle/product/19.0.0.0/dbhome_1/lib", ORACLE_HOME="/u01/app/oracle/product/19.0.0.0/dbhome_1", ORACLE_SID="データベース名" }
- プラグインは
/home/oracle
フォルダ内に置いた想定です。 - dsnで接続用DSNを指定します。ユーザー名sysとしていますが実際の環境に合わせてください。パスワードも実際のDB設定に基いて指定してください。@の後ろは本当はDB名が入ったりするのかもしれないですが、
ORACLE_SID
環境変数を指定しているせいか、ローカルDBにはこれで問題ないようです。asで権限を指定していますが、SYSOPERでは権限不足エラーが出てしまったので、おそらくSYSDBAである必要があるのでしょう。 - envで環境変数を指定しています。oracleユーザーであればこのあたりは自動で設定されているのですが、mackerel-agentはroot権限で動くので、oracleユーザーに設定されている設定内容をコピーしました。
エージェントをsystemctl restart mackerel-agent
で再起動すると、メトリックが取得されます!
ここでは少なめなメトリックですが、リポジトリのREADME.mdにあるとおり、イベント名を-event
オプションで指定して、ほしい情報を取捨選択できるようです。限られた時間内での実験だったので、この辺りは深入りしませんでした。
らくがき
以降は試行錯誤のらくがきです。
もともとOCIのBaseDBに接続してみるお試しをしていました。BaseDBはコントロールするOracle LinuxとOracle DBの構成になっており、公式サポートはちょっと難しそうな形ではあるのですが、理論上はエージェントを入れてOracleの監視はできそうな雰囲気でした。
プラグインビルドについてはシュッと作れたように見えるかもしれませんが、実際にはだいぶ苦戦しています。マニュアル見ないでまずやってしまうのがいけないとも言いますね!
$ git clone https://github.com/mattn/mackerel-plugin-oracle.git $ cd mackerel-plugin-oracle $ go build go: cannot find main module, but found .git/config in /home/kmuto/work/mackerel-plugin-oracle to create a module there, run: go mod init
はい。mackerel-plugin-oracleが作られたのは6年前。メッセージを読みながらgo mod init mporacle
、go mod tidy
だけで済みますが。
$ go mod init mporacle go: creating new go.mod: module mporacle go: to add module requirements and sums: go mod tidy $ go mod tidy go: finding module for package github.com/mattn/go-oci8 go: finding module for package github.com/mackerelio/go-mackerel-plugin-helper go: finding module for package github.com/mattn/mackerel-plugin-oracle/lib go: finding module for package github.com/mackerelio/golib/logging go: found github.com/mattn/mackerel-plugin-oracle/lib in github.com/mattn/mackerel-plugin-oracle v0.0.0-20171214002109-de30cde9cd26 go: found github.com/mackerelio/go-mackerel-plugin-helper in github.com/mackerelio/go-mackerel-plugin-helper v0.1.2 go: found github.com/mackerelio/golib/logging in github.com/mackerelio/golib v1.2.1 go: found github.com/mattn/go-oci8 in github.com/mattn/go-oci8 v0.1.1 $ go build go build github.com/mattn/go-oci8: # pkg-config --cflags -- oci8 Package oci8 was not found in the pkg-config search path. Perhaps you should add the directory containing `oci8.pc' to the PKG_CONFIG_PATH environment variable Package 'oci8', required by 'virtual:world', not found pkg-config: exit status 1
はいはい。mackerel-plugin-oracle自体はシンプルに見えていたのですが、実際のOracleとの接続を担うのはやはりmattnさんのライブラリであるgo-oci8でした。
oci8.pcをREADMEの記載を参考にして用意します。
Oracle Full clientやSDKのダウンロードも必要とのことですね。Linux x86-64のVersion 19.20.0.0.0を使うことにします(英語サイトだと19.21.0.0.0になっているんですが違いはなんなんでしょうね?)。おそらくこの辺りの事情があってビルド済みのものも出せていなかったのかな〜という推測をしました。
Basic Package(ZIP)、SDK Package(ZIP)をmackerel-plugin-oracleの作業フォルダ内に展開すると、instantclient_19_20
ができます。
oci8.pc
もmackerel-plugin-oracleフォルダ内に用意します。
prefix=/home/kmuto/work/mackerel-plugin-oracle/instantclient_19_20 includedir=${prefix}/sdk/include libdir=${prefix} Name: oci8 Description: Oracle Instant Client Version: 19.20 Cflags: -I${includedir} Libs: -L${libdir} -lclntsh
このファイルを探すようPKG_CONFIG_PATH
をセットします。
$ export PKG_CONFIG_PATH=`pwd` $ go build # mporacle /home/kmuto/sdk/go1.21.0/pkg/tool/linux_amd64/link: running gcc failed: exit status 1 /usr/bin/ld: warning: libnnz19.so, needed by /tmp/mackerel-plugin-oracle/instantclient_19_20/libclntsh.so, not found (try using -rpath or -rpath-link) ...
なるほど、それはそうですね。
$ export LD_LIBRARY_PATH=`pwd`/instantclient_19_20 $ go build
成功しました! go-oci8については2021年にv0.0.1がリリースされて以来更新がないのが不安だったのですが、ビルドはこれでできました。
$ ./mporacle 2023/12/XX 10:52:41 ERROR <metrics.plugin.oracle> Failed to select resource. ORA-12162: TNS:net service name is incorrectly specified 2023/12/XX 10:52:41 OutputValues: ORA-12162: TNS:net service name is incorrectly specified
エラーはパラメータの話なので、バイナリとしては機能していそうです。
では、OracleをコントロールしているOracle Linux上で実行してみましょう。Oracle Linuxホストにコピーしてテスト。
$ ./mporacle ./mporacle: error while loading shared libraries: libclntsh.so.19.1: cannot open shared object file: No such file or directory
あーはいはい。
$ export LD_LIBRARY_PATH=/u01/app/oracle/product/19.0.0.0/dbhome_1/lib ./mporacle ./mporacle: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by ./mporacle) ./mporacle: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by ./mporacle)
Oh…。まぁDebian bookwormのlibc(2.36)で作ったので、Oracle Linux 8のlibc 2.28とABI非互換な可能性は十分ありますよね……。
Oracle Linux 8のネイティブバイナリを作るために、Dockerでビルド環境を構築することにしました。
- ベースイメージは「oralelinux:8」
- gcc(ライブラリの関係上cgoを使う必要)、pkg-configをインストール
- Go環境もインストールしておく
# cd /work # export PATH=/usr/local/go/bin:$PATH # export PKG_CONFIG_PATH=`pwd` # export LD_LIBRARY_PATH=`pwd` # go build
無事にビルドできました。Docker内で実行してみます。
# ./mporacle ./mporacle: error while loading shared libraries: libnsl.so.1: cannot open shared object file: No such file or directory
libnsl…2023年も暮れようとしているのにNISの名前を聞くことになるとは……!(もう若い人はNISもYPも知らんのじゃよ……) ビルド環境にlibnslパッケージをインストールしておきます(Dockerfileにも入れておく)。
# yum install libnsl # ./mporacle 2023/12/XX 02:14:09 ERROR <metrics.plugin.oracle> Failed to select resource. ORA-12162: TNS:net service name is incorrectly specified 2023/12/XX 02:14:09 OutputValues: ORA-12162: TNS:net service name is incorrectly specified
よさそうです。ビルドにlibnsl.aが必要なのかとしばらく困っていたのですが、mporacleのビルドには別段関係ありませんでした(それはともかくOracleさんにはlibnsl.so.1にリンクするのは勘弁してほしい気持ちでいっぱいです)。
再度DB環境で試します。
$ export LD_LIBRARY_PATH=/u01/app/oracle/product/19.0.0.0/dbhome_1/lib $ ./mporacle 2023/12/XX 06:14:09 ERROR <metrics.plugin.oracle> Failed to select resource. ORA-12162: TNS:net service name is incorrectly specified 2023/12/XX 06:14:09 OutputValues: ORA-12162: TNS:net service name is incorrectly specified
いけそうです。
さて、ここまでいけばあとはDBに接続です。mackerel-plugin-oracleのREADMEを見たところ、dsnオプションを使うらしく、scott/tiger@XE
というのがあります。Oracle人ならscottと言えばtigerとわかるらしいです。私はOracle人ではないので、長時間わからなくて困りました。
要はscott
をユーザー名、tiger
をパスワードと見たてて、/
で区切る。@
の後にDB名が入るという形式のようでした。
BaseDBで試していたところでは、oracleユーザー環境ではDB名は省略できるようです(ORACLE_SID
環境変数が効いているのかも)。冒頭で書いたように、asパラメータで権限を設定しないと怒られ、かつSYSOPERではダメだったのでSYSDBAを指定します。
$ ./mporacle -dsn sys/パスワード@?as=SYSDBA oracle.resource.processes 73.000000 1703637718 oracle.resource.sessions 97.000000 1703637718 oracle.waitclass.administrative 0.000000 1703637718 oracle.waitclass.cpu 0.004000 1703637718 oracle.waitclass.cpu_os 0.132000 1703637718 oracle.waitclass.concurrency 0.000000 1703637718 oracle.waitclass.configuration 0.000000 1703637718 oracle.waitclass.network 0.000000 1703637718 oracle.waitclass.other 0.001000 1703637718
ヤッター。
あとはmackerel-agent.conf
の設定です。mackerel-agentはroot権限で動いており、プラグインだけ特定のユーザー権限で動かすのはできなくもないけれども、変に悩むことが増えそうなので、普通にrootで動くようにしておきます。
root権限で直接mporacle -dsn
を実行してみると動かないことがいろいろあったので、環境変数設定済みのoracleユーザーと比較しながらそれっぽい環境変数を設定してはmporacle -dsn
を実行していきました。
最終的にこれで動いたな、という環境変数をmackerel-agent.conf
のプラグインのenv
エントリに含めていきます。Oracle 19cのBaseDB環境では以下のようになりました。
env = { LD_LIBRARY_PATH="/u01/app/oracle/product/19.0.0.0/dbhome_1/lib", ORACLE_HOME="/u01/app/oracle/product/19.0.0.0/dbhome_1", ORACLE_SID="データベース名" }
ということで、自ら穴にはまったところもありますが、ひとまず一応動くものができました(最終的にビルド用に作成したDockerfile、docker-compose.yml、build.sh)。
今もしOracleプラグインを改めて実装するとしたら、Pure Goなgo-oraを使うか、あるいはシンプルにsqlplus
コマンドを叩いてその結果を解析するほうがよいのかもしれませんね。
では良い御年を、Happy Hacking!
#Instagram連携が現在停止しているので毎日の料理を貼れない……kmuto Instagramには上げ続けています。