Rackをdockerで動かす



# モチベーション

Rackを知るために、小さなRackアプリケーションを動かしてみたいです。
Rubyは気軽にgem installすると環境が汚れるのでsandboxが欲しいです。
そこでdockerを使ってみます。

# ベースにするDokerfile
[library/ruby - Docker Hub](https://hub.docker.com/_/ruby/)の`ruby:2.4-alpine`を使います。

# 事前に必要なもの
- my_rack_app.rb
- Gemfile

## my_rack_app.rb
[Rack: a Ruby Webserver Interface](http://rack.github.io/)のサンプルを元に修正します。

### `shebang`を設定します。

```ruby:my_rack_app.rb
#! /usr/bin/env ruby

require 'rack'

app = Proc.new do |env|
    ['200', {'Content-Type' => 'text/html'}, ['A barebones rack app.']]
end

Rack::Handler::WEBrick.run app, {Host: '0.0.0.0'}
```

[Perl, Python 及び Ruby スクリプトにおける正しいshebangの書き方 - Qiita](http://qiita.com/tueda/items/369215b99316b2e9f3d8)

#### shebangを設定しないと
こんなエラーが出ます。

```
panic: standard_init_linux.go:175: exec user process caused "exec format error" [recovered]
	panic: standard_init_linux.go:175: exec user process caused "exec format error"

goroutine 1 [running, locked to thread]:
panic(0x88f8a0, 0xc820126d20)
	/usr/local/go/src/runtime/panic.go:481 +0x3e6
github.com/urfave/cli.HandleAction.func1(0xc8200f32e8)
	/tmp/tmp.n151sEscRu/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:478 +0x38e
panic(0x88f8a0, 0xc820126d20)
	/usr/local/go/src/runtime/panic.go:443 +0x4e9
github.com/opencontainers/runc/libcontainer.(*LinuxFactory).StartInitialization.func1(0xc8200f2bf8, 0xc82001a0c8, 0xc8200f2d08)
	/tmp/tmp.n151sEscRu/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/factory_linux.go:259 +0x136
github.com/opencontainers/runc/libcontainer.(*LinuxFactory).StartInitialization(0xc820059630, 0x7fbe739ea728, 0xc820126d20)
	/tmp/tmp.n151sEscRu/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/factory_linux.go:277 +0x5b1
main.glob.func8(0xc820076a00, 0x0, 0x0)
	/tmp/tmp.n151sEscRu/src/github.com/opencontainers/runc/main_unix.go:26 +0x68
reflect.Value.call(0x7f45a0, 0x9a4d88, 0x13, 0x8ebac8, 0x4, 0xc8200f3268, 0x1, 0x1, 0x0, 0x0, ...)
	/usr/local/go/src/reflect/value.go:435 +0x120d
reflect.Value.Call(0x7f45a0, 0x9a4d88, 0x13, 0xc8200f3268, 0x1, 0x1, 0x0, 0x0, 0x0)
	/usr/local/go/src/reflect/value.go:303 +0xb1
github.com/urfave/cli.HandleAction(0x7f45a0, 0x9a4d88, 0xc820076a00, 0x0, 0x0)
	/tmp/tmp.n151sEscRu/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:487 +0x2ee
github.com/urfave/cli.Command.Run(0x8ee970, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x984240, 0x51, 0x0, ...)
	/tmp/tmp.n151sEscRu/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/command.go:191 +0xfec
github.com/urfave/cli.(*App).Run(0xc820001800, 0xc82000a100, 0x2, 0x2, 0x0, 0x0)
	/tmp/tmp.n151sEscRu/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:240 +0xaa4
main.main()
	/tmp/tmp.n151sEscRu/src/github.com/opencontainers/runc/main.go:137 +0xe24
```

### Rackアプリケーションの起動時に引数を追加
`{Host: '0.0.0.0'}`を追加します。

```rb
Rack::Handler::WEBrick.run app, {Host: '0.0.0.0'}
```

- [Rack 1.6 な Sinatra アプリケーションに Docker コンテナ外からアクセスできなかった - Qiita](http://qiita.com/dtan4/items/c7c47b845b6f15c4076f)

> Rack 1.6 からは、明示的に指定しない限り localhost のみを listen するような変更が加わった

- [rack/webrick.rb at master · rack/rack](https://github.com/rack/rack/blob/master/lib/rack/handler/webrick.rb#L29)

オプションは`Host`で指定します。

### ホストで実行権限を設定します。

```
chmod +x my_rack_app.rb
```

#### 実行権限を設定しないと
こんなエラーがでます。

```
docker: Error response from daemon: invalid header field value "oci runtime error: container_linux.go:247: starting container process caused \"exec: \\\"./my_rack_app.rb\\\": permission denied\"\n".

```

## Gemfile
rackだけ入れます。

```
source 'https://rubygems.org'

gem 'rack'
```





# Dockerfile
```
FROM ruby:2.4-alpine

COPY Gemfile /

RUN bundle install --clean

COPY my_rack_app.rb /

CMD ["./my_rack_app.rb"]
```

# 実行
```
docker build -t my-ruby-app .
docker run --rm -p 8080:8080 my-ruby-app
```

`--rm`をつけて、終了時にコンテナを破棄します。
`-p`をつけて、ホストのポートにマッピングします。

- [Dockerのネットワークの基礎 | SOTA](http://deeeet.com/writing/2014/05/11/docker-network/)

> 外部ネットワークからコンテナにアクセスするには，コンテナを起動するときに外部ポートをdocker0に晒した内部portにマップする必要がある

# 動作確認

curlコマンドで動作確認します。

```
curl localhost:8080
```
で

```
A barebones rack app.
```

が、帰ってきます。


# 参考
- [Rack - Qiita](http://qiita.com/bibio/items/7e45af09f3b8a0146c9e) 
- [docker コマンド チートシート - Qiita](http://qiita.com/voluntas/items/68c1fd04dd3d507d4083)