Nginx内部DNS解决问题

时间:2019-05-15 09:11:55

标签: amazon-web-services docker nginx amazon-ecs nginx-reverse-proxy

我在AWS中有nginx容器,它为我的网站提供反向代理,例如https://example.com。我拥有自动在本地DNS中注册的后端服务-aws.local(由AWS ECS自动发现完成)。 我遇到的问题是nginx仅在启动期间将名称解析为IP,因此当服务容器重新启动并获取新IP时,nginx仍尝试使用旧IP,并且出现“ 502 Bad Gateway”错误。

这是我正在运行的代码:

worker_processes 1;
events { worker_connections 1024; }
http {
    sendfile on;
    include    /etc/nginx/mime.types;
    log_format  graylog2_json  '{ "timestamp": "$time_iso8601", '
                       '"remote_addr": "$remote_addr", '
                       '"body_bytes_sent": $body_bytes_sent, '
                       '"request_time": $request_time, '
                       '"response_status": $status, '
                       '"request": "$request", '
                       '"request_method": "$request_method", '
                       '"host": "$host",'
                       '"upstream_cache_status": "$upstream_cache_status",'
                       '"upstream_addr": "$upstream_addr",'
                       '"http_x_forwarded_for": "$http_x_forwarded_for",'
                       '"http_referrer": "$http_referer", '
                       '"http_user_agent": "$http_user_agent" }';


    upstream service1 {
        server service1.aws.local:8070;
    }

    upstream service2 {
        server service2.aws.local:8080;
    }

    resolver 10.0.0.2 valid=10s;

    server {
        listen 443 http2 ssl;
        server_name example.com;
        location /main {
            proxy_pass         http://service1;
        }

        location /auth {
            proxy_pass         http://service2;
        }

我找到一些建议来更改nginx配置以解析每个请求的名称,但是随后我发现我的浏览器尝试打开“ service2.aws.local:8070”,并且由于其AWS本地DNS名称而失败。我应该在浏览器中看到https://example.com/auth“。

server {

        set $main service1.aws.local:2000;
        set $auth service2.aws.local:8070;

        location /main {
            proxy_http_version 1.1;
            proxy_pass http://$main;
        }
        location /auth {
            proxy_http_version 1.1;
            proxy_pass http://$auth;
        }

您能帮我修复它吗? 谢谢!!!

3 个答案:

答案 0 :(得分:0)

您的CloudMap Service Discovery记录的TTL是多少?如果您从NGINX容器中进行NS查找(假设为EC2模式并且可以执行到该容器中),它是否会返回新记录?没有更多信息,很难说,但是我敢说这是TTL问题,而不是NGINX /服务发现问题。

将TTL降低1秒钟,看看是否有效。

AWS CloudMap API Reference DNS Record

答案 1 :(得分:0)

TL; DR

resolver 169.254.169.253;
set $upstream "service1.aws.local";
proxy_pass http://$upstream:8070;

在ECS方面,使用Docker Compose时遇到了同样的问题。

根据six8's comment on GitHub

  

nginx仅在启动时解析主机名。您可以将变量与   proxy_pass,使其可以使用解析器进行运行时查找。

     

请参阅:

     

https://forum.nginx.org/read.php?2,215830,215832#msg-215832

     

https://www.ruby-forum.com/topic/4407628

     

这很烦人。

上面的链接之一提供了一个示例

resolver 127.0.0.1;
set $backend "foo.example.com";
proxy_pass http://$backend;

resolver部分是必需的。而且我们不能在这里引用已定义的upstream

根据Ivan Frolov's answer on StackExchangeresolver的地址应为169.254.169.253

答案 2 :(得分:0)

我找到了这个问题的完美解决方案。 Nginx的“ proxy_pass”不能使用“ etc / hosts”信息。

我建议您在ECS中使用HA-Proxy反向代理。 我尝试了nginx反向代理,但失败了。 HA-Proxy并获得成功。 它比nginx配置更简单。

首先,使用Docker的“链接”选项并设置“环境变量”(例如LINK_APP,LINK_PORT)。

第二,将此“环境变量”填充到haproxy.cfg中。

此外,我建议您使用“动态端口映射”到ALB。它使作品更加灵活。

taskdef.json:

# taskdef.json

{
    "executionRoleArn": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/<APP_NAME>_ecsTaskExecutionRole",
    "containerDefinitions": [
      {
        "name": "<APP_NAME>-rp",
        "image": "gnokoheat/ecs-reverse-proxy:latest",
        "essential": true,
        "memoryReservation": <MEMORY_RESV>,
        "portMappings": [
          {
            "hostPort": 0,
            "containerPort": 80,
            "protocol": "tcp"
          }
        ],
        "links": [
          "<APP_NAME>"
        ],
        "environment": [
          {
            "name": "LINK_PORT",
            "value": "<SERVICE_PORT>"
          },
          {
            "name": "LINK_APP",
            "value": "<APP_NAME>"
          }
        ]
      },
      {
        "name": "<APP_NAME>",
        "image": "<IMAGE_NAME>",
        "essential": true,
        "memoryReservation": <MEMORY_RESV>,
        "portMappings": [
          {
            "protocol": "tcp",
            "containerPort": <SERVICE_PORT>
          }
        ],
        "environment": [
          {
            "name": "PORT",
            "value": "<SERVICE_PORT>"
          },
          {
            "name": "APP_NAME",
            "value": "<APP_NAME>"
          }
        ]
      }
    ],
    "requiresCompatibilities": [
      "EC2"
    ],
    "networkMode": "bridge",
    "family": "<APP_NAME>"
  }

haproxy.cfg:

# haproxy.cfg

global
    daemon
    pidfile /var/run/haproxy.pid

defaults
    log global
    mode http
    retries 3
    timeout connect 5000
    timeout client 50000
    timeout server 50000

frontend http
    bind *:80

    http-request set-header X-Forwarded-Host %[req.hdr(Host)]

    compression algo gzip
    compression type text/css text/javascript text/plain application/json application/xml

    default_backend app

backend app
    server static "${LINK_APP}":"${LINK_PORT}"

Dockerfile(haproxy):

FROM haproxy:1.7
USER root
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
  

请参阅:

     

Github:https://github.com/gnokoheat/ecs-reverse-proxy

     

Docker镜像:gnokoheat / ecs-reverse-proxy:latest