APISIX Ingress 高級使用之 Url Rewrite
前面我們了解了 APISIX Ingress 的基本使用,同樣我們來介紹下如何使用 APISIX 來實(shí)現(xiàn) URL Rewrite 操作,還是以前面測試用過的 Nexus 應(yīng)用為例進(jìn)行說明,通過 ApisixRoute 對象來配置服務(wù)路由,對應(yīng)的資源清單如下所示:
#?nexus.yaml
apiVersion:?apps/v1
kind:?Deployment
metadata:
??name:?nexus
??labels:
????app:?nexus
spec:
??selector:
????matchLabels:
??????app:?nexus
??template:
????metadata:
??????labels:
????????app:?nexus
????spec:
??????containers:
??????-?image:?cnych/nexus:3.20.1
????????imagePullPolicy:?IfNotPresent
????????name:?nexus
????????ports:
????????-?containerPort:?8081
---
apiVersion:?v1
kind:?Service
metadata:
??labels:
????app:?nexus
??name:?nexus
spec:
??ports:
??-?name:?nexusport
????port:?8081
????targetPort:?8081
??selector:
????app:?nexus
---
apiVersion:?apisix.apache.org/v2beta2
kind:?ApisixRoute
metadata:
??name:?nexus
??namespace:?default
spec:
??http:
????-?name:?root
??????match:
????????hosts:
??????????-?ops.qikqiak.com
????????paths:
??????????-?"/*"
??????backends:
??????-?serviceName:?nexus
????????servicePort:?8081
直接創(chuàng)建上面的資源對象即可:
??kubectl?apply?-f?nexus.yaml
??kubectl?get?apisixroute
NAME????HOSTS???????????????????URIS?????AGE
nexus???["ops.qikqiak.com"]???["/*"]???39s
??kubectl?get?pods?-l?app=nexus
NAME?????????????????????READY???STATUS????RESTARTS???AGE
nexus-6f78b79d4c-b79r4???1/1?????Running???0??????????48s
??kubectl?get?svc?-l?app=nexus
NAME????TYPE????????CLUSTER-IP??????EXTERNAL-IP???PORT(S)????AGE
nexus???ClusterIP???10.102.53.243???????????8081/TCP???58s
部署完成后,我們根據(jù) ApisixRoute 對象中的配置,只需要將域名 ops.qikqiak.com 解析到 node2 節(jié)點(diǎn)(上面通過 port-forward 暴露了 80 端口)即可訪問:

url rewrite
同樣如果現(xiàn)在需要通過一個(gè)子路徑來訪問 Nexus 應(yīng)用的話又應(yīng)該怎么來實(shí)現(xiàn)呢?比如通過 http://ops.qikqiak.com/nexus 來訪問我們的應(yīng)用,首先我們肯定需要修改 ApisixRoute 對象中匹配的 paths 路徑,將其修改為 /nexus:
apiVersion:?apisix.apache.org/v2beta2
kind:?ApisixRoute
metadata:
??name:?nexus
??namespace:?default
spec:
??http:
????-?name:?root
??????match:
????????hosts:
??????????-?ops.qikqiak.com
????????paths:
??????????-?"/nexus*"
??????backends:
??????-?serviceName:?nexus
????????servicePort:?8081
更新后我們可以通過 http://ops.qikqiak.com/nexus 訪問應(yīng)用:

仔細(xì)分析發(fā)現(xiàn)很多靜態(tài)資源404了,這是因?yàn)楝F(xiàn)在我們只匹配了 /nexus 的請求,而我們的靜態(tài)資源是 /static 路徑開頭的,當(dāng)然就匹配不到了,所以就出現(xiàn)了404,所以我們只需要加上這個(gè) /static 路徑的匹配就可以了,同樣更新 ApisixRoute 對象,新增 /static/* 路徑支持:
apiVersion:?apisix.apache.org/v2beta2
kind:?ApisixRoute
metadata:
??name:?nexus
??namespace:?default
spec:
??http:
????-?name:?root
??????match:
????????hosts:
??????????-?ops.qikqiak.com
????????paths:
??????????-?"/nexus*"
??????????-?"/static/*"
??????backends:
??????-?serviceName:?nexus
????????servicePort:?8081
更新后發(fā)現(xiàn)雖然靜態(tài)資源可以正常訪問了,但是當(dāng)我們訪問 http://ops.qikqiak.com/nexus 的時(shí)候依然會出現(xiàn) 404 錯(cuò)誤。

這是因?yàn)槲覀冞@里是將 /nexus 路徑的請求直接路由到后端服務(wù)去了,而后端服務(wù)沒有對該路徑做任何處理,所以也就是404的響應(yīng)了,在之前 ingress-nginx 或者 traefik 中我們是通過 url 重寫來實(shí)現(xiàn)的,而在 APISIX 中同樣可以實(shí)現(xiàn)這個(gè)處理,相當(dāng)于在請求在真正到達(dá)上游服務(wù)之前將請求的 url 重寫到根目錄就可以了,這里我們需要用到 proxy-rewrite 這個(gè)插件(需要確保在安裝的時(shí)候已經(jīng)包含了該插件),proxy-rewrite 是上游代理信息重寫插件,支持對 scheme、uri、host 等信息的重寫,該插件可配置的屬性如下表所示:

我們現(xiàn)在的需求是希望將所有 /nexus 下面的請求都重寫到根路徑 / 下面去,所以我們應(yīng)該使用 regex_uri 屬性,轉(zhuǎn)發(fā)到上游的新 uri 地址, 使用正則表達(dá)式匹配來自客戶端的 uri,當(dāng)匹配成功后使用模板替換轉(zhuǎn)發(fā)到上游的 uri, 未匹配成功時(shí)將客戶端請求的uri 轉(zhuǎn)發(fā)至上游,重新修改后的 ApisixRoute 對象如下所示,新增 plugins 屬性來配置插件:
apiVersion:?apisix.apache.org/v2beta2
kind:?ApisixRoute
metadata:
??name:?nexus
??namespace:?default
spec:
??http:
????-?name:?root
??????match:
????????hosts:
??????????-?ops.qikqiak.com
????????paths:
??????????-?"/nexus*"
??????????-?"/static/*"
??????plugins:
??????-?name:?proxy-rewrite
????????enable:?true
????????config:
??????????regex_uri:?["^/nexus(/|$)(.*)",?"/$2"]
??????backends:
??????-?serviceName:?nexus
????????servicePort:?8081
這里我們啟用一個(gè) proxy-rewrite 插件,并且將所有 /nexus 路徑的請求都重寫到了 / 跟路徑下,重新更新后再次訪問 http://ops.qikqiak.com/nexus 應(yīng)該就可以正常訪問了:

只有最后一個(gè)小問題了,從瀏覽器網(wǎng)絡(luò)請求中可以看出我們沒有去匹配 /service 這個(gè)路徑的請求,只需要配置上該路徑即可,如下所示:
apiVersion:?apisix.apache.org/v2beta2
kind:?ApisixRoute
metadata:
??name:?nexus
??namespace:?default
spec:
??http:
????-?name:?root
??????match:
????????hosts:
??????????-?ops.qikqiak.com
????????paths:
??????????-?"/nexus*"
??????????-?"/static/*"
??????????-?"/service/*"
??????plugins:
??????-?name:?proxy-rewrite
????????enable:?true
????????config:
??????????regex_uri:?["^/nexus(/|$)(.*)",?"/$2"]
??????backends:
??????-?serviceName:?nexus
????????servicePort:?8081
現(xiàn)在重新訪問子路徑就完成正常了:

redirect
現(xiàn)在當(dāng)我們訪問 http://ops.qikqiak.com/nexus 或者 http://ops.qikqiak.com/nexus/ 的時(shí)候都可以得到正常的結(jié)果,一般來說我們可能希望能夠統(tǒng)一訪問路徑,比如訪問 /nexus 子路徑的時(shí)候可以自動跳轉(zhuǎn)到 /nexus/ 以 Splash 結(jié)尾的路徑上去。同樣要實(shí)現(xiàn)該需求我們只需要使用一個(gè)名為 redirect 的插件即可,該插件是 URI 重定向插件,可配置的屬性如下所示:

要實(shí)現(xiàn)我們的需求直接使用 regex_uri 這個(gè)屬性即可,只需要去匹配 /nexus 的請求,然后進(jìn)行跳轉(zhuǎn)即可,更新 ApisixRoute 對象:
apiVersion:?apisix.apache.org/v2beta2
kind:?ApisixRoute
metadata:
??name:?nexus
??namespace:?default
spec:
??http:
????-?name:?root
??????match:
????????hosts:
??????????-?ops.qikqiak.com
????????paths:
??????????-?"/nexus*"
??????????-?"/static/*"
??????????-?"/service/*"
??????plugins:
??????-?name:?proxy-rewrite
????????enable:?true
????????config:
??????????regex_uri:?["^/nexus(/|$)(.*)",?"/$2"]
??????-?name:?redirect
????????enable:?true
????????config:
??????????regex_uri:?["^(/nexus)$",?"$1/"]
??????backends:
??????-?serviceName:?nexus
????????servicePort:?8081
我們新啟用了一個(gè) redirect 插件,并配置 regex_uri: ["^(/nexus)$", "$1/"],這樣當(dāng)訪問 /nexus 的時(shí)候會自動跳轉(zhuǎn)到 /nexus/ 路徑下面去。
同樣如果我們想要重定向到 https,只需要在該插件下面設(shè)置 config.http_to_https=true 即可:
#?...?其他部分省略
-?name:?redirect
??enable:?true
??config:
????http_to_https:?true
tls
通過使用上面的 redirect 插件配置 http_to_https 可以將請求重定向到 https 上去,但是我們現(xiàn)在并沒有對我們的 ops.qikqiak.com 配置 https 證書,這里我們就需要使用 ApisixTls 對象來進(jìn)行證書管理。
我們先使用 openssl 創(chuàng)建一個(gè)自簽名的證書,當(dāng)然你有正規(guī) CA 機(jī)構(gòu)購買的證書的話直接將證書下載下來使用即可:
??openssl?req?-x509?-nodes?-days?365?-newkey?rsa:2048?-keyout?tls.key?-out?tls.crt?-subj?"/CN=ops.qikqiak.com"
然后通過 Secret 對象來引用上面創(chuàng)建的證書文件:
#?要注意證書文件名稱必須是?tls.crt?和?tls.key
??kubectl?create?secret?tls?ops-tls?--cert=tls.crt?--key=tls.key
然后就可以創(chuàng)建一個(gè) ApisixTls 資源對象,引用上面的 Secret 即可:
apiVersion:?apisix.apache.org/v1
kind:?ApisixTls
metadata:
??name:?ops-tls
spec:
??hosts:
????-?ops.qikqiak.com
??secret:
????name:?ops-tls
????namespace:?default
同時(shí) APISIX TLS 還可以配置 spec.client,用于進(jìn)行 mTLS 雙向認(rèn)證的配置。上面的資源對象創(chuàng)建完成后,即可訪問 https 服務(wù)了(chrome 瀏覽器默認(rèn)會限制不安全的證書,只需要在頁面上輸入 thisisunsafe 即可訪問了):

而且當(dāng)訪問 http 的時(shí)候也會自動跳轉(zhuǎn)到 https 上面去,此外我們還可以結(jié)合 cert-manager 來實(shí)現(xiàn)自動化的 https。
完整的資源對象如下所示:
apiVersion:?apisix.apache.org/v2beta2
kind:?ApisixRoute
metadata:
??name:?nexus
??namespace:?default
spec:
??http:
????-?name:?root
??????match:
????????hosts:
??????????-?ops.qikqiak.com
????????paths:
??????????-?"/nexus*"
??????????-?"/static/*"
??????????-?"/service/*"
??????plugins:
??????-?name:?proxy-rewrite
????????enable:?true
????????config:
??????????regex_uri:?["^/nexus(/|$)(.*)",?"/$2"]
??????-?name:?redirect
????????enable:?true
????????config:
??????????regex_uri:?["^(/nexus)$",?"$1/"]
??????-?name:?redirect
????????enable:?true
????????config:
??????????http_to_https:?true
??????backends:
??????-?serviceName:?nexus
????????servicePort:?8081
---
apiVersion:?apisix.apache.org/v1
kind:?ApisixTls
metadata:
??name:?ops-tls
spec:
??hosts:
????-?ops.qikqiak.com
??secret:
????name:?ops-tls
????namespace:?default
關(guān)于 APISIX Ingress 更多高級用法請繼續(xù)關(guān)注后續(xù)文章。
