Docker缓存IP地址和提供错误的内容类型中的Nginx [英] NGINX in Docker caching IP addresses and delivering wrong Content-Type

查看:6
本文介绍了Docker缓存IP地址和提供错误的内容类型中的Nginx的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

摘要:
我想通过使用proxy_pass中的变量(如this official Nginx article in the section "Setting the Domain Name in a Variable"中所建议的),让Nginx(而不是Nginx Plus)重新解析来自DNS名称的IP地址。但当我这样做时,它不会设置/转发正确的Content-Type头,但始终使用text/html,对于.css.js等文件。

我的设置:
我有一个前端和一个后端服务运行在不同的Docker容器中(将在生产中部署到OpenShift)。还有第三个容器运行nginx:latest(目前为v1.19.9)并充当反向代理,将对/my-app的调用转发到前端,将/my-app/api转发到后端容器。Nginx反向代理已使用它们的DNS名称将它们设置为上游服务器。 所有这三个容器都运行在相同的自定义Docker网络中,因此解析本身工作得很好-但仅当(重新)启动Nginx时。

问题:
当前端或后端容器重新启动时,它可能会获得新的IP地址。因为Nginx缓存IP地址,所以当我调用它们时得到502。我希望Nginx更频繁地重新解析IP地址,就像Nginx Plus所做的那样。这就是当我尝试让Nginx重新解析DNS名称时,Content-Type出现问题的原因。

配置:
以下是我的Nginx配置(仅简化为相关内容):

  index    index.html index.htm;

  upstream upstream_frontend {
    server frontend:8080;
  }

  upstream upstream_backend {
    server backend:8000;
  }

  server {
    listen       8080;
    root         /usr/share/nginx/html;

    try_files    $uri$args $uri$args/ $uri $uri/ /index.html =404;
    
    rewrite ^/my-app$ $scheme://$http_host/my-app/ permanent;

    location /my-app {
      resolver 127.0.0.11 ipv6=off valid=1s;

      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto  $scheme;
      proxy_set_header X-NginX-Proxy true;
      proxy_ssl_session_reuse off;
      proxy_set_header Host $http_host;
      proxy_redirect off;

      proxy_http_version 1.1;
      proxy_pass_request_headers on;
      proxy_pass_header Content-Type;

#     Attempt #1, NOT working: using a variable and an upstream server setup
      set $frontend_var "http://upstream_frontend/";
      proxy_pass http://$frontend_var;

#     Attempt #2, NOT working: using a variable and directly using the container name
#      set $frontend_var "http://frontend:8080/";
#      proxy_pass $frontend_var;

#     Attempt #3, working fine:  using NO variable and an upstream server setup, , but no DNS re-resolving happening :-(
#      proxy_pass http://upstream_frontend/;

#     Attempt #4, working fine:  using NO variable and directly using the container name, but no DNS re-resolving happening :-(
#      proxy_pass http://frontend:8080/;
    }

    location /my-app/api {
      resolver 127.0.0.11 ipv6=off valid=1s;

      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto  $scheme;
      proxy_set_header X-NginX-Proxy true;
      proxy_ssl_session_reuse off;
      proxy_set_header Host $http_host;
      proxy_redirect off;

#     Attempt #1, NOT working: using a variable and an upstream server setup
      set $backend_var "http://upstream_backend/api";
      proxy_pass http://$backend_var;

#     Attempt #2, NOT working:  using a variable and directly using the container name
#      set $backend_var "http://backend:8000/api";
#      proxy_pass http://$backend_var;

#     Attempt #3, working fine:  using NO variable and an upstream server setup, , but no DNS re-resolving happening :-(
#      proxy_pass http://upstream_backend/api;

#     Attempt #4, working fine:  using NO variable and directly using the container name, but no DNS re-resolving happening :-(
#      proxy_pass http://backend:8000/api;
    }
  }

(请注意location /my-app {...}proxy_pass末尾的/,因为前端是从/my-app提供的,而前端容器本身也是从Nginx提供的,直接在...:8080/上操作,没有/my-app上下文路径。我们对监听:8000的后端容器有相同的设置,但当调用被转发到它时,我们将从它们中删除/my-app,以便它们直接到达...:8000/api处的容器。)

nginx在端口9000上运行,当我使用上面的尝试#1尝试#2打开http://localhost:9000/my-app时,.css.js、图像文件等都与Content-Type: text/html一起提供,这会阻止浏览器正确呈现页面,并在调试器窗格中显示如下消息:

The stylesheet http://localhost:9000/my-app/static/css/main.df1d2133.chunk.css  was not loaded because its MIME type, "text/html" is not "text/css"

起初我认为proxy_pass_header Content-Type;可以解决此问题,但这也没有帮助。

然后我还从this NGINX bug ticket中了解到,当使用PROXY_PASS中的变量时,如果指定了URI,它将按原样传递到服务器,替换原始的请求URI。这似乎是我遇到Content-Type问题的可能原因。

此外,正如您在配置中看到的,我已经设置了Docker DNSIP:resolver 127.0.0.11 ipv6=off valid=1s;。我也尝试过将其设置在location块之外,同样无济于事。

问题:
那么,我如何在仍然设置正确的Content-Type的情况下,在Nginx(开源)中重新解析DNS?我不必使用上游服务器,因此,如果这是可能的修复程序的一部分,我可以删除它们。

附注:
我不能像其他StackOverflow评论中所建议的那样,根据文件夹、文件名等追溯地将单独的location块添加到";修复Content-Type,因为这是一个不断发展的项目,我担心它将需要我定期向Nginx配置添加此类修补程序。

编辑:
我发布的配置包含在Nginx的Docker容器的配置文件中,也就是这个配置文件,如果您想知道几个缺少的设置:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    # This line includes my configuration above
    include /etc/nginx/conf.d/*.conf;
}

推荐答案

这不是Content-Type的问题。您使用proxy_pass不正确。正如您已经注意到的:

在PROXY_PASS中使用变量时,如果指定了URI,它将按原样传递到服务器,替换原始请求URI。

您当前具有以下工作配置,但您希望将其替换为一个变量以强制进行DNS解析:

location /my-app {
    proxy_pass http://frontend:8080/;
}

最简单的解决方案是使用rewrite...break更改URI,并从变量中删除尾随的/

例如:

location /my-app {
    rewrite ^/my-app/?(.*)$ /$1 break;
    set $frontend_var "frontend:8080";
    proxy_pass http://$frontend_var;
}

或者,使用正则表达式location捕获原始请求的其余部分。

例如:

location ~ ^/my-app/?(.*)$ {
    proxy_pass http://frontend:8080/$1;
}

这篇关于Docker缓存IP地址和提供错误的内容类型中的Nginx的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆