【Amazon Linux 2023】ElasticBeanstalkでffmpegが動かなくなった件

どうもこんにちは。

今回は、Railsのバージョンを上げたときに生じた問題を解決したのでその備忘録を書いていきます。

# 変更した点

変更した点は以下です。

| 変更箇所 | 変更前 | 変更後 |
| --- | --- | --- |
| Ruby | 3.0.6 | 3.2.2 |
| Rails | 7.0.5 | 7.1.3.2 |
| プラットフォーム | Ruby 3.0 running on 64bit Amazon Linux 2 | Ruby 3.2 running on 64bit Amazon Linux 2023 |

# 発生したエラー

Railsのバージョンを上げた時に、`jquery-ui`が動作しなくなった問題はありましたが、`@hotwired/turbo-rails"`を先にインポートしたら解決しました。

ただ、今回は`ffmpeg`の`ffprobe`コマンドが正常に実行されなくなった問題を解消した方法を記載します。

# 解消方法

## 0. 前提条件

以下の事柄は実施しているものとします。

- `Ruby 3.2 running on 64bit Amazon Linux 2023`でEB環境を立ち上げていること
- ローカル環境で、Ruby/Railsのバージョンアップ作業が完了していること
- 適当なファイルにテスト用画像を保存しておくこと
    - 今回は、`spec/files/sample.png`という画像を保存しておきます

## 1. ffmpegインストール

ebextensionsを使用して`https://johnvansickle.com/ffmpeg/old-releases/ffmpeg-6.0-amd64-static.tar.xz`からffmpegのライブラリをインストールします。

```config
packages:
  yum:
    git: []
    libyaml-devel: []
    ImageMagick: []
    ImageMagick-devel: []
commands:
  01-wget:
    command: "wget -O /tmp/ffmpeg.tar.xz https://johnvansickle.com/ffmpeg/old-releases/ffmpeg-6.0-amd64-static.tar.xz"
  02-mkdir:
    command: "if [ ! -d /opt/ffmpeg ] ; then mkdir -p /opt/ffmpeg; fi"
  03-tar:
    command: "tar xvf /tmp/ffmpeg.tar.xz -C /opt/ffmpeg"
  04-ln:
    command: "if [[ ! -f /usr/bin/ffmpeg ]] ; then ln -sf /opt/ffmpeg/ffmpeg-6.0-amd64-static/ffmpeg /usr/bin/ffmpeg; fi"
  05-ln:
    command: "if [[ ! -f /usr/bin/ffprobe ]] ; then ln -sf /opt/ffmpeg/ffmpeg-6.0-amd64-static/ffprobe /usr/bin/ffprobe; fi"
  06-pecl:
    command: "if [ `pecl list | grep imagick` ] ; then pecl install -f imagick; fi"
```

## 2. デプロイ

`eb deploy`コマンドを使用してコードをデプロイします。

## 3. SSH接続する

デプロイが完了したら、`eb ssh`でEB環境にアクセスします。
合わせて`cd /var/app/current`と`export $(cat /opt/elasticbeanstalk/deployment/env)`を実行しておきます。

## 4. Railsコンソールを起動する

`bin/rails c`でRailsコンソールを起動します。

## 5. ffmprobeコマンドを実行する

### 5-1. Rails内に保存した画像に対して実行

予め保存しておいた画像に対してffprobeコマンドを実行します。

```sh
$ ffprobe -hide_banner "spec/files/sample.png"

Input #0, png_pipe, from 'spec/files/sample.png':
  Duration: N/A, bitrate: N/A
  Stream #0:0: Video: png, rgb24(pc), 200x200, 25 fps, 25 tbr, 25 tbn
```

### 5-2. インターネット上のサンプル画像に対して実行

`https://picsum.photos/200`という画像に対して実行します。

```sh
$ ffprobe -hide_banner "https://picsum.photos/200"

Segmentation fault (core dumped)
```

上記はS3のURLを指定しても同様のエラーが返ってきます。

このエラーについて、ffmpegライブラリのバージョンを上げても解決できませんでした。

## 6. Rails側の処理を書き換え

今まではRails側での処理は、S3のファイルパスを指定してffprobeコマンドを実行していましたが、Amazon Linux 2023にバージョンアップしたことでこれができなくなりました。

そのため、ローカル（EC2）にファイルをダウンロードしてffprobeコマンドを実行する形に変更しました。

以下のメソッドは参考までに...

```ruby
def download_file(attachment_file)
    # S3へアクセスできるようにする
    access_key = Settings.aws.s3.access_key
    secret_access_key = Settings.aws.s3.secret_access_key
    region_name = Settings.aws.s3.region
    credentials = Aws::Credentials.new(access_key, secret_access_key)
    s3_client = Aws::S3::Client.new(region: region_name, credentials:)

    # 必要な情報を処理、取得しておく
    bucket_name = Settings.aws.s3.bucket
    file_id = attachment_file.id
    file_url = attachment_file.file_url
    path = URI(file_url).path
    object_key = path[1..]

    # ファイルを保存するディレクトリを用意する
    attachment_dir = Rails.root.join('tmp', 'attachment_files', file_id.to_s)
    FileUtils.mkdir_p(attachment_dir) unless Dir.exist?(attachment_dir)
    local_path = attachment_dir.join(file_id.to_s)

    # S3のオブジェクトをローカルファイルにダウンロード
    File.open(local_path, 'wb') do |file|
      s3_client.get_object({ bucket: bucket_name, key: object_key }) do |chunk|
        file.write(chunk)
      end
    end

    local_path.to_s
  end
```

# まとめ

ffmpegが`Amazon Linux 2023`にも対応するまでは、手間ですが一度ファイルをダウンロードしてffprobeコマンドを実行しましょう。