Setting up Sensu-go
この記事は Sensu-go をとりあえず使えたところまでのコマンドログです。
経緯
子供たちにせがまれて家庭内マイクラサーバを立てまして、使えないと非難されるので監視してみました。笑
世の中には途方もない手間のかかったゴイスー素敵なマップを無償公開されている方々が、しかもたくさんおられて、家庭内サーバでは子供たちがJava版マインクラフトのカスタムマップをNintendo Switchから使えるようプロトコル変換して遊ばせています。
監視には sensu-go を使いました。ドキュメント通りやって、うまくいきました。良いドキュメントと思います。ただ、ググっても解説が少なかったので書き残します。お役に立てば幸いです。
@see https://docs.sensu.io/sensu-go/latest/
監視結果は Slack 通知することにしました。通知は意図でチャネルを変えて3パターン(ops/dev/そのほかと)通知できるそうです。設定は全てYAMLかJSONで記述することができ、git保存も可能です。この辺りの自在感が好ましい監視ソフトです。
導入した環境
家庭内サーバは今のところ家庭内LAN (1ギガイーサネット)のみで運用しており、インターネットに出していません。ここは、近所の子が遊び出したら考えることにします。
サーバ上のサービスはローカルホストで以下が同居しています;
- java8 のマイクラサーバ (paper-spigot + 20程度のプラグイン)
- dynmapだとかをプロキシする nginx
- ユーザデータの保存だとかLuckpermsなどが使う MySQL8
サーバは Parallels という仮想マシンソフトの上のVMで、OSは ubuntu 20.04、標準ユーザ?は mc です。ホストマシンは Core i7 の MBP(2018くらい) です。
(後ほど必要になりますが、データベースの接続情報やDB名やらは適宜置き換えてご参照くださいませ)
観測の仕組みについて
観測の仕組みは以下でシンプルに説明されていました。
@see https://docs.sensu.io/sensu-go/latest/observability-pipeline/
Sensu-go の観測の仕組みは backend <-> agent 間の Publish/Subscribe型の非同期メッセージングで、backend がトピックをブロードキャストし、agentが自分がsubscribeしているトピックについてチェックと、backendへのイベント登録をする、という流れだと読みました。イベント登録を受けて backend はイベントを選別・整形・対応するそうです。
agentの内側が Un*x らしいパイプ処理になっているらしく、値の収集元とagentとのデータ変換を柔軟に実装できる様子でした。
積み残し
なお sensu-go の魅力の一つは(sensu と違って RabbitMQ 等の)ミドルウェア不要なことでした。
また Sensu-go 自体の導入やプラグインの導入も統一されたリポジトリと操作で一気通貫なことが簡単でした(DevOpsのツールとしては意外にw)
ただし、今回監視のみなので事足りましたが(我が家、気付いたら再起動するだけですので)、 sensu-go のみですと監視データの蓄積は行わないそうで、記録を残してビジュアル化する場合には追加のセットアップが必要だそうです(fluentdみたいに観測値をDBへ転送・保存し、別途ビジュアル化のツールを使うそうです)。これは後日の課題といたしました。
#以下ログ
以下 ssh した bash でのコマンドのログです。
Installing utilities and repositories
$ sudo apt update -y
:
$ sudo apt-get install gnupg curl wget unzip -y
:
$ curl -s https://packagecloud.io/install/repositories/sensu/stable/script.deb.sh | sudo bash
:
Installing sensu-go backend
$ sudo apt install sensu-go-backend
:
$ sudo curl -L https://docs.sensu.io./sensu-go/latest/files/backend.yml -o /etc/sensu/backend.yml
:
$ sudo systemctl start sensu-backend
$ sudo systemctl enable sensu-backend
:
$ sudo systemctl status sensu-backend
# check active
:
$ sensu-backend init --interactive
? Cluster Admin Username: mc
? Cluster Admin Password: **
? Retype Cluster Admin Password: **
:
$ curl http://localhost:3000
Client sent an API request to the web application port!
Installing sensuctl
$ sudo apt install sensu-go-cli
:
$ sensuctl configure
? Authentication method: username/password
? Sensu Backend URL: http://127.0.0.1:8080
? Namespace: default
? Preferred output format: tabular
? Username: mc
? Password: **
Installing sensu-go agent
$ sudo apt install sensu-go-agent
:
$ sudo curl -L https://docs.sensu.io/sensu-go/latest/files/agent.yml -o /etc/sensu/agent.yml
:
$ sudo systemctl start sensu-agent
$ sudo systemctl enable sensu-agent
:
$ sudo systemctl status sensu-agent
# check active
:
$ sensuctl entity update mc
? Entity Class: agent
? Subscriptions: system,webserver,database
Updated
$ sensuctl entity list
ID Class OS Subscriptions Last Seen
──── ─────── ─────── ───────────────────────────────────── ───────────────────────────────
mc agent linux system,webserver,database,entity:mc 2021-03-29 18:20:39 +0900 JST
$ curl -X POST \
-H 'Content-Type: application/json' \
-d '{
"check": {
"metadata": {
"name": "example-check"
},
"status": 1,
"output": "You should receive this example event"
}
}' \
http://127.0.0.1:3031/events
# test warning
# warning can resolve by console (namespace -> events then check resolve).
Check nginx for example
$ sensuctl asset add ncr-devops-platform/nagiosfoundation -r nagiosfoundation
:
$ sensuctl check create nginx_service \
--command 'check_service --name nginx' \
--interval 15 \
--subscriptions webserver \
--runtime-assets nagiosfoundation
$ sudo systemctl stop nginx
$ sensuctl event list
Entity Check Output Status Silenced Timestamp UUID
──────── ──────────────────── ──────────────────────────────────────────────────────────────────────── ──────── ────────── ─────────────────────────────── ──────────────────────────────────────
mc keepalive Keepalive last sent from mc at 2021-03-29 18:32:39 +0900 JST 0 false 2021-03-29 18:32:39 +0900 JST 3b42374e-d856-475b-9ece-eb2bd9d38839
mc nginx_service CheckService CRITICAL - nginx not in a running state (State: inactive) 2 false 2021-03-29 18:32:34 +0900 JST 68ca677a-b8c4-4619-bac9-654a50dd6615
$ sudo systemctl start nginx
$ sensuctl event list
:
Check MySQL for example
i've installed MySQL8. if so maybe, you shall make mysql speak utf8 (not utf8mb4).
write below on ubuntu 20.04 (**be careful with changing character set. :)
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
collation-server = utf8_general_ci
character-set-server = utf8
don't forget restarting mysqld.
and i have a file, having cred, says ~/backupDB.cnf to connect mysql. this is a very private file.
$ cd ~
$ touch backupDB.cnf
$ chmod o-rw backupDB.cnf
$ vi backupDB.cnf
$ cat backupDB.cnf
[client]
user = (YOUR MYSQL USER)
password = (YOUR MYSQL PASSWD)
host = 127.0.0.1
so i did ↓.
ah, yes, it's dirty way... consider your way...
$ id
uid=1000(mc) gid=1000(mc) groups=1000(mc),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lxd)
$ ps aux|grep sensu|grep -v grep
sensu 4195 4.2 1.5 5456808 126372 ? Ssl 16:42 10:46 /usr/sbin/sensu-backend start -c /etc/sensu/backend.yml
sensu 5507 0.1 0.6 128848 53488 ? Ssl 16:50 0:22 /usr/sbin/sensu-agent start -c /etc/sensu/agent.yml
$ usermod -aG mc sensu
$ id sensu
uid=997(sensu) gid=998(sensu) groups=998(sensu),mc(1000)
$ sudo systemctl restart sensu-backend
$ sudo systemctl restart sensu-agent
installing mysql plugin will be just cute a little.
$ sensuctl asset add sensu/sensu-ruby-runtime -r ruby-plugins
:
$ sensuctl asset add sensu-plugins/sensu-plugins-mysql:3.2.0 -r mysql-plugins
:
$ sensuctl check create mysql_connections \
--command 'check-mysql-connections.rb --warnnum 50 --critnum 75 --host=127.0.0.1 --ini=/home/mc/backupDB.cnf' \
--interval 15 \
--subscriptions database \
--runtime-assets ruby-plugins,mysql-plugins
$ sensuctl event list
:
Send Slack alerts with handlers
i choose sending alert per contact. it'll be done a little bit more.
First, Create three slack channels. (for ops, for dev, and for the others), then create webhook of three.
- #minecraft-server-ops
- #minecraft-server-dev
- #minecraft-server-monitoring
and...
$ sensuctl asset add nixwiz/sensu-go-fatigue-check-filter -r fatigue-filter
:
$ vi sensu-filter-fatigue_check.yaml
$ cat sensu-filter-fatigue_check.yaml
type: EventFilter
api_version: core/v2
metadata:
name: fatigue_check
namespace: default
spec:
action: allow
expressions:
- fatigue_check(event)
runtime_assets:
- fatigue-check-filter
$ sensuctl create -f sensu-filter-fatigue_check.yaml
:
$ sensuctl asset add sensu/sensu-go-has-contact-filter -r contact-filter
:
$ vi sensu-filter-contact.yaml
$ cat sensu-filter-contact.yaml
---
type: EventFilter
api_version: core/v2
metadata:
name: contact_fallback
spec:
action: allow
runtime_assets:
- contact-filter
expressions:
- no_contacts(event)
---
type: EventFilter
api_version: core/v2
metadata:
name: contact_ops
spec:
action: allow
runtime_assets:
- contact-filter
expressions:
- has_contact(event, "ops")
---
type: EventFilter
api_version: core/v2
metadata:
name: contact_dev
spec:
action: allow
runtime_assets:
- contact-filter
expressions:
- has_contact(event, "dev")
$ sensuctl create -f sensu-filter-has_contact.yaml
:
$ sensuctl asset add sensu/sensu-slack-handler -r sensu-slack-handler
:
$ vi sensu-handler-slack.yaml
# be care of slack channels and webhooks.
$ cat sensu-handler-slack.yaml
---
type: Handler
api_version: core/v2
metadata:
name: slack_fallback
spec:
command: sensu-slack-handler --channel "#minecraft-server-monitoring"
env_vars:
- SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T0000/B000/XXXXXXXX
filters:
- is_incident
- not_silenced
- fatigue_check
- contact_fallback
runtime_assets:
- sensu-slack-handler
type: pipe
---
type: Handler
api_version: core/v2
metadata:
name: slack_ops
spec:
command: sensu-slack-handler --channel "#minecraft-server-ops"
env_vars:
- SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T0000/B000/XXXXXXXX
filters:
- is_incident
- not_silenced
- fatigue_check
- contact_ops
runtime_assets:
- sensu-slack-handler
type: pipe
---
type: Handler
api_version: core/v2
metadata:
name: slack_dev
spec:
command: sensu-slack-handler --channel "#minecraft-server-dev"
env_vars:
- SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T0000/B000/XXXXXXXX
filters:
- is_incident
- not_silenced
- fatigue_check
- contact_dev
runtime_assets:
- sensu-slack-handler
type: pipe
---
type: Handler
api_version: core/v2
metadata:
name: slack
namespace: default
spec:
handlers:
- slack_ops
- slack_dev
- slack_fallback
type: set
$ sensuctl create -f sensu-handler-slack.yaml
:
Let's say test.
$ curl -X POST \
-H 'Content-Type: application/json' \
-d '{
"check": {
"metadata": {
"name": "example-check"
},
"status": 1,
"output": "You should receive this example event in the Slack channel specified by your slack_fallback handler.",
"handlers": ["slack"]
}
}' \
http://127.0.0.1:3031/events
$ curl -X POST \
-H 'Content-Type: application/json' \
-d '{
"check": {
"metadata": {
"name": "example-check",
"labels": {
"contacts": "dev"
}
},
"status": 1,
"output": "You should receive this example event in the Slack channel specified by your slack_dev handler.",
"handlers": ["slack"]
}
}' \
http://127.0.0.1:3031/events
$ curl -X POST \
-H 'Content-Type: application/json' \
-d '{
"check": {
"metadata": {
"name": "example-check",
"labels": {
"contacts": "ops"
}
},
"status": 1,
"output": "You should receive this example event in the Slack channel specified by your slack_ops handler.",
"handlers": ["slack"]
}
}' \
http://127.0.0.1:3031/events
$ curl -X POST \
-H 'Content-Type: application/json' \
-d '{
"check": {
"metadata": {
"name": "example-check",
"labels": {
"contacts": "ops,dev"
}
},
"status": 1,
"output": "You should receive this example event in the Slack channel specified by your ops adn dev handler.",
"handlers": ["slack"]
}
}' \
http://127.0.0.1:3031/events
So we can create checks for agent.
$ vi sensu-checks.yaml
$ cat sensu-checks.yaml
---
type: CheckConfig
api_version: core/v2
metadata:
created_by: mc
name: nginx_service
namespace: default
annotations:
fatigue_check/occurrences: '1'
fatigue_check/interval: '3600'
fatigue_check/allow_resolution: 'false'
labels:
contacts: ops
spec:
check_hooks: null
command: check_service --name nginx
env_vars: null
handlers:
- slack
high_flap_threshold: 0
interval: 15
low_flap_threshold: 0
output_metric_format: ""
output_metric_handlers: null
proxy_entity_name: ""
publish: true
round_robin: false
runtime_assets:
- nagiosfoundation
secrets: null
stdin: false
subdue: null
subscriptions:
- webserver
timeout: 0
ttl: 0
---
type: CheckConfig
api_version: core/v2
metadata:
created_by: mc
name: mysql_alive
namespace: default
annotations:
fatigue_check/occurrences: '1'
fatigue_check/interval: '3600'
fatigue_check/allow_resolution: 'false'
labels:
contacts: ops
spec:
check_hooks: null
command: check-mysql-alive.rb --database=playerdata --host=127.0.0.1 --ini=/home/mc/backupDB.cnf
env_vars: null
handlers:
- slack
high_flap_threshold: 0
interval: 15
low_flap_threshold: 0
output_metric_format: ""
output_metric_handlers: null
proxy_entity_name: ""
publish: true
round_robin: false
runtime_assets:
- ruby-plugins
- mysql-plugins
secrets: null
stdin: false
subdue: null
subscriptions:
- database
timeout: 0
ttl: 0
---
type: CheckConfig
api_version: core/v2
metadata:
created_by: mc
name: mysql_connections
namespace: default
annotations:
fatigue_check/occurrences: '1'
fatigue_check/interval: '3600'
fatigue_check/allow_resolution: 'false'
labels:
contacts: ops, dev
spec:
check_hooks: null
command: check-mysql-connections.rb --warnnum 50 --critnum 75 --host=127.0.0.1 --ini=/home/mc/backupDB.cnf
env_vars: null
handlers:
- slack
high_flap_threshold: 0
interval: 15
low_flap_threshold: 0
output_metric_format: ""
output_metric_handlers: null
proxy_entity_name: ""
publish: true
round_robin: false
runtime_assets:
- ruby-plugins
- mysql-plugins
secrets: null
stdin: false
subdue: null
subscriptions:
- database
timeout: 0
ttl: 0
$ sensuctl check delete nginx_service
? Are you sure you would like to delete resource 'nginx_service'? Yes
Deleted
$ sensuctl check delete mysql_connections
? Are you sure you would like to delete resource 'mysql_connections'? Yes
Deleted
$ sensuctl create -f sensu-checks.yaml
$ sudo systemctl stop nginx; \
sleep 20; \
sudo systemctl start nginx
END