前提
いつも拝見させていただいております。
ありがとうございます。
現在Ruby on Railsを用いてGoogle Books ApiにGETリクエストを送りresponseを加工してNuxt.jsにJsonデータを返却する機能を作っています。
Railsの中で以下のmodelに定義したメソッドを使用してGoogle Books ApiにGETリクエストを送る機能を作りました。
ローカル環境では正常に作動しているのですが、
aws(ecs、EC2)にデプロイしたところ表題の通りエラーが発生しました。
数日詰まっているため、皆様の知恵を貸していただきたくて質問しました。
https://ja.stackoverflow.com/questions/90909/nethttp%e3%81%a7netopentimeout-execution-expired%e3%81%ab%e5%af%be%e5%87%a6%e3%81%97%e3%81%9f%e3%81%84
追記
こちらのサイトでも同様の質問を行っております。
解決した場合は双方のサイトにご報告し、私と同様の問題を抱える方の助けになるよう解決策をシェアいたします。
※9月4日追記
教えていただいた事及び調査結果から、現状は「RailsのEc2コンテナからGoogleApiに対しgetリクエストが届かない」事が判明しています。
下記の「Net::HTTPでGoogle Books ApiにGETリクエストを送り、レスポンスを得たい」という目的を達成するまで補足情報に調査経過を記載します。
情報に誤りがあった場合はご指摘いただけると幸いです。
※9月5日補足情報に(私なりの)解決策を提示しました。
実現したいこと
●何が起きているか知りたい。
●Net::HTTPでGoogle Books ApiにGETリクエストを送り、レスポンスを得たい。
発生している問題・エラーログ
●aws環境のログ
Started GET "/api/v1/books/search/?keyword=%E3%83%86%E3%82%B9%E3%83%88" for 000.000.00.000 at 2022-09-03 16:11:58 +0900 Processing by Api::V1::BooksController#search as HTML Parameters: {"keyword"=>"........."} https://www.googleapis.com/books/v1/volumes?q=.........&country=JP https://www.googleapis.com/books/v1/volumes?q=%E3%83%86%E3%82%B9%E3%83%88&country=JP https://www.googleapis.com/books/v1/volumes?q=%E3%83%86%E3%82%B9%E3%83%88&country=JP #<Net::HTTP:0x00007f7e4c5fd008> #<Net::HTTP::Get:0x00007f7e4c5fcdb0> Completed 500 Internal Server Error in 60002ms (ActiveRecord: 0.0ms | Allocations: 2006) ↓関係していそうなlogデータ Net::OpenTimeout (execution expired): /usr/local/lib/ruby/3.0.0/net/http.rb:987:in `initialize' /usr/local/lib/ruby/3.0.0/net/http.rb:987:in `open' /usr/local/lib/ruby/3.0.0/net/http.rb:987:in `block in connect' /usr/local/lib/ruby/3.0.0/timeout.rb:107:in `timeout' /usr/local/lib/ruby/3.0.0/net/http.rb:985:in `connect' /usr/local/lib/ruby/3.0.0/net/http.rb:970:in `do_start' /usr/local/lib/ruby/3.0.0/net/http.rb:959:in `start' /usr/local/lib/ruby/3.0.0/net/http.rb:1512:in `request' ↑関係していそうなlogデータ /app/models/google_book.rb:61:in `search'
●ローカル環境のログ
Started GET "/api/v1/books/search/?keyword=%E3%83%86%E3%82%B9%E3%83%88" for 000.00.0.0 at 2022-09-03 16:03:24 +0900 Processing by Api::V1::BooksController#search as HTML Parameters: {"keyword"=>"........."} https://www.googleapis.com/books/v1/volumes?q=.........&country=JP https://www.googleapis.com/books/v1/volumes?q=%E3%83%86%E3%82%B9%E3%83%88&country=JP https://www.googleapis.com/books/v1/volumes?q=%E3%83%86%E3%82%B9%E3%83%88&country=JP #<Net::HTTP:0x00007fd7a0119e58> #<Net::HTTP::Get:0x00007fd7a0119930> #<Net::HTTPOK:0x00007fd7a0125550> 200 OK Completed 200 OK in 692ms (Views: 0.7ms | ActiveRecord: 0.0ms | Allocations: 4250)
該当のソースコード
models/google_book.rb
1require 'google_books_api' 2 3class GoogleBook 4 include ActiveModel::Model 5 include ActiveModel::Attributes 6 include ActiveModel::Validations 7 8 attribute :google_books_api_id, :string 9 attribute :authors 10 attribute :image, :string 11 attribute :published_at, :date 12 attribute :title, :string 13 attribute :publisher, :string 14 15 16 validates :google_books_api_id, presence: true 17 validates :title, presence: true 18 19 class << self 20 #lib以下に作成したモジュールを使用する 21 include GoogleBooksApi 22 23 def new_from_item(item) 24 @item = item 25 @volume_info = @item['volumeInfo'] 26 new( 27 google_books_api_id: @item['id'], 28 authors: @volume_info['authors'], 29 image: image_url, 30 published_at: @volume_info['publishedDate'], 31 title: @volume_info['title'], 32 publisher: @volume_info['publisher'], 33 ) 34 end 35 36 def new_from_id(google_books_api_id) 37 url = url_of_creating_from_id(google_books_api_id) 38 item = get_json_from_url(url) 39 new_from_item(item) 40 end 41 42 43#エラー発生個所↓ 44#以下のメソッドをコントローラーで使用します。 45#フロントエンドからパラメーターとして送られてくる「keyword」を 46#引数に取っています。 47 48 def search(keyword) 49 #フロントエンドからのリクエストをuriに変換 50 #url_of_searching_from_keywordメソッドは以下のmoduleで定義 51 url = url_of_searching_from_keyword(keyword) 52 #ログに書き込み 53 Rails.logger.debug(url) 54 55 #urlをエンコード 56 enc = Addressable::URI.encode(url) 57 #ログに書き込み 58 Rails.logger.debug(enc) 59 60 #uriに変換 61 uri = URI.parse(enc) 62 #ログに書き込み 63 Rails.logger.debug(uri) 64 65 #hostとポート番号をターミナルに出力 66 #puts uri.host => www.googleapis.com 67 #puts uri.port => 443 68 69 require 'net/https' 70 http = Net::HTTP.new(uri.host, uri.port) 71 Rails.logger.debug(http) 72 http.use_ssl = true 73 http.verify_mode = OpenSSL::SSL::VERIFY_NONE 74 75 76 request = Net::HTTP::Get.new(uri.request_uri) 77 ×#getリクエストが為されているかをlogに書き込む 78 訂正#getリクエストするための objectが作られているかをlogに書き込む 79 Rails.logger.debug(request) 80 81 #↓ここがおかしい(レスポンスが返ってこない) 82 response = http.request(request) 83 #↑ここまでの処理を機能させたい 84
lib/google_books_api.rb
1 2module GoogleBooksApi 3 4 def url_of_searching_from_keyword(keyword) 5 "https://www.googleapis.com/books/v1/volumes?q=#{keyword}&country=JP" 6 end
試したこと
①httpからhttps通信に
当初
response = Net::HTTP.get(uri)
というコードを使用していましたが、これを上記modelの通りssl化しました。
②Rails.logger.debugによるデバッグで問題発生箇所を特定
コードを分解し、Rails.logger.debugでどこまで処理が実行されているか確認
したところ
Production.logのlogで
Net::HTTP::Get:0x00007f7e4af86658
というログを発見したため、RailsからGoogle Books Apiへのgetリクエスト自体は送られていると思われます。
補足情報(FW/ツールのバージョンなど)
現在もエラーの原因を調査中ですが、他の方の知恵や対処法(デバック方法)を知りたくて質問させていただきました(以前ご指摘いただいてビックリしたのですが丸投げする意図は全っっっっくありません)。
どうか、皆様の力を貸してください。
足りない情報やご意見がありましたら、コメントを頂けると助かります!
Ruby 3.0.2
Rails 6.1.6
調査経過
9月4日
Rails
models/google_books.rb
###疎通確認用################################################## require 'net/ping' ## Pingの宛て先はuri.host(www.googleapis.com) pinger = Net::Ping::External.new(uri.host) ## Pingが通るかどうかテストします Rails.logger.debug(pinger.ping?) ローカル環境 => logへの記録はtrue aws環境 => logへの記録無し ##############################################################
NuxtとRailsが入っているクラスター内でping
[ec2-user@ip-00-00-0-000 ~]$ ping www.googleapis.com --- www.googleapis.com ping statistics --- 56 packets transmitted, 56 received, 0% packet loss, time 55082ms rtt min/avg/max/mdev = 1.332/1.408/2.085/0.143 ms
docker execでRailsが入っているコンテナに侵入しping
/ # ping www.googleapis.com --- www.googleapis.com ping statistics --- 55 packets transmitted, 0 packets received, 100% packet loss
現状は「RailsのEc2コンテナからGoogleApiに対しgetリクエストが届かない」
現在awsのセキュリティグループ、ネットワークALC、Route53を調査中
9月5日
公式の設定例に従ってRails側のネットワークモードを「awsvpc」にしておりましたが、
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/bestpracticesguide/networking-outbound.html
↑の記事によればawsvpcはインターネットゲートウェイが使えない事が分かりました。
その為、Rails側のタスク定義でネットワークモードを以下のとおり「bridge」で作り直しました。
結果としてはawsのコンソールにおいて「portが重複しているため、サービスを作成できない」旨のエラーメッセージが発生しサービスを作成できませんでした。
いくつか記事を見たところ
https://aws.amazon.com/jp/premiumsupport/knowledge-center/dynamic-port-mapping-ecs/
を発見し、動的ポートマッピングというものを行えば良いのではないか?と気づきました。
そして、記事に則りネットワーク周り等を作り直しました。
作り直したものは
●アプリケーションロードバランサー(バックエンド用)
●ターゲットグループ(バックエンド用)
●Rails側のタスク定義
●Rails側のサービス
です。
そして、ロードバランサーを作り直したため、Route53を再設定しました(Aレコード)。
その後、以下によればRails側のセキュリティグループで上記ロードバランサーをインバウンドルールに追加する必要がある事が分かり、以下に沿ってRails側のセキュリティグループのインバウンドルールを編集しました。
セキュリティを全てを見せる事は出来ないので、抜粋しますが以下の様になります。
以上の作業を行い、
Rails側の本番用のurlをブラウザに入力し、アクセスしたところ、head200を返すだけのヘルスチェック用アクションにブラウザからアクセスできるようになりました(真白な画面が表示されます)。
また、クラスターにssh接続をした後、Rails側のコンテナにdocker exec で侵入し、外部(GoogleApi)に向けてpingとcurlコマンドを打ったところ、無事レスポンスが返ってくる事を確認しました。
しかし、次は以前ネットワークモードをawsvpcにした状態で正常に作動していたRdsとの接続において、別のエラーが発生し、NuxtとRailsの疎通が不可能になりました。
幾つか記事を読んだところ、以下の記事を発見し、
https://qiita.com/fkana/items/a4b3c4d5d8ca27cd20ec
https://zatoima.github.io/aws-ec2-psql-install.html
Rails側のセキュリティが怪しい、と気づきました。
その後、Rails側のセキュリティグループに以下のインバウンドルールを設定しました。
その結果、表題の
「Net::HTTPでGoogle Books ApiにGETリクエストを送り、レスポンスを得たい」
という目的が達成されました。
ただし、私自身awsの設定やセキュリティの知見はありません。
上記の画像はアクセスの許容範囲が広い設定であるため、セキュリティの問題を孕んでおり、あくまで暫定的な処置になると思われます(アクセスの範囲を絞る必要がある?)。
以上で表題の問題は一旦解決となりますが、何かご意見やご指摘のある方は是非、コメントを頂けると大変助かります。
コメントや回答を下さった皆様(特に辛抱強く何度もコメントを下さったwinterboumさん)、本当にありがとうございました。
回答1件
あなたの回答
tips
プレビュー