Rack 1.6 な Sinatra アプリケーションに Docker コンテナ外からアクセスできなかった

Posted on
qiita Ruby Sinatra rack Docker

この記事はQiitaの記事をエクスポートしたものです。内容が古くなっている可能性があります。

  • [2015-01-24 05:00] @5t111111 さんのコメントに基づき、Rack 1.6 のデフォルト挙動について追記

Rack 1.6.0 を使用した Sinatra アプリケーションを Docker 上で起動したところ、コンテナ外からの接続ができませんでした。EXPOSE 9292 して -p 9292:9292 しているにも関わらず、です。 とりあえずの対処法を書いておきます。

アプリケーション構成例

最小構成の Sinatra アプリケーションを Docker 上で動かすためのファイル例を Gist に上げました。

https://gist.github.com/dtan4/373907a001f3f3ebbd9c

はじめに言っておくと、Ruby のバージョンを変えること(2.1.5 にするとか)は解決になりませんでした。Ruby 2.2.0 のせいとかではない。

あと Docker のバージョンは (2015-01-21 最新の)1.4.1 です。

対処法1: Rack 1.5.2 を使う

一つ前のバージョンである Rack 1.5.2 であればこの問題は発生しません。Gemfile でバージョン指定しましょう。

gem "rack", "~> 1.5.2" # or "= 1.5.2"

対処法2: rackup-o 0.0.0.0 オプションをつける

rackup --help より、

-o は ListenAddress を設定するためのオプションです。

  -o, --host HOST          listen on HOST (default: 0.0.0.0)

というように 0.0.0.0 がデフォルトで設定されるよ、と書いてありますが明示的に指定してあげます。Dockerfile だと最後の CMD がこういう感じになります。

CMD ["bundle", "exec", "rackup", "-p", "9292", "-E", "production", "-o", "0.0.0.0"]

— 2015-01-24 05:00 追記 —

Rack 1.6 からは、明示的に指定しない限り localhost のみを listen するような変更が加わったとのことです。公衆 Wi-Fi につないでるような場合に、他の端末からアクセスされないようにするためです。

プルリクは rack/rack#514 該当コミットは 28b0144

ということで上のヘルプメッセージは変更に追随できてないのですが、これもコミット 076711a で修正が入りました。 次のリリースでは直っているはず!

教えてくださった @5t111111 さん、ありがとうございました。

— 追記ここまで —


ちなみに、localhost からアクセスした時のログですが

-o 0.0.0.0 なしの場合、以下のようにリクエスト元 IP が IPv6 に、

::1 - - [21/Jan/2015:15:35:31 +0900] "GET / HTTP/1.1" 200 8056 2.2458

-o 0.0.0.0 ありの場合、以下のようにリクエスト元 IP が IPv4 になっています。Rack 1.5.2 でも同様のログが得られます。

127.0.0.1 - - [21/Jan/2015:15:37:11 +0900] "GET / HTTP/1.1" 200 8056 2.0355

詳しくはまだ追えていないのですが、多分 Docker のネットワーク部で IPv6 と IPv4 の対応か何かができてないのが理由かな…と思っています。 デフォルト値をそのまま指定しているのに、挙動が変わる Rack もなんか不自然ですが…

— 2015-01-24 05:00 追記 —

上に追記しましたが、Rack 1.6 からはデフォルトで localhost のみを listen するようになりました。この状態では、コンテナ外からアクセス出来ないのは当然ですね…。 (ヘルプに書かれた)デフォルト値をそのまま指定して挙動が変わるの、ヘルプが間違っているのですからこれまた当然です…。 Docker の挙動の問題ではありませんでした。

— 追記ここまで —

おわりに

Rack 1.6 な Sinatra アプリケーションに Docker コンテナ外からアクセスするための対処法を紹介しました。Sinatra アプリケーションを bundle update する際は注意してください。

ここに上げた方法は、その場しのぎの対応である感じが否めません。Docker のネットワーク周り確認したり、Rack のソースコード読まないといけませんね(1.5.2 -> 1.6.0 の ChangeLog が無いの厳しい…)。