Elixirでデータベース操作を行う場合には、Ectoを利用することが多いと思います。
その際に、Fly.ioの「Fly Postgres」をデータベースとして利用している場合に、ローカル環境で動かす際にEctoの設定方法にちょっとハマったので、備忘のために対応方法を書き残しておきます。
前提
Fly Postgresで、「Fly Postgres Cluster」を作成しているという前提とします。
公式ページの情報に従い、ここではクラスター名「pg-test」で作られたとする。
また、その際の設定は以下とします。
Postgres cluster pg-test created
Username: postgres
Password: 45V1YkwVDUzbkHj
Hostname: pg-test.internal
Flycast: fdaa:2:45b:0:1::7
Proxy port: 5432
Postgres port: 5433
Connection string: postgres://postgres:45V1YkwVDUzbkHj@pg-test.flycast:5432
Fly Postgresへの接続するためのポートフォワーディング
Fly Postgresクラスターは、Fly.io内のプライベートネットワーク以外からアクセスするには、以下の対応をする必要があります。
- 方法1: flyコマンドを経由して、ポートフォワーディングする
- 方法2: Fly Postgresクラスターのマシンに、外部アクセス用のIPアドレスを割り当てる
なお、方法2の場合には、IPアドレス割り当ての料金が発生します。
そこで、今回は、方法1の「flyコマンドを経由して、ポートフォワーディングする」で対応します。
ポートフォワーディングの設定
Fly.ioの通信はすべて「WireGuard」を経由して行われます。(WireGuard自体の説明は割愛します)
ここで、ローカル環境では「flyctl
(またはfly
)」コマンドを経由することで、WireGuardを意識せずに、ローカル環境からFly Postgresへの接続ができます。
今回は、flyctl proxy
コマンドを利用することで、アプリケーションはポートフォワード元のアクセス先へつなぎ、ポートフォワードを通じて、Flyコマンド経由でFly Postgresに接続する形となります。
今回は、localhostの15432ポートを指定する形とします。
flyctl proxy 15432:5432 -a pg-test
成功すると、以下のようなメッセージが出てきます
Proxying local port 15432 to remote [pg-test.internal]:5432
Ecto側での設定
今回の例は、Ecto単体で動かした場合を想定しています。
実行内容は、Ectoの「Getting Started」に準じます。
また、ここでは「Fly Postgres クラスター」への接続に関する部分のみを記載しています。
では、本題。
データベースに接続するための設定をconfig/config.exs
に記載しますが、その際には、以下のように記述します。
import Config
config :friends, Friends.Repo,
database: "friends",
username: "postgres",
password: "45V1YkwVDUzbkHj",
hostname: "localhost",
port: "15432"
config :friends, ecto_repos: [Friends.Repo]
または、以下のように記述します。
import Config
config :friends, Friends.Repo,
url: "postgres://postgres:45V1YkwVDUzbkHj@localhost:15432/friends"
config :friends, ecto_repos: [Friends.Repo]
今回は、ポートフォワーディングをしているので、hostomaeはlocalhost、ポート番号は15432となります。
これらは別々に指定する必要があります。
自分は、hostnameについてポート番号まで指定してしまっていたので、接続できずに10分程度悩んでしまっていました。
Ectoでデータベース作成の際に、以下のようにコマンドを実行するのですが、その際に出来上がるconfig/config.exs
のテンプレートには、localhostのみでportは用意されていなかったので追加する必要があります。
mix ecto.gen.repo -r Friends.Repo
最初にurlでやっておけばハマらなかったかもですね。