Redmine 5.1からRedmine 6.1への移行では、できるだけ本番環境へ影響を出さないよう、検証環境で一つずつ作業を進めてきました。

今回は以前のように「一気にアップグレードして問題を追う」のではなく、

  • 検証環境を作る
  • 問題が起きたら原因を調べる
  • 記録として残す
  • 次の工程へ進む

という流れで進められたため、最終的にはかなり安心して6.1環境を完成させることができました。

その途中で遭遇したのが、データベースマイグレーション時の Table already exists エラーです。

最初は単純なテーブル重複かと思いましたが、原因を追っていくとRedmine 6.0で行われた「プラグイン機能の本体統合」が関係していました。

今回は、このマイグレーションエラーの内容と対処手順を記録しておきます。

実データを流し込んだ直後にマイグレーションが止まる

今回の手順では、Redmine 5.1で整理・純化しておいたデータベースをMySQLダンプから復元し、そのままRedmine 6.1側でマイグレーションを実行しました。

cd /home/www-data/redmine_v6
sudo -u www-data RAILS_ENV=production bundle exec rake db:migrate

ところが途中で処理が停止します。

最初に止まったのは、リアクション機能です。

== 20250423065135 CreateReactions: migrating ==================================
-- create_table(:reactions)

Mysql2::Error:
Table 'reactions' already exists

この時点では、

「どこかでマイグレーションを実行し忘れたかな?」

程度に考えていました。ところが、修正して再実行すると、今度はこちら。

== 20250611092155 CreateDoorkeeperTables: migrating ===========================

Mysql2::Error:
Table 'oauth_applications' already exists

また別のテーブルが既に存在すると言われます。つまり偶然ではなく、何か共通した原因がありそうでした。

原因は「昔はプラグイン、今は標準機能」

調べてみると、どちらもRedmine 6.0で本体へ取り込まれた機能でした。

今回衝突したのは、

  • リアクション機能
  • OAuth認証(Doorkeeper)

の二つです。どちらも以前はプラグインとして利用していましたが、Redmine 6ではコア機能になっています。つまり、

Redmine 5.1時代

プラグイン
    ↓
DBにテーブル作成

だったものが、Redmine 6.1では、

Redmine本体
    ↓
同じ名前のテーブルを作成

という流れに変わっています。そのため、旧環境からDBを持ってくると、

既に存在するテーブルを、Redmine本体がもう一度作ろうとする

という状態になっていました。

なぜDROPしてよいのか

ここで少し悩みました。

「既存テーブルを削除してしまって本当に大丈夫なのか?」

しかし今回は、本体側へ正式に統合された機能です。つまり最終的に利用するのはRedmine本体が管理するスキーマになります。古いプラグイン時代のテーブルを残していても、最終的には使われません。

そこで今回は、競合しているテーブルだけを削除し、本体マイグレーションに改めて生成してもらうことにしました。

競合しているテーブルを削除する

MySQLから競合しているテーブルを削除します。

mysql -u redmine_v6 -p redmine_v6 -e "
DROP TABLE IF EXISTS reactions;
DROP TABLE IF EXISTS oauth_access_tokens;
DROP TABLE IF EXISTS oauth_access_grants;
DROP TABLE IF EXISTS oauth_applications;
"

これで、本体側が新しくテーブルを作れる状態になります。

改めてマイグレーションを実行する

続いて再度マイグレーションを実行します。

cd /home/www-data/redmine_v6
sudo -u www-data RAILS_ENV=production bundle exec rake db:migrate

今度は問題なく進みます。

== CreateReactions: migrated
== EnsureWikiTablesortSettingIsStoredInDb: migrated
== CreateDoorkeeperTables: migrated

最後まで完走し、正常終了しました。

プラグイン側も忘れずに更新

本体が終わったら、続いてプラグイン側のマイグレーションも実行します。

sudo -u www-data RAILS_ENV=production bundle exec rake redmine:plugins:migrate

本体だけ更新して安心しがちですが、ここまで実行して初めてプラグイン側も新しい環境へ追従できます。

configuration.ymlも忘れずに引き継ぐ

今回の環境ではSMTP設定も引き継ぐ必要がありました。

既存環境から configuration.yml をコピーします。

sudo -u www-data cp -p \
/home/www-data/redmine/config/configuration.yml \
/home/www-data/redmine_v6/config/configuration.yml

その後、Passengerを再起動します。

sudo touch /home/www-data/redmine_v6/tmp/restart.txt
sudo systemctl reload apache2

最後に管理画面からテストメールを送信し、Zoho Mail経由で正常に届くことまで確認しました。

移行後の確認

今回の検証では、最終的に以下を確認できました。

  • 過去のチケット・Wiki・添付ファイルを正常に閲覧できる
  • ガントチャートも問題なく表示される
  • kodomo テーマもRedmine 6.1環境で正常動作
  • テストメールを送信し、Zoho Mailで受信できることを確認
  • DMSFを利用しなくても、標準添付機能で画像を配置できることを確認

ここまで確認できれば、検証環境としては十分安心できる状態になりました。

今回の移行を振り返って

今回のRedmine 6.1移行では、「作業そのもの」よりも「途中で何が起きたか」を残しながら進められたことが大きかったように思います。

以前であれば、エラーを解消して先へ進むことを優先していた場面でも、

  • なぜ起きたのか
  • Redmine側の仕様変更なのか
  • プラグイン由来なのか
  • 次に同じ作業をするとき、何を確認すればよいのか

という視点で整理しながら進められました。

結果として、今回遭遇した Table already exists も「たまたま起きたエラー」ではなく、Redmine 6でプラグイン機能が本体へ統合されたことによる仕様変更だと理解できました。

移行作業では、どうしてもエラーそのものへ目が向きがちですが、「なぜそのエラーが起きたのか」まで追っておくと、次回以降の作業はずっと楽になります。

今回の6.1環境は、そうした記録を積み重ねながら構築できたこともあり、これまでで一番安心して仕上げられたバージョンアップだったように感じています。