由于 Nginx 的優秀性能表現,所以很多企業在 Kubernetes 中選擇 Ingress Controller 的時候依然會選擇基于 nginx 的 ingress-nginx,前面文章中我們更多的是介紹更加云原生配置更加靈活的 Traefik,特別是 Traefik 2.0 版本新增中間件概念以后,在配置上就更加方便了,各種需求都可以通過中間件來實現,對于 ingress-nginx 來說配置就稍微麻煩一點,一些復雜的需求需要通過 Ingress 的 annotation 來實現,比如我們現在需要實現一個 url rewrite 的功能,簡單來說就是我們之前的應用在 todo.qikqiak.com 下面,現在我們需要通過 todo.qikqiak.com/App/ 來進行訪問。
本次測試使用的集群為 Kubernetes v1.16.2,ingess-nginx 鏡像版本為 0.26.1
最原始的 Ingress 對象如下所示:
apiVersion: extensions/v1beta1kind: Ingressmetadata: name: fe namespace: default annotations: kubernetes.io/ingress.class: "nginx"spec: rules: - host: todo.qikqiak.com http: paths: - backend: serviceName: fe servicePort: 3000 path: /
就是一個很常規的 Ingress 對象,部署該對象后,將域名解析后就可以正常訪問到應用:
ingress nginx demo
按照需求我們需要對訪問的 URL 路徑做一個 Rewrite,在 ingress-nginx 官方文檔中也給出了說明:
ingress nginx rewrite
按照要求我們需要在 path 中匹配前綴 app,然后通過 rewrite-target 指定目標,修改后的 Ingress 對象如下所示:
apiVersion: extensions/v1beta1kind: Ingressmetadata: name: fe namespace: default annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/rewrite-target: /$2spec: rules: - host: todo.qikqiak.com http: paths: - backend: serviceName: fe servicePort: 3000 path: /app(/|$)(.*)
更新后,我們可以遇見到直接訪問域名肯定是不行了,因為我們沒有匹配 / 的 path 路徑:
ingress nginx rewrite 404
但是我們帶上 app 的前綴再去訪問:
ingress nginx rewrite 1
我們可以看到已經可以訪問到頁面內容了,這是因為我們在 path 中通過正則表達式 /app(/|$)(.*) 將匹配的路徑設置成了 rewrite-target 的目標路徑了,所以我們訪問 todo.qikqiak.com/app 的時候實際上相當于訪問的就是后端服務的 / 路徑,但是我們也可以發現現在頁面的樣式沒有了:
ingress nginx rewrite 2
這是因為應用的靜態資源路徑是在 /stylesheets 路徑下面的,現在我們做了 url rewrite 過后,要正常訪問也需要帶上前綴才可以:http://todo.qikqiak.com/stylesheets/screen.css,對于圖片或者其他靜態資源也是如此,當然我們去更改頁面引入靜態資源的方式為相對路徑也是可以的,但是畢竟要修改代碼,這個時候我們可以借助 ingress-nginx 中的 configuration-snippet 來對靜態資源做一次跳轉,如下所示:
apiVersion: extensions/v1beta1kind: Ingressmetadata: name: fe namespace: default annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/rewrite-target: /$2 nginx.ingress.kubernetes.io/configuration-snippet: | rewrite ^/stylesheets/(.*)$ /app/stylesheets/$1 redirect; # 添加 /app 前綴 rewrite ^/images/(.*)$ /app/images/$1 redirect; # 添加 /app 前綴spec: rules: - host: todo.qikqiak.com http: paths: - backend: serviceName: fe servicePort: 3000 path: /app(/|$)(.*)
更新 Ingress 對象后,這個時候我們刷新頁面可以看到已經正常了:
ingress nginx rewrite 3
要解決我們訪問主域名出現 404 的問題,我們可以給應用設置一個 app-root 的注解,這樣當我們訪問主域名的時候會自動跳轉到我們指定的 app-root 目錄下面,如下所示:
apiVersion: extensions/v1beta1kind: Ingressmetadata: name: fe namespace: default annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/app-root: /app/ nginx.ingress.kubernetes.io/rewrite-target: /$2 nginx.ingress.kubernetes.io/configuration-snippet: | rewrite ^/stylesheets/(.*)$ /app/stylesheets/$1 redirect; # 添加 /app 前綴 rewrite ^/images/(.*)$ /app/images/$1 redirect; # 添加 /app 前綴spec: rules: - host: todo.qikqiak.com http: paths: - backend: serviceName: fe servicePort: 3000 path: /app(/|$)(.*)
這個時候我們更新應用后訪問主域名 http://todo.qikqiak.com 就會自動跳轉到 http://todo.qikqiak.com/app/ 路徑下面去了。但是還有一個問題是我們的 path 路徑其實也匹配了 /app 這樣的路徑,可能我們更加希望我們的應用在最后添加一個 / 這樣的 slash,同樣我們可以通過 configuration-snippet 配置來完成,如下 Ingress 對象:
apiVersion: extensions/v1beta1kind: Ingressmetadata: name: fe namespace: default annotations: kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/app-root: /app/ nginx.ingress.kubernetes.io/rewrite-target: /$2 nginx.ingress.kubernetes.io/configuration-snippet: | rewrite ^(/app)$ $1/ redirect; rewrite ^/stylesheets/(.*)$ /app/stylesheets/$1 redirect; rewrite ^/images/(.*)$ /app/images/$1 redirect;spec: rules: - host: todo.qikqiak.com http: paths: - backend: serviceName: fe servicePort: 3000 path: /app(/|$)(.*)
更新后我們的應用就都會以 / 這樣的 slash 結尾了。這樣就完成了我們的需求,如果你原本對 nginx 的配置就非常熟悉的話應該可以很快就能理解這種配置方式了,當然如果你還是喜歡更加簡單明了的方式的話可以推薦使用 Traefik 。