容器构建阶段无法通过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,而是通过构建参数动态传入:
- 修改Dockerfile的builder阶段:
ARG NEXT_PUBLIC_API_URL ENV NEXT_PUBLIC_API_URL $NEXT_PUBLIC_API_URL
- 修改
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
相关产品推荐
相关产品推荐

