JAWS DAYS 2014 発表してきました
JAWS DAYS 2014
ちょっと前の話になりますが、JAWS DAYS 初参加・初発表してきました。発表については会社の方のレポートが詳しいのでそちらでどうぞ。
【イベント登壇レポート】JAWS DAYS 2014で、Miiverseの取り組みを弊社エンジニア渡辺が任天堂と共同で発表しました - Hatena Developer Blog
Jaws Days 2014 Miiverse // Speaker Deck
参加者としての感想をいくつか。
- 1000人規模のイベントで AWS の盛り上がりが相変わらずすごい
- Immutable Infrastracture なんかはとくに盛り上がっていて立ち見状態。あまり見られなかった…
- ELB じゃなくて HAProxy を使っているところが多い。ELBけっこうつらい部分も多いですね。安いのでなるべく使いたいんですが..
- 弊社でも HAProxy けっこうパフォーマンスつらいのでいろいろ検証してもらってます EC2のc3インスタンスでSR-IOVを使うときのNICドライバパラメータ検証 - ゆううきブログ
- 個人的には CookPad さんやDeNA さんの発表が面白かったです。
いろいろやりがいがある環境なのでどんどん改善していきたいと思います
■
よくサンプルにあるやつ
require 'aws-sdk' ec2 = AWS::EC2.new( :access_key_id => ACCESS_KEY, :secret_access_key => SECRET_KEY, :ec2_endpoint => 'ec2.ap-northeast-1.amazonaws.com' )
IAM role を設定したインスタンスだと、ACCESS_KEY, SECRET_KEY は自動で取得してくれて便利
ec2 = AWS::EC2.new
途中でリージョン変えるのは適当にこういう感じで
ec2 = ec2.regions[region] ec2.instances.filter('instance-state-name', 'running')
client を使うとAPIだいたいそのまま叩けていいんだけど、この方法だと region 設定できないので注意する。そのまま多々気に入ってるだけみたい
ec2 = AWS::EC2.new client1 = ec2.client # これは us-east-1 client2 = ec2.regions['ap-northeast-1'].client # これも us-east-1 client3 = AWS::EC2.new(:ec2_endpoint => 'ec2.ap-northeast-1.amazonaws.com').client #ちゃんと設定すると ap-northeast-1 を向く
Docker コンテナにアプリケーションを立てて Graphite でいい感じに可視化するまで
このときにやった可視化部分の話。急いで作ったのでいろいろ雑な部分が多い。
開発合宿でDockerとMesosを使っていい感じにリソース提供とデプロイするやつを作ってた - wtatsuru's blog
はじめに
元のやつから内部情報を削ったサンプルを置いておきます。適当にサーバ名など修正すれば使えるかもしれません。
https://github.com/tatsuru/docker-sample-app
全体の仕組みについてはここの図がわかりやすいと思います
Docker + Mesos + Marathon + Graphite + Fluentd + Sensuを組み合わせたデプロイ管理ツールの話 - ゆううきブログ
やりたいこと
- 目的はアプリケーションの現状を俯瞰できるダッシュボードを作ること。
- それぞれのDockerコンテナは短命なので、下記の情報をうまく集約してやる必要がある。
- レイテンシとHTTPレスポンスの健全性。全体のログを集める必要がある。
- CPUやメモリ使用率の推移。コンテナごと・アプリケーションのバージョンごとに見たい。
Graphite
Graphite - Scalable Realtime Graphing - Graphite
可視化は最初 Growthforecast あたりでやるつもりでいたけど、メンバーの一人から以下のような発言が出たため Graphite を使うことに。
2013-12-14 18:04:30 y_uuki RRDtoolグラフみたくない
Graphite のドキュメントはこっちが最新らしいので注意。
Graphite Documentation — Graphite 0.9.10 documentation
グラフは '.' 区切りの階層構造で表現されていて、こういう感じで送りつけるだけでよく気軽に使える。
PORT=2003 SERVER=graphite.your.org echo "local.random.diceroll 4 `date +%s`" | nc -q0 ${SERVER} ${PORT}
これで Graphite の "local.random.diceroll" に入る。
書式が Sensu plugin の形と同じ(!)なので、Sensu 側で送るのも簡単
"handlers": { "graphite": { "type": "tcp", "socket": { "host": "graphite.example.com", "port": 2003 }, "mutator": "only_check_output" } }
Sensu で送って可視化
- 全部 fluentd でやろうとすると、メトリクスまわりが面倒になってきた
- Sensu Plugin だと標準出力に数字を出すだけで入れられてお手軽。メトリクスはまずこれで集めてみる
- Docker のメトリクスを送る場合、どのホストから・どのバージョンのアプリから送られたのか、という情報で階層化しておきたい
- Marathon 上のジョブ名を docker run の時に環境変数で渡し、起動時に Sensu のホスト名として生成した
- このへん https://github.com/tatsuru/docker-sample-app/blob/master/sensu/run
- ジョブ名にバージョンを入れてある Sampleapp-14_1-1387677685b
- sensu plugin の設定で :::name::: と書くと sensu client 名が渡される(この設定を探すのに苦労した...)
- あとはアプリと一緒にまとめて supervisord で起動 https://github.com/tatsuru/docker-sample-app/blob/master/supervisor/supervisord.conf
- Sensu client がどんどん作られて削除する処理をしてないので、クライアント数が爆発して keep-alive 処理で負荷が高い
コンテナ単位の負荷を親からとる
- docker は所詮 lxc コンテナ内なので、コンテナ単体のを取得するのは親ホストから取得するといい (参考:http://blog.docker.io/2013/10/gathering-lxc-docker-containers-metrics/)
- cgroup ごとに取得する要領で
- というわけで適当に plugin 作って docker ホストに仕込んだ
- https://github.com/tatsuru/docker-sample-app/blob/master/sensu/plugins/docker-container-metrics.rb
- こういうファイルから取れる /path/to/cgroup/lxc/$container/cpuacct.stat
- 解釈は適当にこのへんで
集計は Fluentd
- レスポンスやエラーの集計処理は sensu では難しそうなのでやっぱり fluentd で
- ステータスコードとレイテンシの集計は fluent-plugin-datacounter で、エラーレートは flowcounter で数えるくらい。
- fluentd 力が足りなくて fluent-plugin-graphite にいい感じに渡すのが難しかったのでプラグイン側をいじった
Graphite で描く
適切に名前空間を分けておけば Graphite のグラフを並べてdashboardを作れます(本物は見せられないのでスクショと xslate のテンプレートだけ。。)
こういう名前空間にしてみた
- Sampleapp.{accesslog,errorlog} 以下にアプリ全体のアクセスログ・エラーログの集計結果
- Sampleapp.sampleapp-$version.$container 以下に各コンテナから集計したメトリクス
- docker.$dockerhost.sampleapp-$version.$container.{memory,cpu}.stat. 以下に docker ホストから集計したメトリクス
- Graphite の glob だったり各種記法が便利
- (whisperだと?)ファイルシステム上のファイルにそのままマッピングされるので、この調子でガンガン作るとそのうち破綻するかも
全体のdashboard
<p> <img src="http://graphite.example.com/render?width=350&from=-1hours&until=now&height=250&areaMode=stacked&target=[% ucfirst(service.name) %].accesslog.counts.app.*xx_count&title=Accesses" alt="accesses" /> <img src="http://graphite.example.com/render?width=350&from=-1hours&until=now&height=250&areaMode=stacked&target=[% ucfirst(service.name) %].accesslog.gauges.app.access_*xx_percentage&yMax=100&title=HTTP%20Status%20Code" alt="http status code"/> <img src="http://graphite.example.com/render/?width=350&height=250&target=[% ucfirst(service.name) %].errorlog.gauges.count&lineMode=connected&from=-1hours&title=Errors&hideLegend=true" alt="errors"/> </p> <p> <img src="http://graphite.example.com/render?width=350&from=-1hours&until=now&height=250&areaMode=stacked&target=[% ucfirst(service.name) %].accesslog.gauges.app.access_0-100msec_percentage&target=[% ucfirst(service.name) %].accesslog.gauges.app.access_100-200msec_percentage&target=[% ucfirst(service.name) %].accesslog.gauges.app.access_200-500msec_percentage&target=[% ucfirst(service.name) %].accesslog.gauges.app.access_500msec-1sec_percentage&target=[% ucfirst(service.name) %].accesslog.gauges.app.access_1sec_over_percentage&yMax=100&title=Latency" alt="latency"/> <img src="http://graphite.example.com/render/?width=350&height=250&lineMode=connected&from=-1hours&target=[% ucfirst(service.name) %].[% service.name %]-*.*.load_avg.five&drawNullAsZero=true&hideLegend=true&title=Loadavg5" /> <img src="http://graphite.example.com/render/?width=350&height=250&from=-1hours&target=docker.*.[% service.name %]-*.*.memory.stat.total_rss&drawNullAsZero=true&title=Memory%20Usage(RSS)" alt="memory usage" /> </p>
各バージョンごとに
<img src="http://graphite.example.com/render/?width=400&height=200&from=-1hours&target=scale(derivative(docker.*.[% service.name %]-[% deploy_version.id %].*.cpuacct.stat.user)%2C0.01)&drawNullAsZero=true&title=CPU%20Usage" /> <img src="http://graphite.example.com/render/?width=400&height=200&from=-1hours&target=docker.*.[% service.name %]-[% deploy_version.id %].*.memory.stat.total_rss&drawNullAsZero=true&title=Memory%20Usage" />
まとめ
- docker で立てたアプリを sensu, fluentd から graphite に送っていい感じに可視化するやつを作ってみた
- Dockerコンテナを作って壊す環境だと、中央で適切にクライアント管理しないとすぐに破綻しそう
- Sensu Plugin でメトリクスを送るのは便利だが、クライアント一覧は破綻した
- Graphite も、* でいけるうちはいいが、ここも数が増えるとつらくなりそう
- 分散の仕組みもあるし、ベンチマークは同僚がやってたので期待してます
- 集約する処理が入ると Fluentd で集めてさくっと処理するのが便利だった
- Fluentd, Sensu 2つも動かしたくはないので、どちらかに一本化したい
- 監視までやるなら Sensu でさくっとやると便利そう
- sensu plugin の出力を fluentd/graphite にいい感じに渡す仕組みを作ればよさそう?
- Graphite の記法が便利で楽しい
- あくまで glob なので、GROUP BY 的なものなど機能不足は否めない。dashboard側でテンプレートから生成するなどの工夫は必要そう
開発合宿でDockerとMesosを使っていい感じにリソース提供とデプロイするやつを作ってた
3日間の開発合宿で、Docker と Mesos を使ってリソース管理からテスト・デプロイ管理までするやつのプロトタイプを作ってた。
4人チームで3日間みっちりやって、それなりにいい感じにはできたと思う。id:shiba_yu36 が既に書いてるけど、自分の視点から感想だけ書いておく。
本番環境のBlue-Green Deploymentの仕組みのプロトタイプを作っていた - $shibayu36->blog;
経緯
- 最近忙しくてあまり触れてない、Immutable Infrastracture みたいなのを作ってみたかった。
- Docker を開発に使うのはいい感じだけど、実際の運用に組み込むには、というイメージをつかみたかった。
- というのをラーメン屋で話してたら4人集まったので風呂敷を広げてみた。
どんなものを作ったか
- アプリケーションは Docker コンテナとして動かす。
- Debian Wheezy に 3.10.23 のカーネルを入れて使った。
- コンテナ環境を提供するリソースプールは Mesos 上のフレームワーク Marathon で管理する。
- 特定バージョンの環境は Marathon 上のジョブとして実行される。反映や切り戻しはボタン一発で行える。
- 各種リソースをモニタリングしアプリケーションごと・ジョブごとに可視化される。
- Docker イメージ中に sensu と fluentd を入れてログやメトリクスを転送・監視する。
- 可視化は Graphite で。いい感じにまとめてダッシュボードに表示する。
- コンテナのテストから可視化まで Jenkins で行う。
- git リポジトリに push したら Docker イメージのビルドとテスト。
- 全体のフルビルド・アプリ変更のみの差分ビルドを用意して普段は後者のみ行う。
- Docker イメージを push する形は選ばなかった。
- 全体を統括するダッシュボードアプリから反映操作を行う。
- バージョンごとに Marathon にリソース要求。nginx 設定を生成し、ヘルスチェックが通ったら切り替えボタンでリリースできる。
- 個別のバージョン環境へのアクセス提供。実際にアクセスして確認できる。
- Jenkinsでテストが通ったらすぐに最新版が作られる。手動で作成もでき、各バージョンは削除するまで残されている。
感想
開発用にはすぐにでも導入したい
- コンテナ型の起動時間とリソース消費の少なさで気軽に Immutable にできる。
- サーバ設定変更・反映含めて思った以上に気楽にできた。既存の社内環境やAWS で5-10分かかるのと比較しても心理的な障壁がかなり小さい。
- 気軽に環境作成・分離ができる。
本番導入には課題が多い
- Docker 自身もまだ発展途上にある
- issue になってるところにけっこうはまってた https://github.com/dotcloud/docker/issues?page=1&state=open
- すごい勢いで開発されてるのでそれなりに
- リソース管理まわりのミドルウェアが揃っていない気がする。*1
- Marathon を動かしていると mesos-slave 自身の負荷がかなり高い
- Marathon や executor の mesos-docker もドキュメントが足りなくて、チームメンバがソースを読んで挙動を確認する感じになった。*2
- 何もしない分、オートスケール部分は自分で管理しないといけない。
- Flynn には期待してる。
- (Fluentd|Sensu) + Graphite という組み合わせで可視化と監視はいい感じにできる。
- Fluentd, Sensu 両方動かしたくはないけど、一長一短あって両方動かすことになった。気合いを入れて fluentd に寄せるといいかもしれない
- Sensu を使うと client 一覧をちゃんと管理しないと破滅するので面倒 (作りなおすたびに増える)
- Graphite の記法が強力で楽しい
- Fluentd, Sensu 両方動かしたくはないけど、一長一短あって両方動かすことになった。気合いを入れて fluentd に寄せるといいかもしれない
自分がやったこと
総括
- Immutable infrastructure 環境作成まわりのミドルウェアとその上で動くアプリケーションの要求についてなんとなく感覚が掴めた。
- 動くものを3日で勢いよく開発するのはなかなか楽しかった。3ヶ月に1回くらいやりたい。
疲れてるのでこれくらいにします。自分が触った部分の詳細については別の記事できっと書きます。
dockerをDebianで動かす(2013-12-14版)
これ、まだたまにアクセスあるので現状に合わせたやつを書いておきます。
docker を Debian で動かす - wtatsuru's blog
最近はもっと簡単になってます。Installation のページでも紹介されてますがパッケージからやると簡単です。
Requirements and Installation on Ubuntu Linux - Docker Documentation
curl http://get.docker.io | sudo sh -x sudo adduser `whoami` docker echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
- パッケージで入って適切なiptables, cgroupの設定まで行われます。
- カーネルは新しい方がいいと思います (wheezy でビルドした 3.10.23 で確認)
- ログアウト・ログインすると docker グループに入ってて sudo 無しで docker が使えると思います
- curl でダウンロードしたやつを sudo で食わせるなんて恐ろしいので、可能な人はちゃんと食わせる前にスクリプトを読みましょう
Xfceにした
GNOME3.8 へのアップデート対応で疲れたので勢い余ってXfceにした。
- xfce4 パッケージをインストール
- 起動設定してX再起動。やらなくてもgdmで簡単に選べたぽい。
sudo update-alternatives --config x-session-manager
- capslocl を ctrl にする方法探してたらこういうのにいきあたったので設定 XFCE4 Cheat Sheet
- ショートカット設定。ターミナル起動とウィンドウサイズ操作変更まわり。
- emacsとターミナルを半透明にする。ウィンドウマネージャの設定(詳細)ってやつの合成処理をONにするといけた
- パネルが上下方向場所食ってるの気に食わないので左に動かす
- 電源管理まわり。サスペンド設定など
- 設定確認のため一度ログアウトしてみる
それなりに快適に使えてる。
/etc/network/interfaces で bridge作る
これ見れば最近のやり方が書いてある。BridgeNetworkConnections - Debian Wiki
VMホストでブリッジ生やしたいだけならこれでOK
auto lo iface lo inet loopback auto eth0 iface eth0 inet manual auto br0 iface br0 inet dhcp bridge_ports eth0