React/Next.js docker 尝试连接到本地 API 端点时构建失败

React/Next.js docker build failing when trying to reach out to local API endpoint

我似乎无法获取 node:alpine Docker 图像以构建 react/next.js。

我可以让它在本地正常构建,但是当 Docker 构建到达 API 端点时,我从未在我的 API 日志中看到流量运行 在 Docker 容器中(nginx、headless craft cms 等)。

构建似乎根本不喜欢本地主机,正如我所尝试的那样:

http://localhost:9000/api

...这是我在日志中收到的消息:

#15 13.76 > Build error occurred
#15 13.76 FetchError: request to http://localhost:9000/api failed, reason: connect ECONNREFUSED 127.0.0.1:9000

我听说我可以使用主机名代替“localhost”,所以在我的 MacOS 终端中我输入了“hostname”并且我已经将 localhost 换成了这个值。这并没有完全出错,但是构建挂在构建的“生成页面...”步骤上。

如何让 Docker 构建识别本地主机,或者换句话说,如何将我的 API URL 设置为由本地 [=37] 托管的端点=]容器?

这是我的Docker文件:

# Install dependencies only when needed
FROM node:alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn --frozen-lockfile

# Rebuild the source code only when needed
FROM node:alpine AS builder

WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN yarn static

# Production image, copy all the files and run next
FROM node:alpine AS runner
WORKDIR /app

ENV NODE_ENV production

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# You only need to copy next.config.js if you are NOT using the default configuration
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

USER nextjs

EXPOSE 3000

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry.
# ENV NEXT_TELEMETRY_DISABLED 1

CMD ["yarn", "start"]

好的,我找到了解决方案,或者 一个 解决方案。

翻来覆去,我发现我需要连接到“桥接网络”。

我通过输入“docker network ls”找到了桥接网络 IP 是什么:

这给了我获取 IP 所需的网络名称,我通过键入“docker network inspect craftcms_default”来完成此操作:

在我的例子中,输出相当多,但我唯一需要的是“网关”IP,这里是 172.19.0.1

我的 nginx 服务器已映射 9000:80,因此无头 Craft CMS API 位于:

http://172.19.0.1:9000/api

...但是,作为快速完整性检查,我将其输入浏览器,结果是一个 spinning/loading 页面。没有被吓倒,我将其输入 env.local 作为 PUBLIC_NEXT_API_URL 并且在 Docker 构建期间静态站点生成正常完成。

我仍在试验在 Docker 构建中设置此环境变量的优雅方式,所以如果有人有任何建议,我很乐意听取!

这是一个有趣的挑战,因为我找不到任何 answers/Google 进程 运行 的结果,因为 Docker 构建无法获取到另一个本地 运行 容器中托管的 URL。希望这可以帮助其他正在努力解决这个问题的人!

感谢您的 post - 它帮助我找到了解决问题的方法。我发现定义 bridge 网络网关是一个更优雅的解决方案;它允许您定义 PUBLIC_NEXT_API_URL 而永远不会更改它。

以下是在 docker-compose 文件中的操作方法:

services:
  db:
    image: postgres
    restart: always
    networks:
      - stagingnetwork

  api:
    image: express
    restart: always
    ports:
      - '3008:3008'
    depends_on:
      - db
    networks:
      - stagingnetwork


  adminer:
    image: adminer
    restart: always
    networks:
      - stagingnetwork
    ports:
      - 8080:8080

networks:
  stagingnetwork:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/16
          gateway: 172.28.0.1

现在您可以设置 PUBLIC_NEXT_API_URL to http://172.28.0.1:3008/api, 并确信这将是您每次启动 docker-compose 时的端点。

另请注意,您可能需要删除现有网络,然后 "docker-compose up --force-recreate" 才能获得正确的 IP。

我知道这是一个老问题,但我会把我的解决方案留在这里供任何新人使用。尽管给定的解决方案确实对我有用,但我四处寻找更优雅的东西。这个问题显然是因为 localhost 主机名总是指向当前容器的本地主机,而不是你的主机 machine.

埋在 docker for mac 文档中,他们提到使用 host.docker.internal 从容器连接到另一个服务。使用许多其他答案中推荐的容器名称对我没有帮助,但使用 host.docker.internal 解决了问题。

文档:

https://docs.docker.com/docker-for-mac/networking/

参考:

https://forums.docker.com/t/localhost-and-docker-compose-networking-issue/23100/5

如果您使用的是 docker-compose,通常您可以使用名称引用容器,这些名称将解析为 Docker 的默认网络中的 IP。但是,这似乎在构建期间不起作用。

在 Mac 上,您可以通过 host.docker.internal 连接到主机上的容器,如@MikejdeGroot 所说。所以你可以使用 http://host.docker.internal:9000/api.

在 Linux,您可以考虑在构建期间使用主机网络,例如

nextjs-app:
  build:
    network: "host"
  # ...
  network_mode: "host"

通过此配置,您可以使用 http://localhost:9000/api