n8nのDBをRDS PostgreSQLに外出ししてみた

n8nのDBをRDS for PostgreSQLに外出ししてみました。これでワークフローのデータを永続化させることが可能です。ちょっとしたハマリポイントもまとめておきました。
2020.02.21

こんにちは、臼田です。

みなさん、業務の自動化してますか?(挨拶

先日からn8nというワークフロー自動化OSSを検証しています。詳細は下記をご確認ください。

IFTTTやZapierのようなワークフロー自動化OSSのn8nをECS on Fargate上に建ててみた

今回はこのDBを外出ししてみます。

なぜ外出しするのか

上記ブログにも書いてあるのですが、デフォルトでn8nのコンテナはローカルのSQLiteに保存されます。

データが保持されないので外出しが必要になります。

n8nではMongoDBとPostgreSQLに対応しています。

つい最近MySQLも対応したのですが、Docker版ではまだ利用できないようだったので今回はPostgreSQLを利用します。

RDSと接続してみた

RDS作成

RDS PostgreSQLの作成は一般的なものなので割愛します。下記などをご参照ください。

PostgreSQL データベースを作成して接続する方法 – AWS

作成時の要点をまとめます。

  • ユーザ名 / パスワードを控えておく
  • ストレージサイズはあまりかからないと思うので適当に(私はデフォルト20GBで念の為AutoScalingで100GBまでとしています)
  • n8nをデプロイするECSと同じVPCを選択
  • セキュリティグループは事前に作成しておき、n8nのセキュリティグループからのアクセスを許可しておく
  • 追加でデータベース名n8nでデータベースを作成しておく

データベースの初期作成はn8n側で行わないようなので、RDS作成時に一緒に作っておきましょう。

ECSタスク定義の更新

すでに前回のタスク定義がある想定で進めます。

n8nでDBを外出しする場合の設定方法はこちらにあります。

下記の6つの環境変数を設定する必要があります。

  • DB_TYPE=postgresdb
  • DB_POSTGRESDB_DATABASE=n8n (RDS作成時につけたデータベース名)
  • DB_POSTGRESDB_HOST=
  • DB_POSTGRESDB_PORT=5432
  • DB_POSTGRESDB_USER=
  • DB_POSTGRESDB_PASSWORD=

設定するにはタスク定義画面で前回作成したタスク定義を選択し、「新しいリビジョンの作成」を押します。

真ん中ぐらいのコンテナの定義を選択して環境変数を入力します。パスワードなどが直書きですが、本来はSystems Managerのパラメータストアを利用したほうが適切です。入力したら更新します。

新しいタスク定義でタスクを立ち上げると、PostgreSQLに接続しています。

RDSに接続するためのEC2を別途立ち上げて確認してみます。

[ec2-user@ip-10-0-20-122 ~]$ sudo yum install postgresql
~中略~
インストール:
  postgresql.x86_64 0:9.2.24-1.amzn2.0.1

依存性関連をインストールしました:
  postgresql-libs.x86_64 0:9.2.24-1.amzn2.0.1

完了しました!
[ec2-user@ip-10-0-20-122 ~]$ psql --host=n8n-postgres.************.ap-northeast-1.rds.amazonaws.com --username=n8n_user --password --port=5432 --dbname=n8n
ユーザ n8n_user のパスワード:
~中略~
n8n=> \d
                      リレーションの一覧
 スキーマ |           名前            |     型     |  所有者
----------+---------------------------+------------+----------
 public   | credentials_entity        | テーブル   | n8n_user
 public   | credentials_entity_id_seq | シーケンス | n8n_user
 public   | execution_entity          | テーブル   | n8n_user
 public   | execution_entity_id_seq   | シーケンス | n8n_user
 public   | workflow_entity           | テーブル   | n8n_user
 public   | workflow_entity_id_seq    | シーケンス | n8n_user

テーブルが作成されていることが確認できました。

ワークフローを保存しておけば、タスクを削除して上げ直しても保持されていることが確認できました。

まとめ

n8nのDBを外出しする方法をまとめました。

PostgreSQLもいいですが、MySQLも早く来てほしいですね!

おまけ

本編ではさっくり出来ていますが、途中ドキュメントトラップに阻まれてかなり時間を費やしてしまったのでここに残しておきます。

このドキュメントには下記のように書かれています。

Use with PostgresDB
Replace the following placeholders with the actual data:

POSTGRES_DATABASE
POSTGRES_HOST
POSTGRES_PASSWORD
POSTGRES_PORT
POSTGRES_USER

本来の環境変数はその下に実際のdocker runコマンドとして書かれているのですが、そちらの値を見ずに上記の値が環境変数名だと思って設定してうまく行かずかなり迷走していましたorz

その際のエラーを載せておきます。

17:54:02 UserSettings got generated and saved to: /home/node/.n8n/config
17:54:02 (node:12) UnhandledPromiseRejectionWarning: Error: connect ECONNREFUSED 127.0.0.1:5432
17:54:02 at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1128:14)
17:54:02 (node:12) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
17:54:02 (node:12) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
17:54:07 (node:12) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
17:54:07 (node:12) UnhandledPromiseRejectionWarning: Error: There was an error: connect ECONNREFUSED 127.0.0.1:5432
17:54:07 at Object.error (/usr/local/lib/node_modules/n8n/node_modules/@oclif/errors/lib/index.js:22:17)
17:54:07 at Start.error (/usr/local/lib/node_modules/n8n/node_modules/@oclif/command/lib/command.js:57:23)
17:54:07 at /usr/local/lib/node_modules/n8n/dist/commands/start.js:110:22
17:54:07 (node:12) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)

DBへの接続がECONNREFUSED 127.0.0.1:5432となっていて明らかにおかしいなと思って、正しく名前解決出来ていないのでは?とnslookupしたりしちゃいました。

ドキュメントはちゃんと読みましょう(戒め