Why isn't the simple command ruby my app.rb
working to boot up my Sinatra application from within a Docker container?
I have a very simple Sinatra app:
# myapp.rb
require 'sinatra'
get '/' do
'Hello world!'
end
I run this locally with ruby myapp.rb
and I get the following output
== Sinatra (v2.1.0) has taken the stage on 4567 for development with backup from Puma
Puma starting in single mode...
* Puma version: 5.1.1 (ruby 2.7.0-p0) ("At Your Service")
* Min threads: 0
* Max threads: 5
* Environment: development
* PID: 49242
* Listening on http://127.0.0.1:4567
* Listening on http://[::1]:4567
Use Ctrl-C to stop
Opens up on http://127.0.0.1:4567 with no issue. When moving to Dockerize the app, I create a Gemfile with Sinatra and the following Dockerfile.
FROM ruby:2.7.0
WORKDIR /code
COPY . /code
RUN bundle install
CMD ["ruby", "myapp.rb"]
Standing up the container, it seem successful (Docker Desktop is green, no terminal errors), but clicking on the suggested link http://localhost:4567/ doesn't load (sad Chrome face). Logs from within the container look like so
[2020-12-27 18:04:52] INFO WEBrick 1.6.0
[2020-12-27 18:04:52] INFO ruby 2.7.0 (2019-12-25) [x86_64-linux]
== Sinatra (v2.1.0) has taken the stage on 4567 for development with backup from WEBrick
[2020-12-27 18:04:52] INFO WEBrick::HTTPServer#start: pid=1 port=4567
However, when I add the below config.ru file and change the last line of my Dockerfile to CMD ["bundle", "exec", "rackup", "--host", "0.0.0.0", "-p", "4567"]
, http://localhost:4567/ opens with no issue.
# config.ru
require './myapp'
run Sinatra::Application
Why are these tweaks necessary to make the app work? The logs from with the container look nearly the same.
[2020-12-27 18:01:49] INFO WEBrick 1.6.0
[2020-12-27 18:01:49] INFO ruby 2.7.0 (2019-12-25) [x86_64-linux]
[2020-12-27 18:01:49] INFO WEBrick::HTTPServer#start: pid=1 port=4567
172.17.0.1 - - [27/Dec/2020:18:02:44 +0000] "GET / HTTP/1.1" 200 12 0.0420
I'm not necessarily wondering about "best practices" here (this is a side project). I'm more just trying to understand what I might be missing about how Dockerizing apps works.
Docker commands for both cases (and I clear the images/containers between runs):
docker build --tag sinatra-img .
docker run --name sinatra-app -dp 4567:4567 sinatra-img
When you start your app with ruby myapp.rb
in a Docker container, your app is listening on localhost
because it is running in development mode. If your Docker server runs in a VM, you won't be able to access your app. To fix this, when you run your app in a Docker container, make sure that it is listening on 0.0.0.0: ruby myapp.rb -o 0.0.0.0