合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
[TOC] **背景:** 由于域名和公网费用昂贵。通常是只有一个域名,但是有多个应用需要上线。通常都会域名+应用名称(`www.ecloud.com/app`)。原本应用已经开发好的了,访问是在 `/` 。那就需要改写上下文来实现。 # 原应用演示 ```shell $ 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 ``` > 现在有两个应用分别是 `app` 、`demo`。分别的访问路径为:`/`、`/test/demo`。现在只有一个域名是 `www.ecloud.com` 且需要把两个网页都放在同一个域名访问。 # 添加上下文路径 现在的目标是把 `app` 应用,可以通过 `www.ecloud.com/app/` 来展示 ## 创建ingress ```yaml 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 ``` ## 验证 ```shell $ curl www.ecloud.com/app/ app $ curl www.ecloud.com/app/index.html app ``` # 减少上下文路径 现在的目标是把 `demo` 应用,可以通过 `www.ecloud.com/demo/` 来展示 ## 创建ingress ```yaml 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 ``` ## 验证 ```shell $ curl www.ecloud.com/demo demo $ curl www.ecloud.com/demo/ demo $ curl www.ecloud.com/demo/index.html demo ``` # 修改主域名跳转 应该给应用设置一个 `app-root` 的注解,这样当我们访问主域名的时候会自动跳转到我们指定的 `app-root` 目录下面。如下所示: ```yaml 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 ``` **验证** ```shell $ 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.31.103 - - [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.31.103 - - [16/Sep/2021:08:22:56 +0000] "GET / HTTP/1.1" 302 138 "-" "curl/7.29.0" 78 0.000 [-] [] - - - - 4ffa0129b9fab80b9e904ad9716bd8ca 192.168.31.103 - - [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` 字段 ```yaml 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资源情况 ```shell $ kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE app nginx www.ecloud.com 192.168.31.79 80 20m $ kubectl describe ingress app Name: app Namespace: default Address: 192.168.31.79 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 ``` 测试访问 ```shell $ curl www.ecloud.com app $ curl www.ecloud.com/fskl/fskf/ajfk app ``` > 发现不符合 `/app` 的上下文也可以匹配到 `/` 的页面,这个是不符合我们的预期的。 查看nginx的配置文件 ```shell $ 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>)` 提示,但是影响正常使用。