OSXでDockerを試す
雪がひどすぎて外出る気がしない。あー、そういえば、DockerがOSX対応したっていうし、ぼちぼち試してみるかー、と思って http://docs.docker.io/en/latest/installation/vagrant/ みてみたけど、あんまりかわってない気がする、というみなさんこんにちは。
そのページは前からあまり変わっていなくて、
https://github.com/dotcloud/docker/blob/master/docs/sources/installation/mac.rst
こっちが新しい手順らしい。
手順はそのままな気がするけど、homebrewでやればもうちょい簡単なようです。
まずは事前にVirtualBoxをInstallしておきます。
brew tap homebrew/binary brew install docker brew install boot2docker
とやればcurlでごにょごにょしなくてもPATHへ入れてくれます。
すると、boot2dockerとdockerというコマンドができるので、
boot2docker init boot2docker up
とやると、VirtualBox上でDockerが動作するLinuxマシンが起動する。
ローカルのOSXのポート転送してこのVM内のDocker daemonへ飛ばすように設定されているので、
OSX側のTerminalから、
DOCKER_HOST=localhost docker run ubuntu /bin/echo "hello docker"
とかやると、あたかもOSXからそのままDockerできるようになる、という感じらしい。
DOCKER_HOST=localhostをしないと、
2014/02/08 10:57:50 dial unix /var/run/docker.sock: no such file or directory
というエラーが出るのでexportしておくとよい。
あとは、ふつうにチュートリアルをひととおりこなせばよい。
最初と同じく更新が追いついてないっぽいので直接リポジトリ側をみた方がよさげ。
https://github.com/dotcloud/docker/tree/master/docs/sources/examples
Vagrantを入れてなくてもできるようになった。Vagrant sshしなくてもよい、というぐらいではありますが、確かにお手軽に試せるようになったようです。
追記
チュートリアルとかやるときにポートにバインドする例とかあるけど、残念ながら、OSX側にはバインドされないので、boot2docker sshしてログインしたあとにバインドしたポートを叩かないといけないもよう。このあたりvirtualboxのイメージに対して名前でアクセスできて、直接ポートアクセスできる、とかであればよいんだけどな。。。
VirtualBoxのマシンの設定をいじって、Host Onlyアダプタを追加しておけば、いちいちポートフォワードしなくてよいのでよさげ。
Server-Sent Events覚え書き
なかなか書く機会はなかったのだけど、ふと使えそう!、という場面があったので、Server-Sent Eventsを書いてみたのでメモ。
レスポンスのContent-Typeはtext/event-stream
dataを組み立てる際は、改行(\r, \n, \r\n)をエスケープする。 http://www.w3.org/TR/eventsource/#parsing-an-event-stream
http://dev.ariel-networks.com/wp/archives/4168
任意に改行を入れられると、任意のイベントを定義されてしまうので、何らかの入力を元に出力するときには、改行コードのエスケープが必要。
UTF-8であること、という制約もあり、とりあえずはJSONにしておくのが扱いやすくてよさげ。
JSONにするときに改行はエンコードしてくれないことがあるっぽいので、そこを処理するか、改行で分割してからJSONにするのが良いっぽい。
idを指定しておくと、retry時にLast-Event-Idヘッダにどこまで受信したか教えつつリクエストしてくれる
reconnect/retryが仕様化されているのが非常にすばらですね。
bufferingされると少し遅延がある
frontにnginxがいて、proxy_bufferingがonのとき(デフォルトなのでだいたいのとき)は、X-Accel-Bufferingをoffもつけると遅延されなくなる。
HTML Media Captureの記述の仕方
webでHTML Media Captureについてググると、上の方にでてくるコンテンツはわりと、
<input type="file" accept="image/*;capture=camera" />
とか、
<input type="file" accept="image/*" capture="camera" />
とか書いてあったりするのだけど、http://www.w3.org/TR/html-media-capture/ を見たら、
partial interface HTMLInputElement { attribute boolean capture; };
のようになっていて、capture属性はbooleanになっているなー、ということで、
<input type="file" name="image" accept="image/*" capture>
のように書くらしい。
なんでだろーと思って調べてみたら、
http://www.w3.org/TR/2012/WD-html-media-capture-20120712/
のときの仕様だと、上の方の書き方で、最新のものだと、captureがbooleanになるらしい。
20120712以降で改訂ということは、それ以前のブラウザだと、上の書き方じゃないと動かなかったりすることあるのかな。。。
mod_proxy_balancerで振り先が//にならないようにする。
<Proxy balancer://app> BalancerMember http://192.168.0.1/ </Proxy> <VirtualHost *:80> ProxyPass / balancer://app/ </VirtualHost>
のように、BalancerMemberの定義の末尾に"/"をつけると、振り先で、//に対して振るようになってしまうっぽいので、つけないように気をつける。
<Proxy balancer://app> BalancerMember http://192.168.0.1 </Proxy> <VirtualHost *:80> ProxyPass / balancer://app/ </VirtualHost>
dalliはfork safeか?
ふと、dalliがunicornなどのmulti processで動作するアプリケーションで動かしたときにコネクションを張りなおす処理をしないといけないか気になったので、調べてみた。
これを実行してみると、
true 1 I, [2014-01-07T00:27:41.396287 #9290] INFO -- : localhost:11211 failed (count: 0) I, [2014-01-07T00:27:41.396622 #9291] INFO -- : localhost:11211 failed (count: 0) I, [2014-01-07T00:27:41.396905 #9292] INFO -- : localhost:11211 failed (count: 0) I, [2014-01-07T00:27:41.397327 #9293] INFO -- : localhost:11211 failed (count: 0) I, [2014-01-07T00:27:41.397726 #9294] INFO -- : localhost:11211 failed (count: 0) I, [2014-01-07T00:27:41.398108 #9295] INFO -- : localhost:11211 failed (count: 0) I, [2014-01-07T00:27:41.398495 #9296] INFO -- : localhost:11211 failed (count: 0) I, [2014-01-07T00:27:41.399108 #9297] INFO -- : localhost:11211 failed (count: 0) I, [2014-01-07T00:27:41.399440 #9298] INFO -- : localhost:11211 failed (count: 0) I, [2014-01-07T00:27:41.399961 #9299] INFO -- : localhost:11211 failed (count: 0) [9290, 0, 1] [9292, 0, 1] [9291, 0, 1] [9290, 1, 1] [9293, 0, 1]
こんな感じになり、forkした直後のログで失敗した、というエラーメッセージが出るが、その後、再接続し、通信できているようだ。
dalliのソースコード(acb1ff3afd4d)をpidでgrepすると、
# lib/dalli/server.rb def verify_state failure!(RuntimeError.new('Already writing to socket')) if @inprogress failure!(RuntimeError.new('Cannot share client between multiple processes')) if @pid && @pid != Process.pid end
という処理が出てきて、newしたときと、pidが変わっているかをチェックしていることがわかる。
このverify_stateはクライアントがリクエストしようとしたときには必ず通過するようになっているので、これでpidの変更を検出しているようだ。
failureの中では、
def failure!(exception) message = "#{hostname}:#{port} failed (count: #{@fail_count}) #{exception.class}: #{exception.message}" Dalli.logger.info { message } @fail_count += 1 if @fail_count >= options[:socket_max_failures] down! else close sleep(options[:socket_failure_delay]) if options[:socket_failure_delay] raise Dalli::NetworkError, "Socket operation failed, retrying..." end end
のようになっていて、失敗回数を保持するカウンタを1あげつつ、例外を吐いている。
ここで発生させた例外は、
# lib/dalli/client.rb # Chokepoint method for instrumentation def perform(*all_args, &blk) return blk.call if blk op, key, *args = *all_args key = key.to_s key = validate_key(key) begin server = ring.server_for_key(key) ret = server.request(op, key, *args) ret rescue NetworkError => e Dalli.logger.debug { e.inspect } Dalli.logger.debug { "retrying request with new server" } retry end end
serverを呼びだしている元の、performメソッドで、rescueされて、retryするようだ。
pidファイルの管理をする
pgrep -F pidfileオプションを使うと、pidfileを開いて、その中にあるプロセスIDが存在するか調べ、存在している場合には、0で終了してくれるようだ。
なので、起動スクリプトとかで、pidfileの存在チェックとかをするときには、
if test -e $PIDFILE && pgrep -F $PIDFILE > /dev/null; then restart fi
とか書いてやれば、マシンがハングアップとかして、正常に終了しなくて、pidfileが残っているがファイル内にあるプロセスIDはもういない場合にrestartをしても悲しいことにならずにすむ。
なるほどUNIXプロセス
http://tatsu-zine.com/books/naruhounix
帰省中の新幹線でナルホディウス!しながら読んだ。
中身としては思っていたよりはライトな内容で、わりと知っていることだった。
Resqueのworkerが毎回worker実行するときにforkするのはなんでだろーと思っていたので、そこの解説はよかった。
Resqueのところで、fork時にsrandしている説明があるが、これは解説通りごくごく一部のバージョンのバグなどで動かないというだけなので、以前調査したように、rubyではsrandする必要はない。
waitpid(2)が、子プロセスが死んでしまってから親プロセスが実行しても、Kernelがちゃんと動作を保証してくれる、というのは知らなかったので良い発見だった。
Kindleで読む気だったのだけど、Kindleがちょうど応答不能になってしまっていた関係で、泣く泣くPCで、iBookで読んだのだけど、Kindleよりは目が疲れるけど、サンプルすぐ試したりできるし、PCで本読むのはふつうにありだなと思いました。Cracking The Coding Interviewは重くて持ち運びにくいので、電子版も欲しくなってしまった