You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

容器构建阶段无法通过DNS解析backend服务问题排查

问题描述

我部署了三个服务:DB、backend和frontend,使用docker-compose.yml统一管理。

docker-compose.yml配置

version: '3.9'
services:
  postgres:
    container_name: postgres
    image: postgres:14.6-alpine
    restart: always
    env_file:
      - .env.db
    ports:
      - "5432:5432"
    volumes:
      - postgres-data:/var/lib/postgres/data/pgdata
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - website

  backend:
    container_name: backend
    build: ./backend
    restart: unless-stopped
    env_file: .env.backend
    ports:
      - "1337:1337"
    volumes:
      - ./backend/config:/opt/app/config
      - ./backend/src:/opt/app/src
      - ./backend/package.json:/opt/package.json
      - ./backend/yarn.lock:/opt/yarn.lock
      - ./backend/public/uploads:/opt/app/public/uploads
    networks:
      - website
    depends_on:
      - postgres

  frontend:
    build: ./frontend
    container_name: frontend
    ports:
      - "3000:3000"
    networks:
      - website
    depends_on:
      - backend

volumes:
  postgres-data:
    external: true

networks:
  website:
    driver: bridge

前端Dockerfile配置

# Install dependencies only when needed
FROM node:16-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY yarn.lock* package*.json ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  else echo "Lockfile not found." && exit 1; \
  fi

# Rebuild the source code only when needed
FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED 1
ENV NEXT_PUBLIC_API_URL http://backend:1337/graphql

RUN yarn build

FROM node:16-alpine 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/public ./public

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 up -d postgres backend
# wait logic
docker compose up -d frontend

错误信息

Error: request to http://backend:1337/graphql failed, reason: getaddrinfo ENOTFOUND backend

我确认所有服务在同一网络,临时alpine容器能正常ping通backend,但前端构建时出现上述DNS解析失败错误,请问问题原因是什么?


问题原因及解决办法

核心原因:构建阶段未加入Docker Compose网络

前端的yarn build是在Docker镜像构建阶段执行的,而构建阶段的容器默认不会加入docker-compose.yml中定义的website网络。此时构建容器处于独立的环境,无法解析backend这个服务名,导致DNS解析失败。

虽然你提前启动了backend服务,且前端运行阶段的容器会加入共享网络,但构建过程完全独立于Compose服务网络,所以即使backend已经运行,构建容器也访问不到它。

解决办法

方案1:避免构建阶段依赖真实API

如果前端构建时不需要调用真实API(比如仅生成静态资源,API请求在客户端运行时发起),可以:

  • 将NEXT_PUBLIC_API_URL改为客户端能访问的地址(如http://localhost:1337/graphql);
  • 在构建阶段使用Mock数据替代真实API请求,确保构建过程不依赖backend服务。

方案2:让构建容器加入Compose网络

修改docker-compose.yml中frontend服务的配置,指定构建阶段加入现有网络:

frontend:
  build:
    context: ./frontend
    network: website  # 让构建阶段加入website网络
  container_name: frontend
  ports:
    - "3000:3000"
  networks:
    - website
  depends_on:
    - backend

这样构建阶段的容器就能接入website网络,正常解析backend服务名。

方案3:用构建参数传递API地址

不在Dockerfile中硬编码NEXT_PUBLIC_API_URL,而是通过构建参数动态传入:

  1. 修改Dockerfile的builder阶段:
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL $NEXT_PUBLIC_API_URL
  1. 修改docker-compose.yml:
frontend:
  build:
    context: ./frontend
    args:
      NEXT_PUBLIC_API_URL: http://backend:1337/graphql  # 运行时用服务名
      # 若构建阶段需调用API,可改用宿主机地址:http://host.docker.internal:1337/graphql(需宿主机端口已映射)
  # 其他配置不变

内容的提问来源于stack exchange,提问作者Alex Lebedev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 10:10:15