Ingress在nginx配置中在特定的服务器名上创建location /(根路径匹配所有),避免在默认的服务器名上找到



我遇到了这个问题(或行为)的入口,我无法理解:如果我在ingess中配置了一个路径:/api1,但没有指定主机名,如下所示:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: api1
namespace: somenamespace
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/proxy-body-size: 100m
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
spec:
rules:
- http:
paths:
- path: /api1
pathType: ImplementationSpecific
backend:
serviceName: service-for-api1
servicePort: 1234

然后我可以访问这个路径在任何主机名或IP地址,只要它指向我的服务器,例如my-server.com/api1或1.2.3.4/api1

如果我添加另一个带有指定主机名的入口配置,如:/api2

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: api2
namespace: somenamespace
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/proxy-body-size: 100m
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "300"
spec:
rules:
- host: my-server.com   # Only difference is this one has a host field
http:
paths:
- path: /api2
pathType: ImplementationSpecific
backend:
serviceName: service-for-api2
servicePort: 1234

然后我可以访问my-server.com/api2,但是当访问my-server.com/api1时,我得到了一个404未找到错误。如果尝试通过IP, 1.2.3.4/api1访问,它可以正常工作。

我阅读了ingress生成的nginx配置,发现当ingress配置中没有指定主机时,路径规则(/api1)将被添加到servername _,这是nginx的默认服务器。一旦在ingress配置中提供了主机名,它(/api2)将被添加到nginx配置文件中的服务器名主机名块中。此外,将有一个位置/规则来匹配这个主机名中的所有路径,防止所有路径回退到默认服务器。因此,当访问my-server.com/api2时,路由是好的,但当访问my-server.com/api1时,它匹配的位置/在服务器名my-server.com块,阻止默认服务器的功能。

为什么ingress要这么做??

我认为在ingress config中不指定任何主机名意味着host: *,因此任何主机都可以匹配规则。但是它的行为就像只有未知的主机名可以匹配host: *.

我看到的nginx配置是这样的(原谅我只复制了其中的一部分):

## start server _   
server {        
server_name _ ;
listen 80 default_server reuseport backlog=65535 ;        
listen [::]:80 default_server reuseport backlog=65535 ;       
listen 443 default_server reuseport backlog=65535 ssl http2 ;     
listen [::]:443 default_server reuseport backlog=65535 ssl http2 ;                
set $proxy_upstream_name "-";
...
location /api1 {
...
}
...
}
## end server _
## start server my-server.com
server {
server_name my-server.com

listen 80  ;
listen [::]:80  ;
listen 443  ssl http2 ;
listen [::]:443  ssl http2 ;

set $proxy_upstream_name "-";
location /api2 {
....
}
location / {
set $namespace      "somenamespace";
set $ingress_name   "service-for-api2";
set $service_name   "";
set $service_port   "";
set $location_path  "/";
set $global_rate_limit_exceeding n;

...

# In case of errors try the next upstream server before returning an error
proxy_next_upstream                     error timeout;
proxy_next_upstream_timeout             0;
proxy_next_upstream_tries               3;

...
}
}
## end server my-server.com

复制时,我注意到"在返回错误之前尝试下一个上游服务器",它是否工作不正常,所以我得到了404而不是实际尝试服务器名_ ?当我查看nginx日志时,它说404请求被发送到服务[upstream-default-backend],我不知道这是什么意思。

在我发现这个问题后,我删除了/api2中指定的主机名,它工作正常。但我只是忍不住想知道为什么进入这个行为…

你在Ingress中遇到的问题实际上是预期的,它是由设计的。

当您定义Ingress规则而没有指定主机字段时,就会发生这种情况。当你添加一个带有指定主机字段的新入口规则时,该规则将成为对该特定主机名的传入请求的默认规则,并且默认服务器块将不再用于对该主机名的请求,对该主机名的请求将由服务器块使用匹配的server_name来处理。

在您的示例中,my-server.com的服务器块包括/api2的特定位置块,但它缺少/api1的位置块。这就是为什么当您尝试访问my-server.com/api1时,Nginx找不到匹配的位置块并返回404。

你可以通过在my-server.com的服务器块中添加/api1的位置块来修复这个问题,或者从/api2Ingress规则中删除主机字段,使其再次成为默认规则。

相关内容

  • 没有找到相关文章

最新更新