ダウンタイムゼロのアップグレード

Hello there,

We are wondering if zero downtime upgrades are possible. We are using the discourse_docker installation using separate web and data containers, so the issue is more around the old application code (v2.1) running against a migrated v2.3.0 database schema. This happens between the time we bootstrap the image (which will run the migrations) and the moment the web servers get restarted (updated) to run the upgraded image. Are there any recommendation for this?

数か月前にアップグレードを正常に完了しました。将来同じ質問を持つ方のために、私たちの経験をここに共有します。

Discourse は、デプロイ後マイグレーション を使用することで、ゼロダウンタイムアップグレードをある程度サポートしています。私たちが理解した限り、全体のプロセスは以下の 2 ステップに分けられます。

ステップ 1: 新バージョンへのアップグレードと安全なマイグレーションの実行

  • 新バージョンと互換性のあるように、すべてのプラグインとテーマを更新します(これは設定によってはかなりの作業になります)。
  • 以下を含む web_only.yml を生成します:
    version: <NEW_VERSION>
    SKIP_POST_DEPLOYMENT_MIGRATIONS=1
  • ブートストラップ (./launcher bootstrap web_only)
  • サーバーを再起動

ステップ 2: デプロイ後マイグレーションの実行(カラムやテーブルの削除など、リスクの高いマイグレーション)。この時点ですべてのサーバーが新バージョンのコードを実行しており、削除されるデータに依存しないはずなので、このステップは安全であるはずです。

  • 以下を含む web_only.yml を生成します:
    version: <NEW_VERSION>
    SKIP_POST_DEPLOYMENT_MIGRATIONS=0
  • ブートストラップ (./launcher bootstrap web_only)
  • サーバーを再起動

複雑な点
私たちは ステップ 1ステップ 2 を異なる日付に実行することを決定しましたが、それによりいくつかの問題が発生しました。バージョン 2.1 から 2.3 の間に、polls モデルの大規模な リファクタリング が行われました。当初、ほとんどの poll データは post_custom_fields テーブル上の JSON オブジェクトとして保存されていたようですが、2.3 になると独自の polls テーブルに移動しました。これにはいくつかの データマイグレーション が必要であり、これはデプロイ後マイグレーション(ステップ 2)の一部として行われました。

私たちの具体的な問題は、2.3 へのマイグレーション直後に、アップグレード前に作成された polls が壊れていたことです。おそらく、それらをレンダリングするコードが新しいデータモデルを前提としていたためでしょう。いくつかのユーザーがこの問題に気づき、UI から polls を手動で更新しようとした結果、新しい polls テーブルにレコードを作成してしまいました。後で悲しくも判明したように、そのようなレコードはブートストラップ処理中に postgres の 一意制約 をトリガーし、結果としてブートストラップを失敗させました。

これを回避するために、DB に既に存在する特定の polls マイグレーションをスキップする パッチ を適用することを決定しました。これは完璧な解決策ではありませんでした。なぜなら、post_custom_fields からマイグレーションされなかったデータが失われる可能性があるからです。しかし、私たちの場合、システム全体でそのようなケースは非常に少なかった(観察できたのは 2 インスタンスのみ)ため、このトレードオフは許容範囲でした。これにより、ブートストラップ処理を実行することができました。しかし、パッチのテストと適用により、さらに 2 つの疑問が生じました:

  • PR を提出する前にどのように変更をテストすればよいか?
    私たちは、実際の環境と同じ条件でコードをテストしたいと考えていました。つまり、ブートストラップ処理に対してテストを行う必要がありました。これは、スタンドアロンの Discourse アプリをローカルで実行することでテストできるランタイムコードの変更ほど単純ではありません。

  • 変更をシステムにどう組み込むか?
    パッチが公式の Discourse リリースに含まれるのを待つことはしたくなかったのです。そのプロセスは時間がかかる可能性があり、事実上、別のアップグレードを強いることになります。すでに既存の polls について顧客から不満が出ており、待つ時間が長くなるほど、顧客が polls を手動で変更してデータ整合性の問題を悪化させるリスクが高まります。

そこで、ブートストラップスクリプトが使用するリポジトリの原点を変更することで、導入しようとしている変更をテストする方法を見つけました。これには試行錯誤が必要でした。なぜなら、私たちは pups やこのプロセスに関連する他のツールについてあまり詳しくなかったからです。最終的には、このような ことをしました。

これにより、私たちの修正が意図通りに機能することを確認できました。また、公式の Discourse リリースを待つことなく、パッチを含む Discourse の独自修正版から、本番環境で新しいイメージをブートストラップすることもできました。