Docker Traefik 背后的 Swarm Nginx 服务出现 502 错误

Docker Swarm Nginx Service behind Traefik giving a 502 Error

我有一个 docker swarm 配置为使用 Traefik 作为反向代理。我群中的一个容器是 运行 一个 Nginx 服务器,但是当我导航到该特定端点时,我收到 502 Bad Gateway 错误。 Traefik 设置如下:

version: '3.5'
services:
  traefik:
    image: traefik:alpine
    command: |-
      --entryPoints="Name:http Address::80 Redirect.EntryPoint:https"
      --entryPoints="Name:https Address::443 TLS"
      --defaultentrypoints="http,https"
      --accesslogsfile="/var/log/access.log"
      --acme 
      --acme.acmelogging="true"
      --acme.domains="${SERVER},${SANS1}"
      --acme.email="${ACME_EMAIL}"
      --acme.entrypoint="https"
      --acme.httpchallenge
      --acme.httpchallenge.entrypoint="http"
      --acme.storage="/opt/traefik/acme.json"
      --acme.onhostrule="true"
      --docker
      --docker.swarmmode
      --docker.domain="${SERVER}"
      --docker.network="frontend"
      --docker.watch
      --api
    networks:
      - frontend
    ports: 
      - target: 80
        published: 80
        mode: host
      - target: 443
        published: 443
        mode: host
      - target: 8080
        published: 8080
        mode: host
    volumes:
      - traefik_acme:/opt/traefik
      - traefik_logs:/var/log/access.log
      - /var/run/docker.sock:/var/run/docker.sock:ro
    deploy:
      replicas: 1
      placement:
        constraints: [node.role == manager]
networks:
  frontend:
    name: "frontend"
    driver: overlay
volumes:
  traefik_acme:
  traefik_logs:

这个compose文件提供了overlay网络和Traefik服务。我的群的其余部分在以下组合文件中定义:

version: "3.5"
services:
  test:
    image: emilevauge/whoami
    deploy:
      labels:
        traefik.enable: "true"
        traefik.frontend.rule: "Host:${SERVER};PathPrefixStrip:/test"
        traefik.port: 80
    networks:
      - frontend
  octeditor:
    image: ${DOCKER_OCTEDITOR_IMAGE_TAG}
    deploy:
      replicas: 1
      labels:
        traefik.enable: "true"
        traefik.frontend.rule: "Host:${SERVER}"
        traefik.port: 3000
    networks:
      - frontend
    ports:
      - "3000:80"
  octserver:
    image: ${DOCKER_OCTSERVER_IMAGE_TAG}    
    deploy:
      replicas: 1
      labels:
        traefik.enable: "true"
        traefik.frontend.rule: "Host:${SERVER};PathPrefixStrip:/api"
        traefik.port: 4000
    networks:
      - frontend
    ports:
      - "4000:4000" 
  visualizer:
    image: dockersamples/visualizer:stable
    deploy:
      placement:
        constraints:
          - 'node.role == manager'
      labels:
        traefik.enable: "true"
        traefik.frontend.rule: "Host:${SERVER};PathPrefixStrip:/visualizer"
        traefik.port: 8001
    networks:
      - frontend
    ports: 
      - "8001:8080"
    stop_grace_period: 1m30s
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
  frontend:
    external: true

相关配置是针对octeditor服务的:

  octeditor:
    image: ${DOCKER_OCTEDITOR_IMAGE_TAG}
    deploy:
      replicas: 1
      labels:
        traefik.enable: "true"
        traefik.frontend.rule: "Host:${SERVER}"
        traefik.port: 3000
    networks:
      - frontend
    ports:
      - "3000:80"

我正在将端口 80(Nginx 默认侦听)映射到端口 3000,其中 Traefik 配置为定位此服务。这是 Dockerfile 服务 运行 Nginx:

FROM node:latest as builder

WORKDIR /usr/src/app

COPY package.json . 

RUN npm install

COPY . .

RUN npm run build

FROM nginx

COPY --from=builder /usr/src/app/build /usr/share/nginx/html

我只是简单的建了一个react app然后把build文件夹复制到/usr/share/nginx/html文件夹下。我已经尝试构建 运行 这个 Dockerfile 作为一个独立的容器并且它可以工作,我还检查了 html 文件夹的内容并且一切看起来都是正确的。除了 visualizer 服务外,其他服务都是 运行 正确。只有 octedtior 服务和 visualizer 服务给我 502 错误。谁能提出解决方案,甚至如何检查发送到 nginx 容器的流量?我试过 docker ps servicename 但我看不到来自该服务的任何错误。

编辑:

如果我将 octeditor 的配置更改为:

  octeditor:
    image: ${DOCKER_OCTEDITOR_IMAGE_TAG}
    deploy:
      replicas: 1
      labels:
        traefik.enable: "true"
        traefik.frontend.rule: "Host:${SERVER}"
        traefik.port: 80
    networks:
      - frontend
    ports:
      - "80:80"

并删除之前在端口 80 上侦听的 test 服务,它似乎可以正常工作。但是我不明白以前的配置有什么问题?我以为我之前是从容器的3000端口映射到80端口,而现在我是从80端口映射到80端口,但是从容器的角度来看应该没有什么变化吧?

The relevant configuration is for the octeditor service:

octeditor:
    image: ${DOCKER_OCTEDITOR_IMAGE_TAG}
    deploy:
      replicas: 1
      labels:
        traefik.enable: "true"
        traefik.frontend.rule: "Host:${SERVER}"
        traefik.port: 3000
    networks:
      - frontend
    ports:
      - "3000:80"

I'm mapping port 80 (which Nginx listens to by default) to port 3000 where Traefik is configured to locate this service.

traefik 端口需要是 80,而不是 3000。端口映射将创建从 3000 上的主机到 80 上的容器的转发。但是 traefik 通过共享网络直接与容器对话(frontend) 并且您需要为其提供容器端口。

不需要为通过 traefik 或任何其他反向代理访问的服务发布主机端口,除非您需要在没有代理的情况下直接访问它们(这会让人质疑在这些场景中是否需要反向代理)。换句话说,这可以在没有端口的情况下编写:

  octeditor:
    image: ${DOCKER_OCTEDITOR_IMAGE_TAG}
    deploy:
      replicas: 1
      labels:
        traefik.enable: "true"
        traefik.frontend.rule: "Host:${SERVER}"
        traefik.port: 80
    networks:
      - frontend