我有一个使用 create T3 应用程序堆栈的 Nextjs 项目(除了使用 drizzle orm 代替 pf Prisma)。 在我的开发环境中一切正常 现在我想使用 docker 在我的 Linux 服务器上部署我的项目。
Ubuntu 22.04.2 LTS - Platform: linux/arm64/v8
docker-compose 构建过程运行良好。两项服务均已启动并正在运行,并且环境变量已正确设置(除非我忘记设置重要的变量?),但我无法访问应用程序的任何页面。当我尝试打开它时,服务器正在记录几个运行时错误,抱怨与本地主机的连接被拒绝。 我的设置和错误发布在下面。
我的 Dockerfile(来自 T3 文档)
##### DEPENDENCIES
FROM --platform=linux/arm64/v8 node:16-alpine3.17 AS deps
RUN apk add --no-cache libc6-compat openssl1.1-compat
WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml\* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i; \
else echo "Lockfile not found." && exit 1; \
fi
##### BUILDER
FROM --platform=linux/arm64/v8 node:16-alpine3.17 AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# ENV NEXT_TELEMETRY_DISABLED 1
RUN \
if [ -f yarn.lock ]; then SKIP_ENV_VALIDATION=0 yarn build; \
elif [ -f package-lock.json ]; then SKIP_ENV_VALIDATION=0 npm run build; \
elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && SKIP_ENV_VALIDATION=0 pnpm run build; \
else echo "Lockfile not found." && exit 1; \
fi
##### RUNNER
FROM --platform=linux/arm64/v8 node:16-alpine3.17 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.mjs ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
# USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["node", "server.js"]
我的docker-compose
version: '3.8'
services:
nextjs-app-bpl-v3:
build:
context: .
dockerfile: Dockerfile
container_name: nextjs-app-bpl-v3
restart: unless-stopped
working_dir: /app
ports:
- '3187:3000'
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres-db-bpl-v3:5432/${POSTGRES_DB}
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- NEXTAUTH_URL=${NEXTAUTH_URL}
- DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID}
- DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET}
image: t3-app-bpl-v3
depends_on:
- postgres-db-bpl-v3
networks:
- nginx_network
postgres-db-bpl-v3:
image: postgres:latest
container_name: postgres-db-bpl-v3
restart: unless-stopped
ports:
- '5578:5432'
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
volumes:
- postgres-data-bpl-v3:/var/lib/postgresql/data
networks:
- nginx_network
volumes:
postgres-data-bpl-v3:
networks:
nginx_network:
external: true
我的环境(.env)
NEXTAUTH_SECRET="MY_SECRET"
NEXTAUTH_URL="https://example.com"
# Next Auth Providers
DISCORD_CLIENT_ID="DC_ID"
DISCORD_CLIENT_SECRET="DC_SECRET"
POSTGRES_USER="username"
POSTGRES_PASSWORD="my_password"
POSTGRES_DB="db_name"
下一个.config.mjs
await import("./src/env.mjs");
/** @type {import("next").NextConfig} */
const config = {
reactStrictMode: true,
i18n: {
locales: ["en"],
defaultLocale: "en",
},
webpackDevMiddleware: (
/** @type {{ watchOptions: { poll: number; aggregateTimeout: number; }; }} */ config
) => {
config.watchOptions = {
poll: 1000,
aggregateTimeout: 300,
};
return config;
},
swcMinify: true,
output: "standalone",
};
export default config;
容器日志:
Attaching to nextjs-app-bpl-v3
nextjs-app-bpl-v3 | - ready started server on 07135160c06c:3000, url: http://07135160c06c:3000
nextjs-app-bpl-v3 | Listening on port 3000 url: http://07135160c06c:3000
nextjs-app-bpl-v3 | Warning - Configuring `keepAlive: false` is deprecated. Use `{ headers: { connection: "close" } }` instead.
nextjs-app-bpl-v3 | - error Failed to handle request for /
nextjs-app-bpl-v3 | TypeError: fetch failed
nextjs-app-bpl-v3 | at Object.fetch (/app/node_modules/next/dist/compiled/undici/index.js:1:26669)
nextjs-app-bpl-v3 | at processTicksAndRejections (node:internal/process/task_queues:96:5)
nextjs-app-bpl-v3 | at async invokeRequest (/app/node_modules/next/dist/server/lib/server-ipc/invoke-request.js:21:12)
nextjs-app-bpl-v3 | at async requestHandler (/app/node_modules/next/dist/server/lib/start-server.js:336:33)
nextjs-app-bpl-v3 | at async Server.<anonymous> (/app/node_modules/next/dist/server/lib/start-server.js:152:13) {
nextjs-app-bpl-v3 | cause: Error: connect ECONNREFUSED 127.0.0.1:45761
nextjs-app-bpl-v3 | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1278:16) {
nextjs-app-bpl-v3 | errno: -111,
nextjs-app-bpl-v3 | code: 'ECONNREFUSED',
nextjs-app-bpl-v3 | syscall: 'connect',
nextjs-app-bpl-v3 | address: '127.0.0.1',
nextjs-app-bpl-v3 | port: 45761
nextjs-app-bpl-v3 | }
nextjs-app-bpl-v3 | }
nextjs-app-bpl-v3 | - error Failed to handle request for /favicon.ico
nextjs-app-bpl-v3 | TypeError: fetch failed
nextjs-app-bpl-v3 | at Object.fetch (/app/node_modules/next/dist/compiled/undici/index.js:1:26669)
nextjs-app-bpl-v3 | at processTicksAndRejections (node:internal/process/task_queues:96:5)
nextjs-app-bpl-v3 | at async invokeRequest (/app/node_modules/next/dist/server/lib/server-ipc/invoke-request.js:21:12)
nextjs-app-bpl-v3 | at async requestHandler (/app/node_modules/next/dist/server/lib/start-server.js:336:33)
nextjs-app-bpl-v3 | at async Server.<anonymous> (/app/node_modules/next/dist/server/lib/start-server.js:152:13) {
nextjs-app-bpl-v3 | cause: Error: connect ECONNREFUSED 127.0.0.1:45761
nextjs-app-bpl-v3 | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1278:16) {
nextjs-app-bpl-v3 | errno: -111,
nextjs-app-bpl-v3 | code: 'ECONNREFUSED',
nextjs-app-bpl-v3 | syscall: 'connect',
nextjs-app-bpl-v3 | address: '127.0.0.1',
nextjs-app-bpl-v3 | port: 45761
nextjs-app-bpl-v3 | }
nextjs-app-bpl-v3 | }
为什么运行时尝试连接到本地主机?我看不出有任何地方可以提及这一点。错误发生在服务器上(而不是打开页面时发生在客户端) 客户端仅显示 500:内部服务器错误。
我现在的解决方法是: 我删除了
output: "standalone"
并通过删除 RUNNER 部分更新了 Dockerfile,并使用 npm run start
(next start
) 启动服务器
这是有效的,尽管我仍然想知道为什么它不能与独立输出一起工作
我的问题和目标是通过修复此问题来按预期使用独立服务器
TypeError: fetch failed
。
不使用 docker 容器内部的独立构建的确切缺点是什么?
感谢您的任何解释!
我可能是错的,但我认为在构建时需要一些 ENV 变量,而在运行时使用
output: standalone
文件中的 next.config.{m}js
选项时需要一些 ENV 变量。我不确定这是否正确,但这就是我处理 Dockerfile 的方式 next 13.4.12
:
FROM base AS builder
ARG DATABASE_URL
ARG VERCEL_URL
ARG NEXT_PUBLIC_CLIENTVAR
ENV DATABASE_URL=${DATABASE_URL}
ENV VERCEL_URL=${VERCEL_URL}
ENV NEXT_PUBLIC_CLIENTVAR=${NEXT_PUBLIC_CLIENTVAR}
...
FROM base AS runner
ARG DATABASE_URL
ARG VERCEL_URL
ARG NEXT_PUBLIC_CLIENTVAR
ENV DATABASE_URL=${DATABASE_URL}
ENV VERCEL_URL=${VERCEL_URL}
ENV NEXT_PUBLIC_CLIENTVAR=${NEXT_PUBLIC_CLIENTVAR}
在我的
docker-compose.yml
:
services:
next-app:
restart: unless-stopped
build:
context: ./
dockerfile: Dockerfile
args:
NEXT_PUBLIC_CLIENTVAR: ${NEXT_PUBLIC_CLIENTVAR}
environment:
- DATABASE_URL=${DATABASE_URL}
ports:
- 3000:3000
还值得注意的是,目前存在一个未解决的问题,涉及
next 13.4.13
及以上的 ENV 变量和 output: standalone
。