Rails 6 无法连接到 AWS Elastic Beanstalk 预置的 RDS。 Unix 域套接字“/var/run/postgresql/.s.PGSQL.5432”

Posted

技术标签:

【中文标题】Rails 6 无法连接到 AWS Elastic Beanstalk 预置的 RDS。 Unix 域套接字“/var/run/postgresql/.s.PGSQL.5432”【英文标题】:Rails 6 is unable to connect to AWS Elastic Beanstalk provisioned RDS. Unix domain socket "/var/run/postgresql/.s.PGSQL.5432" 【发布时间】:2021-02-21 16:56:37 【问题描述】:

我很难将示例 Rails 6 应用程序启动到 Elastic Beanstalk。对于上下文,我正在遵循这些说明

ADD RDS to Ruby Application

ADD an RDS to Beanstalk

我已按照这些说明操作 tee,但仍然无法连接到我已配置的 rds 数据库。我不断收到以下错误:

PG::ConnectionBad: 无法连接到服务器:没有这样的文件或目录 服务器是否在本地运行并接受 Unix 域套接字“/var/run/postgresql/.s.PGSQL.5432”上的连接?

每当我尝试运行 RAILS_ENV=production rails db:migrate 或任何其他 rake 任务时,我都会不断收到该错误。

在我的 AWS 控制台上,在 ConfigurationSoftware 下,我有以下环境变量:

另外,在我的 database.yml 文件中,我列出了 rds 配置的变量。

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

我已按照文档中的说明映射了我的值,并确定它们是正确的。

最后,我 ssh 进入了我的 beanstalk 配置的 ec2 实例并执行了以下命令:

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

提供了密码并且能够连接。我真的束手无策,我花了太多时间试图诊断这一点,而且我的想法已经不多了。我不知道下一步该去哪里寻找有关如何解决此问题的想法。我已经阅读了太多堆栈溢出问题和博客,以至于我头晕目眩。如果有人对如何解决此问题有任何想法,我将不胜感激。

---更新---- 我在弹性 beanstalk 控制台上创建了一个新的环境变量。

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

我进行了必要的配置,上传了我的 .zip 文件,但与数据库的连接失败。

---- 更新-----

printenv 不显示 beanstalk 提供的变量,但是此命令可以显示 sudo /opt/elasticbeanstalk/bin/get-config environment

【问题讨论】:

您可以从您的应用程序中启动 Rails 控制台吗? cd /var/app/current 然后启动控制台? rails 服务器和机架环境是否设置为生产模式? 谢谢大家的回复。是的,这两个变量都设置为生产,我可以访问 rails 控制台。但是,如果我尝试进行任何类型的查询或活动记录语句,我会收到no implicit conversion of nil into String (TypeError)。通过在database.yml 中对我部署的rails 应用程序上的生产值进行硬编码,我能够使其暂时工作。这让我觉得应用程序无法以某种方式读取 RDS 环境变量,尽管将它们放在控制台中.. 哦,很好的侦探工作,但奇怪的是环境变量没有被拾取。在控制台中,您能否再次检查它们是否已设置? 目前我还不确定该怎么做。据我所知,它正在吸收所有其他变量。所以我明天要尝试的是创建一个名为DATABASE_URL 的新环境变量并将其设置为这个postgresql 连接字符串。 postgres://YourUserName:YourPassword@YourHostname:5432/YourDatabaseName。我将配置我的database.yml 以使用它,然后我会看看是否能解决问题。 【参考方案1】:

我的第一个建议是,在我看来,自己创建一个 Amazon RDS 是一个更好的选择,而不是绑定到 Beanstalk。

正如 AWS documentation 所指出的(强调我的):

AWS Elastic Beanstalk 支持在您的 Elastic Beanstalk 环境中运行 Amazon Relational Database Service (Amazon RDS) 实例。要了解这一点,请参阅将数据库添加到您的 Elastic Beanstalk 环境。 这非常适合开发和测试环境。但是,它不适合生产环境,因为它将数据库实例的生命周期与应用程序环境的生命周期联系在一起。

还有:

要将您的数据库实例与您的环境分离,您可以在 Amazon RDS 中运行一个数据库实例,并将您的应用程序配置为在启动时连接到它。这使您能够将多个环境连接到数据库、终止环境而不影响数据库,并通过蓝绿色部署执行无缝更新。

在我看来,即使对于测试或开发,始终建议配置一个小型数据库实例并让您的应用程序能够定义最合适的机制来连接到您的数据库。

唯一的缺点是您可能需要配置VPC,尽管它实际上不应该是一个问题,无论如何,它是值得的。

如果出于任何原因您需要使用 Beanstalk 配置的 RDS 数据库,也许您有一些解决问题的方法(这应该是一种解决方法,因为您的配置看起来不错 - 请仅验证数据库配置是否为正确定义Beanstalk 环境)。

例如,您可以尝试的一件事是将数据库连接配置存储在 S3 存储桶中,正如 AWS documentation 中所建议的那样。这个想法基本上是创建一些包含必要连接信息的配置文件,将其存储在 S3 中,然后在您的应用程序中读取该配置,即处理该文件,以初始化您的数据库。

但也许你可以尝试另一种方法。

请考虑这个SO question,以及 Jon McAuliffe 和其他人的回答。如前所述,Beanstalk 将为您的应用程序提供环境变量,但也许这些变量不会作为 shell 变量公开,它们将以不同的方式公开给您的应用程序,具体取决于应用程序需要在其上执行的运行时。

对于 Ruby,您正在访问 correct way 中的这些变量,但出于某种原因,您的程序无法访问该信息。

这可能也解释了为什么 printenv 不打印任何变量,但 get-config 脚本可以。

但也许您可以利用 get-config 为您提供正确信息这一事实,并在您的 ENV 中定义此变量,方法是为每个 RDS* 键(也许在您的 @ 987654336@ - 请注意,我在学生时代使用 Ruby 编程,但从那以后有很长一段时间,请在您认为合适的文件中执行任务 - 或使用 .ebextensions 和自定义配置文件。你可以找到几个例子here。

例如,考虑以下内容(复制和粘贴,对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

类似的方法可能是在this stackoverrun question 中公开的方法,但仅限于 Beanstalk 用于封装您的应用程序的容器。 AFAIK,容器应该以env 变量的形式接收与数据库配置相对应的不同RDS* 变量。

Dan,请注意,我没有测试过这些解决方案,它们只是想法:请小心,我不想对您的系统造成任何损坏。

【讨论】:

@DanRubio,您能尝试任何建议的解决方案吗? 嘿@jccampanero 感谢您的回复,我给了您赏金,但这些建议毕竟没有奏效。我有一个解耦的 rds 数据库,并且完全放弃了 beanstalk,只需要简单地移动到安装了包的预配置 ec2 实例。我发现 beanstalk 在部署和设置的各个步骤中存在太多问题。此时只设置 ec2 实例本身而不是推土机更简单。谢谢你的回答。 嗨@DanRubio。非常感谢你,我真的很感激你给了我赏金。很抱歉,所提供的建议均无效。我认为您做出了一个很好的决定,将数据库分开。配置了正确包的 ec2 实例也可以。在任何情况下,请考虑其他选项,例如直接或使用 Kubernetes 在容器中部署您的应用程序。再次感谢您,Dan:如果您认为我可以提供任何帮助,请随时与我联系,我很乐意为您提供帮助。【参考方案2】:

我在 mysql 服务器上找到了这个问题的答案,它可能仍然可以帮助你。基本上,即使我按照您的所有步骤操作,可以使用sudo /opt/elasticbeanstalk/bin/get-config environment 看到我的 envars,并且可以使用mysql 命令直接连接到我的数据库,但我仍然收到以下错误: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2) (Mysql2::Error::ConnectionError)

结果证明,Elastic Beanstalk 没有在 eb ssh 实例访问中将我的 envars 连接到我的 bundle exec rails console 命令。我通过在 eb ssh 实例访问中运行的任何 rails 命令显式添加所有必需的 envar 来解决该问题。例如,为了运行rails console,我必须运行以下命令:

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

将上面的xxxxxxxs 替换为您的 EB > 配置 > 软件选项卡中相应变量的值,您应该能够连接到远程数据库并运行迁移、rake 任务和其他依赖于数据库的功能。

【讨论】:

以上是关于Rails 6 无法连接到 AWS Elastic Beanstalk 预置的 RDS。 Unix 域套接字“/var/run/postgresql/.s.PGSQL.5432”的主要内容,如果未能解决你的问题,请参考以下文章