简体   繁体   English

尝试访问本地 API 端点时,React/Next.js docker 构建失败

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

I cannot seem to get my node:alpine Docker image for a react/next.js to build.我似乎无法获得我的节点:alpine Docker 图像,以便构建 react/next.js。

I can get it to build fine locally, but I never see the traffic in my API logs when the Docker build reaches out to the API endpoint, which is itself running in a Docker container (nginx, headless craft cms, etc.). I can get it to build fine locally, but I never see the traffic in my API logs when the Docker build reaches out to the API endpoint, which is itself running in a Docker container (nginx, headless craft cms, etc.).

The build does not seem to like localhost at all, as I've tried:正如我尝试过的那样,构建似乎根本不喜欢 localhost:

http://localhost:9000/api http://localhost:9000/api

...and this is the message I get in the logs: ...这是我在日志中收到的消息:

#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

I've heard that I can use the hostname in place of "localhost", so in my MacOS terminal I've typed "hostname" and I've swapped out the localhost for this value.我听说我可以使用主机名代替“localhost”,所以在我的 MacOS 终端中,我输入了“主机名”,并将 localhost 换成了这个值。 This doesn't outright error out, but the build hangs on the "Generating pages..." step of the build.这不会完全出错,但构建会挂在构建的“生成页面...”步骤上。

How can I get the Docker build to recognize localhost, or put another way, how can I set my API URL to an endpoint hosted by a local Docker container? How can I get the Docker build to recognize localhost, or put another way, how can I set my API URL to an endpoint hosted by a local Docker container?

Here is my Dockerfile:这是我的 Dockerfile:

# 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"]

Okay, I figured out the solution, or a solution rather.好的,我想出了解决方案,或者说是一个解决方案。

After digging around, I found that I needed to connect to the "bridge network".挖了一圈,发现需要连接“桥接网络”。

I found out what the bridge network IP was by first typing in "docker network ls":通过首先输入“docker network ls”,我发现了桥接网络 IP 是什么:

在此处输入图像描述

This gave me the name of the network I needed to get the IP for, I did this by typing "docker network inspect craftcms_default":这给了我获取 IP 所需的网络名称,我通过键入“docker network inspect craftcms_default”来做到这一点:

在此处输入图像描述

This outputs quite a bit in my case, but the only thing I need is "Gateway" IP, which here is 172.19.0.1在我的情况下,这输出相当多,但我唯一需要的是“网关”IP,这里是 172.19.0.1

My nginx server is mapped 9000:80, so the headless Craft CMS API is at:我的 nginx 服务器映射为 9000:80,因此无头工艺 CMS API 位于:

http://172.19.0.1:9000/api http://172.19.0.1:9000/api

...however, as a quick sanity check I entered this into the browser and the result was an ever spinning/loading page. ...但是,作为一个快速的健全性检查,我将其输入到浏览器中,结果是一个不断旋转/加载的页面。 Undeterred, I entered this into env.local as the PUBLIC_NEXT_API_URL and the static site generation completed fine during the Docker build.没有被吓倒,我将它作为 PUBLIC_NEXT_API_URL 输入到 env.local 中,并且 static 站点生成在 Docker 构建期间完成得很好。

I'm still experimenting with an elegant way to set this env var within the Docker build, so if anyone has any suggestions I'd love to hear!我仍在尝试用一种优雅的方式在 Docker 构建中设置这个环境变量,所以如果有人有任何建议,我很想听听!

This is was an interesting challenge considering I couldn't find any answers/Google results specifically for a process running as a result of a Docker build being unable to make a fetch to a URL hosted within another locally running container.考虑到由于 Docker 构建无法获取托管在另一个本地运行的容器中的 URL ,因此我找不到任何答案/Google 结果,这是一个有趣的挑战。 Hopefully this helps anyone else struggling with this issue!希望这可以帮助其他在这个问题上苦苦挣扎的人!

Thanks for your post - it helped me get to a solution that should do the trick.感谢您的帖子 - 它帮助我找到了一个可以解决问题的解决方案。 I found that defining the bridge network gateway is a more elegant solution;我发现定义桥接网络网关是一个更优雅的解决方案; it allows you to define the PUBLIC_NEXT_API_URL and never change it.它允许您定义 PUBLIC_NEXT_API_URL 并且从不更改它。

Here's how you can do it in a docker-compose file:这是在 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

Now you can set PUBLIC_NEXT_API_URL to http://172.28.0.1:3008/api, and be confident that this will be the endpoint every time you fire up the docker-compose.现在您可以将PUBLIC_NEXT_API_URL to http://172.28.0.1:3008/api,并确信这将是您每次启动 docker-compose 时的端点。

Also, note that you may need to remove an existing network and then "docker-compose up --force-recreate" in order to get the IP correct.另外,请注意,您可能需要删除现有网络,然后"docker-compose up --force-recreate"才能使 IP 正确。

I know this is an old issue but I'll leave my solution here for anyone new.我知道这是一个老问题,但我会将我的解决方案留给任何新的人。 Although the given solution did work for me I looked around for something more elegant.尽管给定的解决方案确实对我有用,但我环顾四周寻找更优雅的东西。 This problem apparently occurs because the localhost hostname refers always to the current container's localhost and not that of your host machine.这个问题显然是因为localhost主机名总是指当前容器的 localhost 而不是你的主机。

Buried in the docker for mac docs they refer to using host.docker.internal to connect from a container to another service.埋在 docker for mac 文档中,他们指的是使用host.docker.internal从容器连接到另一个服务。 Using the container name as recommended in many other answers did not help me, but using host.docker.internal fixed the issue.使用许多其他答案中推荐的容器名称对我没有帮助,但使用host.docker.internal解决了这个问题。

docs:文档:

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

reference:参考:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM