由於 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 。