【问题标题】:Ingress rule using host使用主机的入口规则
【发布时间】:2021-09-27 15:38:53
【问题描述】:

有人可以帮忙找出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>

【问题讨论】:

  • 你用的是什么kubernetes集群?我猜它是基于服务端点的k3s。集群上还使用了哪个入口?默认traefik?此外,如果您删除第二个入口规则并应用第一个,它仍然有效吗?
  • 我在虚拟机中使用microk8s。它使用nginx-ingress-microk8s-controller-sgnxq

标签: kubernetes nginx-ingress microk8s


【解决方案1】:

入口之间的差异

我创建了一个节点microk8s 集群following official documentation,但我无法重现您描述的正确行为。为每个 pod 添加了两个带有 mendhak/http-https-echo 图像的 pod(强烈推荐:非常方便对 ingress 进行故障排除或了解 ingress 的工作原理)和两个服务。

两个入口规则之间的区别是首先入口规则侦听所有域(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

究竟发生了什么

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

发生这种情况是因为 ingress 从 URL 向具有相同 path 的 Pod 发送请求而没有任何转换。例如(我使用上面提到的图像得到的这个输出):

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

虽然nginxapache 都在/ 上提供服务。

如何解决

Nginx ingress 有很多特性,其中之一是 rewriting,它有助于将 paths 从 ingress 的内容转换为 Pod 的内容。

例如,如果请求发送到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>
...

【讨论】:

  • 感谢您的精彩解释,这完美地解释了我的尝试中根本错误的地方。一个问题,为什么你必须使用 curl -I --header "Host: myapp.com" http://127.0.0.1/httpd ? (在标题中提供主机名?为什么不只是curl -I http://myapp.com/httpd
  • 没关系,我想通了。这个答案值得更多的支持:)
猜你喜欢
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 1970-01-01
  • 2023-01-11
  • 2019-03-26
  • 2017-12-13
  • 2018-09-24
  • 2017-11-24
相关资源
最近更新 更多