MKJのDiscourseデプロイ構成に関する個人的な見解

過去数年間、私は豊富なコンテンツと多数の画像を含む Discourse フォーラムを運営してきました。Maker Forums には100GB以上の画像と40万投稿以上があり、そのうち相当数が主に Google+ からインポートされ、残りはサイト上で作成されました。この投稿では、私が最終的に Maker Forums をどのように設定したか、そして後には他のいくつかの Discourse インスタンスをどのように設定したかについて説明します。これは私が始めた時に知っておきたかったことで、他の人が自分自身の Discourse インスタンスで同じような落とし穴を避けるために活用してきたものです。

より広い読者層に向けて。

:warning: 警告: Linux システム管理者として作業することに慣れていない場合、このガイドはあなたには適していない可能性があります。Linux に関する知識を前提としている点について、私がすべて把握できているとは限りません。読んでいて啓発されるような感じであれば、あなたは対象読者です。読んでいて混乱する感じであれば、おそらく対象読者ではありません。これが仕事のように感じられる場合は、CDCK や @pfaffman に Discourse の運用を任せることを検討してください。彼らはプロフェッショナルです。あるいは、無料の discourse.group サイトから始めて、成長に合わせて有料プランに移行してください。:warning:

:warning: それだけではありません:私は Discourse よりも Linux の方が専門知識があります。私の意見には何の保証もありません。私のアドバイスに従って何か(あなたの Discourse フォーラム、ホストシステム、またはあなたの心)が壊れてしまった場合、両方の破片を鋭い縁付きで受け取ってください。この投稿のコンテンツに対して何らかのサポートを提供する予定はありません。:warning:

このドキュメントを、私が参加して維持している Discourse インスタンスの私のプラクティスに合わせて最新に保つ予定です(ただし、約束ではありません)。これはアドバイスとして書かれていますが、主に私自身と、私が責任を持って展開した Discourse を引き継ぐ管理者たちへのアドバイスとして意図しています。それ以外の場合は、Discourse をどのように展開するかを決定するための あなた自身の調査 の出発点として考えてください。

システム設定

CentOS 派生または Ubuntu LTS の OS を使用してください。Docker をサポートするものはおそらく動作しますが、私はこの2つを使用しています。

Docker

私は Fedora ユーザーです。Red Hat で最初の Fedora プロジェクトリードを務めており、Podman 上で Discourse を実行する方が好みです。なぜなら、そのセキュリティモデルは Docker より優れていると考えるからです。しかし、Discourse の展開は Docker のみでサポートされており、他のものを試そうとすると かなりパイオニア的な存在になります。(将来的には、docker-compose がサポートされた場合、podman-compose を使用して Podman で動作する可能性があります。)

Docker が cgroups v2 をサポートするようになったので、CentOS 派生システムに公式の Docker ビルドをインストールできます:

dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install --allowerasing docker-ce docker-ce-cli

podmanruncbuildah との競合のために --allowerasing を含めます。これらはインストール時に削除する必要があります。)

systemctl enable --now docker

これは AlmaLinux 9 でテストしました。

セキュリティ

このセクションは Discourse 自体とは直接関係ありませんが、私の通常のセキュリティプラクティスの一部です。ネットワーク上のどのシステム(Discourse を実行している VM を含む)にもパスワードのみでのシェルアクセスを許可しないでください。 パスフレーズで暗号化された SSH キーを使用して SSH ベースのアクセスを設定し、VM 上の ssh サーバーがパスワードアクセスを許可しないように設定してください。

laptop$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/.../.ssh/id_rsa):
Enter passphrase (empty for no passphrase): SOME LONG PHRASE
Enter same passphrase again: SOME LONG PHRASE
Your identification has been saved in .ssh/id_rsa
Your public key has been saved in .ssh/id_rsa.pub

Linux ディストリビューションは通常、パスフレーズをメモリに記憶するように設定されているため、起動ごとに1回だけ入力すれば済みます。Windows はそれほど便利ではありません;同じことをするために Pageant と PuTTY を使用することを検討してください

まず、パスワードなしで着信 SSH が機能するかを検証してください。その後に、サーバー上で /etc/ssh/sshd_config ファイルを編集し、PasswordAuthentication 行を見つけます。それを no に設定して、着信パスワードアクセスを無効にします。

PasswordAuthentication no

ファイアウォール

Discourse が公開される前でも、letsencrypt が SSL 証明書を生成および更新できるように、ポート 80 と 443 を一般的に開けておく必要があります。

firewalld を使用している場合、これらのコマンドで実現できます:

firewall-cmd --add-service http --add-service https --zone public
firewall-cmd --runtime-to-permanent

別のデバイスとファイルシステム

/var/discourse/shared を独自のファイルシステムを持つ別の デバイス にし、20GBのスペースと画像に必要な量の少なくとも2倍のスペースを確保してください;prometheus を使用する場合はさらにスペースを追加してください。デバイスが後で簡単に拡張できる場合(LVM や AWS elastic block storage のようなクラウドブロックストレージなど)、必要に応じて監視して拡張できます;そうでない場合は、初めに余裕を持たせてください。ネットワークストレージブロックデバイスを使用している場合は、パーティションテーブルを設定しないでください。パーティションテーブルなしで使用すると、拡張が容易になります;パーティションテーブルを修正する必要はありません。多くの場合、システムダウンタイムなしで拡張できます。

Maker Forums では、これは Maker Forums が実行されている VM に接続されたネットワークストレージブロックデバイスです。別の Discourse フォーラムでは、Digital Ocean Block Storage Volume です。Amazon では、AWS Elastic Block Storage です。Fedora 上の libvirt で KVM VM を実行している私のテストシステムでは、これは AlmaLinux VM に仮想ディスクとしてエクスポートされた Fedora ホスト上の LVM ボリュームです。いずれの場合も、新しい VM を作成し、重要なファイルをそこにコピーし、古い VM を停止し、/var/discourse/shared ボリュームを新しい VM に接続し、数分で復旧できました。これにより、VM 上のオペレーティングシステムのアップグレードが比較的低リスクになります。

VM のルートファイルシステムに少なくとも 25GB のスペースから始めることを確認してください;/var/discourse/shared のスペースは含みません。これはすべての docker コンテナに使用され、5GB 未満の空き容量がある場合、discourse launcher は失敗します。システム更新のためにも十分なスペースが必要です。ディスクスペースが不足している場合、これは回復が困難です。

サイト設定では、force_https を設定しますが、警告に従ってください。Discourse サイトを公開する前に、テストで設定してください。force_https でも、ポート 80 を開けておく必要があります;ポート 443 への SSL リダイレクトと letsencrypt SSL 証明書の更新のためです。(ただし、cloudflare を使用している場合は、その機能を使用してください;Discourse の force_https と互換性がないと報告されています。)

カーネル設定

Redis(Discourse が構築されている主要なコンポーネントの1つ)は オンディスク永続化を使用する際に透明巨大ページを無効にすることを強く推奨しています(Discourse はそうしています)、また、メモリオーバーコミットを許可しています。

echo 'w /sys/kernel/mm/transparent_hugepage/enabled - - - - never
w /sys/kernel/mm/transparent_hugepage/defrag  - - - - never' > /etc/tmpfiles.d/thp.conf
systemd-tmpfiles --create
echo 'vm.overcommit_memory=1' > /etc/sysctl.d/90-vm_overcommit_memory.conf
sysctl --system

Discourse インストール

デフォルトのインストール は単一のコンテナですが、これにより、推奨される月次のアップグレードごとに、コマンドラインから実行する場合、通常10-15分のダウンタイムが発生します。これは、Discourse が構築されているツールの更新、セキュリティや新機能のため、または UI からのライブ更新が何らかの理由で失敗した場合に必要です。2コンテナインストールで、実際のダウンタイムを短縮できます。

2コンテナインストール

2つのコンテナで設定を開始します。

./discourse-setup --two-container --skip-rebuild
${EDITOR:-nano} containers/data.yml
./launcher rebuild data
# my preference to use app.yml but you might stick with web_only.yml, read text
mv containers/web_only.yml containers/app.yml
${EDITOR:-nano} containers/app.yml
./launcher rebuild app

これにより、数ヶ月ごとの必要なシステムダウンタイムが非常に短くなり、ほとんど気づかれません;多くのユーザーは、ダウンタイム中にクリックやスクロールを行わない限り、全く気づかないでしょう。これにより、ほとんどのセキュリティ更新を適用しやすくなります;すべてを再構築する約15分ではなく、一時的なブリップになります。次のプロセスは、ほとんどの更新で機能し、主にホストシステムの性能とインストールされているプラグインのセットに応じて、通常30-90秒のダウンタイムを提供します。

cd /var/discourse
git pull
./launcher bootstrap app
./launcher destroy app && ./launcher start app
./launcher cleanup

bootstrap と destroy/start 呼び出しの間に遅延しないでください。まれに(実際には年に1-2回)、bootstrap フェーズの最後に実行されるデータベース移行が、古いコードが更新されたデータベースにアクセスするために、アプリのユーザーに多少深刻なエラーを引き起こす可能性があります。

これは Discourse を更新する際に、データコンテナも更新する必要があるかどうかを確認する必要がある ことを意味しますが、これはまれに必要です(通常、年に1-2回を想定)。データとアプリコンテナの内容とシステムの速度に応じて、これは通常5-20分のダウンタイムをもたらします。

cd /var/discourse
git pull
./launcher stop app
./launcher rebuild data
./launcher rebuild app

データコンテナを更新するタイミングを知るための詳細については、次を参照してください:

(私の独自の展開では、web_only コンテナを app と呼ぶことを選択しました。これは、タイプしやすく、ほとんどの手順をより簡単に追跡できるためです。これは非標準ですが、使いやすさを常に高く評価しています。しかし、これは追加の作業であり、私が何が起こっているかを知っているため、私には機能します。これが悪く聞こえる場合は、マルチコンテナ展開ではデフォルトの web_only を使用してください。)

将来的に、Docker がコンテナを接続するための新しい構成への移行を強制する可能性があります:

4GB以上のメモリまたは複数の CPU を持っている場合、次のアドバイスを読んでください:

更新スケジュール

release-notes タグを監視してください(release-notes をクリックし、右上のベルをクリックします;私は「最初の投稿を監視」を使用しています)および/または https://meta.discourse.org/tag/release-notes.rss を RSS フィードに追加して、リリースがあることを知ってください。更新前にリリースノートを読んでください。データベース変更がある場合、リリースノートで言及されます。セキュリティ更新を含むリリースも強調されます。一部のバージョンへの実際の更新をスキップしても、すべてのリリースノートを読んでください;データベースを更新するリリースのリリースノートを読まない場合、読んでいないリリースノートのデータベース更新指示を見逃す可能性があります。

メール

メールは依然として人々を繋ぎ続けるための主要な方法の1つです。メールを機能させるために、送信および受信メールを設定してください。問題がある場合は、次を参照してください:

継続的に連絡を取る

Maker Forums には、長い間離れてから戻る偶発的な訪問者が見られます。デフォルトでは、Discourse は1年後にダイジェストメールの送信を停止します。偶発的な訪問者が新しい興味深いものを見たときに戻ってくるように促したい場合は、suppress_digest_email_after_days をデフォルトの365日より長い値に設定することを検討してください。Maker Forums では、偶発的な訪問者が最新情報を把握できるようにするために、これを大幅に長くしました。ダイジェストメールを読むことは、フォーラムで「 lurking(潜伏)」する有効な方法であり、誰かが貢献に興味を持つきっかけになるものがあるかどうかは分かりません。

同様に、デフォルトでは、ほとんど相互作用していない特権のないユーザー(投稿のない信頼レベル0)は、730日間ログインしない場合に最終的に削除されます。ユーザーが indefinitely(無期限に)ダイジェストメールを読んで lurking できるようにしたい場合は、「clean up inactive users after days」を 0 に設定して、ユーザーの削除を無効にします。

yearly review プラグインを追加することを検討してください。これは年に1回、2020: The Year in Review のような投稿を生成し、最終的に非アクティブなユーザーにメールで送信 します。これにより、参加を再開するよう促す可能性があります。

メール受信コンテナ

3番目のコンテナをメール受信として設定します。これにより、バウンス処理が保証され、バウンス処理が送信メールプロバイダーから独立し、メール返信のオプションが提供されます。

メール送信者を信頼するために SPF を設定していることを確認してください;少なくとも、同じ MX を介して送信および受信する場合、v=spf1 +mx -all のようなポリシーですが、より具体的であればスパム保護としてより信頼される可能性があります。DKIM も検討してください。

同じホスト名を使用してメールを受信する場合、本当にコンテナ外で SSL を終了する必要があります(「オフラインページ」の場合と同様)、certbot を実行した後、certbot 証明書をコンテナにマッピング し、コンテナを再起動する必要があります。

コンテナ外でユーザーの SSL 接続を終了する

コンテナ外で SSL を終了するための2つの選択肢があり、いずれもコンテナ内で終了するよりも大幅な利点をもたらします。discourse-setup を正常に完了し、フォーラムをブートストラップした後、そのうちの1つを設定してください。

外部 nginx

メンテナンスページをホストし、ホストが IPv6 サポートを持っている場合、IPv6 アドレスのログ記録をサポートするために、コンテナ内だけでなく、ホストシステム上で実行されている nginx を使用してください。(それ以外の場合、すべての IPv6 接続は、ローカル docker 仮想ネットワークインターフェースに関連付けられた内部 RFC1918 アドレスから来ているとしてログ記録されます。)この構成は、最終的にユーザーが見ていたページにリダイレクトされる一時的なメンテナンスページを、ほとんどのメンテナンス操作中に表示します。

このページの手順(現在)は letsencrypt というパッケージのインストールを提案していますが、現在通常は certbot と呼ばれています。このページの手順に従って --certonly を使用する場合、certbot の nginx プラグインは必要ありませんが、nginx プラグインのインストールは別のメカニズムです。CentOS 派生では:

dnf config-manager --set-enabled crb
dnf install epel-release
dnf install certbot python3-certbot-nginx
systemctl enable --now certbot-renew.timer

certbot が nginx とメール受信コンテナを再起動するように設定し、古い失効した証明書を继续使用するためにブラウザやメールがサイトへのトラフィックをブロックしないようにしてください。

# systemctl edit certbot-renew

メール受信がないシステムでは、次の2行を追加しました:

[Service]
ExecStartPost=/bin/systemctl reload nginx

システムから cert を共有する別のメール受信コンテナを使用しているシステムでは:

[Service]
ExecStartPost=/bin/systemctl reload nginx
ExecStartPost=/bin/sh -c 'cd /var/discourse && ./launcher restart mail-receiver'

SELinux を使用している場合、Ubuntu コンテナは nginx.http.sock ファイルを httpd_sys_content_t でラベル付けするように設定されていないため、外部 nginx がアクセスできません。2つの選択肢があります。

1つ目は、nginx を permissive モードで実行し、SELinux の保護を削除することです:semanage permissive -a httpd_t

しかし、これにより、おそらく最も関連性の高いサービスからの SELinux 保護が削除されます!SELinux を有効に保つには、nginx がエラーページにアクセスできるようにし、unix ドメインソケット経由のプロキシからポート(数µs遅くなりますが、ユーザーには気づかれないはずです)に切り替える必要があります。

まず、次のコマンドを実行して、nginx がエラーページにアクセスできるようにします:

semanage fcontext -a -t httpd_sys_content_t /var/www
restorecon -R -v /var/www

次に、app.yaml で - "templates/web.socketed.template.yml" をコメントアウトまたは削除し、ポート 80 をローカルマシン上の別のポートとして公開し、コンテナを再構築します。

expose:
  - "8008:80"   # http

ここで https を使用しないでください — 外部 nginx で SSL を終了しており、X-Forwarded-Proto ヘッダーが Discourse にリクエストが https を介して到着したことを伝えます。ポート 8008(または選択した他のポート)がファイアウォール設定によって公開されていないことを確認してください。

次に、次のコマンドを実行して、nginx がネットワーク経由でコンテナに接続できるようにします:

setsebool -P httpd_can_network_connect 1

次に、外部 nginx 構成を nginx.http.sock 経由のプロキシから http://127.0.0.1:8008(または選択したポート)に変更し、デフォルトの Connection: close ヘッダーをクリアし、外部 nginx が各リクエストに対して新しい IP 接続を確立する必要がないようにします。

...
  location / {
    proxy_pass http://127.0.0.1:8008;
    proxy_set_header Host $http_host;
    proxy_http_version 1.1;
    # Disable default "Connection: close"
    proxy_set_header "Connection" "";
...

web.socketed.template.yml の削除により、real_ip 呼び出しも削除されたため、それを追加します。使用する IP アドレス範囲が意味をなすようにしてください;Docker のデフォルトは、ポリシーによりパブリックインターネットでルーティングされない 172.16* RFC1918 アドレス空間を使用することです。app.yml ファイルに次のようなものを追加し、展開に適した1つ以上の RFC1918 アドレス空間または他のものを選択します:

run:
  - file:
     path: /etc/nginx/conf.d/outlets/server/real-ip-recursive.conf
     chmod: 644
     contents: |
       real_ip_recursive on;
  - file:
     path: /etc/nginx/conf.d/outlets/server/real-ip-header.conf
     chmod: 644
     contents: |
       real_ip_header X-Forwarded-For;
  - file:
     path: /etc/nginx/conf.d/outlets/server/set-real-ip-from.conf
     chmod: 644
     contents: |
       set_real_ip_from 192.168.0.0/16;
       set_real_ip_from 172.16.0.0/12;
       set_real_ip_from 10.0.0.0/8;

これは、レート制限が正しく機能し、ユーザーの登録および最終使用 IP アドレスを属性するために必要です。

詳細については:

外部サービス

私は Discourse の前に Fastly や Cloudflare を設定していませんが、他の人が設定しており、ホストシステム上で実行されている外部 nginx とは異なり、ホストシステムが完全にダウンしている間(ホストでのシステム更新中に再起動する場合など)メンテナンスページを提供できます。これがあなたにとって価値がある場合、次のように実行します:

S3 アップロードに急がないでください

セットアップ中に enable_s3_uploads を有効にするか、後で移行する前に、アップロードされた画像に S3(または同等のもの)を使用する ことを常に望んでいることを非常に確認してください。S3(s3_endpoint)とその関連 CDN(s3_cdn_url)を画像に使用すると、JavaScript もその CDN を介して提供されることに注意してください。S3 からローカルストレージへの移行はサポートされておらず、現在それを実装する具体的な計画はありません。これは、完全なバックアップと復元ですら取り消せない「一方通行のドア」です。S3 や同等のものを使用する場合、S3 の代わりに Digital Ocean Spaces を使用しないでください。meta で信頼性がないとの言及があります。

私は早期にサイトを Digital Ocean Spaces とその関連 CDN を介して画像を提供するように移動し、「一方通行のドア」が十分に理解されていないため、ローカルストレージに戻すために何百行ものカスタムコードを書く必要があり、その過程で Discourse インスタンスに軽微な損害を与えました。

詳細については:

Discourse に CDN を使用するために S3 アップロードを有効にする必要はありません。独自の画像を管理する Discourse の前に独立した CDN(例:Cloudflare、CloudFront、Fastly、GCS CDN)を使用することを検討してください。Cloudflare が推奨されないという警告は “Rocket Loader” が JavaScript を修正する ためであるという私の間接的な理解であり、現時点では、“Rocket Loader” を使用しない限り、正しく機能します。

モデレーションのための Discourse 設定

モデレーションがアクティブなサイトでは、モデレーターと管理者がトピックについてインラインで話せる enable_whispers 構成を強く検討してください。また、最近の Discourse バージョンでは、カテゴリモデレーターにより多くの機能が与えられています。異なるトピックの専門家が独自のカテゴリを持っている場合、またはサポートなどの機能的に分離されたカテゴリを持っている場合、enable_category_group_moderation を意識する価値があります。

ジオロケーションは、アカウントが正当かどうかを理解しようとする際に役立ちます。

Discourse Templates 機能はモデレーターにとって非常に役立ちます。これにより、一般的なレスポンスで協力できます。Maker Forums には数十個あります。これは、それを置き換える以前の「Canned Responses」プラグインよりも多くの機能を持っています。

User Notes 機能は、モデレーターがユーザーに関するノートを共有するのに役立ちます。これらを次のようなことに使用できます:

  • 「このユーザーに注意してください、彼らは…のため悪意がある可能性があります。」
  • 「この行動は疑わしいようですが、私は…によってこれが正当なユーザーであることを検証しました。」
  • 「私はすでにこのユーザーと会話をして懸念に対処しており、他のモデレーターは追加する必要はありません。」

情報のアクセシビリティ

Discourse Solved プラグインは、解決された問題をマークしてサイト訪問者がそれらをより簡単に識別できるようにするだけでなく、google 検索結果を優先する可能性があります。

公開情報は非公開情報よりもアクセスしやすいです。Maker Forums では、FAQ は個人メッセージを強く抑制し、個人メッセージが真にプライベートではないことをEveryone に思い出させます。しかし、デフォルトでは、ユーザーは次のメッセージを見ることができます:

user に3回返信しました、代わりに個人メッセージを送信できることを知っていましたか?

本当にユーザーを個人メッセージに誘導したい場合は、Admin → Customize → Text に移動し、get_a_room テンプレートを修正してカンマスピスを修正することをお勧めします。

Maker Forums のように、会話を公開に保ち、Everyone に利益をもたらしたい場合は、Admin → Settings → Other → get_a_room_threshold を 1000000 のように高く設定できます。

同様に、ヘルプを提供するフォーラムを持っている場合、max_replies_in_first_day デフォルト 10 は、ヘルプを求める会話で新しいユーザーが返信の予算を使い果たしたときに個人メッセージに誘導する可能性があります。会話を個人メッセージに誘導しないように、この設定を増やすことを検討してください。

ユーザーを繋ぎ、コミュニティを構築する

いくつかのプラグインがユーザーを互いに繋ぐのに役立ちます。

フォーラムに同時ユーザーが多すぎない場合、Who’s Online プラグインを検討して、人々により接続感を与えてください。ログインユーザー、少なくとも信頼レベル1に達したユーザーのみに表示を制限したいかもしれません。whose_online_minimum_display を非常に高く設定し、whos_online_hide_below_minimum_display を true に設定して、アバターに存在フラール(whos_online_avatar_indicator)を追加するだけで使用できます。これは、ユーザーが問題を解決するのに役立つ質問と回答を迅速にサポートし、奨励するためにサポートフォーラムで有用です。

しかし、存在感は両刃の剣です。大多数のフォーラムユーザーとは異なる時間にオンラインのユーザーは孤独を感じるかもしれません、またはフォーラムは「ゴーストタウン」のように感じられるかもしれません。

多くの国のユーザーがいて、互いがより利用可能な時期についてのヒントを得たい場合は、National Flags プラグインを検討し、ユーザーがプロフィールに国旗を設定することを奨励してください。

翻訳は難しいです。同じ言語を話さない人々がコミュニケーションするのを助けるのは便利ですが、現在(この執筆時点)では、無料のサービスティアを持つ翻訳サービスはありません。翻訳サービスに支払うことを選択した場合、Discourse Translator プラグインで翻訳を有効にできます。

バックアップ

システムファイルについては、少なくとも次のものをバックアップすることを検討してください:

  • /var/discourse/containers(discourse 設定の詳細のため)
  • /var/www(エラーページのため)
  • /etc/ssl(letsencrypt 設定のため、バックアップを復元する一部として certbot をブートストラップする必要を避けるため;それ以外の場合、ブートストラップ中に nginx 設定の SSL 部分をコメントアウトする必要があります;これは証明書が短い有効性を持っているため、バックアップを最新に保つ場合にのみ機能します)
  • /etc/systemd/system/backup-uploads.service(S3 への画像バックアップのため)
  • /usr/local/bin/mc(minio-client を画像バックアップツールとして使用する場合)
  • /root/.mc(minio-client による画像バックアップの設定)
  • /root/.ssh(着信 SSH セッション認証のため)

これらのファイルの一部は、Git にチェックインしてオフサイトのある場所にプッシュしてバックアップできます。Git にチェックインするファイルに秘密(データベースパスワードなど)が含まれている場合、絶対に公開リポジトリにプッシュしないでください。代替として、それらをシステムからコピーして、あなたが制御する監視システム上の Git にチェックインするスクリプトを作成できます。/etc/ssl のバックアップを最新に保つために、これを十分に頻繁にスクリプト化してください。

目標は、災害の場合のバックアップと、ミスの場合の変更の記録を持つことです。

これらのファイルのほとんどにとって、より良い代替は、正規のコピーを他の場所に保ち、Ansible のようなツールを使用してシステム上の構成を維持することです。これにより、バックアップ後の更新が同等に容易になります。しかし、それを行う予定であれば、私が言う前に理解しているでしょう!

バックアップのための Discourse 設定

  • include_thumbnails_in_backups でサムネイルをバックアップしてください。サムネイルなしの復元は、それらを再生成するのに時間がかかります。サイトにグラフィックスが少なければ、サムネイルは insignifiant なスペースを取ります。サイトにグラフィックスが多い場合、サムネイルの再生成には数日かかる可能性があります。サムネイルが再生成されている間、メール通知は無効になります。いずれにせよ、バックアップからサムネイルを省略する意味はありません。

  • 多くの画像がある場合、バックアップに画像を含めないでください。これにより、バックアップが遅く、扱いにくくなります。それらを別々にバックアップしてください。データベースバックアップの後に画像をバックアップする場合、バックアップは一貫性があります。

  • バックアップが何らかの方法でオフサイトに行くように手配してください。

このページは、S3 または S3 のようなものへのデータベースバックアップを設定する方法を示しています:

restic でバックアップ

discourse をファイルシステムにバックアップするように設定し、次に restic を使用してファイルシステムからリモートバックアップターゲットにバックアップします。これはサンプルレシピです。

# dnf install restic
# mkdir /var/restic
# mkdir /opt/backup
# cd /opt/backup
# cat > backup <<EOF
#!/usr/bin/bash

set -e
. /opt/backup/backup-config

restic --cache-dir=/var/restic \
	backup \
	/etc \
	/root \
	/var/discourse \
	/opt/backup \
	--exclude /var/discourse/shared/data/postgres_data

restic --cache-dir=/var/restic forget \
	--prune --keep-hourly 24 --keep-daily 7 --keep-monthly 3
EOF
# chmod +x backup

これらの詳細は、使用する restic ターゲットによって異なります。すべてが AWS の環境変数を使用するわけではないため、restic のドキュメントをお読みください。

# cat > backup-config <<EOF
### これらの詳細は設定する restic ターゲットに依存するため、変更してください
export AWS_ACCESS_KEY_ID=yours-here
export AWS_SECRET_ACCESS_KEY=same
export RESTIC_PASSWORD_FILE=/root/restic-password
export RESTIC_REPOSITORY=see-the-restic-documentation
EOF
# {$EDITOR:-nano} /root/restic-password

/root/restic-password に設定した内容のコピーを保管しておく必要があります。保管しないと、バックアップの復元ができなくなります!パスワード保管ツール(パスワードボルト)を使用してください。

最後に、いくつかのサービスを作成し、restic リポジトリを初期化して、バックアップが開始されるようにタイマーを設定します。

# cat > /etc/systemd/system/backup.service <<EOF
[Unit]
Description=Back up to remote target
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
StandardOutput=file:/var/log/backup.out
StandardError=file:/var/log/backup.err
WorkingDirectory=/var/discourse
ExecStart=/opt/backup/backup

[Install]
WantedBy=multi-user.target
EOF
# cat > /etc/systemd/system/backup.timer <<EOF
[Unit]
Description=Regular system backups

[Timer]
Persistent=true
OnCalendar=00/4:30:00
Unit=backup.service

[Install]
WantedBy=timers.target
EOF

# systemctl daemon-reload
# . /opt/backup/backup-config
# restic init
# /opt/backup/backup
# systemctl enable backup.timer

このプロセスの後、初期バックアップが作成されたことを確認できるはずです。

# restic snapshots

この方法で作成された restic バックアップを使用して、restic restore コマンドで Discourse サーバーを別のシステムに移行することに成功しました。

minio による画像のストリーミングバックアップ

Restic の代替案として、データベースのバックアップは S3 に保存できますが、S3 から画像を提供することとは別に、S3 用の画像バックアップ機能はありません。代替案として、minio-client を使用して、画像を任意の S3 互換ストレージにコピーします。これには S3 や minio など多くの S3 互換ターゲットが含まれますが、Ceph ファイルシステムの上に構築されており、S3 とは異なる方法で ListObjectsV2 API を実装しているため、DigitalOcean Spaces は対象外です。

S3 で、パブリックアクセスをブロックするバケットを作成します(AWS でこれを正しく設定する簡単な方法は、PermissionsBlock public access です)。

minio-client (mc) を何らかの方法でインストールします。以下はその一例です。

curl https://dl.min.io/client/mc/release/linux-amd64/mc > /usr/local/bin/mc && chmod +x /usr/local/bin/mc

以下のようなコマンドを使用して、backup というエイリアスで minio-client を設定します。

# mc alias set backup https://s3.amazonaws.com ACCESSKEY SECRETKEY --api S3v4
# mc mirror /var/discourse/shared/standalone/uploads backup/UPLOADS-BACKUP-BUCKET

次に、以下のように /etc/systemd/system/backup-uploads.service サービスを作成します。

[Unit]
Description=Neartime remote backup sync of discourse uploads
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=600
User=root
ExecStart=/usr/local/bin/mc mirror --overwrite -a --watch /var/discourse/shared/app/uploads backup/UPLOADS-BACKUP-BUCKET

[Install]
WantedBy=multi-user.target

ここで、UPLOADS-BACKUP-BUCKET は、Discourse がデータベースバックアップをアップロードするように設定する s3_backup_bucket とは異なるバケットである必要があります。また、標準のマルチコンテナデプロイメントを使用している場合、パスは /var/discourse/shared/web_only/uploads になる点に注意してください。

# systemctl enable backup-uploads
# systemctl start backup-uploads
# journalctl -fu backup-uploads

テスト用の画像をアップロードし、元の画像と最適化された画像のバックアップが成功したことを示す行が表示されることを確認します。Control-C で journalctl の追従モードを終了できます。

復旧

執筆時点では、このプランを実際にテストしたことはありません。この概要では何か見落としている可能性があります。

  • 一般的に、バックアップされたすべてのファイルを復元します
  • nginx を起動します(これでメンテナンスページが表示されます)
  • /var/discourse/containers にある復元されたファイルを使用して、Discourse の通常デプロイを実行します
  • バックアップから復元していない場合は、/usr/local/bin/mc に minio-client をインストールします
  • /root/mc のバックアップを行わなかった場合は、バックアップエイリアスを設定します # mc alias set backup https://s3.amazonaws.com ACCESSKEY SECRETKEY --api S3v4
  • # mc cp backup/UPLOADS-BACKUP-BUCKET /var/discourse/shared/app/uploads
  • 最新のデータベースバックアップを復元します。Restore a backup from the command line を推奨します
  • サイトが正常に動作することを確認した だけで、上記のドキュメントに従って S3 へのアップロードバックアップを再設定します。

PostgreSQL のストリーミングバックアップ

将来、PostgreSQL の continuous WAL archiving を使用して、postgresql の archive-command で minio-client を使用し、アップロードバックアップのストリーミングと同様に、ほぼリアルタイムの Postgres バックアップをストリーミングする設定を作成、テスト、提供する可能性があります。

パフォーマンスモニタリング

パフォーマンスモニタリングには、少なくとも2つのアプローチがあります。

Prometheus コンテナ

Prometheus を設定し、同じシステムで実行している場合は、Prometheus のログを /var/discourse/shared/prometheus に配置します。Prometheus のファイルは大きくなる可能性があり、ルートファイルシステムが埋め尽くされるのを防ぎたいです。また、新しいホストシステム(より大きな VM へのアップグレードや、新しいオペレーティングシステムのインストールされた VM)に移行する際に、これらのファイルを移行したい場合もあるでしょう。

Prometheus を Discourse システム(またはパブリックインターネット上の他の場所)にデプロイする場合は、その前にセキュリティを設定してください。このようにインストールした場合、以下のような nginx 設定が一つの選択肢となります。

  location /prometheus/ {
    auth_basic "Prometheus";
    auth_basic_user_file /etc/nginx/prometheus-htpasswd;
    proxy_pass http://localhost:9090/;
  }

Sysstat

Prometheus が複雑すぎる場合は、代わりに sysstat を検討してください。

  • dnf install sysstat(Debian およびその派生システムでは apt install sysstat
  • systemctl enable --now sysstat
  • systemctl enable --now sysstat-collect.timer
  • systemctl enable --now sysstat-summary.timer
  • systemctl edit sysstat-collect.timer を実行し、OnCalendar=*:00/10OnCalendar=*:00/2 に変更します
  • /etc/default/sysstat が存在する場合は、falsetrue に変更します

これ以降、sar コマンドを使用して、時々リソースが不足していないか確認できます。

その他のリソース

以下は、Discourse を社内コミュニケーションの主要な手段として内部的に使用することに関する補足的(かつよりコンパクトな)議論です。

「いいね!」 54

こんにちは、このハウツーを教えていただきありがとうございます。

現在の CPU(コア数)と RAM はどれくらいですか?
現在の設定は以下の通りですか:

  db_shared_buffers: "xGB"
  db_work_mem: "xMB"
  UNICORN_WORKERS:

vCPU 2 個(L5640 Xeon)、RAM 4GB です。ただし、大規模なインポートにより、完全に有機的に構築された一般的な Discourse インスタンスよりも、同時ユーザーあたりのコンテンツ量が多くなっています。同時に 5 人を超えるユーザーが接続することはめったにありません。

現在は data.ymldb_work_mem を設定していませんが、/etc/postgresql/13/main/postgresql.conf では 10MB に設定されているようです。私の data.yml では db_shared_buffers: "768MB" と設定していますが、データコンテナ内の /etc/postgresql/13/main/postgresql.conf には shared_buffers = 512MB と表示されており、驚きました。どうやら、最後の設定変更後にデータコンテナを再構築していなかったようです。:roll_eyes: Prometheus(より多くのメモリを消費)を追加する前に設定変更を行っていたため、その設定を変更する前に、まず Prometheus を別のサーバーインスタンスに移すつもりです。

アプリ側では UNICORN_WORKERS: 4 と設定しています。

「いいね!」 1

@mcdanlj、たくさんの良い情報をありがとうございます。定期的なメンテナンスについて何かアドバイスはありますか?例えば、週次/月次での再起動や、アップ/ダウン監視と自動再起動などです。その他、定期的な手動または自動メンテナンスはありますか?

「いいね!」 1

@jaffadog リリースノートは #release-notes タグ(右上にあるベルのアイコンです。「最初の投稿を監視」を使用しています)を監視するか、RSSフィードに https://meta.discourse.org/tag/release-notes.rss を追加して、リリース時に通知を受け取るようにしてください。アプリのリリースは通常月1回で、月1回の再起動をカバーしています。定期的な再起動はそれ以上の頻度では行っていません。また:

letsencryptとmail_receiverを使用している場合は、新しい証明書を取得した後にmail_receiverを再起動するように設定することをお勧めします。

現時点で思いつくのは以上です。ご質問ありがとうございます。リリースノートの監視方法と再起動に関する詳細を本文に盛り込みました。これで元の投稿で完全にカバーされていると思います。

ベースイメージのバージョンを変更するために /var/discourse でアップデートを取得するようにアップデート手順を拡張しました。これは、Update base image for polkit vulnerability を確認したところ、この手順を明示しないと誤解を招く可能性があることに気づいたためです。以前は、これはベースラインドキュメントの一部として考えていました。launcher スクリプトにはベースイメージバージョンへの特定の参照が含まれており、git pull を実行するまで古いベースイメージの上にビルドすることになり、テスト済みのものを実行することにはなりません。(ファイルの先頭近くの image= を探してください。)

「いいね!」 1

それよりも悪いのは、デフォルトで非アクティブなレベル 0 のアカウントを一定期間後に削除するように設定されていることです。私の場合は、まったく望んでいなかったことです!「非アクティブなユーザーを日数後にクリーンアップする」を確認し、ゼロまたは非常に大きな数に設定してください。

「いいね!」 2

それを確認しましたが、私の理解では、彼らが「メールアドレスを確認してください」というフローに応答しなかったため、そもそもメールを受け取っていなかったということになります。「非アクティブ」が「サイトにログインしていない」という意味ではないと思いますが、私が間違っているかどうか知りたいです。

いいえ、「非アクティブ」はここでは active=false を意味しません。

以下のすべてに該当するユーザーを意味します。

  • トラストレベル 0
  • 投稿なし
  • 管理者でもモデレーターでもない
  • X日以上前に最後に確認された。

そしてはい、その表現は確かに紛らわしいですが、設定でいくらか説明されています(「投稿のないトラストレベル 0」)。

「いいね!」 8

実際には、異なる設定を混同しており、「未使用のステージング済みユーザーを日数後にクリーンアップする」ことを念頭に置いていました。Maker Forumsでは「非アクティブなユーザーを日数後にクリーンアップする」をずっと前にゼロに設定しており、ここで言及するのを忘れていました。一般に関心のある可能性のあるものを探していたときに、変更されたサイト設定の監査で見落としていたようです。@Ed_Sと@RGJのお二人ともありがとうございます!さらに、潜伏を有効にすることに関する段落を投稿に追加しました。:smiling_face:

「いいね!」 4

Hi @mcdanlj、素晴らしい洞察を共有していただきありがとうございます。2コンテナのインストールに関して、アップグレード実行時のダウンタイム削減にどのように役立つのかが分かりません。私のテストインストールでは、GUIの/admin/upgrade#/upgrade/allインターフェース経由でのアップグレードには数分かかりますが、プロセス全体を通してサイトはユーザーが操作可能です。

コマンドラインから 2 つのコンテナのインストールを再構築する必要がある場合、古いコンテナが引き続き実行されている間に新しいイメージをブートストラップできます。

「いいね!」 2

いつものように、@pfaffman は私よりも素早く、自分のことをよく知っています。:smiley:

私はGUIからアップグレードすることは決してありません。そうすれば、更新するたびに、Discourseが実行されているコンテナの下にあるシステムセキュリティアップデートも含まれるようになります。これはGUIの使用が悪いということではなく、他の人全員への推奨でもありません。GUIのアップデートはダウンタイムがわずかに短くなります(Webコンテナを再起動するとサービスが一時的に停止します。これは、外部nginxと組み合わせて検討するいくつかの理由の1つです)。したがって、これはトレードオフであり、私はあまり一般的でない道を選びました。

シングルコンテナのインストールでは、Discourseが新しいPostgreSQLの機能を利用するため、セキュリティアップデートや時折のデータベースバージョンのアップデートを定期的に行う場合、ダウンタイムが長くなることが多くなります。実際のデータを確認せずに、私の直感では、年に3〜4回再構築する理由があると考えています。そのダウンタイム量があなたの観点から問題ない場合、2コンテナ展開の複雑さを引き受ける理由はあまりありません。

「いいね!」 4

それはとても親切ですが、これはあなたの意見についてです。 :wink:

私もです。ダッシュボード以外は、コンテナにたくさんの追加機能(Ansibleや、正確には覚えていませんが、その他もろもろ)があり、dashboard.literatecomputing.com を使用してアップグレードを実行している人がいて、そのコンテナを削除すると、再構築が終了してしまう可能性があり、問題が発生する可能性があります。そのため、最近は docker_manager のアップグレードをいくつか行っていますが、非常にスムーズです。

実際にはそうではありません。新しいベースイメージがある場合、docker_manager はそれを取得するように強制します(少なくとも、試みます)。

だいたいそんなところです。参考までに、お勧めしませんが、何年も問題なくゼロアップグレードを行った人をたくさん知っています。

「いいね!」 1

はい、コンテナ内アップデートがうまく実装されていることは間違いありません!

はい、それが私が言いたかったことです。:tada:

「いいね!」 2

こんにちは、またお二人とも洞察をありがとうございます。それで、本番環境のセットアップをどうするかまだ決めかねています。理論的には、2コンテナインストールがダウンタイムを減らす理由を理解しています。しかし、GUIアップデートメカニズムでは、まだほとんどダウンタイムが発生していません。今、時間を計ってみましたが、docker-managerのアップデートがあり、Discourseは22コミット遅れていました。プロセス全体で5分もかからず、プロセス全体を通してフォーラムは完全に稼働していました。確かに今回はPostgreSQLのアップデートはありませんでしたが、もしそれもアップデートする必要があった場合、2コンテナ方式でもダウンタイムが最大になるということですよね?ですから、私の理解が正しければ、2コンテナ方式は、SSHログインとアプリコンテナの再構築が必要な場合にのみダウンタイムを削減するということですか(プラグインの追加/削除など)?本番環境の設定を頻繁に変更することは想定していません。そのため、私のケースではダウンタイムの削減の可能性はないと考えています。それとも、特定の種類の機能/セキュリティアップデートを適用するために、SSHでログインしてコンテナを再構築する必要もありますか?

問題ありません。

はい、PostgreSQL を更新するたびに(おそらく1〜2年に一度、さらにPostgreSQL自体のセキュリティアップデートもですが、それほど頻繁ではありませんでした)、完全なダウンタイムが発生します。

変更する前は、GUIの更新で数回失敗しましたが、詳細はもう覚えていません。昔の話です。

GUIの更新ではベースイメージは更新されないため、画像処理などの提供されているソフトウェアのすべてのセキュリティアップデートは適用されません。

私は、アプリコンテナのセキュリティアップデートが利用可能になったときに、それを消費するための「通常」モードとして、アプリコンテナの再構築を高速に行うことを好みます。そのため、すべてを再構築するための10分間のダウンタイムを延期することはありません。だからこそ、ランチャーでの git pull は、私がすべてのアップデートを適用する際の最初の部分に含まれています。これにより、画像処理プログラムなどのベースイメージが更新された場合、セキュリティアップデートを適用する必要があるかどうかを考える必要もなく、それらが適用されます。:smiling_face:

しかし、最終的には、私 個人的 には、2コンテナアプローチの方がシンプルだと感じています。そして、私は 絶対に 他の人にそれを勧めているわけではありません。あなたの知識と経験に基づいて、それがよりシンプルに思えないのであれば、私の個人的な意見に基づいたガイドが特定のコンテキストで役立つと特定しているからといって、それを実行しないでください。:grin:

「いいね!」 2

了解しました! :wink: テックの実装方法についても強い意見を持つ傾向がありますが、あなたの追加的な視点に感謝します。

うーん、これはまだそうなのでしょうか?

いずれにしても、コンテナ化せずに LAMP/LEMP スタックにインストールされた従来のフォーラムでの私の経験では、実際のウェブサイトが侵害される典型的な脆弱性/攻撃ベクトルは、ほぼ常にウェブアプリのコードまたはそのウェブ開発フレームワークのいずれかにあります。そのため、Discourse のコードベースのアップデートに対する緊急性がより高く感じられ、これは GUI によって処理されているように見えるため、そちらに傾いているのかもしれません。


ところで、ダウンタイムの件ですが、Clear Linux を少し宣伝させてください。純粋な数値計算における低レベルの最適化のためにテストを開始し、巨大なフォーラムのインポートプロセスから数時間短縮しようとしました。そのケースでは確かに速度向上の可能性があるかもしれませんが、一般的に、聖なるサバ、特に KVM ゲストとしての再起動は_クレイジーに速い_です。最も安価なティアの VPS では、再起動して 5 秒もかからずに SSH にログインし直すことができます。したがって、重要なホスト OS のアップデートがある場合は、それを使用することを楽しみにしています。

はい。しかし、コンテナ内のコンポーネントが更新されたため、年に数回はコマンドラインで再構築する必要があります。その場合、5〜15分間のダウンタイムが発生します。私は(ダッシュボードプラグインを1日に数回更新する可能性のあるダッシュボードを除き)ほとんどコマンドラインからのみアップグレードを実行しており、それらのコマンドラインアップデートが必要な顧客も多数います(おそらく彼らはWebインターフェイスからアップデートを実行しているのでしょうが、そうでないこともよくあります)。

「いいね!」 2

Discourseダッシュボードは、そのような必須の更新について具体的に通知しますか?それともDebianのPSAに注意を払うべきですか?