既存システムのEC2 to ECS化の対応の中でハマったこと on Ruby on Rails

# はじめに
この記事では、既存のAWS EC2で動作していたRailsアプリケーションをAWS ECSに移行する際に直面した問題とその解決方法について共有します。内容的には主な問題が、 **Railsのバージョンを5.1から6.1にアップデート** する過程での問題でしたので、それらについての共有となります。

# 遭遇した問題と解決策（ハマった順）
## 1. File:Classの`exists`メソッドが使えない
Rails 6.1にアップデートした後、unicornでアプリケーションを起動しようとすると、`File:Class`の`exists`メソッドが使えないというエラーに遭遇しました。
また、こちらについては unicornの設定上エラーが出たときにはコンテナ内部のログ・ファイルへ出力されてしまう状態になっていたことで、タスクが起動はするがヘルスチェックが成功せず、何度もタスクが起動してはSTOPする挙動で、Cloudwatch Logsのログを見てもエラーがわからない状態になり、ハマりました💦 (Railsが得意な方はハマらないんでしょうね :thinking: )

実際にコンテナ内部で起きていたエラーの一部がこちら👇️

```
I, [2025-02-17T12:21:50.972920 #86]  INFO -- : Refreshing Gem list
/usr/local/lib/ruby/gems/3.3.0/gems/activesupport-6.1.7.7/lib/active_support/dependencies.rb:332: warning: mutex_m was loaded from the standard library, but will no longer be part of the default gems since Ruby 3.4.0. Add mutex_m to your Gemfile or gemspec. Also contact author of activesupport-6.1.7.7 to add mutex_m into its gemspec.
I, [2025-02-17T12:21:55.155461 #86]  INFO -- : listening on addr=/opt/tmp/unicorn.sock fd=10
E, [2025-02-17T12:21:55.216506 #86] ERROR -- : undefined method `exists?' for class File (NoMethodError)
config/unicorn/production.rb:33:in `block in reload'
/usr/local/lib/ruby/gems/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:541:in `spawn_missing_workers'
/usr/local/lib/ruby/gems/3.3.0/gems/unicorn-6.1.0/lib/unicorn/http_server.rb:143:in `start'
/usr/local/lib/ruby/gems/3.3.0/gems/unicorn-6.1.0/bin/unicorn:128:in `<top (required)>'
/usr/local/bin/unicorn:25:in `load'
/usr/local/bin/unicorn:25:in `<top (required)>'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/cli/exec.rb:58:in `load'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/cli/exec.rb:58:in `kernel_load'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/cli/exec.rb:23:in `run'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/cli.rb:455:in `exec'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/vendor/thor/lib/thor/command.rb:28:in `run'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/vendor/thor/lib/thor.rb:527:in `dispatch'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/cli.rb:35:in `dispatch'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/vendor/thor/lib/thor/base.rb:584:in `start'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/cli.rb:29:in `start'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/exe/bundle:28:in `block in <top (required)>'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
/usr/local/lib/ruby/gems/3.3.0/gems/bundler-2.5.10/exe/bundle:20:in `<top (required)>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
```

### エラー内容
```
undefined method `exists?' for File:Class (NoMethodError)
```

### 解決策
このエラーは、Railsのバージョンアップに伴い、`File.exists?メソッドがFile.exist?に変更されたために発生します。コード内でFile.exists?をFile.exist?`に置き換えることで解決しました。

### :link: 参考リンク: [ruby - undefined method `exists?' for File:Class (NoMethodError)? - Stack Overflow](https://stackoverflow.com/questions/14351272/undefined-method-exists-for-fileclass-nomethoderror)

## 2. rake assets:precompileのSegmentation Fault
ECSタスクの起動時に Dockerの entrypointでシェル実行を利用して、 `rake assets:precompile`を実行すると、Segmentation Faultが発生しました。

### エラー内容
```
Segmentation fault (core dumped)
```

### 解決策
`rake assets:precompile`コマンドを実行すると、セグメンテーション違反が発生し、それ以降の処理が中断されていました。しかし、コンテナとしては起動していたので、`aws ecs exec` にてコンテナ内部でデバッグを進めました。エラーが起こってる状態を確認したので、試しにコンテナ内部で手動で実行をしたところ、そのときは問題なく処理が完了したため、 :question: :question: :question: となりましたが、
このことから、該当コマンドを実行するタイミング（タスク起動時での実行だとNGだが、起動後のコンテナ内部での実行だとOK）が関係してると考えました。
また、そもそもRailsでの本番環境にてDockerで動かす場合において、このコマンドがいつ実行されるべきなのかという観点から調査をしたところ、Dockerfile内で実行してるものが多いかなというところから、Dockerfile内で実行されるように修正をして解決させました。

### :link: 参考リンク: [Ruby on Rails: segmentation fault when running ‘rake assets:precompile’ - Stack Overflow](https://stackoverflow.com/questions/10188638/ruby-on-rails-segmentation-fault-when-running-rake-assetsprecompile)

## 3. protect_from_forgeryの有効化によるAPIエラー
Rails 6.1にアップデートした後、`protect_from_forgery`がデフォルトで有効化されることで、APIリクエストがエラーになる問題が発生しました。

### エラー内容
```
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken)
```

### 解決策
APIコントローラで`protect_from_forgery` を無効化するために、`ApplicationController`に以下の設定を追加しました。

:warning: こちらのAPIは社外へ公開してるものではなく、社内NW内で動作するAPIになってるというところから、この方法でも大きな問題はないと判断してこうしていますが、WEBに公開するようなAPIにおいてこの状態だとNGですのでその点は注意です :bow: 

```ruby
class HelloController < ApplicationController
   skip_before_action :verify_authenticity_token
```

### :link: 参考情報: これについてはGithub Copilotさんに教えてもらいました :cop: 

# おわりに
AWS ECSへの移行とRailsのバージョンアップは多くの利点がありますが、同時にいくつかの問題にも直面しました。
この記事が、同様の問題に直面している方々の参考になれば幸いです。