#tvrendo テレビ連動サーバ勉強会 で発表しました
http://connpass.com/event/10424/
弊社にて、テレビ連動サービスに特化した勉強会を開催しました。
で、自分も発表してました。
スライドはこちら。
http://www.slideshare.net/tsuyoshitorii5/public-43549341
時間配分全然わかってなかったので、(特に後半)かけ足になってしまいました。
申し訳ございません。
デモの辺りの補足
背景
そもそもだいぶ前から
「こういう感じでsocket.ioコンテナ化して自由に上げ下げできると面白いな。
で、実際どうなのかな?実運用できそう?」
ということを考えていました。
そして今回いい機会なので急ぎでプロトタイプ書いてみたところ
なんとなく上手くいったのでデモとして公開してみました。
またこの構成だとLBが最初にサチるので、この構成単体だと限界があります。
あくまでサーバ1台辺りのリソースをうまく使いきりたいなーというところが目的です。
あと半分は遊びですねw
デモ動作説明
スライドにも書いてますが、以下のような仕組みで実現しています。
- LBは Openresty+Luaで実現。sticky idからsocket.ioサーバを決定
- socket.ioコンテナを増やすと以下のような処理が動く
- Registratorが増えたコンテナ情報をconsulに通知する
- consulと繋がっているconsul-templateに変更情報が通知される
- consul-templateがnginx.confのサーバリストを書き換え、自動で restart が行なわれる
- 複数コンテナはsocket.io-redis adapterで繋がっているのでブロードキャストも通知される
デモでやったこと
定期的にsocket.ioクライアントでコネクションし続け、
その状態でDockerコンテナ増やしたり減らしたりしても
問題なく接続/再接続できる様子を動画にしてみました。
反応ないのでわからないんですが、この手法どうだったんだろうかw
(動画アップロードしてもいいんですが、やりかたわからん…)
感想
クラスメソッドさんの大規模通知の話も共感しながら聞けましたし、
voluntasさんのMQTT話も本当にとてもわかりやすくて勉強になったし、
a2cさんのマル秘話も非公開にするのが惜しいほどすごいお話で刺激受けました。
正直言うと自分はめっちゃ面白かったので
第2回もあると良いですね!!!
omnibus-gitlabを利用したGitlabアップグレードの手順メモ
毎回ドキュメント見つつ実行するのがダルいのでメモしておく。
7.10.x 以降: 手順
これだけでOKになりました:)
# ubuntuバージョン sudo apt-get update sudo apt-get install gitlab-ce
7.9.x 以前のバージョンから上記手順に移行したい場合は
普通に最新版install手順から繰り返せばそのまま移行することができます。
https://about.gitlab.com/downloads/
※一応前バージョン移行手順も残しておきます
7.9.x 以前: 手順
1. 最新バージョンのGitlabダウンロード
こちらのページから最新バージョンを確認し、ダウンロードをしておきます。
https://about.gitlab.com/downloads/
ex) Gitlab-7.6.2の場合
wget https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.6.2-omnibus.5.3.0.ci-1_amd64.deb
2. デーモン停止
sudo gitlab-ctl stop unicorn sudo gitlab-ctl stop sidekiq sudo gitlab-ctl stop nginx
3. バックアップ実行(※必須ではないが、念のため)
バックアップ先は /var/opt/gitlab/backups です。
sudo gitlab-rake gitlab:backup:create
4. 1. でダウンロードしたパッケージをインストール
# Ubuntu/Debian: sudo dpkg -i gitlab_x.x.x-omnibus.xxx.deb # CentOS: sudo rpm -Uvh gitlab-x.x.x_xxx.rpm
5. プロビジョニング実行
sudo gitlab-ctl reconfigure
6. デーモン再起動
sudo gitlab-ctl restart
isucon4予選問題のLua(Lapis)バージョンを書いてみた
isuconアプリを書いてみましたシリーズ。
生でOpenresty+Luaで書いても良かったんですが
せっかくなのでLapisというWebフレームワークを使ってみました。
実は自分も初触り。
最初にLapisの概要など
LuaのWebアプリケーションフレームワークです。*1
バックエンドはOpenresty(Nginx)を利用しています。既に速そうな感じがしますね…!
WebFrameworkBenchmarksでも割と上位にいます。
Lapis、実は生のLuaスクリプトではなく moonscript で書くのを推奨しているようです。
JavaScriptにおけるCoffeeScriptのようなものですね。
構文も似ているのでJS書いている人には取っ付き易いかもしれません。
isucon4 Lapis版ソースコード
こちら。
https://github.com/toritori0318/isucon4
また、Gistにitamaeレシピを置いておきました。
こちらを実行すると Openresty+Luarocks+Lapis がインストールされますので
試したい方はお使いください。
# itamaeインストール gem install itamae # レシピダウンロード wget https://gist.githubusercontent.com/toritori0318/2f2e080f906dbbbd0dea/raw/b0de3d7e8ece81fc81514b074e49549d0975da16/isucon4_lapis_recipe.rb # レシピ実行 itamae ssh isucon4_lapis_recipe.rb -h xxx.xxx.xxx.xxx -u ec2-user -i /path/to/aws.pem
isucon4 Lapisバージョンを動かすための手順
1. isucon4アプリを上記ソースコードに置き換えます
2. /etc/supervisord.confのminfdsを増やしておき、 service supervisord restart を実行します。
[supervisord] logfile=/tmp/supervisord.log loglevel=info pidfile=/var/run/supervisord.pid nodaemon=false minfds=100000 minprocs=200
3. /etc/supervisord.confに以下を追記し、supervisorctl reload を実行します。
[program:isucon_lua] directory=/home/isucon/webapp/lua command=/opt/openresty/nginx/sbin/nginx -p /home/isucon/webapp/lua -c "nginx.conf.compiled" #command=/home/isucon/env.sh /usr/bin/lapis server production user=isucon environment=LAPIS_OPENRESTY="/opt/openresty",PATH="/opt/openresty/nginx/sbin:$PATH" stdout_logfile=/tmp/isucon.lua.log stderr_logfile=/tmp/isucon.lua.log autostart=true
ベンチマーク
kazeburoさんの "ISUCON4 予選でアプリケーションを変更せずに予選通過ラインを突破するの術" を参考にし、
サーバに対してほぼ同じ修正をした後のベンチマークです。
perlアプリケーション(kazeburoさんversion)で実行
$ ./benchmarker bench --workload 8 18:17:59 type:info message:launch benchmarker 18:17:59 type:warning message:Result not sent to server because API key is not set 18:17:59 type:info message:init environment 18:18:07 type:info message:run benchmark workload: 8 18:19:07 type:info message:finish benchmark workload: 8 18:19:12 type:info message:check banned ips and locked users report 18:19:15 type:report count:banned ips value:593 18:19:15 type:report count:locked users value:4357 18:19:15 type:info message:Result not sent to server because API key is not set 18:19:15 type:score success:186360 fail:0 score:40258
Lapisアプリケーションで実行
$ ./benchmarker bench --workload 8 18:54:06 type:info message:launch benchmarker 18:54:06 type:warning message:Result not sent to server because API key is not set 18:54:06 type:info message:init environment 18:54:14 type:info message:run benchmark workload: 8 18:55:14 type:info message:finish benchmark workload: 8 18:55:19 type:info message:check banned ips and locked users report 18:55:22 type:report count:banned ips value:859 18:55:22 type:report count:locked users value:4747 18:55:22 type:info message:Result not sent to server because API key is not set 18:55:22 type:score success:221580 fail:0 score:47865
やはり速かった。
Lapis雑感
全体的につらい方が多い :(
つらい点
実例が少ない
Lapis(Lua)自体のユーザ数が少ないこともあり、ノウハウ的な情報はほぼ皆無です。
自力で頑張る必要があるでしょう。
Webに情報が少ない公式ドキュメント以外は情報少ないというかほぼ皆無です。
自力で頑張る必要があるでしょう。
エコシステムが弱い
そもそも便利ライブラリが少ない、またはメンテされていないのが多いので
普通のWebアプリケーションを作ろうとした時につらいです。
自力で頑張る必要があるでしょう。
MySQL非対応
PostgreSQLはバッチリ対応していますが、現時点で何故かMySQLは非対応です。
Pull Requestはされているようなのでその内当たるかも。
しかも現時点ではそのまま利用しようとすると動かないバグがあるので
1行パッチを当てる必要があります。(こちらのレシピでもパッチを実行しています)
良い点
Openrestyの遺産が使える
普通にngxの情報にアクセスできますし、Openrestyのライブラリも使えます。
これは結構な利点だと思います。
速い
パフォーマンスはだいぶ良いので
単純なアプリでパフォーマンスが必要であれば
選択肢として考えてもよいかもしれません。
まとめ
Lapisでisucon4予選問題アプリを書いてみました。
実際のWebアプリケーションを作るにはだいぶ茨の道だと思いますが
LLのように書ける割には速いですし
isuconのような一発アプリに使うのはアリかなと思いました。
またLua/MoonScript、実際書いてみるとわかるのですが
構文はJavaScript/CoffeeScriptに似ている部分があるので
実は(書くだけであれば)そんなに違和感なく書けたりします。
Go速いけどまだちょっと手を出しにくい…という人には
割とマッチするかもしれません。
ぼくはオススメはしませんが!!!
2014年振り返りと2015年
まずは振り返ってみる。
家電その他の故障率が異常
最初に仕事の話持ってこようかと思ったんですが、
去年一番印象に残っているのは とにかくモノがよく壊れた ということ。
壊れたもの一覧。
- 冷蔵庫
- 洗濯機
- 炊飯器
- 給湯器
- 自転車
- イヤホン
「家電は一気に壊れる」といいますが、本当に立て続けにきたのでびびった。
これだけで50万くらい飛んでる。。
というわけで家電用に自分で修繕積立することにした。
みなさまもしておいたほうが良いですよ!
仕事
2014年前半はかなり駆け抜けた感がありますが、後半は今後に向けてひっそりと動いてた感じです。
(サボっていたわけではない!!!!)
今年は忙しくなりそうなヨカン。たぶん。
業務内容のほうですが、サーバ運用の部分を勉強しつつ
新たにLuaやGolang触ってみたり、相変わらず広く浅くやってる感じでした。
Dockerはそれなりに触っていて開発フローにも組み込んでいたりするので
来年は本番運用にも持って行きたいと思っています。
またあまり技術的な話ではないんですけど、去年はチーム開発をするにあたって
自分の中で HRT(謙虚/尊敬/信頼) を特に意識していました。
システム開発ではメンバー間の衝突*1することはよくあることですが
基本的には自分よりも相手の方を尊重して進めてた(つもり…)*2
というか「チームの雰囲気を悪くしない心構え」というか。
結構大事だと思った。
その他ではYAPCでトークできたこともあってか色んな意味で広がりました。とても良かった。
今気になってるOSSやキーワードなど。いくつか取り入れていきたい。
家庭
上の子はすっかり大きくなって、きちんと(?)人っぽくなってきた。
ただ最近また言うこと聞かなくなってきているので真面目にしつけしないとなぁと思ってる…
下の子は3才になってますます可愛くなってる…が、女の子だからかわからないけど主張が強い。
あとジャイアンみたいに「人のものは私のもの」という感じなので見ててヒヤヒヤする。
パンチ、キックが得意。
2015年
特にこれといって大きな目標は決めてないんですけど、*3
今年は色んな意味でバリュー出すチャンスがありそうなので
それを逃さずに自分を高められればいいかなと思ってます。
では、本年もよろしくお願いします!!!!
lua-resty-woothee というモジュールを書きました
Lua Advent Calendar 2014 7日目の記事です。
wootheeというUA解析プロジェクトを最近知ったのですが、
Lua版が無さそうだったので書いてみました。
本当はLua単体で動くようにしたかったんですが、諸事情によりOpenresty依存となっております。
理由は後述。
ちなみに書いた動機など。
- ちょうど、エンドユーザのUA解析してDB登録したりゴニョゴニョ出来たらいいなーと思っていた
- Nginx+Luaを書き始めているが、がっつりLuaを触っていたわけではないのでライブラリっぽいのも練習がてら書いてみたかった
- 期待された https://twitter.com/songmu/status/525610905946447872
使い方
READMEそのままですが…
インストール
luarocks install https://raw.githubusercontent.com/toritori0318/lua-resty-woothee/master/lua-resty-woothee-dev-1.rockspec
または git clone でリポジトリダウンロード後に
lua_package_path をよしなに指定すると使えるようになります。
アップデートしたい場合は、再インストールしてNginxをリスタートするだけで行けるはず。
基本
server { location /test { content_by_lua ' local woothee = require "resty.woothee" -- parse local r = woothee.parse(ngx.var.http_user_agent) -- => {"name": "xxx", "category": "xxx", "os": "xxx", "version": "xxx", "vendor": "xxx"} -- crawler? local crawler = woothee.is_crawler(ngx.var.http_user_agent) -- => true ngx.header.content_type = "text/plain" ngx.say(r.name) '; } }
あとはparseメソッドにUserAgent渡せば結果がtableで返ってきます。簡単。
応用編
parseした結果をアクセスログに直接埋め込んだり、プロキシしているバックエンドサーバに渡したりと
いろいろ応用が効きそうですね。
この辺りのサンプルもREADMEに書いてあるので参考にどうぞ。
アクセスログ出力した時はこんな感じでparseした情報を付与できます。
xxx.xxx.xxx.xxx - - [01/Nov/2014:15:47:38 +0000] "GET /test HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36" "Chrome" "pc" "Mac OSX" "38.0.2125.111" "Google" "10.9.5" xxx.xxx.xxx.xxx - - [01/Nov/2014:15:47:41 +0000] "GET /test HTTP/1.1" 200 18 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:33.0) Gecko/20100101 Firefox/33.0" "Firefox" "pc" "Mac OSX" "33.0" "Mozilla" "10.9" xxx.xxx.xxx.xxx - - [01/Nov/2014:15:48:01 +0000] "GET /test HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/600.1.17 (KHTML, like Gecko) Version/7.1 Safari/537.85.10" "Safari" "pc" "Mac OSX" "7.1" "Apple" "10.9.5"
Openresty依存になった理由など
実は最初はLua単体で動くように書いていました。
実装がだいたい終わってよっしゃーテストやるぞーとテスト通し始めたら
全然テスト通らん\(^o^)/
で、あとで知ったんですが(オイ) Luaのは正規表現というか独自パターンマッチングなのでそりゃ通らないわけですね。
最初は独自の方に寄せようとしたんですが「(a|b)」とか「()?」とか使えなくてだいぶ辛い…
正規表現ライブラリ使うことも考えたんですが
あまり他のライブラリに依存するとユーザの導入障壁が高くなるでしょうし、
自分は(そして多分殆どの人が)Openrestyでしか使わないでしょうし、
OpenrestyはPCREの正規表現実装を含んでいるのでそれ使えば解決するし、
という感じでOpenresty依存にしました。
(関連する会話 https://twitter.com/toritori0318/status/527151195719077891)
この辺り、うまく共存してOpenresty依存無くすことも出来るかもしれないですが
自分は必要なかったのでそこは頑張りませんでした。
もしLua単体で動かしたいという要件があれば挑戦してみてください。
まとめ
Nginx+luaで解析することによって
高いパフォーマンスで、かつ汎用的に解析結果を使えるようになりました。
大抵はアプリケーションサーバよりNginxのほうがリソース空いていることが多いと思いますし、
そちらによけいな処理をお任せしてしまうのは悪いことではないと思います。
よろしければ使ってみてください〜
おまけ1:luaのyamlモジュールでハマった
http://yaml.luaforge.net/
これの最新版使ったらバグなのかわからないけどtestsetsのparse結果がおかしくてめっちゃハマった。つらい*1
おまけ2:Nginxのset変数はLuaから定義出来ない
Nginxのset変数もライブラリの中からよしなに出来ればもう少しシンプルに書けるかなと思いましたが
"That is, nginx variables cannot be created on-the-fly." とのことでした:(
おまけ3:Openrestyモジュールのテストについて
Openrestyモジュールのテスト、coreから野良モジュールまでほとんどperlのTest::Nginxで書かれています。
「perl...うっ」となるかもしれないですが、実際にperlを知らなくても書けます。
なかなか面白い手法だったので紹介してみます。
# vim:set ft= ts=4 sw=4 et: use Test::Nginx::Socket::Lua; use Cwd qw(cwd); repeat_each(1); plan tests => repeat_each() * (3 * blocks()); my $pwd = cwd(); our $HttpConfig = qq{ lua_package_path "$pwd/lib/?.lua;;"; }; $ENV{TEST_NGINX_RESOLVER} = '8.8.8.8'; no_long_string(); #no_diff(); run_tests(); __DATA__ === TEST 1: basic --- http_config eval: $::HttpConfig --- config location /t { content_by_lua ' local woothee = require "resty.woothee" ngx.say("OK") '; } --- request GET /t --- response_body OK --- no_error_log [error]
たとえばこちら、lua-resty-wootheeのテストです。
__DATA__ 以下のところだけ変えればOKです。
見たらわかりますが、Nginxコンフィグをそのまま記述して、期待するレスポンスを書く感じです。簡単ですね。
(ただ、printデバッグなどが非常に面倒なのが少し辛い…)
おまけ4:ベンチマーク
単純なLuaスクリプトと比較し、どの程度性能劣化するかを検証してみました。
now()を返すだけのLuaスクリプト
ab -c 10 -n 50000 -H "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)" http://localhost/now Requests per second: 10291.40 [#/sec] (mean)
woothee.parse ON
ab -c 10 -n 50000 -H "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)" http://localhost/test Requests per second: 8541.17 [#/sec] (mean)
たぶんUser-Agentによって多少は性能変化すると思いますが、許容範囲ではないでしょうか。
GitLab+DroneでHerokuにCIする、という最高の環境を10分で作る
※2015/4/17
GitLab7.9 / Drone0.3 版に記事をアップデートしました。
Drone0.3で大きく変更されたため、手順もだいぶ変わっています。
今回の手順で主な変更点としては以下の様なものがあります。
- GitLabでDroneアプリケーションを登録する必要がある
- Drone側でリポジトリをsyncする機能が追加され、その中から選択する方式になっている
- Herokuへのdeployについて、0.3からsshキーではなくAPIキー(token)を用いる方法に変更されている
GitLab+OSS版DroneをEC2に0から構築し、herokuにCIする
という環境を10分くらいで作ってみます*1
また、すこしだけDroneについての説明もメモ程度ですが書き記しておきます。
GitLabとは/Droneとは
GitLabはGitHubクローンのOSSです。
DroneはTravisやCircleCIに似たCIサービスです。
全てがDockerコンテナ上で動く、というのが特徴です。
OSS版も公開されていて、v0.2.1のREADMEを見ると
どのようなことができるかざっくり確認できると思います。
テストを動かしたり、S3やHerokuにパブリッシュしたり、DBコンテナを起動できたりと
主要なものは機能提供されていますし
普通にシェルスクリプトも書けるので柔軟なデプロイなども行うことが出来ます。
また現在は GitHub/GitLab/Bitbucket と連携することが出来るようです。
なのでGitLab限定というわけではないですよ:)
DroneのOSS版が公開されているので今回はこちらをEC2上に構築します。
構築環境
Droneがubuntu推奨らしいので、EC2のubuntu(ami-e74b60e6)に0から構築してみます。
たぶんt2.microでもよいですが、メモリが若干心配なのでt2.smallで構築してみました。
また、本番として使うときにはディスクサイズ多めで起動したほうが良いでしょう。
(さらにプラスでセキュリティ周りも追加しておいたほうが良いですね)
ami | ami-e74b60e6 |
インスタンスタイプ | t2.small |
Drone webポート | 80 |
GitLab webポート | 81 |
前準備
GitLabとDroneの連携について補足説明
連携するためにどういうことが必要か説明します。
- GitLabにDroneアプリケーションを登録。
- GitLabにリポジトリ登録。.drone.ymlを追加しておく。
- Droneの設定でGitLabのURLやクライアントキーを登録。
- DroneにログインするとGitLabのリポジトリ一覧がsyncされているので、CIしたいリポジトリをActiveにする
あとはGitLabのリポジトリが更新されると .drone.yml の内容でCIが実行されます。
意外と簡単。
GitLabにDroneアプリケーション登録
それでは設定を準備する手順を進めていきましょう。
まずはGitLabにDroneアプリケーションを登録します。
管理者用画面から「Applications」から名前とコールバックURLを登録します。
コールバックURLは「
この辺りのドキュメントはこちら。
GitLabにリポジトリ作成/Herokuへpush
次に、GitLabのGUIからリポジトリ作成しソースコードをpushしておきます。
今回はこちらのチュートリアルのコードを利用してみました。
さらにプラスで.drone.ymlを追加しておきましょう。以下のようなファイルを用意しておきます。
image: dockerfile/ubuntu deploy: heroku: app: gitlab-drone-test token: "<Herokuで確認したAPIキー>" force: false
また、この時点でHerokuへpushしておきましょう*2
Drone
コンフィグ設定
まず、インストール後にGitLabの情報を/etc/drone/drone.tomlに記述しておく必要があります。
[gitlab] url="http://<GitLabのURL>" client="<GitLabで登録したアプリケーションのApplication Id>" secret="<GitLabで登録したアプリケーションのSecret>" skip_verify=false open=false
修正後に restart drone で反映しておきます。
すると、Droneの画面で以下のような画面が表示されているはずです。
ここの GitLab のボタンをクリックするとGitLabへのOAuthが開始されるので
GitLabでログインしている情報でAcceptすると、DroneとGitLabの連携が完了します。
Drone:気になるところ/ハマりどころ
CI速度について
一度目、Dockerイメージのpullが入ると遅いですが
二回目以降は速くなるので気にしなくてよいです。
公式のイメージサイズがバカでかい
割とサイズが大きい物が多いので、自前で必要な物だけインストールしたイメージを使うのが良いでしょう。
Dockerなので
ディスク容量には気をつけましょう。
コンテナに入りたいナリ〜
Droneの機能としては(おそらく)提供されていないので入るのは難しそうです。
.drone.ymlがscriptの羅列だけであれば
ローカルで同じコンテナ起動してscript実行してみる、というくらいでしょうか…
(もしかしたらもっといい方法があるのかも)
まとめ
繰り返しますが、このスクリプトを実行すると一発で構築できます!!
またここでは詳しく説明しませんでしたが、
OSS版Droneがよく出来ているのでお手軽CIツールとしてだいぶ良いのではないでしょうか。
オススメです!
Drone:ref
- Stable版のREADME https://github.com/drone/drone/tree/22268eb2e669619b8dbc4b92f65a487eec946861
- 公開されているOSS版ドキュメント(ちょっと古い)http://drone.readthedocs.org/en/latest/index.html
- 上記の最新版?ドキュメント(自前ビルドが必要)https://github.com/drone/docs
- サービス版ドキュメント(OSS版と異なる部分が多いので参考程度に) http://docs.drone.io/
- 使える環境変数など http://docs.drone.io/env.html
- Drone用ダッシュボード https://github.com/drone/drone-wall