スケーリング

複数のアプリノードとワーカーに分割した AnsibleForms と、一つ以上の RTE

  1. ロール
  2. RTE
  3. 複数のアプリノード
  4. 構成例

ロール

すべての AnsibleForms コンテナーは同じサーバーコードを実行し、 AF_ROLE が何をするかを決めます。

AF_ROLE イメージ 実行するもの 数
all (未設定) ansibleforms Web アプリとワーカーを一つのプロセスで。既定です 1
app ansibleforms Web インターフェースと API ロードバランサーの背後にいくつでも
worker ansibleforms バックグラウンドの処理。データベーススキーマとそのアップグレード、構成シード、スケジュール、夜間バックアップ、リポジトリの同期、クリーンアップ 稼働するのは一つ。ほかは待機して引き継ぎます
rte ansibleforms-rte-full (または -rte-core 、 -rte-base ) プレイブック いくつでも

最小のインストールは、 AF_ROLE のないコンテナー一つと RTE 一つです。 Docker Compose プロジェクト と Helm チャート はこの構成で動作します。 AF_ROLE にそれ以外の値を指定すると、プロセスは起動時に停止します。


RTE

プレイブックを実行するランタイム環境である RTE には、専用のセクション ランタイム環境 があります。そこでは、RTE が ジョブを実行する仕組み、 そのイメージ 、 実行方法 、ランナーまたはレプリカとしての 複数の RTE 、 そして 別のデータセンターの RTE を扱います。


複数のアプリノード

より多くのユーザーに対応したり、ノードを一つ失っても稼働を続けたりするには、アプリをロードバランサーの背後の app ノードと worker に分割します。

ノードが共有するもの

ノードはデータベースと共有ボリュームを通じて互いに整合を取ります。

  • データベース :ジョブ、ワーカーのロック、デザイナーのロック、ノードのリスト、ランナーのリース(各 RTE のソケットを どのアプリノードが持っているか)、そして各ノードのキャッシュを最新に保つ変更通知。一つのノードで編集した認証情報、ランナー、スケジュールは、 5 秒以内にすべてのノードで有効になります
  • 永続ボリューム ( /app/dist/persistent ):フォーム、設定、リポジトリ、アップロード、バックアップ、管理対象の .env 。 すべてのアプリノードとワーカーが同じものを読み書き可能でマウントします
  • ssh フォルダー ( /home/node/.ssh ):ssh 経由の git に使うキーと既知のホスト。ワーカーが最初の起動時にキーを作成します
  • ACCESS_TOKEN_SECRET :すべてのアプリノードで同じにします。そうしないと、一つのノードが署名した トークンが次のノードで拒否されます。アプリノードはこれがないと起動しません
  • ENCRYPTION_SECRET :すべてのアプリノードとワーカーで同じにします。そうしないと、一つのノードが 保存した認証情報を別のノードで読めません。ソケットモードの RTE はこれを読みません。必要なのは、自分自身を登録する非推奨のデータベースモードの RTE だけです

すべてのコンテナーに同じデータベースユーザーも与えてください。待機中のワーカーが停止したワーカーのセッションを終了できるのは、それが自分と同じユーザーの場合だけです。

ワーカーのロック

同時に稼働するワーカーは一つだけです。稼働中のワーカーはデータベースのロック ansibleforms_worker を保持します。停止するとデータベースがロックを解放し、 待機中のワーカーが 10 秒以内にそれを取得します。ワーカーのホストが別れを告げずに停止すると、データベースは何時間もロックを保持し続けることがあるため、 2 分間どのワーカーもハートビートを書き込まなければ、待機中のワーカーがそのセッションを終了して引き継ぎます。

別のワーカーにロックを奪われたワーカーは停止し、そのコンテナーは待機側として再起動します。起動に失敗したワーカーも停止するので、 何もせずにロックを保持し続けることはありません。Galera とグループレプリケーションは、データベースノード間でロックを共有しません。すべての ワーカーを同じデータベースノードに向けてください。

ジョブとノード

各コンテナーは、何も設定しなくても自分に <role>-<hostname>-<port> という名前を付けます。 ステータス ページにはそのすべてがロールと バージョン、どれがワーカーかとともに表示され、異なるバージョンが動作している場合は警告が出ます。

RTE で実行中のジョブはその RTE に属し、それを開始したアプリノードがなくなっても続行します。それ以外のジョブ(AWX やほかのランナーの テンプレートジョブ、ワークフロージョブ、非推奨のマルチステップフォームのステップ)は、それを開始したアプリノードに属します。再起動したコンテナーは 自分の未完了のジョブを終了し、置き換えられた Pod のように 2 分間応答しなくなったコンテナーのジョブはワーカーが終了します。

どのノードに SIGHUP を送っても、 構成シード が再適用されます。アプリノードはワーカーにそれを依頼します。

アップグレード

先にワーカー をアップグレードし、その後でアプリノードをアップグレードします。ワーカーがスキーマにパッチを当て、新しいバージョンのアプリノードは スキーマにパッチが当たるまで待機し、何を待っているかをログに記録します。先にアップグレードしたアプリノードはワーカーが追いつくまで準備ができていない状態のままで、 その間は古いノードが処理を続けます。RTE は、同じ契約で通信できる限り、いつ追従してもかまいません。

制限

一つのノードにとどまるものもいくつかあります。

  • チャットアシスタント は、会話を一つのアプリノードのメモリに保持します。ロードバランサーでスティッキーセッションを使う(nginx の ip_hash )か、アプリノードを一つにしてください
  • ログ は各コンテナーにとどまります。複数のプロセスが一つのファイルをローテーションすると行が失われるため、 LOG_PATH は 共有ボリュームの外に設定してください。ログビューアーは応答したノードのログを表示するので、ログは一元的に収集してください
  • 設定ページで変更した 設定 は共有ボリューム上の管理対象の .env に書き込まれ、すべてのノードに反映されます。再起動が必要な設定は、 すべてのノードで再起動が必要です

構成例

アプリのリポジトリには、 examples/scale に完全な出発点があります。

サービス イメージ ロール
db mariadb:11 データベース。 AnsibleForms スキーマにだけ権限を持つユーザー付き
app1 、 app2 ghcr.io/ansibleforms/ansibleforms:7 AF_ROLE=app 。ロードバランサーの背後
worker1 、 worker2 ghcr.io/ansibleforms/ansibleforms:7 AF_ROLE=worker 。二つ目は待機して引き継ぎます
rte ghcr.io/ansibleforms/ansibleforms-rte-full:7 RTE_MODE=inbound と RTE_FILES=local でプレイブックを実行します。アプリがそこに接続します
lb nginx:stable ポート 8443 で HTTPS を終端し、 ip_hash でブラウザーをアプリノードに振り分けます

RTE のランナー rte と、それがサインインに使う認証情報(アドレス http://rte:8000 と RTE_TOKEN )は、ワーカーが起動のたびに適用する 構成シード seed.yaml で宣言されています。RTE は RTE_URL を設定せず、ホストには公開されません。

アプリノードとワーカーは一つの .env を共有し、そこにはデータベースユーザー、 ENCRYPTION_SECRET 、 ACCESS_TOKEN_SECRET 、 RTE_TOKEN 、 CONFIG_SEED_PATH 、ロードバランサーの背後なので HTTPS=0 、そして共有ボリュームの外の LOG_PATH があります。RTE には env_file がなく、 compose.yaml から RTE_TOKEN だけを受け取るので、データベースのパスワードは保持しません。アプリノード、ワーカー、RTE は同じ 永続ボリュームと ssh ボリュームをマウントします。

cp .env.example .env   # and fill in the secrets
docker compose up -d   # then https://localhost:8443