Search code examples
ruby-on-railspostgresqldockerpuma

Docker (rails, postgresql) hanging when started, rather than connecting to DB


I'm new to docker, and trying to workout why my Docker setup is hanging and not connecting like I expect it to.

I'm running

  • Docker version 18.09.2, build 6247962
  • docker-compose version 1.23.2, build 1110ad01
  • OSX 10.14.5

My setup is based on this Gist that I found.

I've reduced it somewhat, to better demonstrate the issue.

Dockerfile

FROM ruby:2.4

ARG DEBIAN_FRONTEND=noninteractive

RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main" >> /etc/apt/sources.list.d/postgeresql.list \
 && wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
 && apt-get update                                     \
 && apt-get update                                     \
 && apt-get install -y --no-install-recommends apt-utils \
 && apt-get install -y build-essential \
 && apt-get install -y nodejs \
 && apt-get install -y --no-install-recommends         \
   postgresql-client-9.6 pv ack-grep ccze unp htop vim \
 && apt-get install -y libxml2-dev libxslt1-dev \
 && rm -rf /var/lib/apt/lists/*                        \
 && apt-get purge -y --auto-remove

# Set environment
ENV APP_HOME /usr/src/app
ENV BUNDLER_VERSION 2.0.2

# Setup bundler
RUN gem install bundler -v $BUNDLER_VERSION

WORKDIR $APP_HOME

EXPOSE 7051

CMD ["bundle", "exec", "puma", "-p", "7051", "-C", "config/puma.rb"]

docker_compose.yml

version: '3.1'
services:
  app: &app_base
    build: .
    working_dir: /usr/src/app
    volumes:
      - .:/usr/src/app
      # to be able to forward ssh-agent to github through capistrano (bundle on server)
      - "~/.ssh/id_rsa:/root/.ssh/id_rsa"
      - $SSH_AUTH_SOCK:$SSH_AUTH_SOCK
    environment: &app_environment
      # to keep bundle effect between container restarts (without rebuild):
      BUNDLE_PATH: /usr/src/app/.bundle
      BUNDLE_APP_CONFIG: /usr/src/app/.bundle
      DATABASE_HOST: db
      SSH_AUTH_SOCK: # this left empty copies from outside env
    env_file: '.env'
    ports:
      - "7051:7051"
    depends_on:
      - db

  db:
    image: postgres:9.5.17
    ports:
      - "5432:5432"
    environment:
      POSTGRES_DB: my_project_development
      POSTGRES_USER: root
      POSTGRES_PASSWORD: root

config/database.yml

development:
  adapter: postgresql
  encoding: unicode
  pool: 5
  database: my_project_development
  username: root
  password: root
  host: db

config/puma.rb

threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count

# Specifies the `port` that Puma will listen on to receive requests, default is 3000.
#
port        ENV.fetch("PORT") { 7051 }

# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV") { "development" }

# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart

So what I'm doing is:

  1. Running docker-compose build to first build the images & containers
  2. Running docker-compose run --rm app bundle install to install the gems
  3. Running docker-compose run --rm app bundle exec rake db:create db:migrate db:seed to create/migrate/seed the database

Step 3. is the step I am stuck on. It just hangs there with no feedback:

docker-compose run --rm app bundle exec rake db:create db:migrate db:seed
Starting my_project_db_1 ... done

I know the database is running, as I can connect to it locally.

I can also log into the app container, and connect via psql, so I know that the app container can talk to the db container:

docker exec -it f6d6edadaed4 /bin/bash                                                                                       (52s 699ms)
root@f6d6edadaed4:/usr/src/app# psql "postgresql://root:root@db:5432/my_project_development"
psql (9.6.14, server 9.5.17)
Type "help" for help.

my_project_development=# \dt
No relations found.

If I try to boot the app with docker-compose up, then it also just hangs:

app_1  | Puma starting in single mode...
app_1  | * Version 3.11.4 (ruby 2.4.6-p354), codename: Love Song
app_1  | * Min threads: 5, max threads: 5
app_1  | * Environment: ci

I.e. puma would normally show a 'listening' message once connected:

* Listening on tcp://0.0.0.0:7051
Use Ctrl-C to stop

But it's not getting to that point, it just hangs.

What could be going on? Why can't my Rails container just connect to the PostgreSQL container and have puma boot normally?

MORE INFORMATION:

I've learn't now, if I wait 10+ minutes, it does eventually boot!

During that 10 mins, my CPU fans are spinning like crazy, so it's really thinking about something.

But when it finishes, the CPU fans shut off, and puma has booted and I can access it locally at http://127.0.0.1:7051 like I would expect.

Why would it be so slow to startup? My machine is otherwise pretty fast.


Solution

  • I found an actual working answer to this, which I also posted here: https://stackoverflow.com/a/58603025/172973

    Basically, see the article here to see how to properly setup Dockerfile and docker-compose.yml, so that it performs well on OSX.

    The main thing to understand:

    To make Docker fast enough on MacOS follow these two rules: use :cached to mount source files and use volumes for generated content (assets, bundle, etc.).

    So if anyone else comes across this, just follow the article or see my other answer.