6

I'm trying to containerize my Ruby on Rails 5.1.0 application, but I'm having some trouble with it not picking up DATABASE_URL from the environment. In docker-compose.yml, I have the following service:

app:
  build: .
  command: bundle exec rails s -p 3000 -b '0.0.0.0'
  volumes:
    - .:/myapp
  environment:
    DATABASE_URL: postgres://postgres:pw@db:5432/myapp_development

The environment gets picked up just fine if I run docker-compose run app rails c:

$ docker-compose run app rails c
Running via Spring preloader in process 25
Loading development environment (Rails 5.1.0)
irb(main):001:0> ENV['DATABASE_URL']
=> "postgres://postgres:pw@db:5432/myapp_development"

But then if I run docker-compose run app rake db:create, I get an error about not being able to connect to localhost:

$ docker-compose run app rake db:create
Database 'myapp_development' already exists
could not connect to server: Connection refused
    Is the server running on host "localhost" (::1) and accepting
    TCP/IP connections on port 5432?
could not connect to server: Connection refused
    Is the server running on host "localhost" (127.0.0.1) and accepting
    TCP/IP connections on port 5432?
Couldn't create database for {"adapter"=>"postgresql", "host"=>"localhost", "pool"=>10, "timeout"=>5000, "database"=>"myapp_test"}
rake aborted!

Any idea what I'm doing wrong here?

Edit: Here's what database.yml looks like:

common: &common
  adapter: postgresql
  pool: 10
  timeout: 5000

development:
  <<: *common
  database: myapp_development

test:
  <<: *common
  database: myapp_test

production:
  <<: *common
  database: myapp_production
1
  • I can share with you my solution, but it does't direct answer your question, so i put it in comment. You can add separated container to postgres, add host config to your database.yml that match postgres container name. Then log into container and you will be able to run any command you want without errors.I can put detailed answer if you are interested in. Commented Jun 22, 2017 at 6:36

4 Answers 4

3

I also had a similar issue, the causes of which were multi-fold.

TL;DR, make sure that:

  1. Your app container is correctly linked to and dependent on your postgres container
  2. Your DATABASE_URL references the correct hostname of your postgres container
  3. The RAILS_ENV ENV variable is explicitly set within your app container

First off, I had to make sure my app container in docker_compose.yml was linked to and depended on the postgres container:

version: '3'
    services:
      app:
        container_name: 'app'
        depends_on:
          - postgres
        links:
          - postgres

Second, the DATABASE_URL ENV variable I was providing database.yml did not reference the correct hostname of the postgres container. Originally, mine looked like:

'postgres://postgres:@localhost:5432/my_app_development'

I changed it to:

'postgres://postgres:@postgres:5432/my_app_development'

Not an apparent issue in your case, but worth noting for others.

Third, I wasn't explicitly specifying the RAILS_ENV environment. I set that ENV variable to development in docker_compose.yml so that the correct database.yml configuration was used.

The end result of my database.yml file:

development: &default
  adapter: postgresql
  encoding: unicode
  database: my_app_development
  username: postgres
  pool: 5
  timeout: 5000
  url: <%= ENV['DATABASE_URL'] %>

test:
  <<: *default
  database: my_app_test
  pool: 5
  url: <%= ENV['DATABASE_URL'] %>

production:
  <<: *default
  url: <%= ENV['DATABASE_URL'] %>

The end result of my docker_compose.yml file:

version: '3'
services:
  app:
    container_name: 'app'
    environment:
      DATABASE_URL: 'postgres://postgres:@postgres:5432/my_app_development'
      RAILS_ENV: 'development'
    build: .
    ports:
      - '3000:3000'
    volumes:
      - ./:/dev
    depends_on:
      - postgres
    links:
      - postgres
    tty: true

  postgres:
    container_name: 'postgres'
    image: postgres:9.5
    ports:
      - '5432:5432'
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD:

After that, all bundle exec rake db: commands worked just fine.

Hope that helps!

Sign up to request clarification or add additional context in comments.

1 Comment

Unfortunately, it doesn't
2

The problem is in the rake task, it is trying to create the test database, I assume your database.yml has a test environment with localhost host.

From the description of rake db:create

Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases in the config). Without RAILS_ENV it defaults to creating the development and test databases

You should pass the env evidently or it could create a test database by default.

I suggest you to change the test database credentionals in the database.yml.

Connection Preference

6 Comments

This makes sense, but I don't understand why it tells me to that myapp_development already exists, and then doesn't connect when trying to create myapp_test – in database.yml they connect to the same place. I'll edit my answer to include database.yml.
I don't get your comment. Change the database.yml and set the host evidently in the both environments.
But isn't it the case that I don't need to set the host if I'm providing a DATABASE_URL in the environment?
Yes, it is. Looks like for some reason the env varaible was not exported.
Also the matter thing is in some cases the database.yml have the preference over env configuration.
|
1

I had the same issue, it seems like the config merging is somehow broken on Rails 5.1.x

You can force the use of DATABASE_URL by adding url: <%= ENV['DATABASE_URL'] %> in your default block.

Comments

0

I think @Зелёныйenter's answer is mostly correct, the problem is that the rake task is trying to create databases for development and test.

The line

Database 'myapp_development' already exists

is probably there because the DB was created in a previous execution of the same command, that created the DB and also failed in trying to create the test DB.

One would think that by specifying the DB name in the URL, in this case myapp_development

DATABASE_URL: postgres://postgres:pw@db:5432/myapp_development

that would be the only DB to create, but it is not. I used DATABASE_URL without specifying the DB name, like:

DATABASE_URL: postgres://postgres:pw@db:5432

with the same result, one created, one failed.

As I understand, however, this is not a problem of RAILS_ENV definition. This is expected behaviour, according to this comment on an issue about this very subject, which by the way, is still in discussion.

So far, there are 3 suggested workarounds: two are gems, and the other is the modification or elimination of database.yml.

One possible database.yml that works is:

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  url: <%= ENV['DATABASE_URL'] %>

development:
  <<: *default
  database: app_development

test:
  <<: *default
  database: app_test

Which will create both databases without error.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.