TL;DR:アップグレードでミスがあり、支援を求めています
Home Assistant では、コミュニティ運営のために Discourse を利用しています。AWS の EC2 インスタンス上で discourse_docker 方式で運用しています。
オープンソースプロジェクトであるため、フォーラムのメンテナンスがおろそかになり、最終的に 2019 年初頭に最後に更新された古いバージョンのままになってしまいました。
さらに悪いことに、以前のアップグレードで、Postgres 10 へのアップグレードに必要なディスク容量が不足していたため、Postgres を 9.5 に固定してしまいました。この問題は未解決のまま放置されていました。
また、過去に Cloudflare のテンプレートに変更を加え、それをリポジトリにコミットしてしまいました。これにより、docker_discourse ブランチが最新バージョンに自動更新されなくなっていました。
昨日、アップグレードを実行することにしました…
データベースのマイグレーション中に、9.5 と互換性のない構文が使用されているという問題に遭遇しました。
== 20200429095034 AddTopicThumbnailInformation: migrating =====================
-- execute("ALTER TABLE posts\nADD COLUMN IF NOT EXISTS image_upload_id bigint\n")
9.5 が固定されている問題をすぐに気づき、Postgres 10 への移行を試みました。しかし、それは失敗し、以下のエラーが発生しました。
I, [2020-06-12T00:30:55.448351 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 10
WARNING: Upgrading PostgresSQL would require an addtional 89M of disk space
Please free up some space, or expand your disk, before continuing.
利用可能な容量は 47GB あり、これは奇妙でした。その後、discourse_docker が古かったことに気づき、最新バージョンに更新しました。驚いたことに、Postgres 12 が直ちにリリースされていました。
再度 rebuild を実行すると、今度は以下のエラーが発生しました。
I, [2020-06-12T00:41:17.378129 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 12
WARNING: Upgrading PostgresSQL would require an addtional 92G of disk space
Please free up some space, or expand your disk, before continuing.
これは少し多くの容量が必要ですが、まあ仕方ありません。ディスク容量を 300GB に増やして、再度実行してみましょう。
今回は pg_upgrade がマイグレーション中に失敗しました。
Restoring database schemas in the new cluster
template1
discourse
*failure* Consult the last few lines of "pg_upgrade_dump_16384.log" for the probable cause of the failure. Failure, exiting
pg_upgrade_dump_16384.log ファイルを確認すると、以下のエラーが表示されていました。
pg_restore: creating VIEW "postgres_exporter.pg_stat_activity"
pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 721; 1259 678554 VIEW pg_stat_activity postgres
pg_restore: [archiver (db)] could not execute query: ERROR: column pg_stat_activity.waiting does not exist
LINE 27: "pg_stat_activity"."waiting",
^
Command was:
-- For binary upgrade, must preserve pg_type oid
SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('678556'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_type array oid
SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('678555'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_class oids
SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('678554'::pg_catalog.oid);
CREATE VIEW "postgres_exporter"."pg_stat_activity" AS
SELECT "pg_stat_activity"."datid",
"pg_stat_activity"."datname",
"pg_stat_activity"."pid",
"pg_stat_activity"."usesysid",
"pg_stat_activity"."usename",
"pg_stat_activity"."application_name",
"pg_stat_activity"."client_addr",
"pg_stat_activity"."client_hostname",
"pg_stat_activity"."client_port",
"pg_stat_activity"."backend_start",
"pg_stat_activity"."xact_start",
"pg_stat_activity"."query_start",
"pg_stat_activity"."state_change",
"pg_stat_activity"."waiting",
"pg_stat_activity"."state",
"pg_stat_activity"."backend_xid",
"pg_stat_activity"."backend_xmin",
"pg_stat_activity"."query"
FROM "pg_stat_activity";
あーあ。
ここで、いくつかの手順を戻すことにしました。バックアップの問題を解決する間、フォーラムを再起動し、読み取り専用モードにすることはできないでしょうか。postgres と redis の権限問題を修正することでこれを達成し、フォーラムは古いバージョンでオンラインに戻りました。すべてが動作するわけではありません。例えば、管理画面からユーザー → グループに移動すると、以下のエラーが発生します。
NoMethodError (undefined method `automatic_membership_retroactive' for #<Group:0x00007fcaca3045e8>)
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
しかし、残りは動作しているようです。
この時点で、動作するインスタンスに戻るために chown を実行する必要があったため、新しいインスタンスを開始し、バックアップをインポートすることにしました。
新しい EC2 インスタンスを開始し、discourse_docker のセットアップ手順に従ってインポートを開始しました。しかし、奇妙な問題に遭遇しました。データがインデックスの一意性の要件に一致しないため、インデックスを作成できないというエラーです。
ERROR: could not create unique index "index_incoming_domains_on_name_and_https_and_port"
DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
EXCEPTION: psql failed: DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
/var/www/discourse/lib/backup_restore/database_restorer.rb:95:in `restore_dump'
しかし、実行中のインスタンスの Rails コンソールに移動すると、重複はありませんでした。
[7] pry(main)> IncomingDomain.where(name: "homeassistant.home")
=> [#<IncomingDomain:0x000055e5cabc3760 id: 8648, name: "homeassistant.home", https: false, port: 8123>]
これが現在の状況です。私たちはかなり行き詰まっています。
- Ruby コードに対して不良な DB を持つ実行中のインスタンスがあり、新しい Postgres へのマイグレーションができません
- 新しいインスタンスにインポートできないバックアップがあります
有料のホスト型 Discourse への移行を検討しましたが、月間 300 万ページビューと 100 万件の投稿があるため、エンタープライズ価格ではコミットメントが大きすぎます。
そのため、何らかの解決策を見つける必要があります。できればバックアップをインポートしたいですが、古いインスタンスをマイグレーションすることも可能です。
何かアイデアはありますか?有料で誰かに手伝ってもらうことも構いません。