nginx-ingress-controler改写上下文

背景:
由于域名和公网费用昂贵。通常是只有一个域名,但是有多个应用需要上线。通常都会域名+应用名称(www.ecloud.com/app)。原本应用已经开发好的了,访问是在 / 。那就需要改写上下文来实现。

原应用演示

$ kubectl get svc app demo
NAME   TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
app    ClusterIP   10.183.0.36   <none>        8001/TCP   6m13s
demo   ClusterIP   10.183.0.37   <none>        8002/TCP   2m47s

$  curl 10.183.0.36:8001
app

$ curl 10.183.0.37:8002/test/demo/
demo

现在有两个应用分别是 appdemo。分别的访问路径为://test/demo。现在只有一个域名是 www.ecloud.com 且需要把两个网页都放在同一个域名访问。

添加上下文路径

现在的目标是把 app 应用,可以通过 www.ecloud.com/app/ 来展示

创建ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: app
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2  # 真实到服务的上下文
spec:
  ingressClassName: nginx
  rules:
  - host: www.ecloud.com
    http:
      paths:
      - path: /app(/|)(.*)  # 浏览器访问上下文
        backend:
          serviceName: app
          servicePort: 8001

验证

$ curl www.ecloud.com/app/
app

$ curl www.ecloud.com/app/index.html
app

减少上下文路径

现在的目标是把 demo 应用,可以通过 www.ecloud.com/demo/ 来展示

创建ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: demo
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /test/demo/$2 # 真实到服务的上下文
spec:
  ingressClassName: nginx
  rules:
  - host: www.ecloud.com
    http:
      paths:
      - path: /demo(/|)(.*) # 浏览器访问上下文
        backend:
          serviceName: demo
          servicePort: 8002

验证

$ curl www.ecloud.com/demo
demo

$ curl www.ecloud.com/demo/
demo

$ curl www.ecloud.com/demo/index.html
demo

修改主域名跳转

应该给应用设置一个 app-root 的注解,这样当我们访问主域名的时候会自动跳转到我们指定的 app-root 目录下面。如下所示:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: demo
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /test/demo/$2 # 真实到服务的上下文
    nginx.ingress.kubernetes.io/app-root: /demo/    # 这里写浏览器访问的路径
spec:
  ingressClassName: nginx
  rules:
  - host: www.ecloud.com
    http:
      paths:
      - path: /demo(/|)(.*) # 浏览器访问上下文
        backend:
          serviceName: demo
          servicePort: 8002

验证

$ curl www.ecloud.com
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

# nginx-ingress-controller 的日志
192.168.32.134 - - [16/Sep/2021:08:22:39 +0000] "GET / HTTP/1.1" 302 138 "-" "curl/7.29.0" 78 0.000 [-] [] - - - - 5ba35f028edbd48ff316bd544ae60746

$ curl www.ecloud.com -L
demo

# nginx-ingress-controller 的日志
192.168.32.134 - - [16/Sep/2021:08:22:56 +0000] "GET / HTTP/1.1" 302 138 "-" "curl/7.29.0" 78 0.000 [-] [] - - - - 4ffa0129b9fab80b9e904ad9716bd8ca
192.168.32.134 - - [16/Sep/2021:08:22:56 +0000] "GET /demo/ HTTP/1.1" 200 5 "-" "curl/7.29.0" 83 0.003 [default-demo-8002] [] 20.0.32.159:8002 5 0.002 200 3d17d7cb25f3eacc7eb848955a28675f

注意事项

不能定义默认的 ingress.spec.backend 字段。否则会发生不符合预期的跳转。

模拟定义 ingress.spec.backend 字段

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: app
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  backend:  # 设置默认的backend
    serviceName: app
    servicePort: 8001
  rules:
  - host: www.ecloud.com
    http:
      paths:
      - path: /app(/|$)(.*)
        backend:
          serviceName: app
          servicePort: 8001

查看ingress资源情况

$ kubectl get ingress
NAME   CLASS   HOSTS            ADDRESS          PORTS   AGE
app    nginx   www.ecloud.com   192.168.32.138   80      20m

$ kubectl describe ingress app
Name:             app
Namespace:        default
Address:          192.168.32.138
Default backend:  app:8001 (20.0.32.157:8001)
Rules:
  Host            Path  Backends
  ----            ----  --------
  www.ecloud.com  
                  /app(/|$)(.*)   app:8001 (20.0.32.157:8001)
Annotations:      nginx.ingress.kubernetes.io/rewrite-target: /$2
Events:
  Type    Reason  Age                  From                      Message
  ----    ------  ----                 ----                      -------
  Normal  Sync    7m52s (x5 over 21m)  nginx-ingress-controller  Scheduled for sync

测试访问

$ curl www.ecloud.com
app

$ curl www.ecloud.com/fskl/fskf/ajfk
app

发现不符合 /app 的上下文也可以匹配到 / 的页面,这个是不符合我们的预期的。

查看nginx的配置文件

$ kubectl -n ingress-nginx exec -it ingress-nginx-controller-6c979c5b47-bpwf6 -- bash
$ vi /etc/nginx/nginx.conf
                # 找到 `server_name` 为设置的域名,找到为 `location ~* "^/"`
                # 没有匹配到 `/app` 的上下文,则进入该location。
                # 该location读取app应用的 `/` 。所以访问 `/fskl/fskf/ajfk` 都可以访问到 `/` 的页面
                # 原本我们的预期是访问错了上下文,应该是报 `404` 的,而不是访问主域名页面
                location ~* "^/" {                                                                                                             
                        set $namespace      "default";                                                                                         
                        set $ingress_name   "app";                                                                                             
                        set $service_name   "app";                                                                                             
                        set $service_port   "8001";                                                                                            
                        set $location_path  "/"
                        ...
                }

虽然没有定义默认的 ingress.spec.backend 字段。在 kubectl describe ingress 查看ingress详情时,会有 Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>) 提示,但是影响正常使用。

原文地址:https://www.cnblogs.com/mycloudedu/p/15293913.html