我遇到了这个问题(或行为)的入口,我无法理解:如果我在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
的位置块来修复这个问题,或者从/api2
的Ingress
规则中删除主机字段,使其再次成为默认规则。