Redmineをv1.4からv5.1へアップグレード

最近、とあるお仕事で長年運用してきたRedmine v1.4をRedmine v5.1へアップグレードしました。
Redmineの構築は約10年ぶり。作業しながらだんだん思い出してきましたが、Redmineのインストールはとても面倒です。Redmineの、というよりは、Ruby on Railsベースのアプリの、というほうが正しいのかもしれませんが。
作業のログを残しておきます。

# 要件

* __OSのEOSL対応__。元々Redmineを運用してきたサーバーのOSのEOSL対応が必要なため、別途新しくサーバーを用意してRedmineをインストールする。
* __基盤をさくらのVPSからAWSへ移行__。構築や運用における様々な利便性を考慮し、新しいサーバーOSはAWS上に構築する。
* __旧環境のデータを新環境へ移行__。旧環境のRedmineからデータベース内の全データとディスク上の添付ファイルを移行する。
* __DBもEOSL対応__。OS同様にEOSL対応が必要なため、新しいサーバー上に最新のMySQLをインストールする。
* __RDS化やコンテナ化はなし__。移行対象のRedmineはアクセス数もデータ量も限られ、SLAもとくに考慮しなくていい環境のため、1つのEC2インスタンス上ですべて完結させることとする。技術的には魅力的ではあったがコスト最適の観点で思いとどまった。

# スペック比較

今回のアップグレードによる旧環境と新環境のスペック（バージョン等）を対比すると以下のようになる：

| 項目 | 旧環境 | 新環境 |
|:-|:-|:-|
| サーバースペック  | 仮想コア2、メモリ1GB、HDD100GB  | 仮想コア2、メモリ0.5GB、HDD10GB（インスタンスタイプにt4g.nano、EBSにgp3を使用） |
| OSディストリビューション＆バージョン  | CentOS v6.8  | Amazon Linux 2023（minimal）  |
| Rubyバージョン  | v1.9  |  v3.2 |
|  Apache httpdバージョン | v2.2  | v2.4  |
| MySQLバージョン  | v5.1  |  v8.0 |
|  Redmineバージョン | v1.4  | v5.1  |

:::note warn
EC2インスタンスタイプは基本的には `t4g.nano` なのだが、`bundle install`や`gem install`実行時だけ一時的に `t4g.xlarge`に引き上げている。`gem install`は依存関係の解決とビルドに大きなリソースを要求するようで、`nano`のままでは実質的にハングしてしまったため。
:::

# 手順1：仮想マシンの作成

インスタンスタイプは`t4g.nano`。とにかく安価なオプションを求めていたので、サイズは最小しかもARMアーキテクチャを選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/4f1f6acb-8ec6-0b84-4632-4c88578cca16.png)

AMIは `amazon/al2023-ami-minimal-2023.4.20240319.1-kernel-6.1-arm64`。
OSのディストリビューションは旧環境がCentOSであったため、Amazon Linux 2023を選択した。CentOSの後継としてはRockyなど複数がありえたが、AWS上で運用する上で「あえて」Amazon Linux以外を選ぶ理由が今回はなかったので。
さらにディスク容量もなるべく節約したかったため、Amazon　Linux 2023のAMIのうちでも「minimal」のものを利用。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/4c7cbf92-504a-6b33-2a84-a8969cf044df.png)

:::note info
作成した仮想マシン（EC2インスタンス）にはSSH接続およびSFTP接続を行うためのセットアップをいたしましたが、この記事の趣旨とはあまり関係がないので、ここではその手順は割愛いたします。
:::

# 手順2：パッケージのインストール

RubyやApache httpdをはじめとしたパッケージをインストール。まずは`dnf`でインストールできる範囲。

```sh
sudo dnf install ruby3.2 ImageMagick ghostscript httpd
````

Apache httpdをサービスとして起動しておく：

```sh
sudo systemctl start httpd
sudo systemctl enable httpd
```


Amazon Linux 2023の標準YumリポジトリーにはMySQLが含まれないため、MySQLのサイトからPRMを入手する。
[MySQL Yum Repository](https://dev.mysql.com/downloads/repo/yum/)にリストアップされたもののうち、以下のRPMを利用した：

> Red Hat Enterprise Linux 9 / Oracle Linux 9 (Architecture Independent), RPM Package
> (mysql80-community-release-el9-5.noarch.rpm)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/23d7d0bd-e36c-26a5-0ccb-627671bc0c56.png)

```sh
sudo dnf localinstall  https://dev.mysql.com/get/mysql80-community-release-el9-5.noarch.rpm
sudo dnf install mysql-community-server mysql-community-client
```

MySQLをサービスとして起動しておく：
```sh
sudo systemctl start mysqld
sudo systemctl enable mysqld
```

さらに`bundle install`や`gem install`で依存性解決とビルドを行うために必要になるパッケージをインストール：

```sh
sudo dnf groupinstall "Development Tools"
sudo dnf install ruby-devel openssl-devel readline-devel zlib-devel curl-devel libffi-devel mysql-community-devel httpd-devel libpq-devel
```

:::note warn
ここでははじめからインストールすべきパッケージが分かっているかのような書き方になっていますが、実際にこのアップグレードを行った時にはトライ＆エラーでした。`bundle install`や`gem install`の実行中に様々な依存性不足のエラーに見舞われており、そのたび`dnf install`で不足している依存性（パッケージ）をインストールしています。
:::

# 手順3：旧環境のデータを転送

旧環境から各種データをエクスポートして新環境に転送する。
まずはデータベースをダンプしてGZIP圧縮（データベースのユーザー名やデータベース名は適宜読み替えて）：

```sh
mysqldump -u redmine_user -p redmine_db | gzip > redmine_db_`date +%y_%m_%d`.gz
```

次に添付ファイルをTARアーカイブ化してGZIP圧縮（Redmineのインストール・ディレクトリは適宜読み替えて）：

```sh
tar zcvf redmine_files_`date +%y_%m_%d`.tar.gz  /var/lib/redmine/files
```

さらに設定ファイルをTARアーカイブ化してGZIP圧縮（同上）：

```sh
tar zcvf redmine_config_`date +%y_%m_%d`.tar.gz  /var/lib/redmine/config
```

これらのGZIPファイルを新環境の仮想マシンにアップロードしておく。

:::note warn
言うまでもないことですが、いずれのコマンドについても、ファイルパスやデータベース・ユーザー名、データベース名などは旧環境のインストール状況にあわせて指定する必要があります。
:::

# 手順4：空のデータベースを作成

先ほどMySQLを起動した時にMySQLが出力したログから、`root`ユーザーの初期パスワードを入手する：

```sh
cat /var/log/mysqld.log |grep "A temporary password"
```

パスワードの規則を厳格化し、`root`ユーザーのパスワードを変更し、不要なデータベースを削除する：

```sh
mysql_secure_installation
```

MySQLデータベースに接続し：

```sh
mysql -u root -p
```

空のデータベースを作成する：

```sql
CREATE DATABASE redmine_db CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
CREATE USER 'redmine_user'@'localhost' IDENTIFIED BY 'xxxx';
GRANT ALL PRIVILEGES ON redmine_db.* TO 'redmine_user'@'localhost';
```

旧環境のデータベースのダンプ・ファイルを解凍して、今しがた作成した空のデータベース上に復元する：

```sh
tar -zxvf redmine_db_...gz
mysql -u user_redmine -p db_redmine < redmine_db_...
```

# 手順5：Redmineをインストール

Redmineの公式サイトの[Latest releases](https://www.redmine.org/projects/redmine/wiki/Download)ページから、最新のstableなリリースの`tar.gz`ファイルをダウンロードし、新環境の仮想マシン上にアップロードする。
今回は `redmine-5.1.2.tar.gz`：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/fce1346e-1eb8-58bc-8a69-43eb3429d234.png)

ファイルを解凍・展開して `/var/lib/redmine` として配置（移動＆リネーム）：

```sh
tar -zxvf redmine-5.1.2.tar.gz
sudo mv redmine-5.1.2 /var/lib/redmine
```
旧環境から転送してきた添付ファイルを `/var/lib/redmine/files/` 配下に配置：

```sh
tar -zxvf redmine_files_24_03_23.tar.gz
sudo mv files/* /var/lib/redmine/files/
```
旧環境から転送してきた設定ファイルを `/var/lib/redmine/config/` 配下に配置。
今回のアップグレード対応では `database.yml` と `configuration.yml` のみを配置しているが、必要に応じて他のファイルも配置する：

```sh
tar -zxvf redmine_config_24_03_23.tar.gz

sudo cp config/database.yml /var/lib/redmine/config/
sudo cp config/configuration.yml /var/lib/redmine/config/
```

設定ファイルに記述されているデータベースの接続情報を、新環境のデータベースにあわせて修正する。またアダプター名が `mysql` となっていたので、 `mysql2` に書き換え：

```sh
sudo vi /var/lib/redmine/config/database.yml
```

`build install`コマンドを実行する前にEC2インスタンスのインスタンスタイプを `t4g.nano`から`t4g.xlarge`に変更。

:::note info
`t4g.nano`のまま`build install`コマンドを実行すると、スペック不足のためか、依存性解決の開始後その先に処理が進まなくなってしまい、事実上のハング状態となってしまいました。このため一時的にインスタンスタイプを変更しています。`xlarge`を選んだことにとくに理由はなく、「さすがにこれくらいあれば十分だろう」と思ってこうしたというにすぎません。。
:::

Redmineの依存性解決とビルドのために`build install`を行う：

```sh
cd /var/lib/redmine/
sudo bundle install --without development test
```
Railsがセッション情報の管理に使用するCookieの暗号化に使用するトークンを（再）生成：

```sh
sudo bundle exec rake generate_secret_token
```

インスタンスタイプを`t4g.xlarge`から `t4g.nano`に変更（元に戻す）。

:::note warn
戻し忘れに注意してください。言うまでもないことですが戻し忘れるとEC2インスタンスの利用料として無用なコストを払うことになります。
:::

データベースをバージョンアップしているのでマイグレーションを実行：

```sh
sudo bundle exec rake db:migrate RAILS_ENV=production
```

# 手順6：Passengerをインストール

Railsアプリケーションを実行するためのApache httpdモジュール Passengerをインストールする。

```sh
sudo gem install passenger
sudo passenger-install-apache2-module
```

インストールが完了すると、以下のようなメッセージが表示され、Apache httpdの設定ファイルの編集を案内される：

```
Please edit your Apache configuration file, and add these lines:

 LoadModule passenger_module /usr/local/share/ruby3.2-gems/gems/passenger-6.0.20/buildout/apache2/mod_passenger.so
 <IfModule mod_passenger.c>
   PassengerRoot /usr/local/share/ruby3.2-gems/gems/passenger-6.0.20
   PassengerDefaultRuby /usr/bin/ruby3.2
 </IfModule>

After you restart Apache, you are ready to deploy any number of web
applications on Apache, with a minimum amount of configuration!

Press ENTER when you are done editing.
```

`/ect/httpd/conf.module.d/passenger.conf`を作成して、指示された内容＋αを書き込む。今回は サイトのルート・ディレクトリでRedmineを配信するのでドキュメント・ルートを`/var/lib/redmine/public`とする。これに伴う権限設定を`Directory`ディレクティブで行っている：

```sh
sudo vi /ect/httpd/conf.module.d/passenger.conf
```

```conf
LoadModule passenger_module /usr/local/share/ruby3.2-gems/gems/passenger-6.0.20/buildout/apache2/mod_passenger.so
<IfModule mod_passenger.c>
  PassengerRoot /usr/local/share/ruby3.2-gems/gems/passenger-6.0.20
  PassengerDefaultRuby /usr/bin/ruby3.2

  Header always unset "X-Powered-By"
  Header always unset "X-Rack-Cache"
  Header always unset "X-Content-Digest"
  Header always unset "X-Runtime"
</IfModule>

<Directory "/var/lib/redmine/public">
  Require all granted
</Directory>
```

:::note info
`passenger.conf`は旧環境では`/etc/conf.d/`配下に作成していましたが、新環境では`/ect/httpd/conf.module.d/`配下に作成しています。これはApache httpdにより自動的に読み込まれるモジュールの設定ファイルの置き場所が変わったためです。
:::


前述の通りドキュメント・ルートを`/var/lib/redmine/public`とするのでその設定を `httpd.conf`に行う：

```sh
sudo vi /ect/httpd/conf/httpd.conf
```

`DocumentRoot /var/www/html`となっている行をコメントアウトし、 `DocumentRoot /var/lib/redmine/public`という行を追加する。

ここまで追加した各種ファイルについてオーナーを `root:root`から`apache:apache`に変更する：

```sh
sudo chown -R apache:apache /var/lib/redmine
```

Apache httpdを再起動して設定を反映させる：

```sh
sudo systemctl restart httpd
```

:::note warn
今回は サイトのルート・ディレクトリ（例：`http://www.example.com/`）でRedmineを配信するのでこのような設定になりました。
サブディレクトリ（例：`http://www.example.com/redmine/`）で配信する場合は`httpd.conf`と`passenger.conf`の記載内容が異なってくるのでご注意ください。
:::

どうにかこうにかRedmineのアップグレードが完了。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/9fd113d3-8b2b-3dd2-35e3-b7419fc54536.png)