使用主机的入口规则

Ingress rule using host

有人可以帮助发现 ingress-2 入口规则的问题吗?为什么 ingress-1 有效而 ingress-2 无效。

我的设置说明,我有两个部署:

第一次部署是 nginx
第二次部署是 httpd

这两个部署都是通过 ClusterIP 服务公开的,分别名为 nginx-svchttpd-svc。所有 endpoints 都适用于服务。然而,虽然 为这些服务设置入口,我无法使用 host 设置入口(如 ingress-2 中所述)。但是,当我使用 ingress-1 时,一切正常。

//我的名称解析主机文件

grep myapp.com /etc/hosts
127.0.0.1        myapp.com

// 部署细节

kubectl get deployments.apps
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           29m
httpd   3/3     3            3           29m

//服务详情

kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.152.183.1     <none>        443/TCP   7h48m
nginx-svc    ClusterIP   10.152.183.233   <none>        80/TCP    28m
httpd-svc    ClusterIP   10.152.183.58    <none>        80/TCP    27m

// 端点详细信息

kubectl get ep
NAME         ENDPOINTS                                      AGE
kubernetes   10.0.2.15:16443                                7h51m
nginx-svc    10.1.198.86:80,10.1.198.87:80,10.1.198.88:80   31m
httpd-svc    10.1.198.89:80,10.1.198.90:80,10.1.198.91:80   31m

尝试 1:ingress-1

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-1
spec:
  rules:
  - http:
      paths:
      - path: /nginx
        pathType: Prefix
        backend:
          service:
            name: nginx-svc
            port:
              number: 80

      - path: /httpd
        pathType: Prefix
        backend:
          service:
            name: httpd-svc
            port:
              number: 80

// 显示入口路由在使用 ingress-1 时工作正常的示例:

 curl myapp.com/nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>


 curl myapp.com/httpd
<html><body><h1>It works!</h1></body></html>

// 以下入口规则没有像我预期的那样工作

尝试 2:ingress-2

kind: Ingress
metadata:
  name: ingress-2
spec:
  rules:
  - host: "myapp.com"
    http:
      paths:
      - pathType: Prefix
        path: "/nginx"
        backend:
          service:
            name: nginx-svc
            port:
              number: 80
      - pathType: Prefix
        path: "/httpd"
        backend:
          service:
            name: httpd-svc
            port:
              number: 80

// 我无法在 ing describe

中发现任何问题
kubectl describe  ingress ingress-2
Name:             ingress-2
Namespace:        default
Address:          127.0.0.1
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host          Path  Backends
  ----          ----  --------
  myapp.com
                /nginx   nginx-svc:80 (10.1.198.86:80,10.1.198.87:80,10.1.198.88:80)
                /httpd   httpd-svc:80 (10.1.198.89:80,10.1.198.90:80,10.1.198.91:80)
Annotations:    <none>
Events:
  Type    Reason  Age                  From                      Message
  ----    ------  ----                 ----                      -------
  Normal  Sync    9m15s (x2 over 10m)  nginx-ingress-controller  Scheduled for sync

// 显示入口路由的示例不适用于此入口资源

curl myapp.com/nginx
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.21.1</center>
</body>
</html>

curl myapp.com/httpd
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>

入口之间的差异

我创建了一个单节点 microk8s 集群 following official documentation 但我无法重现您描述的正确行为。添加了两个 pods 和 mendhak/http-https-echo 图片(强烈推荐:非常方便排除入口问题或了解入口的工作原理)和每个 pods.

的两个服务

两个入口规则的区别是第一个入口规则侦听所有域(HOSTS):

$ mkctl get ing -o wide
NAME        CLASS    HOSTS   ADDRESS     PORTS   AGE
ingress-1   public   *       127.0.0.1   80      2m53s

$ curl -I --header "Host: myapp.com" http://127.0.0.1/httpd
HTTP/1.1 200 OK

$ curl -I --header "Host: example.com" http://127.0.0.1/httpd
HTTP/1.1 200 OK

$ curl -I --header "Host: myapp.com" http://127.0.0.1/missing_url
HTTP/1.1 404 Not Found

虽然第二个入口规则将仅服务于 myapp.com 域 (HOST):

$ mkctl get ing
NAME        CLASS    HOSTS       ADDRESS     PORTS   AGE
ingress-2   public   myapp.com   127.0.0.1   80      60s

$ curl -I --header "Host: myapp.com" http://127.0.0.1/httpd
HTTP/1.1 200 OK

$ curl -I --header "Host: example.com" http://127.0.0.1/httpd
HTTP/1.1 404 Not Found

到底发生了什么

你问题的最后结果实际上表明入口正在按预期工作。您收到的响应不是来自 kubernetes ingress,而是来自集群内的 pods。第一个响应是 nginx 1.21.0404,第二个是 apache.

404

发生这种情况是因为 ingress 向 pods 发送了来自 URL 的相同 path 的请求,但没有进行任何转换。例如(我使用上面提到的图像得到的这个输出):

$ curl myapp.com/httpd
{
  "path": "/httpd"
...

虽然 nginxapache 都在 / 投放。

如何解决

Nginx ingress 有很多特性,其中之一是 rewriting,它有助于将 paths 从 ingress 得到的东西转变为 pods 得到的东西。

例如,如果请求转到 http://myapp.com/nginx,那么它将被定向到具有 /nginx 路径的 nginx 服务,这将导致 nginx 抛出 404 因为这个 path.

上什么都没有

下面的入口规则通过将 rewrite-target 添加到 / 来修复此问题,我们需要将其传递给 nginxapache 服务:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-2
  annotations:
#    kubernetes.io/ingress.class: nginx # this should be uncommented if ingress used in "regular" cluster
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /nginx
        pathType: Prefix
        backend:
          service:
            name: service-a
            port:
              number: 80
      - path: /httpd
        pathType: Prefix
        backend:
          service:
            name: service-b
            port:
              number: 80

快速测试它是如何工作的:

$ curl myapp.com/nginx
{
  "path": "/",
...

$ curl myapp.com/httpd
{
  "path": "/",
...

正如您现在看到的 path/

将图像切换到 nginx 和:

$ curl myapp.com/nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
...