From 67f8f81fcf962b25c14b224bd876decfee47ed15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AD=A6=E8=94=B5=E4=B8=80=E5=BC=98?= Date: Sun, 4 Oct 2026 18:38:54 +0900 Subject: [PATCH] =?UTF-8?q?NAS=20=E3=81=A7=E3=81=AE=E3=83=90=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=82=A2=E3=83=83=E3=83=97=E3=81=AE=E5=AE=9F=E6=A9=9F?= =?UTF-8?q?=E7=B5=90=E6=9E=9C=E3=82=92=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT.md | 6 ++++-- docs/deploy.md | 40 +++++++++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/PROJECT.md b/PROJECT.md index 3b1873f..77da2d6 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -144,11 +144,13 @@ TVer(`https://tver.jp/`)で公開中の動画情報を取得し、選んだ - 本番の`/healthz`はHTTP `200`、新着バラエティは98件だった。4分の本編`ep5hcgopp2`は登録から20秒以内に完了し、92,340,468バイトの1080p H.264/AAC MP4をNASへ保存した。所有者はUID `1024`・GID `100`、`.incoming`は空で、`/library`とHTTP Range `206`も確認した [実機] 2026-10-04 確認 - NASは番組フォルダ内に所有者UID `0`の`@eaDir`を作る。ライブラリ一覧はDBから作るため、アプリへの影響はない [実機] 2026-10-04 確認 - `callNewerDetail/drama`は毎回100件を返し、応答に続きや総件数を示す項目はなかった。`result.contents`は`type=newer`で、`content`は`id`・`version`・`title`のみ。`page=2`・`offset=100`・`limit=200`を付けても先頭・末尾IDが同じ100件となり、パラメータは無視された。100件を超えて取得する手段は見つからなかったが、非公開APIのため不可能とは断定しない。新着一覧は直近100件までとなる一方、登録番組の自動確認は番組ごとの`callSeriesSeasons`→`callSeasonEpisodes`を使うため、新着から外れた回も取りこぼさない [実機] 2026-10-04 確認 -- dockage上の使い捨て`postgres:17`コンテナへマイグレーション001〜003を適用してテスト用の行を投入し、`backup-db.sh`と`restore-test.sh`を実行した。gzip圧縮・権限600のダンプ作成、同じ`STAMP`での2回目が`ln`の失敗で非0終了して既存ダンプを保持すること、主要4表の行数一致、一時DBの削除、ログに`psql`の標準出力が残らないことを確認した。NASの`tver-postgres`とDSMタスクスケジューラでの実行は未確認 [実機] 2026-10-04 確認 +- dockage上の使い捨て`postgres:17`コンテナへマイグレーション001〜003を適用してテスト用の行を投入し、`backup-db.sh`と`restore-test.sh`を実行した。gzip圧縮・権限600のダンプ作成、同じ`STAMP`での2回目が`ln`の失敗で非0終了して既存ダンプを保持すること、主要4表の行数一致、一時DBの削除、ログに`psql`の標準出力が残らないことを確認した [実機] 2026-10-04 確認 +- NASの`/volume1/docker/tver-db/`へスクリプトを配置し、DSMタスクスケジューラのrootタスクから実行して、`/volume1/backups/tver/`へ`tver_20261004_182838.sql.gz`(2,286バイト)と`tver_20261004_183256.sql.gz`(2,289バイト)を作成した。ダンプはroot所有・権限600で、バックアップディレクトリはroot所有・`drwxr-xr-x`だった。`restore-test.sh`を`sudo`で実行し、`download_jobs` 1件・`subscriptions` 1件・`known_episodes` 1件・`schema_migrations` 3件の一致、ログへの結果記録、一時DBの削除を確認した。一般ユーザーではroot所有のログへ書き込めず失敗する [実機] 2026-10-04 確認 +- DSMのACLで全員書き込み可だった`/volume1/docker`配下について、`/volume1/docker/tver-db`を`chmod 755`、`backup-db.sh`と`restore-test.sh`を`chmod 700`にしてACLが外れたことを確認した。変更後も本番アプリの`/queue`と`/subscriptions`はHTTP `200`でDBを読み取れた。PostgreSQLコンテナ再起動後の動作は未確認 [実機] 2026-10-04 確認 ## 課題 -- DSMの日次バックアップタスクを登録し、本物の`tver-postgres`でバックアップ作成と`restore-test.sh`による一時DBへの復元を1回確認する [要確認] +- 登録済みのDSM日次バックアップタスクが翌日以降に自動実行され、新しいダンプを作ることを確認する [要確認] - DRM・地域制限の実例探しはTVerへの大量アクセスになるため行わず、運用中に観測する。workerは失敗時の`error_message`をDBへ保存し、既知の文言に一致しない失敗は`unknown`にする。実例が出た時点で分類を見直す ## 確かめ方 diff --git a/docs/deploy.md b/docs/deploy.md index 016a938..3a2139f 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -56,13 +56,18 @@ tags: /volume1/docker/tver-db/pgdata/ ``` -2. [[../deploy/nas/tver-db/compose.yaml|NAS用compose.yaml]]、`.env.example`、`backup-db.sh`、`restore-test.sh`を`/volume1/docker/tver-db/`に配置し、スクリプトを所有者だけが実行できるようにする。 +2. [[../deploy/nas/tver-db/compose.yaml|NAS用compose.yaml]]、`.env.example`、`backup-db.sh`、`restore-test.sh`を`/volume1/docker/tver-db/`に配置する。ディレクトリはroot以外がファイルを削除・置換できないようにし、スクリプトはrootだけが実行できるようにする。 ```bash + chmod 755 /volume1/docker/tver-db chmod 700 /volume1/docker/tver-db/backup-db.sh chmod 700 /volume1/docker/tver-db/restore-test.sh + ls -ld /volume1/docker/tver-db + ls -l /volume1/docker/tver-db/backup-db.sh /volume1/docker/tver-db/restore-test.sh ``` + DSMのACLが付いている場合、`chmod`後の`ls`でパーミッション表示の末尾から`+`が外れ、ディレクトリが`drwxr-xr-x`、スクリプトが`-rwx------`になったことを確認する。`/volume1/docker`では全員書き込み可のACLが確認されたため、スクリプトだけでなく配置ディレクトリにも`chmod 755`を適用する。 + 3. `.env.example`を`.env`へコピーし、`POSTGRES_PASSWORD`に十分長いランダムな値を設定する。値には、URLへの埋め込みで追加のエスケープが不要な16進文字列を使える。 ```bash @@ -257,37 +262,46 @@ DSMの「コントロール パネル」→「タスク スケジューラ」で `DOCKER`、`CONTAINER`、`BACKUP_DIR`、`KEEP_DAYS`、`DB_USER`、`DB_NAME`は環境変数で上書きできる。通常運用では既定値を使う。 -> [!todo] NAS実機で確認する -> DSMタスクの登録、1回の手動実行、日次実行の履歴、14日より古い世代の削除は未確認である。[要確認] +> [!success] NASで手動実行を確認済み +> DSMタスクスケジューラへrootの日次タスクを登録し、手動実行で2つのgzipダンプを作成した。復元確認も成功している。翌日以降の日次自動実行は未確認である。[実機] 2026-10-04 確認 + +> [!todo] 日次自動実行を確認する +> 翌日以降にDSMタスクの実行履歴と新しいダンプを確認する。[要確認] ### 5.2 手動でバックアップを確認する NASへSSH接続し、初回は手動で実行する。 ```bash -bash /volume1/docker/tver-db/backup-db.sh -LATEST=$(find /volume1/backups/tver -name 'tver_*.sql.gz' -type f -print | sort | tail -n 1) +sudo bash /volume1/docker/tver-db/backup-db.sh +LATEST=$(sudo find /volume1/backups/tver -name 'tver_*.sql.gz' -type f -print | sort | tail -n 1) test -n "$LATEST" -test -s "$LATEST" -gzip -t "$LATEST" -ls -lh "$LATEST" +sudo test -s "$LATEST" +sudo gzip -t "$LATEST" +sudo ls -lh "$LATEST" ``` スクリプトが`OK:`、保存先、バイト数を表示し、`gzip -t`が成功することを確認する。`pg_dump`の失敗や空のダンプでは非0で終了し、完成ファイルを残さない。同じ秒の完成ファイルが既にある場合も非0で終了し、既存ファイルを上書きしない。同時実行時は同一ディレクトリ内のハードリンク作成に成功した一方だけが完成ファイルを公開する。 +> [!success] NASでのバックアップ結果 +> DSMタスクスケジューラから実行し、`tver_20261004_182838.sql.gz`(2,286バイト)と`tver_20261004_183256.sql.gz`(2,289バイト)を`/volume1/backups/tver/`へ作成した。ダンプはroot所有・権限600で、バックアップディレクトリはroot所有・`drwxr-xr-x`だった。[実機] 2026-10-04 確認 + ### 5.3 別DBへの復元を確認する 最新ダンプを本番DBへ戻す前に、同じコンテナ内の一時DB`tver_restore_test`へ復元する。 ```bash -bash /volume1/docker/tver-db/restore-test.sh -tail -n 100 /volume1/backups/tver/restore-test.log +sudo bash /volume1/docker/tver-db/restore-test.sh +sudo tail -n 100 /volume1/backups/tver/restore-test.log ``` -`download_jobs`、`subscriptions`、`known_episodes`、`schema_migrations`の行数が本番DBと一致し、最後に「復元確認に成功」と表示されることを確認する。復元SQLの通常出力は抑制され、ログには開始、各表の結果、成功または失敗が残る。SQLエラーは標準エラーとしてログに残る。一時DBは成功・失敗のどちらでもEXIT trapで削除される。本番DBに対しては行数取得の`SELECT`だけを実行する。 +`restore-test.sh`はrootで実行する。バックアップディレクトリとログがroot所有のため、一般ユーザーでは`restore-test.log`への書き込みに失敗する。`download_jobs`、`subscriptions`、`known_episodes`、`schema_migrations`の行数が本番DBと一致し、最後に「復元確認に成功」と表示されることを確認する。復元SQLの通常出力は抑制され、ログには開始、各表の結果、成功または失敗が残る。SQLエラーは標準エラーとしてログに残る。一時DBは成功・失敗のどちらでもEXIT trapで削除される。本番DBに対しては行数取得の`SELECT`だけを実行する。 -> [!todo] 復元確認を実行する -> 本物のNASと`tver-postgres`では未実行である。手動バックアップ後に`restore-test.sh`を1回実行し、ログと一時DBの削除を確認する。[要確認] +> [!success] NASでの復元確認結果 +> 一般ユーザー`kazu634`での実行は`restore-test.log`へ書き込めず、`touch: Permission denied`で終了した。`sudo`で実行すると、`download_jobs` 1件、`subscriptions` 1件、`known_episodes` 1件、`schema_migrations` 3件が本番DBと一時DBで一致し、「復元確認に成功」と表示された。同じ結果がログに残り、一時DBも削除された。[実機] 2026-10-04 確認 + +> [!note] 配置ディレクトリの権限変更後の状態 +> `/volume1/docker/tver-db`を`chmod 755`にした後も、本番アプリの`/queue`と`/subscriptions`はHTTP `200`を返し、DBを読み取れた。PostgreSQLコンテナを再起動した後の動作は未確認である。[要確認] ### 5.4 障害時に本番DBへ復元する