CoreOS でシステムメトリクスを収集し、グラフ化する
どうも、僕です。
CoreOS
Beta まできましたね。GCEにもイメージが乗るようなので興味をもった方多いかも知れません。
今回は CoreOS
の運用のお話をしたいと思います。
まず CoreOS
について知りたい方は CoreOS 入門を読んでおくとよいでしょう。
(少し古いですが)
今回はクラスタ上の CoreOS
のシステム情報をかき集めてグラフ表示するというお話です。
以下のとこまでもっていくのがゴールです。
追記
期間限定でGCE上にデモを配置しました。
http://108.59.85.122/#/dashboard/elasticsearch/CoreOS
CoreOS ならではの運用上の問題
CoreOS
ですが、パッケージマネージャーを持ちません。
そのため、アプリケーションはほぼ Docker
上で動作させることになります。
ですが、Docker
上で動作させるとホスト OS の情報にアクセスできません。
そのため CoreOS
自体のシステム情報の監視を行うためにはなんらかしらの工夫が必要になります。
ホストの色々な情報がある /proc
や /sys/fs/cgroup
を Docker
から参照できればうまくいきそうです。
また CoreOS
はクラスタサポート込の設計がなされています。
なので複数台でクラスタを組んで運用することが多いかと思います。
そうなると各ホストの状態を一箇所にまとめて監視したくなります。
この辺もカバーしたいところです。
Docker を使う場合の限界
では早速確認してみましょう。
Docker
は別の名前空間で動くのですがマウントでなんとかごまかせるかも知れません。。
システム情報を取得したいのでホストの/proc
をマウントしてみましょう。
$ sudo docker run -t -i --privileged=true -v /proc:/proc ubuntu /bin/bash
2014/05/xx xx:xx:xx set apparmor profile unconfined: permission denied
特権モードでもできませんでした。。。
やはり無理がありますね。
つまり、Docker
上から ps
コマンドの類からはホスト OS の情報にアクセスすることは不可能ということです。
ではこれではどうでしょう?
$ sudo docker run -t -i --privileged=true -v /proc:/host_proc ubuntu /bin/bash
root@7a589eceb66a:/#
うまくいったように見えますね。
root@7a589eceb66a:/# cat /host_proc/diskstats
.....
省略していますが、ホストと同じ情報が表示されているはずです。
問題なさそうです。
では /proc/mounts
はどうでしょう?
root@7a589eceb66a:/# cat /host_proc/mounts
....
ホストと見比べてみましょう。
やはりここは無理のようです。。。
あと欲しいのは /sys/fs/cgroup
配下でしょうか?
ここには cgroup で管理されているプロセスの情報があります。
試してみましょう。
$ sudo docker run -t -i --privileged=true -v /sys:/sys ubuntu /bin/bash
root@9234d03c8638:/#
root@9234d03c8638:/# cat /sys/fs/cgroup/memory/docker/9234d03c863892f03237ac1a6d0f4a8d1022ba2cab6ff0eb3edc34def4959fb0/memory.stat
cache 675840
rss 610304
rss_huge 0
mapped_file 0
writeback 0
swap 0
pgpgin 978
pgpgout 664
pgfault 3296
pgmajfault 2
inactive_anon 28672
active_anon 618496
inactive_file 413696
active_file 192512
unevictable 0
hierarchical_memory_limit 18446744073709551615
hierarchical_memsw_limit 18446744073709551615
total_cache 675840
total_rss 610304
total_rss_huge 0
total_mapped_file 0
total_writeback 0
total_swap 0
total_pgpgin 978
total_pgpgout 664
total_pgfault 3296
total_pgmajfault 2
total_inactive_anon 28672
total_active_anon 618496
total_inactive_file 413696
total_active_file 192512
total_unevictable 0
今起動している自身のコンテナのメモリ情報にもアクセスできました。
/proc/mounts
はやはり上書き不可能でしたが、その他は頑張ればいけそうな気がします。
頑張れば。。。
Docker
を使う場合の問題は以下でしょうか。
-
/proc
がそのまま使えないので/host_proc/
などを使わなければいけない(それでも全ての情報にアクセスできるとは限らない) - システム情報を収集するツールが
/proc
部のパスを変更しても動作する必要がある
もちろんシステム情報を収集するツールにパッチを当てて収集ツールを動かすといった方法もあるでしょう。
これはツールのアップデートに合わせて再度パッチをあて改修していくといった作業が必要になるため現実的で
はありませんね。
参照:現実的ではない例
これが CoreOS
+ Docker
できゃあきゃあ言ってる連中のリアル(現実)です。
なんだかダサいですね。もっとスタイリッシュにできないもんでしょうか?
2 種類のコンテナを使って問題を乗り越える
さて、実際問題この問題を乗り越えるにはどうしたらよいでしょう?
coreos-dev を読んでる人ならすぐにわかりますね。
CoreOS に付属する toolbox
CoreOS
にはパッケージマネージャーが存在しません。
ですが、これではデバッグがあまりにも大変です。
そのため、CoreOS
標準でデバッグに使うための toolbox
というツールが付属してきます。
toolbox
を使うと fedora20
の yum が使えたり fedora20
の多くの機能を使うことが出来ます。
例:
core@coreos-local ~ $ toolbox
unknown
Spawning container core-fedora on /var/lib/toolbox/core-fedora. Press ^] three times within 1s to abort execution.
/etc/localtime is not a symlink, not updating container timezone.
[root@coreos-local ~]#
[root@coreos-local ~]# yum install -y emacs
...
toolbox
の中身はどうなっているのでしょう??
#!/bin/bash
TOOLBOX_DOCKER_IMAGE=fedora
TOOLBOX_USER=root
toolboxrc="${HOME}"/.toolboxrc
if [ -f "${toolboxrc}" ]; then
source "${toolboxrc}"
fi
machinename=$(echo "${USER}-${TOOLBOX_DOCKER_IMAGE}" | sed -r 's/[^a-zA-Z0-9_.-]/_/g')
machinepath="/var/lib/toolbox/${machinename}"
if [ ! -d ${machinepath} ] || systemctl is-failed ${machinename} ; then
sudo mkdir -p "${machinepath}"
sudo chown ${USER}: "${machinepath}"
docker pull "${TOOLBOX_DOCKER_IMAGE}"
docker run --name=${machinename} "${TOOLBOX_DOCKER_IMAGE}" /bin/true
docker export ${machinename} | sudo tar -x -C "${machinepath}" -f -
docker rm ${machinename}
sudo touch "${machinepath}"/etc/os-release
fi
sudo systemd-nspawn -D "${machinepath}" --share-system --bind=/:/media/root --bind=/usr:/media/root/usr --user="${TOOLBOX_USER}" "$@"
なにやら怪しいコマンドを実行していますね。
systemd-nspawn
がキモのようです。
systemd-nspawn
systemd-nspawn
は systemd
の機能の一部にある軽量コンテナ実装のひとつです。
詳しくは Arch の Wiki などを見てもらえばわかりますが、Docker
と同じように別の名前空間で動作したり、ネットワークも切り離したりすることができます。
コンテナも machinectl
で管理することが出来ます。
(CoreOS
上での machinectl からのログインは一部のサービスが足りないのでエラーになります)
Docker
と異なる点は コンテナ内のディレクトリ、ライブラリなどを自分で用意する必要があるという点です。
Docker
でいうイメージの部分は自前管理です。
例:
$ yum -y --releasever=19 --nogpg --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora install systemd passwd yum fedora-release vim-minimal
$ systemd-nspawn -bD /srv/mycontainer
使用方法はシンプルですね。
コンテナになるディレクトリにbaseになるパッケージを入れてしまえばディレクトリも作成されるので簡単に使うことができます。
上記のように systemd-nspawn
はコンテナのディレクトリを自前で用意しなければなりません。
この部分に Docker
Imageを使ってるのがtoolbox
です。
Docker
Image を export した tar 解凍すれば systemd-nspawn
でそのまま使用できます。
toolbox
では fedora20
のイメージが指定されています。
また systemd-nspawn
には --share-system
フラグというものがあります。
これは名前空間をホストと共有して動作するモードです。
そうです、これを使えばホスト OS の情報に簡単にアクセスできます。
nspawn-container
toolbox
を元に任意のコンテナを実行できればホスト OS のシステム情報を集めることが出来そうです。
なので以下のようなスクリプトを書きました。
#!/bin/bash
TOOLBOX_DOCKER_IMAGE=$1
TOOLBOX_USER=root
machinename=$(echo "${USER}-${TOOLBOX_DOCKER_IMAGE}" | sed -r 's/[^a-zA-Z0-9_.-]/_/g')
machinepath="/var/lib/toolbox/${machinename}"
if [ ! -d ${machinepath} ] || systemctl is-failed ${machinename} ; then
sudo mkdir -p "${machinepath}"
sudo chown ${USER}: "${machinepath}"
docker pull "${TOOLBOX_DOCKER_IMAGE}"
docker run --entrypoint="/bin/bash" --name=${machinename} "${TOOLBOX_DOCKER_IMAGE}" /bin/true
docker export ${machinename} | sudo tar -x -C "${machinepath}" -f -
docker rm ${machinename}
sudo touch "${machinepath}"/etc/os-release
fi
sudo systemd-nspawn -D "${machinepath}" --share-system --bind=/:/media/root --bind=/usr:/media/root/usr --bind-ro=/sys/fs/cgroup:/sys/fs/cgroup --bind-ro=/sys/fs/cgroup/memory:/sys/fs/cgroup/memory --bind-ro=/sys/fs/cgroup/cpuacct:/sys/fs/cgroup/cpuacct --bind=/run:/run --user="${TOOLBOX_USER}" "$2" "${@:3:$#}"
修正箇所はイメージを引数で受け取れるようにしたのと起動プログラム、そして引数を渡せるようにした点です。
今回はさらにシステム情報を集めるために各種パスをbindしています。
/sys/fs/cgroup
などは明示的に指定しないとうまくbindできなかったので指定します。あとは /run
をbindしてるのでdocker.sockにもアクセスできます。
システム情報を集め、グラフ化する
では早速システム情報を集めてホストの情報を監視してみましょう。
今回はシステム情報を集めるのにDiamondを使用します。
Diamond
でシステム情報を集め、Graphite(Grafana)
でグラフに表示するのが目標です。
まず、システム情報を集める先にGraphite
+ Carbon
を起動します。
セットアップがめんどいのでmopemope/graphite-dockerを使うといいでしょう。
Graphite
+ Grafana
の他に Elasticsearch
+ StatsD
込みのイメージとなっています。
起動方法は以下です。
Port 80 には素の Graphite
、81 には Grafana
が立ち上がります。
下記の例では8080, 8081にそれぞれ Graphite
/ Grafan
aを割り当てています。
Port 2003はcarbonのポートです。ここに向けて Diamond
でデータを送信します。
$ sudo docker run -d -p 8081:81 -p 8080:80 -p 20030:2003 -p 2004 -p 7002 -p 8125:8125/udp -p 8126:8126 mopemope/graphite
集める先なので CoreOS
でなくても任意のOS上の Docker
で起動して問題ありません。
私も CoreOS
クラスタ外にGraphiteをセットアップしています。
では CoreOS
に Diamond
を仕込みます。
fleet
から起動するserviceファイルは以下です。
[Unit]
Description=Diamond Service
After=docker.service
Requires=docker.service
[Service]
User=core
ExecStartPre=/usr/bin/curl -so /home/core/nspawn-container https://gist.githubusercontent.com/mopemope/79476588ed3650bc08d4/raw/8fd78056ebcbca86df51c5092c7b441e288ea2eb/nspawn-container
ExecStartPre=/usr/bin/chmod +x /home/core/nspawn-container
ExecStart=/bin/sh -c '/home/core/nspawn-container mopemope/diamond-docker /diamond/run_diamond 192.168.2.28 20030'
Restart=always
[X-Fleet]
X-Conflicts=diamond.*.service
mopemope/diamond-docker は私が作成した Diamond
起動用の Image です。
Trusted Builds になっているのでソースも見れます。
Collectorは12個動いていますが、とりあえず設定も公開されているので適当に見て下さい。
システム情報の取得は60秒間隔です。
起動するプログラム /diamond/run_diamond
にはホスト、ポートを指定します。
今回は Graphite
が192.168.2.28に動作しているものとします。
fleet
から起動し、以下のようになっていればOKです。
しばらくすると Graphite
側にデータが送られてきます。
例:3台のクラスタ
diamond.1.service launched loaded active running Diamond Service 790495b4.../192.168.2.52
diamond.2.service launched loaded active running Diamond Service d5a76cb1.../192.168.2.51
diamond.3.service launched loaded active running Diamond Service 872761f0.../192.168.2.50
まとめ
CoreOS
の運用監視についてはまだあまり確立されてない状態です。
上記の方法が一番スマートな方法だと思います。
ホスト OS の運用監視は Docker
では無理があるので他の方法を検討するのがよいでしょう。
CoreOS
の場合はsystemd
などの総合的な知識が必要になると思います。
次回はログ監視 + Alert、cabotによるしきい値チェックによる監視、Alert、etcd, fleetのチューニングなどお話でもしようかと思います。
(書き起こしめんどい。。。)