概要
前回はFirebase Authのローカル化を行った。
今回はNeonDBをローカルで動作させた。
ローカル環境
- Windows 11 Home 24H2 26100.2605
- Docker version 27.3.1, build ce12230
- Node v22.11.0
- bun 1.1.42
- ⛅️ wrangler 3.99.0
DBの準備
こちらにならってdocker-composeを記載。
services:
postgres:
image: postgres:17
command: '-d 1'
volumes:
- db_data:/var/lib/postgresql/data
ports:
- '5432:5432'
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=main
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 10s
timeout: 5s
retries: 5
neon-proxy:
image: ghcr.io/timowilhelm/local-neon-http-proxy:main
environment:
- PG_CONNECTION_STRING=postgres://postgres:postgres@postgres:5432/main
ports:
- '4444:4444'
depends_on:
postgres:
condition: service_healthy
volumes:
db_data:
docker-compose up
で無事起動した。
Drizzleを使ったマイグレーション
ローカルのneonDBへの接続のためにpostgresql
が必要なので追加する。
bun add -D postgres
ローカル用と本番用と2つの環境ができたので、環境変数も二つ用意。
NEON_CONNECTION_STRING=postgres://postgres:postgres@127.0.0.1:5432/main
NEON_CONNECTION_STRING=postgresql://<DB_USER_NAME>:<DB_PASSWORD>@<NEON_DB_DOMAIN>.us-west-2.aws.neon.tech/main?sslmode=require
import { config } from 'dotenv';
import { defineConfig } from 'drizzle-kit';
- config({ path: '.env.local' });
+ config({ path: process.env.DOTENV_CONFIG_PATH });
export default defineConfig({
schema: './src/schema.ts',
out: './migrations',
dialect: 'postgresql',
dbCredentials: {
url: process.env.NEON_CONNECTION_STRING!,
},
});
{
"name": "@odyssage/database",
"version": "0.0.0",
"type": "module",
"private": true,
"scripts": {
"apply": "drizzle-kit generate",
- "migrate": "drizzle-kit migrate",
+ "migrate": "cross-env DOTENV_CONFIG_PATH=.env.prod drizzle-kit migrate",
+ "migrate-local": "cross-env DOTENV_CONFIG_PATH=.env.local drizzle-kit migrate"
},
"devDependencies": {
+ "cross-env": "^7.0.3",
"dotenv": "^16.4.7",
"drizzle-kit": "^0.30.1",
+ "postgres": "^3.4.5"
},
"dependencies": {
"@neondatabase/serverless": "^0.10.4",
"drizzle-orm": "^0.38.3"
}
}
bun run migrate-local
を行いローカルのDBにマイグレーションを行う。
なお、このときpostgres
を追加せずにmigrationのコマンドを実行すると下記のようなエラーとなる。
$ drizzle-kit migrate
No config path provided, using default 'drizzle.config.ts'
Reading config file 'D:\projects\odyssage\packages\database\drizzle.config.ts'
Using '@neondatabase/serverless' driver for database querying
Warning '@neondatabase/serverless' can only connect to remote Neon/Vercel Postgres/Supabase instances through a websocket
[⣷] applying migrations...ErrorEvent {
[Symbol(kTarget)]: _WebSocket {
_events: [Object: null prototype] {
...
省略
...
[Symbol(kError)]: Error: Client network socket disconnected before secure TLS connection was established
at TLSSocket.onConnectEnd (node:_tls_wrap:1732:19)
at TLSSocket.emit (node:events:530:35)
at endReadableNT (node:internal/streams/readable:1698:12)
at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
code: 'ECONNRESET',
path: undefined,
host: '127.0.0.1',
port: 443,
localAddress: undefined
},
[Symbol(kMessage)]: 'Client network socket disconnected before secure TLS connection was established'
}
error: script "migrate" exited with code 1
マイグレーション結果の確認
a5SQLを使って確認した。
バックエンドからの接続
hostsの修正
接続文字列に127.0.0.1
を使うと下記エラーが発生する。そのため、127.0.0.1 db.localtest.me
の名前解決をローカル環境で行う必要がある。
[wrangler:inf] GET /api/user/ 500 Internal Server Error (26ms)
X [ERROR] NeonDbError: invalid hostname: Common name inferred from SNI ('0.0.1') is not known
各OSごとの設定を参考に設定した。
C:\Windows\System32\drivers\etc\host
をメモ帳の管理者モードで開いて、下記を追記。
127.0.0.1 db.localtest.me
バックエンドソースの修正
- NEON_CONNECTION_STRING=postgresql://<DB_USER_NAME>:<DB_PASSWORD>@<NEON_DB_DOMAIN>.us-west-2.aws.neon.tech/main?sslmode=require
+ NEON_CONNECTION_STRING=postgres://postgres:postgres@db.localtest.me:5432/main
- import { neon } from '@neondatabase/serverless';
+ import { neon, neonConfig } from '@neondatabase/serverless';
import { drizzle } from 'drizzle-orm/neon-http';
import type { NeonQueryFunction } from '@neondatabase/serverless';
import type { NeonHttpDatabase } from 'drizzle-orm/neon-http';
type NeonDBClient = NeonHttpDatabase<Record<string, never>> & {
$client: NeonQueryFunction<false, false>;
};
let db: NeonDBClient | null = null;
export const getDb = (
connectionString = process.env.NEON_CONNECTION_STRING!,
) => {
if (db != null) {
return db;
}
+ if ( connectionString === 'postgres://postgres:postgres@db.localtest.me:5432/main' ) {
+ neonConfig.fetchEndpoint = `http://db.localtest.me:4444/sql`;
+ neonConfig.useSecureWebSocket = false;
+ }
const sql = neon(connectionString);
db = drizzle({ client: sql });
return db;
};
ちなみに、接続文字列だけ変更すると下記エラーが発生する。
X [ERROR] NeonDbError: Error connecting to database: Network connection lost.
at execute
(file:///D:/projects/odyssage/node_modules/@neondatabase/serverless/index.mjs:1549:24)
参考
Local Development with Neon
Neon (Postgres) をコンテナで動かす
Neon Serverless Postgres: 便利な機能と導入パターン
サーバレスDB(Postgresql : NeonDB ) の無料版にCloudflare Workers ( Node.js) から繋いだメモ