Docker環境のServerComponentからlocalhostにアクセスできない
2023-08-09
a year ago
開発環境
- node 18.16.1
- NextJS 13.4.10
- NestJS 10.0.0
前提
NextJS x NestJS を Dockerを利用してモノレポで環境構築しています。
NextJS はAppRouterを利用しています。
参考までに、今回の記事で取り上げる環境のdocker-compose.ymlを下記します。
version: '3.8'
x-common: &common
tty: true
environment:
NODE_ENV: ${NODE_ENV}
DATABASE_URL: ${DATABASE_URL}
TZ: ${TZ}
volumes:
- .:/app
services:
db:
container_name: db
image: postgres:14.2-alpine
restart: always
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
TZ: ${TZ}
volumes:
- ./db/postgres/init.d:/docker-entrypoint-initdb.d
- ./db/postgres/pgdata:/var/lib/postgresql/data
ports:
- 5432:5432
server:
<< : *common
build:
context: .
dockerfile: ./dockerfiles/server/Dockerfile
container_name: server
command: yarn start:dev
depends_on:
- db
ports:
- 3300:3300
- 5555:5555
client:
<< : *common
build:
context: .
dockerfile: ./dockerfiles/client/Dockerfile
container_name: client
command: yarn dev
depends_on:
- server
ports:
- 3000:3000
- 6006:6006
- 8080:8080
本題
AppRouterが stable になったことで、実務では利用できていませんが個人的に色々試してる段階です。
現状は、テストやモック関連のライブラリがうまく動かなかったりと、仕事で利用するのはまだ先になりそうだなと感じています。
そんな中、個人開発で出会したエラーを1つ紹介します。
結論
APIのURLはhttp://localhost:3300ではなくhttp://host.docker.internal:3300を利用する
説明
ポート番号(3300)は試した環境で設定したものなので重要ではありません。
ホスト名のところが重要です。
同一のネットワーク内でコンテナを実装していますが、ServerComponentではホスト名の解決ができていない?ようです。(←ここの理解が浅いので分かる方に教えてほしいです・・)
例えば、以下のようなServerComponentを実装するとエラーが発生します。
import axios from 'axios';
export default async function TestFetch() {
const result = await axios.get('http://localhost:3300');
console.log({ result });
return <></>;
}
client | - error Error: connect ECONNREFUSED 127.0.0.1:3300
client | at RedirectableRequest.emit (node:events:513:28)
client | at ClientRequest.emit (node:events:513:28)
client | at Socket.socketErrorListener (node:_http_client:502:9)
client | at Socket.emit (node:events:513:28)
client | digest: "4000622448"
※host.docker.internal は Docker for Mac および Docker for Windows で提供される特別なホスト名であり、ホストマシン自体を指す IP アドレスに解決されます。この方法を使用することで、コンテナ内部からホストマシン上のサービスにアクセスできるようになります。
さいごに
今回のケースは公式ドキュメントやissueなどに情報がなかったので一旦動作することを目的にしました。
一つの解決策として参考にしてもらえると嬉しいです。