6
votes

I'm not sure how to a correctly expose the Sinatra port 4567 from Docker back to the host. Running the app locally has no issues.

The following repository show cases the issue https://gitlab.com/davidhooey/sinatra-docker

From searching I noticed the following issue Running Ruby Sinatra inside a Docker container not able to connect (via Mac host) or find commands (in different scenario)? where the --host 0.0.0.0 is passed into the rackup command. However, I'm launching the site programmatically through using Site.run!.

File tree

.
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── README.md
├── app.rb
├── docker-compose.yml
├── site.rb
└── views
    └── index.erb

app.rb

module App
    class App
        def initialize(args)
            # Do some stuff before launching site.
            # Launch site
            Site.run!
        end
    end
end

App::App.new(ARGV)

In site.rb the :bind Sinatra setting is set to 0.0.0.0.

site.rb

require 'sinatra'

module App
    class Site < Sinatra::Base
        set :bind, '0.0.0.0'
        set :static, true
        set :public_dir, File.expand_path(__dir__)

        get '/' do
            erb :'/index'
        end
    end
end

Even still the site is inaccessible when run within a Docker container.

Dockfile

FROM ruby:2.2.6

EXPOSE 4567

RUN mkdir /app
WORKDIR /app
COPY . /app

RUN gem install bundler && bundle install

CMD ["/bin/bash"]

docker-compose.yml

version: '3.2'

services:
    app:
        build: .
        hostname: app
        ports:
            - "4567:4567"
        environment:
            - RUBYOPT=-W0 -KU -E utf-8:utf-8
        volumes:
            - type: bind
              source: .
              target: /app

Local works:

ruby app.rb

Docker not so much:

docker-compose build
docker-compose run --rm app ruby app.rb

Docker run example.

$ docker-compose run --rm app ruby app.rb
[2018-07-27 14:21:10] INFO  WEBrick 1.3.1
[2018-07-27 14:21:10] INFO  ruby 2.2.6 (2016-11-15) [x86_64-linux]
== Sinatra (v2.0.3) has taken the stage on 4567 for development with backup from WEBrick
[2018-07-27 14:21:10] INFO  WEBrick::HTTPServer#start: pid=1 port=4567

Launch a bash shell into the running container to access Sinatra within the container.

$ docker exec -it aa8f64b009b0 bash
root@app:/app# curl localhost:4567
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Sinatra Docker</title>
    </head>
   <body>
        <h1>Sinatra Docker</h1>
   </body>
</html>
root@app:/app#

Any ideas are more than welcome on how to access the Sinatra port running within the container from the localhost when Sinatra is launched programmatically.

1
Did you log into the docker image to check that your app is running properly and bound to an interface? - Casper
I have added the Docker Run, showing the startup of Sinatra within the container. Seems like it is starting on the port without issues. - hooinator

1 Answers

7
votes

When running an app with docker-compose run, service ports will not be mapped. This is by design, because run is meant for one-off tasks and not for booting the whole compose stack.

See documentation here:
https://docs.docker.com/compose/reference/run/

The second difference is that the docker-compose run command does not create any of the ports specified in the service configuration. This prevents port collisions with already-open ports.

To map the ports you either need to use run with --service-ports, or add a command section to your docker-compose.yml and then use docker-compose up:

Option 1 (using run):

docker-compose run --service-ports --rm app ruby app.rb -o 0.0.0.0

Option 2 (booting the whole stack):

services:
  app:
    build: .
    hostname: app
    command: ruby app.rb -o 0.0.0.0  # <-- Add this
    ports:
      - "4567:4567"
    ...

And then:

docker-compose up