スタンドアロンコンテナから別々のWebおよびデータコンテナへの移行

このプロセスは安全でしょうか?開発環境ではマルチコンテナ構成を問題なく実行できますが、本番環境で使用する際、ユーザーが古いコンテナにアクセスしている間に新しいコンテナがブートストラップされ、データベース移行ステップが実行されると、古いコンテナへのリクエストは依然として古いバックエンドロジックを使用し、前のバージョンで定義された通りにデータを保存してしまいます。これはデータベース移行ステップが終了した後(ただし、ブートストラッププロセス全体が完了する前)にも発生します。

これは Discourse 自体の問題ではないことは理解しています(複数のレプリカを持つ環境では、1 つのレプリカが他よりも先に更新される場合に同様の問題が発生する可能性があります。すべてのレプリカをアップグレード前に停止しない限り、HA を目指す場合はおそらくそのようにはならないでしょう)が、一般的に言って、説明されたプロセスは安全でしょうか?

考えられる対策の 1 つは、Discourse を常に最新に保ち、ビルド間のデータベース移行を最小限に抑えることです。しかし、いずれにせよこれは理想的ではなく、この場合でも問題が発生する可能性があります。

マルチコンテナ構成は推奨されるアプローチの 1 つのようです(1 つのコンテナのみを使用する標準的な方法ではありませんが)。したがって、これは安全であり、私が考えすぎているだけなのかもしれません。

本番サイトでも(1 つのコンテナでブートストラップを実行している間に別のコンテナが動作していても)問題なく機能するかどうかご存知でしょうか?本番環境ですでにこの方法を実践された方のフィードバックをお聞きしたいだけです。複数のビルドの後でも問題ないか、注意点はあるかなどを知りたいのです。繰り返しになりますが、開発環境では問題なく動作しています。

ダウンタイムをゼロにしたい場合は、いくつか追加の手順が必要です。新しいコンテナで「post-migrations」を無効にし、新しいコンテナを完全にロールアウトした後、post-migrations を有効にして再度ロールアウトします。これにより、古いコードが実行されなくなるまで、カラム削除に関するマイグレーションの実行が停止されます。

これに関する具体的な手順(howto)はまだありませんが、以下のページでドキュメント化されています。

ただし、ほとんどの場合、フォーラムは月に 1〜3 分程度のダウンタイムであれば問題なく運用できます。

「いいね!」 4

はい、問題ありません。通常、実行中のコンテナを破壊するマイグレーションは存在しません。

web_only.yml でマイグレーションを無効化し、新しいコンテナが起動した後、次のように実行することもできます。

 cd /var/www/discourse;SKIP_POST_DEPLOYMENT_MIGRATIONS=0 rake db:migrate 

実行中のコンテナ内で上記コマンドを実行してください。

「いいね!」 3

はい、nginx をフロントエンドのリバースプロキシサーバーとして使用すれば、本番環境でも完璧に動作します。

私の構成は以下の通りです。

3 つのコンテナ:

  • Data (data.yml)
  • Socket1 (socket1.yml)
  • Socket2 (socket2.yml)

nginx configでは、単一の UNIX ドメインソケットを指定します。例:

location / {
        proxy_pass http://unix:/var/run/nginx.http.sock;
        proxy_set_header Host $http_host;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;
 }

その後、実際のソケットへの記号リンク(シンボリックリンク)を設定することで、ライブ化したいコンテナを選択します。

例えば、socket2コンテナをライブ化したい場合:

ls -sf /var/discourse/shared/socket2/nginx.http.sock /var/run/nginx.http.sock

socket1に変更を加え、socket1をライブ化したい場合:

cd /var/discourse
./launcher rebuild socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock

socket1コンテナのみをブートストラップする必要はありません。なぜなら、コンテナは独自の共有ディレクトリ/ボリューム内の UNIX ドメインソケット経由で公開されるため、両方の「Web アプリ」コンテナを同時に実行できるからです。

  • Socket1: /var/discourse/shared/socket1/nginx.http.sock
  • Socket2: /var/discourse/shared/socket2/nginx.http.sock

これは、TCP/IP コンテナポートを公開した場合のような「ポートバインディングの競合」が発生しません。このため、本番環境では TCP/IP ポートではなく、UNIX ドメインソケットのみを公開しています。

もちろん、必要であればブートストラップを実行することも可能です:

cd /var/discourse
./launcher bootstrap socket1
./launcher start socket1
ls -sf /var/discourse/shared/socket1/nginx.http.sock /var/run/nginx.http.sock

どちらの方法を選んでも構いませんが、両方のコンテナを同時に実行すると、両方ともsidekiqを実行し、スケジュールされたジョブも実行される点に注意してください。私たちの経験では、そのため両方のコンテナ間でアップロードファイルを定期的に同期させています。

この方法で私たちは完璧に運用しており、Web アプリコンテナを再構築してライブ化する場合でも、実質的にダウンタイムゼロで実現できます。私たちは本番環境でのダウンタイムを非常に重視しており、可能な限り避けるようにしています。

注:

上記の方法は、ソリューションの Web アプリ部分向けに設計されたものであり、データコンテナ用ではありません。データコンテナ向けの同様のソリューションは作成していませんが、将来的にはデータコンテナ向けに(もちろん異なる形で)何らかのものを作成するかもしれません(「2 つのデータコンテナで DB を同期させる方法」など、現時点では完全に未定です)。

つまり、私は実際にはこれと逆のことをしています:

前述の通り、開発環境では問題なく動作します。

一般的に、私は開発環境ではこの設定を行いません。設定に時間がかかるためです。また、開発環境では少しのダウンタイムでも問題ないため、この設定は不要です(「私とコード」だけで、ユーザーやボットがサイトにアクセスしているわけではないため)し、さらに私は開発(デスクトップ上)では Docker を使用していません。

参考になれば幸いです。


ここで言う「開発」とは、ソフトウェア(例えばプラグイン)の開発を指します。単に Discourse インストールを「ステージング」することを指すわけではありません(「ステージング」と呼んでいます。念のため明確にしておきます)。

「いいね!」 2

ありがとうございます、そのことは知りませんでした。素晴らしい機能ですね。以前挙げたような問題を防げると思います(既存のカラムを使ったロジックの変更は防げないかもしれませんが、そのケースはより稀でしょう)。

回答ありがとうございます。SKIP_POST_DEPLOYMENT_MIGRATIONS@riking さんが言及していたもので、実行中のコンテナで実施した処理を壊すマイグレーションを防ぎたいという私の意図に合致しているようです。

ご説明ありがとうございます。2 つのコンテナを切り替える(一方が起動している間に他方をブートストラップする)というアプローチは、私にとって良い方法のように思えます。

私が「dev 環境」と言ったのは、マルチコンテナセットアップをテストするために使用したリモート開発環境のことです(同じマシン上でも、異なるマシン上のコンテナでも)。

「staging」ではなく「dev」と言ったのは、ステージング環境であれば、同じプラグインを含む yml ファイルを使用し、バックアップした本番データベースを使ってテストするからです。ただし、単に dev 環境を設定したいだけなら、ほとんどの場合、1 つのコンテナのアプローチを使うのはその通りです。

「いいね!」 2

私の知る限り、このガイドは以下の手順を複雑に説明しているに過ぎません:

  • バックアップ
  • discourse_setup 2containerを実行するだけで得られる結果と同じものを、より多くの手順を踏むことで得る、完全に新しい Discourse インスタンスの作成
  • 復元

なぜ、クリーンなシャットダウン後に /var/discourse/shared/standalone/{postgres,redis}*/var/discourse/shared/data へ移動またはコピーし、その後、別の containers/*.yml ファイルから 2 つの新しいコンテナを起動しないのでしょうか?バックアップと復元は、すべてのデータを移動させるには非常に重厚な方法であり、プロセスに不必要に何時間も追加しているように思えます。何か見落としているのでしょうか?

私はテスト用の Discourse でこの手順を試しました。ついでに Redis も分離して、すべてのケースを網羅しているか確認しました。編集:説明を新しいトピックに移しました:

バックアップと復元のプロセスを経なくても、サイトは正常に機能しているようです。何か見落としがちな確認事項があるでしょうか?

私は それなりに大きな Discourse でも同じ手順を行いました。問題なく動作しています。本番環境では、新しい web_only コンテナを app と命名することにしました。そうすれば、指が自然に正しい操作を行ってくれるからです。新しい container/*.yml ファイルを作成した後、移行全体のダウンタイムは 12 分でした。バックアップと復元のプロセスを経るよりもはるかに高速でした。

それは、もう少し作業が必要で、仕組みを理解する必要があるからです。バックアップからの復元の方が、より失敗しにくいです。

「いいね!」 1

まあ、意見が一致しないことには同意しましょう。複数のコンテナを運用できる人が、いくつかのコマンドを実行できないはずがないと思いますし、そのコマンドを打つのが bin/rails c と Ruby コマンドをここで打ち込むことより難しいとも思いません。また、複数のコンテナを使うために必要なスキルと比べて、本質的に難易度や種類が異なるスキルも必要ないでしょう。:smiling_face: ただ、このコメントの中に埋もれさせておくのは避けて、内容を新しい投稿に移行します。

「いいね!」 1

それは妥当な意見ですね。手順をより恐ろしいものに見せることで、スキルがない人が挑戦しないようにするのかもしれません。

…そして、もしミスが発生しても、移行前のバックアップに代わるものはありません!上記のリンク先にある私の記事で、それが明確に伝わるように書きました!:smiling_face:

「いいね!」 1

ここがあなたの議論の欠陥です。./discourse-setup に 2container を追加しただけでは、運用能力の証明にはなりません。このようなトピックを見て「何か特別な秘訣があるのか」「これがやるべきことだ」と思い込み、単に2つのコンテナを動かしている人は大勢います。

Postgres 12 のトピックは、複雑性が加わる際の戒めとなるべきでしょう。状態遷移の中間ステップとしてバックアップを利用すれば、単一のファイルをリネームするだけで単一コンテナ構成に戻せますが、フォルダの移動を始めると、その簡便さは失われます。

「いいね!」 2

@Stephen あなたの議論には欠陥があります。マルチコンテナの説明には、更新の責任を自分が負い、仕組みを理解する必要があるという警告が満載であり、上記の長い説明はあまりにも難解で、それを見た人は誰でも諦めてしまうでしょう。私の Migrate quickly to separate web and data containers を読んで、それを読めば混乱する人々を遠ざけてしまうこと、あるいは万が一の際にバックアップの必要性と、何か問題が起きた場合にバックアップに戻れる能力を強調していないことを否定してみてください。

セキュリティ修正のために機能性の高いサーバーに移行した直後に ./launcher rebuild app を実行した際、サイトが非常に長い間ダウンし、その大部分がコンテナ内の PostgreSQL 部分の再構築に費やされました。その時に 2 コンテナのドキュメントとこのドキュメントを見つけ、4 時間のダウンタイムを再び避けるために、復元に 4 時間かかることを避けるため、./launcher rebuild app による長いダウンタイムを繰り返し受けることになりました。ある程度有能な人間として、この設定が事実上隠されていたことに長い間非常に腹が立ちました。

PostgreSQL 12 のトピックは優れた参考資料です。なぜなら、人々は 全体 のアプリを複数回再構築しなければならないため、かえって より ダウンタイムが長くなるからです。本来なら PostgreSQL コンテナを 2 回だけ再構築すれば済むはずなのにです。6 日間の自動削除機能のためスレッド全体を読んだわけではありませんが、そこでの大きな問題は、無能なマルチコンテナデプロイである、あるいは少なくとも大きな問題の一つであるとは全く思えません。
(申し訳ありませんが、ここでは「すべてのユーザーが無能である」という雰囲気に時々疲れ果ててしまいます。)

「いいね!」 2

あなたには理解しがたいかもしれませんが、Support で6〜7年間人々の支援に携わってきた私たちにとって、ロールバック戦略を備えておくことは常に意味があります。

バグはテストを通過した後にもしばしば発生し、時には RubyGems のレート制限が再構築に影響を与え、GitHub にも稀に不具合が起きることがあります。その理由だけでも、単にファイル名を変更して ./launcher start app と実行するのを難しくする状態変更には価値を見出せません。

あなたのリスク許容度が異なる場合は、別の方法を選ぶことも可能です。しかし、片付けを定期的に手伝っている人々にとって、現在のガイドは非常に有効に機能しています。

「いいね!」 3

あなたは私が書いたプロセスを本当に読んだとは思えません。なぜなら、復元機能の必要性を強調したかのように書かれているからです。まずそれを読んでから戻ってきて、私の指示に関する真実を述べるように、あなたが書いた内容を編集することを検討してください。現状では、私が書いたものをわざわざ読むという配慮もせず、私に対して「説明する」態度をとっているように感じられます。
ただし、私はさらに多くの警告を追加しました。その中にはトップにも警告を含んでいます。この投稿は5年間存在し、この移行プロセスに関する公式の指示場所として現在も機能していますが、それ以上の警告を追加しました。

「いいね!」 2

まず第一に、冒険者たちのためにこの「ジャングル」を片付けようとしてくれてありがとう:sweat_smile:。数日後には私もあなたの後を追うことになるでしょう…
multisite.yml ファイルには何が記されていますか?

こんにちは。

最近、VPS にセルフホスト型の Discourse フォーラムをセットアップしました。アップロードとバックアップは Wasabi に保存されています。すべて Linode でホストされています。

スタンドアロンテンプレートを使用しましたが、他のソフトウェアに比べてセットアップは本当に新鮮で、素晴らしい体験でした。純粋な喜びです。オープンソースプロジェクトのすべてが、Discourse のようにインストールとセットアップにこれほど多くの注意を払ってくれることを願っています。

ただし、問題があります。私は、インターネットからはアクセスできず、RFC-1918 アドレスでのみアクセス可能な、別のサーバー上で実行されている専用 PostgreSQL を使用したいと考えています。データベースサーバーを Web/アプリケーションサーバーと同じサーバー上で実行するのはあまり好きではありません。

そこで、スタンドアロンのデータベースを分離し、専用のデータベースクラスタに移行する方法はありますか?

私がやるべきことは、Discourse データベースの pgdump を行い、それを専用データベースに移動して復元し、復元/インポート後にすべてのテーブルに対して postgres vacuum analyze を実行し、その後 Discourse アプリをネットワーク経由で新しいデータベースを指すように設定するだけだと思っています。

しかし、データベース認証情報がどこに保存されているのか見つかりません。app.yml を確認しましたが、データベースに関するエントリは見当たりませんでした。また、../templates/ フォルダを確認しても、どの yml ファイルにもデータベース認証情報が含まれていないようです。

私がやろうとしていることは可能でしょうか?

「いいね!」 1

設定方法を解説したガイドはこちらをご覧ください:

「いいね!」 3

素晴らしい!まさに探していたものです。本当にありがとうございます!

さて、CloudFlare の背後にある実際の IP を nginx に認識させる方法ですね…… :wink:

組み込みの PostgreSQL データベースには通常、認証情報が存在しない場合、スタンドアロンコンテナから pgdump を実行してデータベースをダンプすることはできますか?

「いいね!」 1

Discourse の標準的なバックアップは tarball 内の pg_dump なので、それを使用できます。

ダンプをパイプ接続したり、異なる形式にしたりするなど、カスタム処理を行いたい場合は、いつでも以下のように実行できます:

ssh root@forum
cd /var/discourse
./launcher enter app
su postgres
psql # または pg_dump
「いいね!」 2