Rubyのバージョンアップに伴い、Rialsをインストールする必要ができたので、gem updateやgem install コマンドを実行したところ、長時間待たされた挙句、次のようなエラーが発生。
$ gem update --system
ERROR: While executing gem ... (Gem::RemoteFetcher::UnknownHostError)
timed out (https://rubygems.org/specs.4.8.gz)
$ gem install bundler
ERROR: Could not find a valid gem 'bundler' (>= 0), here is why:
Unable to download data from https://rubygems.org/ - timed out (https://api.rubygems.org/specs.4.8.gz)
https://rubygems.org/specs.4.8.gz および、https://api.rubygems.org/specs.4.8.gzにアクセスしようとしたが、接続できずタイムアウトが発生している。
このエラーの原因と解決方法についてです。
エラーの原因
このエラーは、gemの最新情報を取得するために、https://api.rubygems.org/specs.4.8.gz にアクセスする必要がありますが、このURLにアクセスできなかったために発生しています。
エラーの要因は大きく2つあります。
- IPv6を利用している
- 会社のVPNなどプロキシサーバーを利用している
会社のVPNやIPv6アドレスで接続しようとすると接続できません。api.rubygems.orgの暫定的なエラーと思いますがとにかくできません。
(補足)接続状況の確認方法
どのIPアドレスで接続できていなくて、どのIPアドレスだと接続できるのかを確認します。
wgetコマンドを使います。wgetは接続に失敗した場合に、自動でリダイレクトをかけて接続できるホストを探してくれます。(再帰処理と言います)
$ wget URL
$ wget https://api.rubygems.org/specs.4.8.gz
--2021-07-07 16:57:51-- https://api.rubygems.org/specs.4.8.gz
api.rubygems.org (api.rubygems.org) をDNSに問いあわせています... 2a04:4e42:200::483, 2a04:4e42:400::483, 2a04:4e42:600::483, ...
api.rubygems.org (api.rubygems.org)|2a04:4e42:200::483|:443 に接続しています... 失敗しました: Operation timed out.
api.rubygems.org (api.rubygems.org)|2a04:4e42:400::483|:443 に接続しています... 失敗しました: Operation timed out.
api.rubygems.org (api.rubygems.org)|2a04:4e42:600::483|:443 に接続しています... 失敗しました: Operation timed out.
api.rubygems.org (api.rubygems.org)|2a04:4e42::483|:443 に接続しています... 失敗しました: Operation timed out.
api.rubygems.org (api.rubygems.org)|151.101.193.227|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 4431303 (4.2M) [application/octet-stream]
`specs.4.8.gz' に保存中
specs.4.8.gz 100%[==========>] 4.23M 11.7MB/s 時間 0.4s
2021-07-07 17
実行結果を見ると、IPv6のアドレス(2a04:4e42:200::483など)は接続に失敗しています。
一方で、IPv4アドレス(151.101.193.227)は接続に成功しています。ちなみに後ろの443はSSL(https)で接続しているという意味です。
エラー対処法
IPv4で接続できることがわかったので、まずはrubygems.orgがどのIPアドレスを使っているかを確認します。
IPv4アドレスの確認
hostコマンドでドメイン名を指定すると、IPアドレスの一覧が表示されます。
$ host rubygems.org
$ host rubygems.org
rubygems.org has address 151.101.193.227
rubygems.org has address 151.101.1.227
rubygems.org has address 151.101.65.227
rubygems.org has address 151.101.129.227
rubygems.org has IPv6 address 2a04:4e42:600::483
rubygems.org has IPv6 address 2a04:4e42:400::483
rubygems.org has IPv6 address 2a04:4e42::483
rubygems.org has IPv6 address 2a04:4e42:200::483
rubygems.org mail is handled by 10 mxa.mailgun.org.
rubygems.org mail is handled by 10 mxb.mailgun.org.
※サブドメインも同じIPアドレスになります。
$ host api.rubygems.org
api.rubygems.org is an alias for rubygems.org.
rubygems.org has address 151.101.129.227
rubygems.org has address 151.101.65.227
rubygems.org has address 151.101.1.227
rubygems.org has address 151.101.193.227
rubygems.org has IPv6 address 2a04:4e42:600::483
rubygems.org has IPv6 address 2a04:4e42::483
rubygems.org has IPv6 address 2a04:4e42:200::483
rubygems.org has IPv6 address 2a04:4e42:400::483
rubygems.org mail is handled by 10 mxb.mailgun.org.
rubygems.org mail is handled by 10 mxa.mailgun.org.
ドメイン名とIPv4アドレスを紐付ける
MacなどUnix系OSには /etc/hosts というファイルがあります。この中で、「このドメイン名の場合はこのIPアドレスにつなげる」といった処理を記述することができます。
このファイルをvimエディタで開きます。読み込みのみのアクセス権限がかかっているので、sudoでスーパーユーザーとして開きます。
$sudo vim /etc/hosts
開いたら以下のように末尾に追記します。
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
# Added by Docker Desktop
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
##以下追記
#gem IPv4アドレス
151.101.193.227 rubygems.org
151.101.1.227 rubygems.org
151.101.65.227 rubygems.org
151.101.129.227 rubygems.org
IPv6で接続しようとすることでエラーが発生するので、指定のドメイン名でIPv4のIPアドレスに接続するように設定します。
/etc/hosts の書き方は 「<IPアドレス> <紐づけるドメイン名>」 とします。
上記の場合、「rubygems.org」のドメイン名でアクセスしようとしたら、IPアドレスは「151.101.193.227」「151.101.1.227」「151.65.1.227」「151.129.1.227」を叩くという処理になります。
以上で設定が完了です。
社内VPNを切る
会社のVPNにつかがっているとプロキシサーバーで弾かれてデータを取得できないことがあります。
もし、VPNに接続している場合は切断します。
コマンドの実行
コマンドを実行してみるとtimeoutすることなく無事処理を実行することができました。
$ gem install bundler
Fetching bundler-2.2.22.gem
Successfully installed bundler-2.2.22
Parsing documentation for bundler-2.2.22
Installing ri documentation for bundler-2.2.22
Done installing documentation for bundler after 4 seconds
1 gem installed
(補足)Docker上のRailsプロジェクトの場合
Docker上にあるプロジェクトの場合は、自分のPC(ローカル)でgemやRailsのコマンドを叩いても、Docker上のプログラムには反映されません。
そもそも、Docker上のプログラムを指していないので、本来は出ないはずのエラーが発生したりします。
その場合は、Railsが動いているDockerコンテナに入り、gemコマンドを実行します。
#起動中のdockerコンテナ一覧を確認
docker ps
#コンテナの中に入る
docker exec -it <コンテナ名> bash
root@cee9a2a0d27e:/app#