Rails 6 is unable to connect to AWS Elastic Beanstalk provisioned RDS. Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"

Viewed 533

I am having a very difficult time trying to launch a sample Rails 6 application to Elastic Beanstalk. For context, I am following these instructions

ADD RDS to Ruby Application

ADD an RDS to Beanstalk

I have followed these instructions to a tee and am still unable to connect to the rds database that I have provisioned. I keep receiving the following error:

PG::ConnectionBad: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?

Whenever I try to run RAILS_ENV=production rails db:migrate or any other rake task, I keep getting that error.

On my AWS console, under Configuration and Software, I have the following environment variables:

enter image description here

Also in my database.yml file I have the rds configured variables listed as such.

production:
 adapter: postgresql
  database: <%= ENV['RDS_DB_NAME'] %>
  username: <%= ENV['RDS_USERNAME'] %>
  password: <%= ENV['RDS_PASSWORD'] %>
  host: <%= ENV['RDS_HOSTNAME'] %>
  port: <%= ENV['RDS_PORT'] %>

I have mapped my values as instructed in the documentation and am certain that they are correct.

Finally, I have sshed into my beanstalk provisioned ec2 instance and have executed the following command:

psql -U username -p 5432 -h examplehost.rds.amazonaws.com -d ebdb

provided the password and am able to connect. I am really at my wits end, I've spent too much time trying to diagnose this and am running out of ideas. I don't know where to look too next for ideas on how to trouble shoot this. I've read so many stack overflow questions and blogs that my head is spinning. If anyone has any ideas on how to resolve this, I would greatly appreciate it.

---Update---- I have created a new environment variable on the elastic beanstalk console.

ENV['DATABASE_URL'] = postgres://YourUserName:YourPassword@YourHostname:5432/YourDatabaseName

I made the necessary configurations, uploaded my .zip file and the connection to the database failed.

---- UPDATE-----

printenv does not show the varialbes provided by beanstalk, however this command does sudo /opt/elasticbeanstalk/bin/get-config environment.

3 Answers

My first advice is that, in my opinion, it is a much better option to create an Amazon RDS on their own, and not tied to Beanstalk.

As the AWS documentation indicates (emphasis mine):

AWS Elastic Beanstalk provides support for running Amazon Relational Database Service (Amazon RDS) instances in your Elastic Beanstalk environment. To learn about that, see Adding a database to your Elastic Beanstalk environment. This works great for development and testing environments. However, it isn't ideal for a production environment because it ties the lifecycle of the database instance to the lifecycle of your application's environment.

And:

To decouple your database instance from your environment, you can run a database instance in Amazon RDS and configure your application to connect to it on launch. This enables you to connect multiple environments to a database, terminate an environment without affecting the database, and perform seamless updates with blue-green deployments.

In my opinion, even for testing or development, it is always advisable to configure a small database instance and give your application the ability of define the most appropriate mechanism for connecting to your database.

The only downside is that you will probably need to configure a VPC, although it should not be actually a problem and, in ay case, it is worth value.

If for any reason you need to use the Beanstalk provisioned RDS database perhaps you have some workarounds to your problem (it should be a workaround because your configuration looks fine - please, only, verify that the database configuration is defined for the right Beanstalk environment).

For instance, one thing you can try is to store the database connection configuration in a S3 bucket, as also suggested in the AWS documentation. The idea is basically create some configuration file with the necessary connectivity information, store it in S3, and read that configuration in your application, i.e., process that file, in order to initialize your database.

But maybe you can try another approach.

Please, consider this SO question, and the answer from Jon McAuliffe and others. As indicated, Beanstalk will provide your application with environment variables, but maybe this variables will not be exposed as shell variables, they will be exposed to your application in different ways depending on the runtime the application needs to be executed on.

In the case of Ruby, you are accessing these variables in the correct way but, for any reason, your program is not having access to that information.

This probably also explains why printenv does not print any if your variables but the get-config script does.

But maybe you can take advantage of the fact that get-config provides you the right information and, either define this variables in your ENV by executing the get-config script for every RDS* key, perhaps in your environment.rb - please, be aware that I programmed in Ruby when I was a student but there is a long time since that, do the task in the file you consider appropriate - or using .ebextensions and a custom configuration file. You can find several examples here.

For instance, consider the following (copy and paste, with minor modifications of this example configuration):

commands:
  01_update_env:
    command: "/tmp/update_environment_variables.sh"

files:
  "/tmp/update_environment_variables.sh":
      mode: "000755"
      content : |
        #!/bin/bash

        RDS_HOSTNAME=$(/opt/elasticbeanstalk/bin/get-config environment -k RDS_HOSTNAME)
        if [ -z "$RDS_HOSTNAME" ]; then
                echo "Could not determine RDS hostname"
                exit 1
        fi
        echo "RDS hostname $RDS_HOSTNAME..."
        # Just export the variable at OS level, or make it visible to
        # the rails env in some other way
        export RDS_HOSTNAME=$RDS_HOSTNAME

        # Process the rest of the variables...
        # Probably we should create a list and iterate through it

A similar approach could be the one exposed in this stackoverrun question, but restricted to the container that Beanstalk will use to encapsulate your app. AFAIK, the container should receive as env variables the different RDS* ones corresponding to the database configuration.

Dan, be aware that I have not tested these solutions, they are only ideas: please, be careful with that, I do not want to cause any damage to your system.

I found an answer for this problem with a mysql server that might still help you. Basically, even though I followed all your steps, could see my envars using sudo /opt/elasticbeanstalk/bin/get-config environment and could connect directly to my database with the mysql command, I was still getting the following error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) (Mysql2::Error::ConnectionError)

The solution turned out to be the fact that Elastic Beanstalk was not connecting my envars to my bundle exec rails console command in the eb ssh instance access. I solved the issue by prepending all of the required envars explicitly to any rails commands I ran from within the eb ssh instance access. So for example, in order to run rails console, I had to run the following:

RAILS_MASTER_KEY=xxxxxxx RAILS_ENV=production RDS_HOSTNAME=xxxxxxx RDS_PASSWORD=xxxxxxx RDS_USERNAME=xxxxxxx RDS_DB_NAME=xxxxxxx AWS_REGION=xxxxxxx AWS_BUCKET=xxxxxxx bundle exec rails c

Replace the xxxxxxxs above with the values from the corresponding variables in your EB > Configuration > Software tab, and you should be able to connect to the remote database and run migrations, rake tasks and other database-reliant functions.

For Linux2 instances I was having the same issue and just noticed that the env variables I set in the config just didn't exist for su that I had set myself to -- if I remain the default login after eb ssh env prints everything I expected

edit: sorry -- env printing of variables on linux 2 instance enabled by https://aws.amazon.com/premiumsupport/knowledge-center/elastic-beanstalk-env-variables-shell/

so what I did was find where those env variables were being exported for default user shell, which was /etc/profile.d/sh.local as noted in the above aws knowledge center link and just source that file when I needed to start the rails console as su

Related