Dockerfile.prodからイメージをビルドしてECRにプッシュしてデプロイを行なっていたところ、ECSのサービスのタスクログにexec /usr/bin/sh: exec format errorが出ました。
(初回のみ)
$ docker buildx create --use
$ docker image inspect イメージID
でイメージのアーキテクチャを確認するとDockerイメージのアーキテクチャがarm64であることが確認できました。一方、ECSのホスト環境がx86_64である場合、この互換性の問題が原因で「exec format error」が発生しているようでした。
結論としてDockerfile.prodで--platform=linux/x86_64を指定することで解決できました。
Dockerfile.prod
# ベースイメージの指定
# FROM ruby:3.3.0 としていたものを下記に変更
FROM --platform=linux/x86_64 ruby:3.3.0
# 環境変数の設定
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo
ENV RAILS_ENV=production
# アプリケーションディレクトリの作成
RUN mkdir /myapp
WORKDIR /myapp
# GemfileとGemfile.lockをコピー
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
# Bundlerのバグを処理
RUN gem update --system && \
bundle update --bundler && \
bundle install
# アプリケーションのソースコードをコピー
COPY . /myapp
# 必要なディレクトリの作成
RUN mkdir -p tmp/sockets tmp/pids
# ボリュームの設定
VOLUME /myapp/public
VOLUME /myapp/tmp
# エントリーポイントスクリプトをコピーし、実行可能にする
COPY entrypoint.prod.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.prod.sh
# エントリーポイントとポートの設定
ENTRYPOINT ["entrypoint.prod.sh"]
EXPOSE 3000
entrypoint.prod.sh
#!/bin/bash
set -ex
echo "Start entrypoint.prod.sh"
echo "Removing old server PID file if it exists..."
rm -f /myapp/tmp/pids/server.pid
# データベースの作成は、既に存在する場合に失敗する可能性があるため、エラーを無視するオプションを追加します
echo "Creating database (if it doesn't exist)..."
bundle exec rails db:create RAILS_ENV=production --trace || echo "Database creation failed, but continuing..."
echo "Running database migrations..."
bundle exec rails db:migrate RAILS_ENV=production --trace
# データベースシード処理が失敗した場合もエラーを無視するオプションを追加します
echo "Seeding the database..."
bundle exec rails db:seed RAILS_ENV=production --trace || echo "Database seeding failed, but continuing..."
echo "Starting Rails server with Puma..."
bundle exec puma -C config/puma.rb
# コマンドライン引数で指定されたコマンドを実行
exec "$@"
その他にもビルド時にプラットフォームを指定する方法でも解決できました。
$ docker buildx build --platform linux/amd64 -t イメージ名 .