Redmineのデータを旧サーバーから新サーバーへ移行する。
新サーバーのRedmineは『Redmine構築』で作成したDocker構築となっている。
事前容量確認
ディスク容量を確認する。
df -h
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 50G 14G 37G 28% /
ルートマウント(/)に37GBの空きがあるため問題ない。※使用率が80%を超えるようであれば、ボリューム拡張を検討する。
/dev/nvme0n1p2 と /dev/xvda2 の違い
/dev/xvda*:Xen ベースの仮想ディスク。/dev/nvme*:NVMe ベースのストレージ。
AWSでインスタンスタイプを変更したため、ストレージインターフェースが変更された。
既存Redmineのデータを取得
以下を取得する
- DBデータのダンプ
- 添付ファイルの圧縮データ
バックアップ用ディレクトリを作成
バックアップ用ディレクトリを作成する。
sudo mkdir -p /var/backups/redmine
権限を確認する。
ls -la /var/backups/redmine
DBダンプを取得
DBコンテナの名前(NAME)を確認する。
sudo docker compose ps
NAME IMAGE
redmine redmine:5.1.11
redmine-db-1 mysql:8.0
redmine-nginx nginx:1.27
DBダンプを取得する。
sudo docker exec redmine-db-1 mysqldump \
--single-transaction \
--default-character-set=utf8mb4 \
--no-tablespaces \
-u root -p"xxx" \
redmine \
> /tmp/redmine_dump.sql
ちなみに、具体的には以下のディレクトリのデータをダンプしている。
コンテナ内
/var/lib/mysql/redmine/
ホスト側
/var/lib/docker/volumes/redmine_db_data/_data/redmine/
ダンプファイルを確認
ファイルサイズを確認する。
ls -lh /tmp/redmine_dump.sql
先頭を確認する(正常にダンプできているか)。
head -5 /tmp/redmine_dump.sql
末尾を確認する(最後まで書き出せているか)。
tail -5 /tmp/redmine_dump.sql
期待結果
# ファイルサイズ
-rw-r--r--. 1 root root [XMB] ... /tmp/redmine_dump.sql
# 先頭
-- MySQL dump 10.13 Distrib 8.0.xx, for Linux (x86_64)
-- Host: localhost Database: redmine
# 末尾
-- Dump completed on YYYY-MM-DD HH:MM:SS
filesアーカイブを取得
ホスト側(実体)の添付ファイルデータを圧縮する。※3~5分かかる
sudo tar czvf /tmp/redmine_files.tar.gz \
-C /var/lib/docker/volumes/redmine_redmine_files/_data .
圧縮ファイルを確認
ファイルサイズを確認する。
ls -lh /tmp/redmine_files.tar.gz
アーカイブの中身の先頭を確認する。
tar tzf /tmp/redmine_files.tar.gz | head -10
DBマイグレーション
先ほど取得した既存RedmineのDBダンプを新サーバーに展開する。
※ダンプデータは容量が大きく、ヒューマンエラーでコピペ時に破損したりするので、コピー元の容量と、最終的に配置したデータの容量が一致するか確認すること
任意の場所にダンプファイルをアップロードする。
今回は以下とする。
/opt/redmine/migration/
Redmineコンテナを停止
docker-compose.yml を配置したフォルダへ移動する。
cd /opt/redmine
sudo docker compose stop redmine
Redmineデータベースを初期化
MySQLへログインする。
sudo docker exec -it redmine-db-1 mysql -u root -p"password"
※ -p の後にはスペースを入れないこと。
下記のSQLを実行してデータベースを初期化する。
SHOW DATABASES;
DROP DATABASE redmine;
CREATE DATABASE redmine
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
SHOW DATABASES;
SHOW CREATE DATABASE redmine;
EXIT;
下記のコマンドでリストアする。
※ リストア実行中にエラーが発生した場合は「インシデント1」を参照すること。
DBリストア
以下のコマンドを実行して、ダンプファイルをMySQLへリストアする。
nohup sudo docker exec -i redmine-db-1 mysql \
--default-character-set=utf8mb4 \
-u root -p"[root_password]" \
redmine < /opt/redmine/migration/redmine_dump.sql \
> /tmp/restore.log 2>&1 &
以下のようなプロセスIDが表示される。
[1] 1458100
プロセスを確認
ps aux | grep "mysql" | grep -v mysqld | grep -v grep
先ほど表示されたプロセスIDでリストアが進行していることを確認する。
ログを確認
tail -f /tmp/restore.log
エラーが出力されていなければ問題ない。
1〜2分経過したら、再度プロセスを確認する。
※ 完了ログは出力されないため、プロセスが終了していることをもって完了と判断する。
ps aux | grep "mysql" | grep -v mysqld | grep -v grep
最終確認
下記のSQLでデータが反映されたか確認する。
sudo docker exec -it redmine-db-1 mysql -u root -p"[root_password]" -e \
"USE redmine;
SELECT COUNT(*) AS table_count
FROM information_schema.tables
WHERE table_schema='redmine';
SELECT COUNT(*) AS projects FROM projects;
SELECT COUNT(*) AS issues FROM issues;
SELECT COUNT(*) AS users FROM users;
SELECT COUNT(*) AS time_entries FROM time_entries;"
projects や issues(チケット)、users が相当数登録されていればOK。
filesの展開
続いて、圧縮した添付ファイルデータを展開する。
先ほど取得した添付ファイルのtar.gzデータを以下に配置したものとする。
/opt/redmine/migration/
まずはアーカイブの構成を確認する。
sudo tar tzf /opt/redmine/migration/redmine_files.tar.gz | head -20
→ files/xxx のようなパス構成になっていれば最も一般的な構成。
※以下は files/xxx 構成の場合。
下記のコマンドでファイルを展開する。
※ファイル展開中にエラーが発生した場合は「インシデント2」を参照。
sudo tar xzvf /opt/redmine/migration/redmine_files.tar.gz \
-C /var/lib/docker/volumes/redmine_redmine_files/_data/ \
--strip-components=1 \
2>&1 | sudo tee /tmp/tar_extract.log
以下のようなプロセスIDが表示される。
[1] 1458100
プロセスを確認する。
ps aux | grep "tar" | grep -v grep
先ほどのプロセスIDでファイル展開が進行していることを確認する。
ログを監視する。
tail -f /tmp/restore.log
エラーが表示されていなければOK。
1~2分後に改めてプロセスを確認する。
※完了ログは出力されないため、プロセスが終了していることをもって完了と判断する。
ps aux | grep "tar" | grep -v grep
最終確認
tar.gz内のファイル数を確認する。
sudo tar tzf /opt/redmine/migration/redmine_files.tar.gz | grep -v '/$' | wc -l
期待結果
25005
展開済みファイル数を確認する。
sudo find /var/lib/docker/volumes/redmine_redmine_files/_data/ -type f | wc -l
期待結果
25005
両者が一致していればOK。
権限調整
展開されたファイルは所有者が root になっている可能性があるため、状態を確認する。
展開されたファイルの所有者を確認する。
(ホストOSとコンテナで見え方が異なるため、UID・GIDを数値で表示する。)
cd /var/lib/docker/volumes/redmine_redmine_files/_data
sudo ls -lan /var/lib/docker/volumes/redmine_redmine_files/_data/
下記のコマンドでRedmineのUIDとGIDを確認する。
cd /opt/redmine
sudo docker compose up -d redmine
sleep 10
sudo docker exec redmine id redmine
期待結果
uid=999(redmine) gid=999(redmine) groups=999(redmine)
展開したファイルの所有者がRedmineになっていることを確認する。
※他の所有者になっている場合は権限の修正が必要。
起動確認
コンテナの状況を確認する。
cd /opt/redmine
sudo docker compose ps
STATUS が Up になっていればOK。
コンテナのログを確認する。
sudo docker logs redmine --tail 30
Listening on http://0.0.0.0:3000 が表示されていればOK。
ブラウザからアクセスできるか確認する。
https://<このサーバーのIP>/redmine
または
https://<このサーバーのIP>/login/
- 404エラー:インシデント3を参照。
- ログインできない:インシデント4を参照。
インシデント
リストア実行中にエラー(インシデント1)
ERROR 1118 (42000) at line 1282207: Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
1つの行(レコード)のサイズが8126バイトを超えているため発生するエラー。
MySQLのInnoDBには、「1行あたり最大8126バイト」という制限がある。
docker-compose.ymlの設定を変更する
事前にバックアップを取得しておく。
docker-compose.yml に以下の設定を追加する。
db:
image: mysql:8.0
environment:
MYSQL_DATABASE: redmine
MYSQL_USER: redmine
MYSQL_PASSWORD: "change_me_db_password"
MYSQL_ROOT_PASSWORD: "change_me_db_password"
command: >
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--innodb-strict-mode=0 # 追加
--max-allowed-packet=256M # 追加
--innodb-log-file-size=256M # 追加
volumes:
- db_data:/var/lib/mysql
| 設定 | 目的 | 備考 |
|---|---|---|
--innodb-strict-mode=0 |
行サイズエラーを警告に格下げする。 | ★★★ 必須(今回のエラー対策) |
--max-allowed-packet=256M |
大きなSQLステートメントを許可する。 | ★★ 保険(大きいダンプ対策) |
--innodb-log-file-size=256M |
大きなトランザクションのログ領域を確保する。 | ★★ 保険 |
YAML構文をチェックする。
sudo docker compose config
DBコンテナを再起動する。
sudo docker compose up -d db
起動状態を確認する。
sudo docker compose ps
db コンテナの STATUS が Up になっていればOK。
設定が反映されたか確認する。下記の確認SQLを実行する。
sudo docker exec -it redmine-db-1 mysql -u root -p"change_me_db_password" -e \
"SHOW VARIABLES LIKE 'innodb_strict_mode';
SHOW VARIABLES LIKE 'max_allowed_packet';
SHOW VARIABLES LIKE 'innodb_log_file_size';"
DBを再作成
以下のSQLを実行
sudo docker exec -it redmine-db-1 mysql -u root -p"[PASSWORD]" -e "
DROP DATABASE redmine;
CREATE DATABASE redmine CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
SHOW DATABASES;"
リストア再実行
以下のSQLを実行
nohup sudo docker exec -i redmine-db-1 mysql \
--default-character-set=utf8mb4 \
-u root -p"[PASSWORD]" \
redmine < /opt/redmine/migration/redmine_dump.sql \
> /tmp/restore.log 2>&1 &
ファイル展開時にエラー(インシデント2)
ファイル検証
サーバー上の tar.gz ファイルが破損していないか確認する。
sudo tar tzf /opt/redmine/migration/redmine_files.tar.gz | awk -F'/' '{print $2}' | sort -u
実行結果
gzip: stdin: unexpected end of file
tar: Unexpected EOF in archive
tar: Error is not recoverable: exiting now
2018
2019
2020
2021
2022
2023
delete.me
ファイルが破損している。2024年以降のデータも出力されていない。
ローカルの tar.gz の破損有無確認
Git Bashで以下を実行する。
gzip -t redmine_files.tar.gz && echo "GZIP OK" || echo "GZIP NG"
実行結果
gzip: redmine_files.tar.gz: unexpected end of file
GZIP NG
→ ファイルが破損している。
サーバー上の tar.gz とローカルの tar.gz のサイズを比較する。→ 一致。
ローカルの tar.gz と、データ受領元の tar.gz のサイズを比較する。→ 不一致。
これらのことから、データ受領元からローカルへダウンロードした際に破損したと判断できる。
files の再展開
破損していないファイルを再配置する。
ファイルが破損していないか確認する。
sudo gzip -t /opt/redmine/migration/redmine_files.tar.gz && echo "GZIP OK" || echo "GZIP NG"
実行結果
GZIP OK
展開に失敗したファイル群を削除する。
sudo rm -rf /var/lib/docker/volumes/redmine_redmine_files/_data/*
sudo rm -f /var/lib/docker/volumes/redmine_redmine_files/_data/.[!.]*
以下のコマンドで正常に削除されたことを確認する。
# 中身確認(隠しファイルも含む)
sudo ls -la /var/lib/docker/volumes/redmine_redmine_files/_data/
# サイズ確認(ほぼ0になっているはず)
sudo du -sh /var/lib/docker/volumes/redmine_redmine_files/_data/
# ファイル数(0件のはず)
sudo find /var/lib/docker/volumes/redmine_redmine_files/_data/ -type f | wc -l
以下のコマンドで files を再展開する。
sudo tar xzvf /opt/redmine/migration/redmine_files.tar.gz \
-C /var/lib/docker/volumes/redmine_redmine_files/_data/ \
--strip-components=1 \
2>&1 | sudo tee /tmp/tar_extract.log
ログインページでID・パスワードを入力すると404エラー(インシデント3)
ログインページ:https://<IP>/redmine/login
ID・パスワードを入力すると、http://<IP>/login にリダイレクトされ、/redmine が消えている。
docker-compose.yml では以下を設定している。
RAILS_RELATIVE_URL_ROOT: /redmine
これにより、アプリはバックエンドに対し、/redmine を付与してリクエスト・レスポンスを送受信するはずだが、その設定が反映されていない。
Dockerの環境変数として定義されているだけで、Railsが読み込んでいない可能性がある。
明示的にこの変数を読み込む。
以下のコマンドで config.ru を作成する。
sudo tee /opt/redmine/config/config.ru > /dev/null <<'EOF'
# This file is used by Rack-based servers to start the application.
require_relative 'config/environment'
map (ENV['RAILS_RELATIVE_URL_ROOT'] || '/') do
run Rails.application
end
EOF
sudo chown 999:999 /opt/redmine/config/config.ru
cat /opt/redmine/config/config.ru
map(Rackの機能)で指定パスにアプリをマウントする。これにより、Railsアプリが /redmine 配下で動作するようになる。
以下を参考に docker-compose.yml にマウント設定を追加する。
volumes:
- redmine_files:/usr/src/redmine/files
- /opt/redmine/config/config.ru:/usr/src/redmine/config.ru # 追加
コンテナを再起動する。
sudo docker compose restart redmine
データ移行後にログインできなくなった(インシデント4)
既存環境ではLDAPのSSO認証を使用していたためと思われるが、一応ログを確認する。
sudo docker logs -f redmine
# 出力例
An error occurred when authenticating [username]: LDAP: getaddrinfo: Name or service not known
やはりLDAP認証になっているため、内部認証(Basic認証)へ変更する。
次のコマンドでBasic認証に書き換える。※以下は書き換えること。
User.find_by(login: '[username]')TempPass123:任意のパスワード
sudo docker exec -it redmine bash -c "cd /usr/src/redmine && bundle exec rails runner -e production \
\"u = User.find_by(login: 'your_username'); \
u.auth_source_id = nil; \
u.password = 'TempPass123'; \
u.password_confirmation = 'TempPass123'; \
u.must_change_passwd = false; \
u.save!; \
puts 'OK: ' + u.login + ' / auth_source_id: ' + u.auth_source_id.to_s\""
以下、解説。これらを1行で書いたものが上記。
sudo docker exec -it redmine bash
# コンテナ内に入る
bundle exec rails console -e production
# Railsコンソールを起動
u = User.find_by(login: '[username]')
# ユーザーを取得
# u.auth_source_id
# 現在の認証方式を確認したい場合
u.auth_source_id = nil
# Basic認証(内部認証)へ切り替え
u.password = 'TempPass123'
u.password_confirmation = 'TempPass123'
u.save!

コメント