Gregology
Gregology

Reputation: 1725

docker-compose rails app not accessible on port 3000

I'm building docker containers for a simple rails/postgres app. The rails app has started and is listening on port 3000. I have exposed port 3000 for the rails container. However, http://localhost:3000 is responding with ERR_EMPTY_RESPONSE. I assumed that the rails container should be accessible on port 3000. Is there something else I need to do?

greg@MemeMachine ~ $ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                    NAMES
eed45208bbda        realestate_web      "entrypoint.sh bash …"   About a minute ago   Up About a minute   0.0.0.0:3000->3000/tcp   realestate_web_1
a9cb8cae310e        postgres            "docker-entrypoint.s…"   About a minute ago   Up About a minute   5432/tcp                 realestate_db_1
greg@MemeMachine ~ $ docker logs realestate_web_1
=> Booting Puma
=> Rails 6.0.2.2 application starting in development 
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 3.12.4 (ruby 2.6.3-p62), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop
greg@MemeMachine ~ $ curl http://localhost:3000
curl: (52) Empty reply from server

Dockerfile

FROM ruby:2.6.3

RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN gem install bundler -v 2.0.2
RUN bundle install
COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

docker-compose.yml

version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    env_file:
      - '.env'
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
    env_file:
      - '.env'

entrypoint.sh

#!/bin/bash

# Compile the assets
bundle exec rake assets:precompile

# Start the server
bundle exec rails server

Upvotes: 5

Views: 3390

Answers (2)

David Maze
David Maze

Reputation: 158908

When you provide both an ENTRYPOINT and a CMD, Docker combines them together into a single command. If you just docker run your image as it's built, the entrypoint script gets passed the command part rails server -b 0.0.0.0 as command-line parameters; but it ignores this and just launches the Rails server itself (in this case, without the import -b 0.0.0.0 option).

The usual answer to this is to not try to run the main process directly in the entrypoint, but instead end the script with exec "$@" to run the command from additional arguments.

In this case, there are two additional bits. The command: in the docker-compose.yml file indicates that there's some additional setup that needs to be done in the entrypoint (you should not need to override the image's command to run the same server). You also need the additional environment setup that bundle exec provides. Moving this all into the entrypoint script, you get

#!/bin/sh
# ^^^ this script only uses POSIX shell features

# Compile the assets
bundle exec rake assets:precompile

# Clean a stale pid file
rm -f tmp/pids/server.pid

# Run the main container process, inside the Bundler context
exec bundle exec "$@"

Your Dockerfile can stay as it is; you can remove the duplicate command: from the docker-compose.yml file.

Upvotes: 4

Sijmen
Sijmen

Reputation: 506

 * Listening on tcp://localhost:3000

This logline makes me think rails is binding to only the localhost ip. This means that rails will only listen to requests from within the container. To make rails bind to all ips, and listen to requests from outside the container you use the rails server -b parameter. The last line in your entrypoint.sh should change to:

bundle exec rails server -b 0.0.0.0

Upvotes: 4

Related Questions