Я запускаю приложение Next.js в Docker. Однако при вызове моего API я получаю следующую ошибку
TypeError: fetch failed
at node:internal/deps/undici/undici:13178:13
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async m (/app/.next/server/chunks/961.js:3:716)
at async b (/app/.next/server/pages/user/administration.js:51:1030)
at async e3 (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/compiled/next-server/pages.runtime.prod.js:31:594)
at async doRender (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1425:30)
at async cacheEntry.responseCache.get.routeKind (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1599:28)
at async NextNodeServer.renderToResponseWithComponentsImpl (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1507:28)
at async NextNodeServer.renderPageComponent (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1924:24)
at async NextNodeServer.renderToResponseImpl (/app/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:1962:32) {
[cause]: AggregateError [ECONNREFUSED]:
at internalConnectMultiple (node:net:1118:18)
at afterConnectMultiple (node:net:1685:7)
at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) {
code: 'ECONNREFUSED',
[errors]: [ [Error], [Error] ]
Это происходит только при вызове API из getServerSideProps
. При вызове со стороны клиента все работает как положено, включая аутентифицированные и общедоступные вызовы API.
API создан на базе .NET Core и работает на localhost:5068
(не в Docker). Приложение Next работает на localhost:3050
из Docker.
Все работает так, как ожидалось, когда я запускаю приложение Next локально. Итак, я предполагаю, что мне нужна некоторая конфигурация где-то в Next (или .NET API), чтобы выполнить успешный вызов из getServerSideProps
, когда Next работает в контексте Docker.
Докерфайл
FROM node:22.4-alpine AS base
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml* ./
RUN corepack enable pnpm && pnpm i --frozen-lockfile
FROM base AS builder
ENV NEXT_PRIVATE_STANDALONE true
ENV NEXT_PUBLIC_BACKEND_ROOT_URI http://localhost:5068
ENV NEXT_PUBLIC_FRONTEND_URI http://localhost:3050
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN corepack enable pnpm && pnpm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
RUN mkdir .next
RUN chown nextjs:nodejs .next
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3050
ENV PORT 3050
CMD HOSTNAME = "0.0.0.0" node server.js
Докер Составление
services:
sweetnotes.fe:
image: myimage
container_name: mycontainer
build:
context: .
dockerfile: Dockerfile
ports:
- '3050:3050'
По умолчанию контейнеры Docker запускаются в виртуальной сети Docker, созданной Docker для изоляции контейнеров от хоста. Для сетевых целей вы можете рассматривать каждый контейнер как отдельную машину. А localhost
в контейнере означает сам контейнер.
Чтобы получить доступ к хосту из контейнера, вам необходимо добавить хост к известным именам хостов контейнера, используя extra_hosts
в вашем файле компоновки. В качестве имени хоста обычно используют имя host.docker.internal
.
В вашем случае это будет выглядеть так
services:
sweetnotes.fe:
image: myimage
container_name: mycontainer
build:
context: .
dockerfile: Dockerfile
ports:
- '3050:3050'
extra_hosts:
- 'host.docker.internal:host-gateway'
Затем вы можете изменить URL-адрес бэкэнда на
ENV NEXT_PUBLIC_BACKEND_ROOT_URI http://host.docker.internal:5068
в вашем Dockerfile, и он должен работать после восстановления образа.
Это потому, что клиент работает в браузере на хост-компьютере. Отсюда адрес localhost
. Контейнер работает в сети Docker Bridge, и оттуда хост имеет другой адрес.
Имеет смысл. Большое спасибо!
Спасибо. Добавление
extra_hosts
и изменение внутреннего URI наhttp://host.docker.internal:5068
решает проблему, когда Next вызывает серверную часть API изgetServerSideProps
. Однако клиентская часть перестала работать. Мне пришлось создать две переменные среды: одну для использования на стороне сервера и одну на стороне клиента, и соответствующим образом обработать их в коде JS.NEXT_PUBLIC_BACKEND_CLIENT_SIDE_ROOT_URI http://localhost:5068
иNEXT_PUBLIC_BACKEND_SERVER_SIDE_ROOT_URI http://host.docker.internal:5068
Знаете, почему такое поведение?