

### 前提

現在Ruby on Railsを用いてGoogle Books
ApiにGETリクエストを送りresponseを加工してNuxt.jsにJsonデータを返却する機能を作っています。

Railsの中で以下のmodelに定義したメソッドを使用してGoogle Books ApiにGETリクエストを送る機能を作りました。  
ローカル環境では正常に作動しているのですが、  
aws(ecs、EC2)にデプロイしたところ表題の通りエラーが発生しました。

数日詰まっているため、皆様の知恵を貸していただきたくて質問しました。

追記  
こちらのサイトでも同様の質問を行っております。  
解決した場合は双方のサイトにご報告し、私と同様の問題を抱える方の助けになるよう解決策をシェアいたします。  
<https://teratail.com/questions/dljdho1ts6d9ha>

※９月４日～  
上記サイトにて教えていただいた事や調査結果から「RailsのEc2コンテナからGoogleApiに対しgetリクエストが届かない(Ec2コンテナとGoogleApiとの疎通が取れていない)」という現状が把握が出来たため上記サイト側では解決済となっています。  
しかし、「Net::HTTPでGoogle Books
ApiにGETリクエストを送り、レスポンスを得たい」という目標は未達のため、調査を継続し、解決するまで補足情報に途中経過を記載しています。

### 実現したいこと

●何が起きているか知りたい。  
●Net::HTTPでNet::OpenTimeout (execution expired)に対処したい。

### 発生している問題・エラーログ

●aws環境のログ

[code]

    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'
    
[/code]

●ローカル環境のログ

[code]

    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)
    
[/code]

### 該当のソースコード

models/google_book.rb

[code]

    require 'google_books_api'
    
    class GoogleBook
      include ActiveModel::Model
      include ActiveModel::Attributes
      include ActiveModel::Validations
      
      attribute :google_books_api_id, :string
      attribute :authors
      attribute :image, :string
      attribute :published_at, :date
      attribute :title, :string
      attribute :publisher, :string
      
      
      validates :google_books_api_id, presence: true
      validates :title, presence: true
      
      class << self
      #lib以下に作成したモジュールを使用する
      include GoogleBooksApi
      
        def new_from_item(item)
          @item = item
          @volume_info = @item['volumeInfo']
          new(
            google_books_api_id: @item['id'],
            authors: @volume_info['authors'],
            image: image_url,
            published_at: @volume_info['publishedDate'],
            title: @volume_info['title'],
            publisher: @volume_info['publisher'],
          )
        end
      
        def new_from_id(google_books_api_id)
          url = url_of_creating_from_id(google_books_api_id)
          item = get_json_from_url(url)
          new_from_item(item)
        end
     
    
    #エラー発生個所↓
    #以下のメソッドをコントローラーで使用します。
    #フロントエンドからパラメーターとして送られてくる「keyword」を
    #引数に取っています。
    
        def search(keyword)
          #フロントエンドからのリクエストをuriに変換
          #url_of_searching_from_keywordメソッドは以下のmoduleで定義
          url = url_of_searching_from_keyword(keyword)
          #ログに書き込み
          Rails.logger.debug(url)
    
          #urlをエンコード
          enc = Addressable::URI.encode(url)
          #ログに書き込み
          Rails.logger.debug(enc)
    
          #uriに変換
          uri = URI.parse(enc)
          #ログに書き込み
          Rails.logger.debug(uri)
          
          #hostとポート番号をターミナルに出力
          #puts uri.host => www.googleapis.com
          #puts uri.port => 443
    
          require 'net/https'
          http = Net::HTTP.new(uri.host, uri.port)
          Rails.logger.debug(http)
          http.use_ssl = true
          http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    
    　　
          request = Net::HTTP::Get.new(uri.request_uri)
          ×#getリクエストが為されているかをlogに書き込む
          訂正#getリクエストするための objectが作られているかをlogに書き込む
          Rails.logger.debug(request)
    　　
    　　#↓ここがおかしい(レスポンスが返ってこない)
          response = http.request(request)
    　　#↑ここまでの処理を機能させたい
    
    
[/code]

lib/google_books_api.rb

[code]

    module GoogleBooksApi
      
      def url_of_searching_from_keyword(keyword)
        "https://www.googleapis.com/books/v1/volumes?q=#{keyword}&country=JP"
      end
    
[/code]

### 試したこと

①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


CC BY-SA 4.0
2022-09-03T09:02:58.410
90909
2022-09-07T05:30:13.870
2022-09-07T05:30:13.870
54249
54249
question
ruby-on-rails ruby aws
Net::HTTPでNet::OpenTimeout (execution expired)に対処したい


公式の設定例に従ってRails側のネットワークモードを「awsvpc」にしておりましたが、  
<https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/bestpracticesguide/networking-
outbound.html>  
↑の記事によればawsvpcはインターネットゲートウェイが使えない事が分かりました。  
![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2022-09-05/9f32664a-f612-42c9-8fc2-1b0688d71e59.jpeg)  
その為、Rails側のタスク定義でネットワークモードを以下のとおり「bridge」で作り直しました。  
![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2022-09-05/c44d3bb7-7599-4dd3-956f-823512d0e230.jpeg)  
結果としてはawsのコンソールにおいて「portが重複しているため、サービスを作成できない」旨のエラーメッセージが発生しサービスを作成できませんでした。  
いくつか記事を見たところ  
<https://aws.amazon.com/jp/premiumsupport/knowledge-center/dynamic-port-
mapping-ecs/>  
を発見し、動的ポートマッピングというものを行えば良いのではないか？と気づきました。  
![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2022-09-05/6167c660-82a1-4fed-
aa42-2a791249d17b.jpeg)  
そして、記事に則りネットワーク周り等を作り直しました。  
作り直したものは  
●アプリケーションロードバランサー(バックエンド用)  
●ターゲットグループ(バックエンド用)  
●Rails側のタスク定義  
●Rails側のサービス  
です。  
そして、ロードバランサーを作り直したため、Route53を再設定しました(Aレコード)。  
その後、以下によればRails側のセキュリティグループで上記ロードバランサーをインバウンドルールに追加する必要がある事が分かり、以下に沿ってRails側のセキュリティグループのインバウンドルールを編集しました。  
![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2022-09-05/4a42c052-5689-4209-b7a3-e64bd68993bc.jpeg)  
セキュリティを全てを見せる事は出来ないので、抜粋しますが以下の様になります。  
![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2022-09-05/af96f9e1-7a04-4d22-8cfe-9ec2ef47af65.jpeg)  
以上の作業を行い、  
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側のセキュリティグループに以下のインバウンドルールを設定しました。  
![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2022-09-06/ec80b35e-9ec5-4bc1-9162-e3e6eadd0f3a.jpeg)  
その結果、表題の  
「Net::HTTPでNet::OpenTimeout (execution expired)に対処したい」  
という目的が達成されました。  
ただし、私自身awsの設定やセキュリティの知見はありません。  
上記の画像はアクセスの許容範囲が広い設定であるため、セキュリティの問題を孕んでおり、あくまで暫定的な処置になると思われます(アクセスの範囲を絞る必要がある？)。


CC BY-SA 4.0
2022-09-05T17:39:04.220
90948
2022-09-06T05:16:32.537
2022-09-06T05:16:32.537
54249
54249
90909
answer