LoginSignup
83

More than 5 years have passed since last update.

CoreOS でシステムメトリクスを収集し、グラフ化する

Last updated at Posted at 2014-05-26

CoreOS でシステムメトリクスを収集し、グラフ化する

どうも、僕です。
CoreOS Beta まできましたね。GCEにもイメージが乗るようなので興味をもった方多いかも知れません。
今回は CoreOS の運用のお話をしたいと思います。
まず CoreOS について知りたい方は CoreOS 入門を読んでおくとよいでしょう。
(少し古いですが)

今回はクラスタ上の CoreOS のシステム情報をかき集めてグラフ表示するというお話です。
以下のとこまでもっていくのがゴールです。
Screenshot from 2014-05-26 11:20:13.png

追記
期間限定でGCE上にデモを配置しました。
http://108.59.85.122/#/dashboard/elasticsearch/CoreOS

CoreOS ならではの運用上の問題

CoreOS ですが、パッケージマネージャーを持ちません。
そのため、アプリケーションはほぼ Docker 上で動作させることになります。
ですが、Docker 上で動作させるとホスト OS の情報にアクセスできません。
そのため CoreOS 自体のシステム情報の監視を行うためにはなんらかしらの工夫が必要になります。
ホストの色々な情報がある /proc/sys/fs/cgroupDocker から参照できればうまくいきそうです。

また 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 の中身はどうなっているのでしょう??

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-nspawnsystemd の機能の一部にある軽量コンテナ実装のひとつです。
詳しくは 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 のシステム情報を集めることが出来そうです。
なので以下のようなスクリプトを書きました。

nspawn-container
#!/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をセットアップしています。

では CoreOSDiamond を仕込みます。
fleet から起動するserviceファイルは以下です。

diamond.1.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台のクラスタ

fleetctl
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

例:各ホストのDockerコンテナのメモリ使用量
Screenshot from 2014-05-26 11:47:48.png

まとめ

CoreOSの運用監視についてはまだあまり確立されてない状態です。
上記の方法が一番スマートな方法だと思います。
ホスト OS の運用監視は Docker では無理があるので他の方法を検討するのがよいでしょう。
CoreOS の場合はsystemdなどの総合的な知識が必要になると思います。
次回はログ監視 + Alert、cabotによるしきい値チェックによる監視、Alert、etcd, fleetのチューニングなどお話でもしようかと思います。
(書き起こしめんどい。。。)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
83