简体   繁体   English

504来自ngingx反向代理与Node.js + Docker的响应

[英]504 response from ngingx reverse proxy with nodejs + docker

UPDATE UPDATE

I have found out that it works if I restart nginx on the container with docker exec -it backend_gateway_1 nginx -s reload . 我发现如果我使用docker exec -it backend_gateway_1 nginx -s reload在容器上重新启动nginx,它将起作用。 I have found some information from this question . 我从这个问题中找到了一些信息。 It seems that connecting to 127.0.0.1 rather than localhost would work, however I am using docker networks so I'm not sure what my situation would be. 似乎可以连接到127.0.0.1而不是localhost,但是我使用的是docker网络,所以我不确定我的处境。

ORIGINAL QUESTION 原始问题

I am trying to use nginx as a reverse proxy with docker. 我正在尝试将nginx用作docker的反向代理。 I cannot quite work out what's wrong as sometimes it works when but then if I use docker-compose down && docker-compose up to restart it all, i will then usually get this 504 error 我不能完全弄清楚出什么问题了,有时它有时在什么时候起作用,但是如果我使用docker-compose down && docker-compose up重新启动所有功能,我通常会收到此504错误

I have a feeling this is to do with the nginx or docker configuration. 我觉得这与nginx或docker配置有关。 I am able to make a request to / fine but any request to /user is causing the intermittent issue. 我可以向/发出请求,但对/ user的任何请求都导致间歇性问题。

When I am not receiving a 504, the node app is working well and creates/returns a user. 当我没有收到504消息时,节点应用程序运行良好,并创建/返回了用户。 I am also able to connect to the database fine with mongo-express so that should help narrow something down. 我还可以使用mongo-express很好地连接到数据库,这样应该可以缩小范围。

docker-compose.yml 泊坞窗,compose.yml

version: '3.5'
services:
  gateway:
    image: nginx:latest
    restart: always
    ports:
      - 8080:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/nginx-error.log:/var/log/nginx/error.log
    networks:
      - poker_network
  poker_mongo:
    image: mongo:latest
    container_name: poker_mongo
    restart: unless-stopped
    volumes:
      - db-data:/data/db
    expose: 
      - "27017"
    environment:
      MONGO_INITDB_ROOT_USERNAME: test
      MONGO_INITDB_ROOT_PASSWORD: 123
    networks:
      - poker_network
    depends_on:
      - gateway
  poker_user:
    container_name: poker_user
    build: ./user/
    image: poker/user:latest
    volumes:
      - ./user/:/usr/src/app
      #- /usr/src/app/node_modules
    expose:
      - "8080"
    depends_on:
      - gateway
      - poker_mongo
    networks:
      - poker_network
    environment:
      WAIT_HOSTS: poker_mongo:27017
  mongo-express:
    container_name: mongo-express
    image: mongo-express
    restart: always
    ports:
      - 8085:8081
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: test
      ME_CONFIG_MONGODB_ADMINPASSWORD: 123
      ME_CONFIG_MONGODB_SERVER: poker_mongo
    depends_on:
     - gateway
     - poker_mongo
    networks:
      - poker_network

networks:
  poker_network:
volumes: 
  db-data:

nginx.conf nginx.conf

events { worker_connections 1024; }

http {

    server {
        listen 80;
        location /user {
            rewrite /user/(.*) /$1  break;
            proxy_pass http://poker_user:8080/;
            proxy_set_header X-Real-IP  $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Host $host;
        }
        location / {
            return 200 'hello';
        }

    }
}

Any help is appreciated, thanks. 任何帮助表示赞赏,谢谢。

I found several similar related questions and will try to compile two possible solutions out of those: 我发现了几个类似的相关问题,并将尝试从中找出两个可能的解决方案:

First solution 第一个解决方案

First solution is to reverse dependency between services: instead of poker_user depend on gateway you can may gateway depend on user. 第一个解决方案是扭转服务之间的依赖关系:不是poker_user取决于gateway可以可以gateway依赖于用户。 This way when gateway starts if will be able to resolve poker_user hostname. 这样,当gateway启动时便能够解析poker_user主机名。

The Dockerfile would look this way in this case: 在这种情况下,Dockerfile的外观如下:

version: '3.5'
services:
  gateway:
    image: nginx:latest
    restart: always
    ports:
      - 8080:80
    depends_on: poker_user
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/nginx-error.log:/var/log/nginx/error.log
    networks:
      - poker_network
  poker_mongo:
    image: mongo:latest
    container_name: poker_mongo
    restart: unless-stopped
    volumes:
      - db-data:/data/db
    expose: 
      - "27017"
    environment:
      MONGO_INITDB_ROOT_USERNAME: test
      MONGO_INITDB_ROOT_PASSWORD: 123
    networks:
      - poker_network
  poker_user:
    container_name: poker_user
    build: ./user/
    image: poker/user:latest
    volumes:
      - ./user/:/usr/src/app
      #- /usr/src/app/node_modules
    expose:
      - "8080"
    depends_on:
      - poker_mongo
    networks:
      - poker_network
    environment:
      WAIT_HOSTS: poker_mongo:27017
  mongo-express:
    container_name: mongo-express
    image: mongo-express
    restart: always
    ports:
      - 8085:8081
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: test
      ME_CONFIG_MONGODB_ADMINPASSWORD: 123
      ME_CONFIG_MONGODB_SERVER: poker_mongo
    depends_on:
     - gateway
    networks:
      - poker_network

networks:
  poker_network:
volumes: 
  db-data:

I also removed some other dependencies as I think they are redundant. 我还删除了一些其他依赖项,因为我认为它们是多余的。

Second solution 第二解决方案

This solution is based on changing nginx configuration. 该解决方案基于更改nginx配置。 It looks like nginx tries to resolve hostname specified in proxy_pass upfront and since it's not available yet when nginx starts it will keep responding with 504 because it doesn't try to resolve it again. 它看起来像nginx尝试解析指定hostname proxy_pass前期和因为它是尚未公布的时候nginx启动,将保持与响应504 ,因为它不会再次尝试解决这个问题。

There seems to be a workaround with using variables inside proxy_pass directive which are treated differently and force nginx to perform DNS resolution again. 使用proxy_pass指令内的变量似乎有变通办法,这些变量会被区别对待并迫使nginx再次执行DNS解析。 This requires resolver to be configured in nginx and luckily there's one built into Docker when using user-defined networks. 这需要在nginx中配置解析器, 幸运的是 ,使用用户定义的网络时,Docker中内置了一个解析器。

Here's an example nginx configuration (though I haven't tested it myself): 这是一个示例nginx配置(尽管我自己尚未对其进行测试):

events { worker_connections 1024; }

http {

    server {
        listen 80;
        location /user {
            # Docker DNS server in user-defined networks
            # https://docs.docker.com/v17.09/engine/userguide/networking/configure-dns/
            resolver 127.0.0.11 ipv6=off;

            rewrite /user/(.*) /$1  break;

            # Using a variable will force nginx to re-resolve DNS name
            # https://serverfault.com/a/593003
            set $backend "http://poker_user:8080/";
            proxy_pass $backend;

            proxy_set_header X-Real-IP  $remote_addr;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Host $host;
        }
        location / {
            return 200 'hello';
        }

    }
}

Hope this help! 希望对您有所帮助!

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

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