Mackerel はそのままだと Zabbix より監視項目が少ないけど、プラグインを使えば、より個々の構成に固有なメトリクスを過不足なく取得できて嬉しいです。
自分はよく PHP のウェブサーバーを Ansible でプロビジョニングしているのですが、そういうお仕事でオススメな監視設定について、理解しながらチュートリアルを進める感じで紹介します。
お膳立てとして、なるべく CLI をシンプルにするために、カレントに ansible.cfg
があるものとします。
[defaults]
roles_path = ./roles
private_key_file = ./path/to/private_key
OS は Ubuntu 16.04 を想定します。そのままだと Python2 が入ってないので、ansible_python_interpreter=/usr/bin/python3
を... もし Python が 2.x の世代だった場合はいらないです。
[default]
xxx.xxx.xxx.xxx server_identity=171202-001
xxx.xxx.xxx.xxx server_identity=171202-002
[default:vars]
ansible_python_interpreter=/usr/bin/python3
server_identity=
変数をホストごとにユニークな値を持つように設定しておきます。これあとで使います。
Ansible で Mackerel をインストールしてみる
はてなの中の人が作ってくださった Ansible ロールが Gallaxy に上がっています。
$ ansible-galaxy install mackerelio.mackerel-agent
- downloading role 'mackerel-agent', owned by mackerelio
- downloading role from https://github.com/mackerelio/ansible-mackerel-agent/archive/v0.7.0.tar.gz
- extracting mackerelio.mackerel-agent to /Users/tanakahisateru/Desktop/macka/roles/mackerelio.mackerel-agent
- mackerelio.mackerel-agent (v0.7.0) was installed successfully
使い方はざっくりこんな感じです。
---
-
hosts: default
vars:
mackerel_agent_apikey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
mackerel_agent_display_name: "web-server-{{ server_identity }}"
mackerel_agent_roles: ["my_service:web_server"]
mackerel_agent_start_on_setup: no
roles:
- mackerelio.mackerel-agent
mackerel_agent_roles
を書いておけば、立ち上がった瞬間からもう、指定したサービスの指定したロールに登録されます。事前に Mackerel にサービスやロールを定義しておく必要はありません。そういう名前のが勝手に作られます。
これはぜひやってください。とくに初期導入時、いっぺんにサーバー追加したらどれがどれだか... IP アドレスから推測して GUI で役割を仕分けするの、まじ辛いです。
さらに mackerel_agent_display_name
では、インベントリに付け足しで書いた server_identity
変数を使って表示名を工夫しています。IPアドレスかインスタンスIDかをもとに勝手に付けられた名前そのままではなく、ホストごとに名前を見たら意味がわかるようにしておくと、ちょっと便利です。(まあこれはオートスケールしない場合に限りますが)
リハーサルで正しくインストールできるか試すだけのうちは mackerel_agent_start_on_setup
を no
にして、いきなり起動しないようにしておくのがオススメです。課金対象のサーバーがいつの間にか増えてたら、いくら安いからって言っても、やっぱ上の人に怒られますよね。
ここで紹介しているのはいずれもオプションです。最低、mackerel_agent_apikey
さえ正しく設定されていれば何とかなります。(逆に、これ設定されていないとエージェントが動きません)
実行はこうですね。
$ ansible-playbook -i hosts -u ubuntu -b playbook.yml
PLAY [default] ************************************************
TASK [Gathering Facts] ****************************************
ok: [xxx.xxx.xxx.xxx]
:
:
SSH で対象サーバーに接続して、/usr/bin/mackerel-agent
がインストールされており、/etc/mackerel-agent/mackerel-agent.conf
という設定ファイルが思ったように生成できているかを確認します。
apikey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
display_name = "web-server-171202-001"
roles = [
"my_service:web_server",
]
Mackerel の Ansible インストールって話なら、このまま本番用に mackerel_agent_start_on_setup
の行を消しておしまいです。簡単ですね。これだけでも、ロードアベレージやメモリなどは監視できます。
ここからは PHPer のためのコーナーです。Nginx ベースの PHP 環境を監視するには、ちょっとひと工夫必要です。
Nginx と PHP-FPM 自体の監視機能を有効にする
Ansible Gallaxy にある geerlingguy さんのロールを使う仮定でいきます。
---
- geerlingguy.nginx
- geerlingguy.php
- mackerelio.mackerel-agent
$ ansible-gallaxy install -r requirements.yml
Nginx と PHP-FPM はともに、監視用の特殊な URL を提供する機能があり、そこに HTTP アクセスすることで、ステータスを調べるようになっています。
playbook.yml
の vars
の頭で、それを表す変数を導入します。(最初の php_enable_php_fpm
は geerlingguy の php の設定変数です)
vars:
php_enable_php_fpm: yes
nginx_status_port: 8089
nginx_status_path: "/nginx_status"
php_fpm_status_path: "/php_fpm_status"
先に PHP のほう。FPM の設定ファイル /etc/php/*/fpm/pool.d/www.conf
にあるコメントアウトされた ;pm.status_path=
を pm.status_path = /php_fpm_status
のように書き換えれば OK。この書き換えは lineinfile
でやるのが最短です。
tasks:
- name: Configure php-fpm pool status path.
lineinfile:
dest: "{{ php_fpm_pool_conf_path }}"
regexp: '^;?pm\.status_path.?=.+$'
line: "pm.status_path = {{ php_fpm_status_path }}"
state: present
notify: restart php-fpm
もしうまく変更できてれば FPM をリスタートするように notify
しています。
つぎ、Nginx で FPM の監視パスを公開するとともに、Nginx 自身の監視パスも設定しないといけません。Nginx は基本 stub_status
ディレクティブを書くだけです。
で、この監視用のパスが外から見えるといけないので、中からしか叩けないようにしたほうがいいでしょう。また、ポートも 80 や 8080 でないものにしておくのがベターです。
geerlingguy のロール変数でカスタマイズしてやるのは逆にややこしいので、ここは、そのものズバリなファイル内容をテンプレートから作り、/etc/nginx/conf.d
に放り込むことにします。
server {
listen {{ nginx_status_port }};
server_name _;
location = {{ nginx_status_path }} {
access_log off;
stub_status;
allow 127.0.0.1;
deny all;
}
location = {{ php_fpm_status_path }} {
access_log off;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass {{ php_fpm_listen }};
allow 127.0.0.1;
deny all;
}
}
playbook.yml
の tasks
に追加で...
tasks:
# - name: Configure php-fpm pool status path.
- name: Configure Nginx status listener.
template: src=nginx_stat.conf.j2 dest=/etc/nginx/conf.d/stat.conf
notify: restart nginx
ここまで、まとめて書くとこうなります。Mackerel 関連はいったん外してます。
---
-
hosts: default
vars:
php_webserver_daemon: nginx
php_enable_php_fpm: true
nginx_status_port: 8089
nginx_status_path: "/nginx_status"
php_fpm_status_path: "/php_fpm_status"
roles:
- geerlingguy.nginx
- geerlingguy.php
tasks:
- name: Configure php-fpm pool status path.
lineinfile:
dest: "{{ php_fpm_pool_conf_path }}"
regexp: '^;?pm\.status_path.?=.+$'
line: "pm.status_path = {{ php_fpm_status_path }}"
state: present
notify: restart php-fpm
- name: Configure Nginx status listener.
template: src=nginx_stat.conf.j2 dest=/etc/nginx/conf.d/stat.conf
notify: restart nginx
なるべくロール固有な事情に依存しないように買いてみました。ここで紹介したものとは違うロールを使っている場合でも、適宜そのルールに合わせて書き換えれば多分大丈夫です。
うまくできたのかどうか確認します。HTTP アクセスだけど外からは見えないので SSH でサーバーの中に入って...
$ curl http://127.0.0.1:8089/nginx_status
Active connections: 1
server accepts handled requests
21 21 21
Reading: 0 Writing: 1 Waiting: 0
$ curl http://127.0.0.1:8089/php_fpm_status
pool: www
process manager: dynamic
start time: 02/Dec/2017:00:00:00 +0000
start since: 6497
accepted conn: 5
listen queue: 0
max listen queue: 0
listen queue len: 128
idle processes: 4
active processes: 1
total processes: 5
max active processes: 1
max children reached: 0
slow requests: 0
Nginx と FPM を監視できるようになりました。これができればもう勝ちは見えています。
Mackerel プラグインで監視項目を拡張
Mackerel には、ハードウェアの基本監視以外のメトリクスを取るために、多くのプラグインがあります。まあ、プラグインと言ってもその実体は、標準出力に文字列を吐くコマンドでしかありません。とても扱いやすいし、なんなら自分でも簡単に作れます。
公式プラグインのソースはここに:
https://github.com/mackerelio/mackerel-agent-plugins
https://github.com/mackerelio/go-check-plugins
エージェントプラグインというのは、ホストにいろいろなメトリックを追加するもの、チェックプラグインは特定の名前を持つプロセスがあるかみたいなyes/noのやつ(? まだよくわかっていません)、という感じみたいです。
公式プラグインを使って Nginx と FPM を監視できるようにしましょう。
mackerel_agent_apikey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
mackerel_agent_display_name: "web-server-{{ server_identity }}"
mackerel_agent_roles: ["my_service:web_server"]
mackerel_use_plugins: yes
mackerel_agent_plugins:
nginx: "/usr/bin/mackerel-plugin-nginx -port=8089 -path=/nginx_status"
php-fpm: "/usr/bin/mackerel-plugin-php-fpm -url=http://127.0.0.1:8089/php_fpm_status?json"
mackerel_check_plugins:
nginx_proc: "/usr/bin/check-procs -p nginx"
php-fpm_proc: "/usr/bin/check-procs -p php-fpm"
mackerel_agent_start_on_setup: no
mackerel_use_plugins
が yes
だと、/usr/bin/mackerel-plugin-*
といったコマンドがわんさか入るようになります。 (/usr/local/bin
に同じようなセットが入りますが、そっちはレガシーの残骸だそうで、より新しいものは /usr/bin
にしかありませんでした)
あとは、mackerel_agent_plugins
に、個々のエージェントプラグインのコマンドライン引数を調べて追加、mackerel_check_plugins
は簡単に名前だけ...
こうすると、プロビジョニング後 /etc/mackerel-agent/mackerel-agent.conf
はこうなります。
apikey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
display_name = "web-server-171202-001"
roles = [
"my_service:web_server",
]
[plugin.metrics.nginx]
command = "/usr/bin/mackerel-plugin-nginx -port=8089 -path=/nginx_status"
[plugin.metrics.php-fpm]
command = "/usr/bin/mackerel-plugin-php-fpm -url=http://127.0.0.1:8089/php_fpm_status?json"
[plugin.checks.php-fpm_proc]
command = "/usr/bin/check-procs -p php-fpm"
[plugin.checks.nginx_proc]
command = "/usr/bin/check-procs -p nginx"
ほんと、ただコマンドラインに流す文字列が書かれてるだけですね。こんなので監視エージェント起動したらほんとに動くのか、って心配なので、試しに実行してみましょう。各コマンドはただの標準出力なので、実際に送信することなく、あらかじめ単独で動作を確認しておけます。
$ /usr/bin/mackerel-plugin-nginx -port=8089 -path=/nginx_status
nginx.connections.connections 1.000000 1511986657
nginx.requests.accepts 30.000000 1511986657
nginx.requests.handled 30.000000 1511986657
nginx.requests.requests 30.000000 1511986657
nginx.queue.reading 0.000000 1511986657
nginx.queue.writing 1.000000 1511986657
nginx.queue.waiting 0.000000 1511986657
$ /usr/bin/mackerel-plugin-php-fpm -url=http://127.0.0.1:8089/php_fpm_status?json
php-fpm.max_active_processes.max_active_processes 1 1511986670
php-fpm.max_children_reached.max_children_reached 0 1511986670
php-fpm.queue.listen_queue 0 1511986670
php-fpm.queue.listen_queue_len 128 1511986670
php-fpm.max_listen_queue.max_listen_queue 0 1511986670
php-fpm.slow_requests.slow_requests 0 1511986670
php-fpm.processes.total_processes 5 1511986670
php-fpm.processes.active_processes 1 1511986670
php-fpm.processes.idle_processes 4 1511986670
$ /usr/bin/check-procs -p php-fpm
Procs OK: Found 6 matching processes; cmd /php-fpm/
$ /usr/bin/check-procs -p nginx
Procs OK: Found 3 matching processes; cmd /nginx/
バッチリですね。あと mackerel_agent_start_on_setup: no
を消しておけば、本番用 playbook の出来上がりです。
---
-
hosts: default
vars:
php_webserver_daemon: nginx
php_enable_php_fpm: true
nginx_status_port: 8089
nginx_status_path: "/nginx_status"
php_fpm_status_path: "/php_fpm_status"
mackerel_agent_apikey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
mackerel_agent_display_name: "web-server-{{ server_identity }}"
mackerel_agent_roles: ["my_service:web_server"]
mackerel_use_plugins: yes
mackerel_agent_plugins:
nginx: "/usr/bin/mackerel-plugin-nginx -port=8089 -path=/nginx_status"
php-fpm: "/usr/bin/mackerel-plugin-php-fpm -url=http://127.0.0.1:8089/php_fpm_status?json"
mackerel_check_plugins:
nginx_proc: "/usr/bin/check-procs -p nginx"
php-fpm_proc: "/usr/bin/check-procs -p php-fpm"
# mackerel_agent_start_on_setup: no
roles:
- geerlingguy.nginx
- geerlingguy.php
- mackerelio.mackerel-agent
tasks:
- name: Configure php-fpm pool status path.
lineinfile:
dest: "{{ php_fpm_pool_conf_path }}"
regexp: '^;?pm\.status_path.?=.+$'
line: "pm.status_path = {{ php_fpm_status_path }}"
state: present
notify: restart php-fpm
- name: Configure Nginx status listener.
template: src=nginx_stat.conf.j2 dest=/etc/nginx/conf.d/stat.conf
notify: restart nginx
あ、肝心のアプリケーション用のドキュメントルート設定とかは省いてあるし、いいかげん大きいので別ファイルにするとかは、みなさん各自工夫してくださいね。
ハードウェアの負荷だけ見ているとわからないことも、実際にアクティブなFPMプロセス数なんかを監視すれば、すぐわかるかもしれません。
PHP は小さな公開サイトによく使われるので、予想外のスパークが起きたときすぐわかるよう監視しておきたいところです。が、なんせプロジェクト規模も小さいのでなかなかエンジニアリソースが... なんてとき、導入が簡単で技術的なことは任せきりにできる Mackerel は、ちょうどいい選択かもしれませんね。