前提
Ruby on Rails(v5.2)でWebアプリケーションを開発・運用しています。
- 本番サーバ:AWS EC2(Nginx, unicorn)
- ELBにより冗長化構成
- 本番へのデプロイ:Capistranoを使って自動化。複数台のEC2(可変IP)にデプロイする形。
- デプロイ対象のEC2情報(DNS名)の取得方法:EC2のSDK(
describe_instances
)を使用。取得したDNS名をデプロイ先のサーバ情報としてセットしてCapistranoを動かしています。 - デプロイのコマンド実行方法:ローカルのdocker(
mutagen-compose
)上からCapistranoのコマンドを打つことで実行しています。(mutagen-compose run --rm -e NODE_OPTIONS=--max-old-space-size=8192 web bash -c "ssh-agent && ssh-add ~/.ssh/github_id_rsa && bundle exec cap production deploy"
)
実現したいこと
- デプロイ時のEC2情報の取得でエラーが出てしまっているため、エラーなくEC2情報を取得できるようにしたいです。
- なお、以前からずっと上記の方法で正常にデプロイを行ってきていましたが、7月上旬のある日、急にエラーが出るようになってしまいました。
- デプロイ周りの処理の変更は直近1年以上行っていない状況です。
- デプロイ実行の担当者は自分だけでなく他のメンバーもおり、他メンバーは同じやり方で正常にデプロイできている状況です。(ソースコードなどローカル環境もGitHubで管理しているdockerfileなど使っているので同じ。クライアントPCは個々人のものを使っているため異なりますが、機種がM1macなのは皆同じ)
発生している問題・エラーメッセージ
上記デプロイのコマンドを実行すると、
EC2情報の取得において下記エラーが出てしまっています。
❯ mutagen-compose run --rm -e NODE_OPTIONS=--max-old-space-size=8192 web bash -c "ssh-agent && ssh-add ~/.ssh/github_id_rsa && bundle exec cap production deploy" SSH_AUTH_SOCK=/tmp/ssh-**********/agent.8; export SSH_AUTH_SOCK; SSH_AGENT_PID=11; export SSH_AGENT_PID; echo Agent pid 11; Identity added: /root/.ssh/github_id_rsa (*******@****.com) rails aborted! SocketError: getaddrinfo: Name or service not known /bundle/gems/redis-3.3.5/lib/redis/connection/ruby.rb:229:in `getaddrinfo' /bundle/gems/redis-3.3.5/lib/redis/connection/ruby.rb:229:in `connect' /bundle/gems/redis-3.3.5/lib/redis/connection/ruby.rb:313:in `connect' /bundle/gems/redis-3.3.5/lib/redis/client.rb:336:in `establish_connection' 〜中略〜 /bundle/gems/redis-3.3.5/lib/redis/client.rb:100:in `connect' /bundle/gems/newrelic_rpm-6.12.0.367/lib/new_relic/agent/instrumentation/redis.rb:181:in `block in connect' 〜中略〜 /bundle/gems/redis-3.3.5/lib/redis/client.rb:364:in `ensure_connected' 〜中略〜 /bundle/gems/redis-3.3.5/lib/redis/client.rb:120:in `call' 〜中略〜 /bundle/gems/newrelic_rpm-6.12.0.367/lib/new_relic/agent/instrumentation/redis.rb:75:in `call' /bundle/gems/redis-3.3.5/lib/redis.rb:862:in `block in get' 〜中略〜 /bundle/gems/redis-3.3.5/lib/redis.rb:861:in `get' /bundle/gems/redis-store-1.6.0/lib/redis/store/interface.rb:5:in `get' 〜中略〜 /bundle/gems/redis-store-1.6.0/lib/redis/store/namespace.rb:23:in `get' /bundle/gems/redis-activesupport-5.2.0/lib/active_support/cache/redis_store.rb:288:in `block (2 levels) in read_entry' /bundle/gems/redis-activesupport-5.2.0/lib/active_support/cache/redis_store.rb:270:in `with' 〜中略〜 /bundle/gems/redis-activesupport-5.2.0/lib/active_support/cache/redis_store.rb:287:in `read_entry' /bundle/gems/activesupport-5.2.5/lib/active_support/cache.rb:313:in `block in fetch' 〜中略〜 /bundle/gems/activesupport-5.2.5/lib/active_support/cache.rb:663:in `instrument' /bundle/gems/activesupport-5.2.5/lib/active_support/cache.rb:312:in `fetch' /myapp/app/models/area.rb:321:in `<class:Area>' /myapp/app/models/area.rb:1:in `<main>' /bundle/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require' 〜中略〜 /bundle/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/active_support.rb:17:in `allow_bootsnap_retry' /bundle/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/active_support.rb:48:in `require_or_load' /bundle/gems/activesupport-5.2.5/lib/active_support/dependencies.rb:510:in `load_missing_constant' /bundle/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/active_support.rb:61:in `block in load_missing_constant' 〜中略〜 /bundle/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/active_support.rb:60:in `load_missing_constant' /bundle/gems/activesupport-5.2.5/lib/active_support/dependencies.rb:195:in `const_missing' /myapp/config/routes.rb:241:in `block in <main>' /bundle/gems/actionpack-5.2.5/lib/action_dispatch/routing/route_set.rb:432:in `instance_exec' /bundle/gems/actionpack-5.2.5/lib/action_dispatch/routing/route_set.rb:432:in `eval_block' /bundle/gems/actionpack-5.2.5/lib/action_dispatch/routing/route_set.rb:414:in `draw' /myapp/config/routes.rb:11:in `<main>' 〜中略〜 /bundle/gems/railties-5.2.5/lib/rails/application/routes_reloader.rb:30:in `block in updater' /bundle/gems/activesupport-5.2.5/lib/active_support/file_update_checker.rb:83:in `execute' /bundle/gems/railties-5.2.5/lib/rails/application/routes_reloader.rb:10:in `execute' /bundle/gems/railties-5.2.5/lib/rails/application/finisher.rb:130:in `block in <module:Finisher>' /bundle/gems/railties-5.2.5/lib/rails/initializable.rb:32:in `instance_exec' 〜中略〜 /bundle/gems/railties-5.2.5/lib/rails/application.rb:361:in `initialize!' /myapp/config/environment.rb:5:in `<main>' /bundle/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require' 〜中略〜 /bundle/gems/railties-5.2.5/lib/rails/commands/rake/rake_command.rb:23:in `block in perform' 〜中略〜 /bundle/gems/railties-5.2.5/lib/rails/commands.rb:18:in `<main>' /bundle/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require' 〜中略〜 /bundle/gems/bootsnap-1.4.7/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:31:in `require' /bundle/gems/activesupport-5.2.5/lib/active_support/dependencies.rb:291:in `block in require' 〜中略〜 /bundle/gems/activesupport-5.2.5/lib/active_support/dependencies.rb:291:in `require' bin/rails:4:in `<main>' Tasks: TOP => aws_ec2:describe_instances => environment (See full trace by running task with --trace) (Backtrace restricted to imported tasks) cap aborted! NoMethodError: undefined method `each' for false:FalseClass Tasks: TOP => production (See full trace by running task with --trace)
該当のソースコード
デプロイの定義ファイル(config/deploy/production.rb
)
ruby
1set :stage, :production 2set :rails_env, :production 3set :unicorn_rack_env, "production" 4 5hostnames = %x(RAILS_ENV=production bundle exec rails aws_ec2:describe_instances[all]) 6YAML.load(hostnames).each do |instance, instance_detail| 7 dns_name = instance_detail[:dns_name] 8 instance_roles = instance_detail[:roles] 9 10 server dns_name, 11 user: 'ec2-user', 12 roles: instance_roles, 13 ssh_options: { keys: %w(~/.ssh/****.pem), forward_agent: true, auth_methods: %w(publickey) }, 14 instance_name: instance 15end
aws_ec2:describe_instances
のrakeタスク(lib/tasks/aws_ec2.rake
)
ruby
1namespace :aws_ec2 do 2 desc 'Get the public DNS names of the given (two or more) AWS EC2 instances' 3 task :describe_instances, ['instance_names'] => :environment do |task, args| 4 names = args.instance_names == 'all' ? 5 Settings.ec2_instance_roles.keys.map(&:to_s) : 6 args.instance_names.split(' ') 7 details = names.map { |name| get_details(name) }.compact 8 puts YAML.dump(details.to_h) 9 end 10 11 def ec2(access_key_id: Settings.ec2.aws_access_key_id, secret_access_key: Settings.ec2.aws_secret_access_key, region: 'ap-northeast-1') 12 credentials = Aws::Credentials.new(access_key_id, secret_access_key) 13 Aws.config.update(region: region, credentials: credentials) 14 Aws::EC2::Client.new 15 end 16 17 def perform_request(method, params) 18 ec2.send(method, params) 19 rescue 20 nil 21 end 22 23 def get_detail_of_instances(instance_names) 24 perform_request :describe_instances, filters: [{name: 'tag:Name', values: instance_names}] 25 end 26 27 def get_public_dnses(instance_names) 28 detail_of_instances = get_detail_of_instances(instance_names) 29 detail_of_instances&.reservations&.first&.instances&.first&.public_dns_name 30 end 31 32 def get_details(instance) 33 roles = get_roles instance 34 dns_name = get_public_dnses([instance]) 35 return nil if dns_name.blank? 36 [ 37 instance.to_sym, 38 { 39 dns_name: dns_name, 40 roles: roles 41 } 42 ] 43 end 44 45 def get_roles(instance) 46 Settings.ec2_instance_roles[instance] 47 end 48end
関係ないかもしれませんが、上記エラーのバックトレースで
app/models/area.rb
config/routes.rb
などが出ているのでコードを載せます。
(なぜこんなところでエラーが出ているのか不明ですが、、)
redisはキャッシュストアなどとして使っています。
/myapp/app/models/area.rb:321
のコード
ruby
1 if ActiveRecord::Base.connection.table_exists?('areas') 2 SEARCHABLE_MAIN_IDS = Rails.cache.fetch('searchable_main_area_ids') do # ここが321行目 3 Area.where(*****).ids 4 end 5 6 Area.****_arr.map {|item| item[:status]}.each do |status| 7 Area.singleton_class.send(:define_method, "#{status}_name_id_arr") { 8 Rails.cache.fetch("#{status}_name_id_arr") do 9 Area.send(status).first.searchable_areas.map {|item| {name: item.name, id: item.id}} 10 end 11 } 12 end 13 end
/myapp/config/routes.rb:241:in
のコード(一部マスクなどしています)
ruby
1 if ENV['RAILS_ENV'] != 'test' && ActiveRecord::Base.connection.table_exists?('areas') 2 Area.domestic.first.searchable_areas.each do |area| # ここが241行目 3 get "test/#{area.status}" => 'search#index', area_ids: [area.id], description: "〜略〜" 4 end 5 end
config/environments/production.rb
(抜粋)
ruby
1 host = '//******.jp' 2 cache_store = :redis_store 3 path = "redis://*****************.cache.amazonaws.com:6379/0/cache" 4 config.cache_store = cache_store, path
試したこと
- aws_ec2.rakeを単独で実行してみましたが、同じエラーが出ました。( `mutagen-compose run --rm web bash -c "RAILS_ENV=production bundle exec rails aws_ec2:describe_instances[all]" )
- SSHで各サーバへアクセスは可能な状態です
- 前述しましたが、他メンバーは正常にデプロイできるため、アクセスキーやリージョン指定などは問題ないと思われます。(このエラー内容でググると、よく「リージョンの記載が間違っていた」が原因として出てきますが)
- PC再起動、dockerコンテナをbuildしなおしても変わらずでした。
- エラー内容で色々と検索してみましたが、当事象に該当するものはなさそうでした。
- ローカルからのawscliのdescribe_instancesは上手くいっています。
補足情報(FW/ツールのバージョンなど)
- クライアントPCの機種:https://gyazo.com/f737e6daa3dc68841f67215dd7ad901c
- 自分のPCからEC2へはSSHではアクセスできる状態
- Rails5.2.5
- Ruby2.6.6
- Gemfile抜粋
ruby
1gem 'aws-sdk' 2gem 'aws-sdk-rails' 3gem 'redis', '3.3.5' 4gem 'redis-rails' 5gem 'redis-namespace' 6group :deployment do 7 gem 'capistrano', '~> 3.4.0' 8 (略) 9end
何か「これっぽいのでは?」という観点だけでも大変ありがたいです。
お手数をお掛けしますが、よろしくお願いいたします。

あなたの回答
tips
プレビュー