AWS Elastic Beanstalk部署Rails应用时无法连接AWS RDS数据库
解决AWS Elastic Beanstalk上Rails应用无法连接RDS数据库的问题
问题背景
基于Ruby 3.2.2、Rails 7.1和Bundler 2.5.23的Rails应用部署到AWS Elastic Beanstalk后,默认路由可正常访问,但调用涉及数据库查询的API时出现连接错误。数据库托管在AWS RDS上,已在app/config/database.yml中配置主机、数据库名、密码和用户名等信息,且在EC2实例上手动使用相同凭证可正常连接RDS。
报错信息
{ "error": "Database connection error. Please check your database configuration.", "details": "We could not find your database: my_db. Available database configurations can be found in config/database.yml file.\n\nTo resolve this error:\n\n- Did you create the database for this app, or delete it? You may need to create your database.\n- Has the database name changed? Check your database.yml config has the correct database name.\n\nTo create your database, run:\n\n bin/rails db:create\n" }
现有配置
database.yml 内容
development: adapter: postgresql encoding: utf8 database: <%= ENV['database_name'] %> #musea_staging pool: 5 username: <%= ENV['database_username'] %> password: <%= ENV['database_password'] %> host: <%= ENV['database_url'] %> port: <%= ENV['database_port'] %> reaping_frequency: 10 staging: adapter: postgresql encoding: utf8 database: musea_staging pool: <%= ENV['database_pool'] %> username: <%= ENV['database_username'] %> password: <%= ENV['database_password'] %> host: <%= ENV['database_url'] %> port: <%= ENV['database_port'] %> reaping_frequency: 10 beta: adapter: postgresql database: musea_beta encoding: utf8 username: <%= ENV['database_username'] %> port: <%= ENV['database_port'] %> password: <%= ENV['database_password'] %> host: <%= ENV['database_url'] %> pool: <%= ENV['database_pool'] %> reaping_frequency: 10 production: adapter: postgresql database: musea encoding: utf8 username: <%= ENV['database_username'] %> port: <%= ENV['database_port'] %> password: <%= ENV['database_password'] %> host: <%= ENV['database_url'] %> pool: <%= ENV['database_pool'] %> reaping_frequency: 10
部署脚本
require 'aws-sdk' require 'fileutils' require 'yaml' def current_branch `git rev-parse --abbrev-ref HEAD`.chomp end def current_sha `git rev-parse --short HEAD`.chomp end def archive_path(name) File.join(File.expand_path(File.dirname(__FILE__)), "#{name}-#{current_sha}.zip") end def export_archive(archive_path, branch) `git archive --format zip --output #{archive_path} #{branch}` end def upload_archive(key, data_path) Aws.config.update({ region: 'us-east-1', credentials: Aws::Credentials.new( ENV['deploy_aws_key'], ENV['deploy_aws_secret'])}) s3_uploader = Aws::S3::FileUploader.new bucket_name = ENV['app_backup_bucket'] retry_on_failure do s3_uploader.upload(data_path ,{bucket: bucket_name, key: key} ) #s3.put_object( #bucket: bucket_name, #key: key, #content_type: "application/zip", #body: open(data_path) #) end end def retry_on_failure 3.times do begin return yield rescue => e puts "#{e}. retrying operation" end end fail "3 attempts failed !!!" end def create_application_version(beanstalk, config, data_key) version_label = File.basename(data_key, '.zip') unless has_application_version?(beanstalk, config['application_name'], version_label) bucket_name = ENV['app_backup_bucket'] beanstalk.create_application_version( application_name: config['application_name'], version_label: version_label, description: "Created by deployment script.", source_bundle: { s3_bucket: bucket_name, s3_key: data_key, }, auto_create_application: false, ) end end def has_application_version?(beanstalk, application_name, version_label) response = beanstalk.client.describe_application_versions( application_name: application_name ) response.data[:application_versions].any? {|version| version[:version_label] == version_label} end def update_environment(beanstalk, config, data_key) beanstalk.client.update_environment( environment_name: config['environment_name'], version_label: File.basename(data_key, '.zip'), ) end def deploy_application(config, branch) data_path = archive_path(config['application_name']) data_key = "#{config['application_name']}/#{File.basename(data_path)}" export_archive(data_path, branch) upload_archive(data_key, data_path) Aws.config.update({ region: 'us-east-1', credentials: Aws::Credentials.new( ENV['deploy_aws_key'], ENV['deploy_aws_secret'])}) beanstalk = Aws::ElasticBeanstalk::Client.new(region: 'us-east-1') create_application_version(beanstalk, config, data_key) update_environment(beanstalk, config, data_key) cleanup_local_archive(data_path) end def cleanup_local_archive(archive_file) FileUtils.rm_f(archive_file) puts "Cleaned up local archive" end def get_configuration yaml = File.join(File.dirname(File.expand_path(__FILE__)),'/beanstalk.yml') config = YAML.load_file(yaml) end namespace :beanstalk do desc 'Deploy application to Elastic Beanstalk' task :deploy => :environment do branch_config = get_configuration target = current_branch puts "Deploying branch #{target}." deploy_application(branch_config[target], target) puts "Deployed #{current_sha}." end desc 'Create archive without uploading' task :dry_run => :environment do branch_config = get_configuration target = current_branch puts "Creating archive for branch #{target}." dry_run(branch_config[target], target) end end
排查与解决方案
- 确认Rails运行环境:AWS Elastic Beanstalk默认使用production环境,若部署的是staging分支,需确保EB环境变量中设置
RAILS_ENV=staging。报错中提到找不到my_db,说明当前加载的数据库名与配置不符,大概率是环境变量未正确设置导致Rails使用了错误的database.yml配置段。 - 验证环境变量有效性:登录EB的EC2实例,执行
printenv | grep RAILS_ENV和printenv | grep database_,确认所有数据库相关环境变量(database_username、database_password等)与手动连接时的凭证一致且已正确加载。 - 检查database.yml环境匹配:若部署staging分支,确认EB环境对应staging配置段,该段数据库名为硬编码的
musea_staging,无依赖未设置的环境变量。注意development段的database依赖ENV['database_name'],若误加载development环境且该变量未设置,会导致数据库找不到。 - 确认数据库存在性:手动连接RDS后执行
\l命令,查看对应环境的数据库(如staging的musea_staging)是否存在。 - 检查安全组配置:确保EB的EC2安全组被允许访问RDS的安全组,RDS入站规则需开放5432端口给EB安全组。
- 查看Rails日志:登录EB实例,查看
/var/app/current/log/[对应环境].log(如production.log或staging.log),获取更详细的数据库连接错误信息,定位具体问题(如权限、主机地址错误等)。 - 硬编码配置测试:若环境变量存在问题,可先在database.yml对应环境段硬编码所有正确的数据库信息(主机、用户名、密码、数据库名),重新部署测试,排除环境变量问题。
内容的提问来源于stack exchange,提问作者Farooq Haider
相关产品推荐
相关产品推荐

