n8n Queue ModeをDocker Composeで構成する

n8n Queue ModeをDocker Composeで構成する記事のサムネイル

n8nを長く使っていると、UIやWebhookを受ける処理と、実際にワークフローを実行する処理を分けたくなる場面があります。特にCode Nodeや定期実行が増えてくると、どのコンテナが何を担当しているのかを分けておいた方が、更新や障害調査を進めやすくなります。

この記事では、Docker Composeでn8n Queue Modeを構成し、Main、Worker、Task Runner、Redis、PostgreSQLの役割を整理します。完全な無停止構成を作る話ではなく、受付・実行・キュー・データ保存の責務を分け、運用しやすい形にするのが狙いです。

ARCHITECTUREn8n Queue Modeの全体像
flowchart LR
  Internet[Internet / Webhook] --> Caddy[Caddy]
  Caddy --> Main[n8n-main]
  Main --> Redis[(Redis Queue)]
  Redis --> Worker1[n8n-worker]
  Redis --> Worker2[n8n-worker-2]
  Worker1 --> Runner1[Task Runner]
  Worker2 --> Runner2[Task Runner 2]
  Main -. read/write .-> DB[(PostgreSQL)]
  Worker1 -. read/write .-> DB
  Worker2 -. read/write .-> DB
Mainは受付、Redisは実行IDの受け渡し、Workerは実行、PostgreSQLは永続データを担当します。

Queue Modeで分かれる役割

n8nのQueue Modeでは、MainインスタンスがトリガーやWebhookを受け付け、実行そのものはWorkerへ渡します。公式ドキュメントでも、Mainが実行IDをRedisへ渡し、WorkerがRedisから実行IDを受け取り、データベースからワークフロー情報を取得して処理する流れとして説明されています。

n8n-mainUI、Webhook、Trigger管理。実行ジョブをRedisへ登録する。
RedisPending executionのキュー。Workerへ実行IDを受け渡す。
n8n-workerキューからジョブを取得し、ワークフローを実行する。
Task RunnerCode Nodeなどのタスク実行をn8n本体から分ける。
PostgreSQLWorkflow、Credential、実行履歴などの永続データを保存する。

ここで大事なのは、Redisがワークフロー定義やCredentialを保存するわけではない点です。Redisはジョブの受け渡し、PostgreSQLは永続データという役割で見ると、トラブルシュート時に確認する場所を間違えにくくなります。

VERIFICATION LABこの記事の検証環境
動作確認済み
HostAWS Lightsail
OSUbuntu 24.04 LTS
RuntimeDocker Compose
Applicationn8n Queue Mode
BrokerRedis
DatabasePostgreSQL

バージョンは環境に合わせて固定してください。Task Runnerを外部モードで使う場合、n8n本体とrunner imageのバージョンを揃えます。

Queue Modeは高可用性そのものではない

Queue Modeは、実行処理をWorkerへ分けるための構成です。Workerを増やせば同時に処理できる量を広げられますが、それだけでMain、Redis、PostgreSQLまで冗長化されるわけではありません。Mainを1台で動かすなら、Main更新中はUIやWebhook受付が短時間止まります。

  • できること: MainとWorkerの責務を分け、Workerを追加・削除しやすくする
  • できないこと: Queue Modeだけで全体を無停止化する
  • 運用上の見方: まず役割分離、次にバックアップや監視、必要なら冗長化を考える

.envを用意する

Main、Worker、Runnerで共有する値を .env にまとめます。特に N8N_ENCRYPTION_KEY は全n8nプロセスで同じ値にします。これが違うと、データベースに保存されたCredentialをWorkerが扱えません。

シークレットを生成する BASH
openssl rand -hex 32
openssl rand -hex 32
.envの主要項目 PLAINTEXT
N8N_VERSION=2.25.7
N8N_ENCRYPTION_KEY=CHANGE_ME
N8N_RUNNERS_AUTH_TOKEN=CHANGE_ME
POSTGRES_PASSWORD=CHANGE_ME
REDIS_PASSWORD=CHANGE_ME
N8N_DEFAULT_BINARY_DATA_MODE=database
N8N_BLOCK_ENV_ACCESS_IN_NODE=true
N8N_COMMUNITY_PACKAGES_ENABLED=false

Queue ModeではMainとWorkerが同じバイナリデータへアクセスできる必要があります。n8n公式ドキュメントでは、Queue Modeで filesystem モードはサポートされず、database を使うよう案内されています。

docker-compose.ymlの要点

共通設定

MainとWorkerで共通するDB、Redis、暗号化キーなどはYAML anchorでまとめます。値を分散させないことで、更新時の見落としを減らします。

n8n共通設定 YAML
x-n8n-shared: &n8n-shared
  image: docker.n8n.io/n8nio/n8n:${N8N_VERSION:-2.25.7}
  restart: unless-stopped
  environment: &n8n-env
    EXECUTIONS_MODE: queue
    DB_TYPE: postgresdb
    DB_POSTGRESDB_HOST: postgres
    DB_POSTGRESDB_DATABASE: n8n_cluster
    DB_POSTGRESDB_USER: n8n
    DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
    QUEUE_BULL_REDIS_HOST: redis
    QUEUE_BULL_REDIS_PORT: 6379
    QUEUE_BULL_REDIS_PASSWORD: ${REDIS_PASSWORD:?REDIS_PASSWORD is required}
    N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY:?N8N_ENCRYPTION_KEY is required}
    N8N_DEFAULT_BINARY_DATA_MODE: database
    N8N_BLOCK_ENV_ACCESS_IN_NODE: "true"

n8n-main

n8n-mainはUIとWebhookを受ける入口です。手動実行もWorkerへ逃がしたい場合は OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS を有効にします。

n8n-main YAML
n8n-main:
  <<: *n8n-shared
  ports:
    - "${N8N_PORT:-5678}:5678"
  environment:
    <<: *n8n-env
    WEBHOOK_URL: ${WEBHOOK_URL:-http://localhost:5678/}
    OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS: "true"
  depends_on:
    - redis

WorkerとTask Runner

WorkerはRedisからジョブを取得して実行します。Task Runnerを外部モードで使う場合、公式ドキュメントではQueue Modeの各Workerに専用sidecarを持たせる構成が案内されています。n8n本体と n8nio/runners のバージョンも揃えます。

WorkerとRunnerを1対1で持たせる YAML
x-n8n-worker-env: &n8n-worker-env
  <<: *n8n-env
  N8N_RUNNERS_ENABLED: "true"
  N8N_RUNNERS_MODE: external
  N8N_RUNNERS_BROKER_LISTEN_ADDRESS: 0.0.0.0
  N8N_RUNNERS_AUTH_TOKEN: ${N8N_RUNNERS_AUTH_TOKEN:?N8N_RUNNERS_AUTH_TOKEN is required}

n8n-worker:
  <<: *n8n-shared
  command: worker
  environment:
    <<: *n8n-worker-env
  depends_on:
    - redis
    - n8n-worker-runner

n8n-worker-runner:
  image: n8nio/runners:${N8N_VERSION:-2.25.7}
  restart: unless-stopped
  environment:
    N8N_RUNNERS_AUTH_TOKEN: ${N8N_RUNNERS_AUTH_TOKEN:?N8N_RUNNERS_AUTH_TOKEN is required}
    N8N_RUNNERS_TASK_BROKER_URI: http://n8n-worker:5679

Workerを2台にする場合は、n8n-worker-2 と n8n-worker-runner-2 を同じ考え方で追加します。docker compose –scale で増やす方法も考えられますが、Runnerとの対応を明示したいなら個別定義の方が読みやすくなります。

RedisとPostgreSQL

Redisはコンテナ間通信だけで使うため、基本的には外部へポート公開しません。PostgreSQLはローカル検証ではCompose内で起動し、長期運用ではバックアップや可用性を考えて外部DBやマネージドDBへ移す選択肢があります。

RedisとPostgreSQL YAML
redis:
  image: redis:8-alpine
  restart: unless-stopped
  command: >
    redis-server --requirepass ${REDIS_PASSWORD:?REDIS_PASSWORD is required}

postgres:
  image: postgres:17-alpine
  restart: unless-stopped
  profiles:
    - local-db
  environment:
    POSTGRES_DB: n8n_cluster
    POSTGRES_USER: n8n
    POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
  volumes:
    - postgres-data:/var/lib/postgresql/data

起動と確認

ローカルDB込みで起動する BASH
docker compose --profile local-db up -d
docker compose ps
curl -s http://localhost:5678/healthz
{"status":"ok"}

問題が起きたら、まず docker compose ps で全体を見てから、Main、Worker、Redis、PostgreSQLのログへ分けて追います。役割が分かれているぶん、どこを見るかを決めやすいのがQueue Modeの良いところです。

ログを確認する BASH
docker compose logs -f n8n-main
docker compose logs -f n8n-worker
docker compose logs -f redis
docker compose logs -f postgres

Workerを片方ずつ更新する

Workerを複数にしていると、片方ずつ止めて更新する運用を試せます。ただし、長時間実行中のジョブを必ず無停止で守れるという意味ではありません。N8N_GRACEFUL_SHUTDOWN_TIMEOUT などで停止待ち時間を取りつつ、更新後にRedisとDBへ再接続できていることを確認します。

Worker 2から更新する例 BASH
docker compose stop -t 300 n8n-worker-2
docker compose stop n8n-worker-runner-2
docker compose pull n8n-worker-2 n8n-worker-runner-2
docker compose up -d n8n-worker-runner-2 n8n-worker-2
docker compose ps

バックアップで忘れてはいけないもの

PostgreSQLにはWorkflow、Credential、実行履歴などが入ります。さらにCredentialの復号には N8N_ENCRYPTION_KEY が必要です。DBだけバックアップしても、暗号化キーを失うとCredentialを復号できません。

PostgreSQLをバックアップする BASH
docker compose exec postgres pg_dump -U n8n n8n_cluster > backup.sql
# restore
docker compose exec -T postgres psql -U n8n n8n_cluster < backup.sql

ハマりやすいところ

TROUBLESHOOTINGWorkerがジョブを処理しない
症状 SYMPTOM

Workflowが実行待ちのまま進まない、またはWorkerのログにRedisやDB接続エラーが出る。

考えられる原因 LIKELY CAUSE

Redis接続情報、PostgreSQL接続情報、N8N_ENCRYPTION_KEY、Runner認証トークンの不一致が考えられます。

確認すること CHECKLIST
  • MainとWorkerでN8N_ENCRYPTION_KEYが一致しているか
  • WorkerがRedisとPostgreSQLへ接続できているか
  • n8n本体とRunnerのバージョンが揃っているか
  • Queue ModeでN8N_DEFAULT_BINARY_DATA_MODE=databaseになっているか
  • Runnerごとに正しいN8N_RUNNERS_AUTH_TOKENを共有しているか
解決の方向 RESOLUTION

まずdocker compose psと各コンテナのログを確認し、Redis、DB、暗号化キー、Runner接続の順に切り分けます。

参考にした公式ドキュメント

使ってみた感想

Queue Modeは、単にWorkerを増やすためだけの機能ではなく、n8nの処理を役割ごとに見えるようにする構成だと感じました。Main、Worker、Runner、Redis、PostgreSQLの境界がはっきりすると、ログを見る場所や更新時に気をつける場所も決めやすくなります。

一方で、構成要素は増えます。最初から大きな負荷があるかどうかより、ワークフローを継続的に育てるつもりがあるか、Code Nodeをどの程度使うか、更新やバックアップをどう考えるかで採用を判断するのが良さそうです。

WRAP UPまとめ

n8n Queue Modeは、受付と実行を分けて運用しやすくするための構成です。

  • MainはUI、Webhook、Trigger管理を担当する
  • WorkerはRedisからジョブを取得して実行する
  • Task RunnerはCode Nodeの実行をn8n本体から分ける
  • Redisはキュー、PostgreSQLは永続データとして役割を分けて見る
  • Queue Modeだけで全体が無停止になるわけではない

TAKEAWAY個人環境でも、n8nを長く育てるなら、役割分離された構成にしておくと更新・調査・拡張の見通しが良くなります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です