APISIX Ingress 高級(jí)使用之 Url Rewrite
前面我們了解了 APISIX Ingress 的基本使用,同樣我們來(lái)介紹下如何使用 APISIX 來(lái)實(shí)現(xiàn) URL Rewrite 操作,還是以前面測(cè)試用過(guò)的 Nexus 應(yīng)用為例進(jìn)行說(shuō)明,通過(guò) ApisixRoute 對(duì)象來(lái)配置服務(wù)路由,對(duì)應(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)建上面的資源對(duì)象即可:
- ➜ 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 <none> 8081/TCP 58s
部署完成后,我們根據(jù) ApisixRoute 對(duì)象中的配置,只需要將域名 ops.qikqiak.com 解析到 node2 節(jié)點(diǎn)(上面通過(guò) port-forward 暴露了 80 端口)即可訪問(wèn):
url rewrite
同樣如果現(xiàn)在需要通過(guò)一個(gè)子路徑來(lái)訪問(wèn) Nexus 應(yīng)用的話(huà)又應(yīng)該怎么來(lái)實(shí)現(xiàn)呢?比如通過(guò) http://ops.qikqiak.com/nexus 來(lái)訪問(wèn)我們的應(yīng)用,首先我們肯定需要修改 ApisixRoute 對(duì)象中匹配的 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
更新后我們可以通過(guò) http://ops.qikqiak.com/nexus 訪問(wèn)應(yīng)用:
仔細(xì)分析發(fā)現(xiàn)很多靜態(tài)資源404了,這是因?yàn)楝F(xiàn)在我們只匹配了 /nexus 的請(qǐng)求,而我們的靜態(tài)資源是 /static 路徑開(kāi)頭的,當(dāng)然就匹配不到了,所以就出現(xiàn)了404,所以我們只需要加上這個(gè) /static 路徑的匹配就可以了,同樣更新 ApisixRoute 對(duì)象,新增 /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)資源可以正常訪問(wèn)了,但是當(dāng)我們?cè)L問(wèn) http://ops.qikqiak.com/nexus 的時(shí)候依然會(huì)出現(xiàn) 404 錯(cuò)誤。
這是因?yàn)槲覀冞@里是將 /nexus 路徑的請(qǐng)求直接路由到后端服務(wù)去了,而后端服務(wù)沒(méi)有對(duì)該路徑做任何處理,所以也就是404的響應(yīng)了,在之前 ingress-nginx 或者 traefik 中我們是通過(guò) url 重寫(xiě)來(lái)實(shí)現(xiàn)的,而在 APISIX 中同樣可以實(shí)現(xiàn)這個(gè)處理,相當(dāng)于在請(qǐng)求在真正到達(dá)上游服務(wù)之前將請(qǐng)求的 url 重寫(xiě)到根目錄就可以了,這里我們需要用到 proxy-rewrite 這個(gè)插件(需要確保在安裝的時(shí)候已經(jīng)包含了該插件),proxy-rewrite 是上游代理信息重寫(xiě)插件,支持對(duì) scheme、uri、host 等信息的重寫(xiě),該插件可配置的屬性如下表所示:
我們現(xiàn)在的需求是希望將所有 /nexus 下面的請(qǐng)求都重寫(xiě)到根路徑 / 下面去,所以我們應(yīng)該使用 regex_uri 屬性,轉(zhuǎn)發(fā)到上游的新 uri 地址, 使用正則表達(dá)式匹配來(lái)自客戶(hù)端的 uri,當(dāng)匹配成功后使用模板替換轉(zhuǎn)發(fā)到上游的 uri, 未匹配成功時(shí)將客戶(hù)端請(qǐng)求的uri 轉(zhuǎn)發(fā)至上游,重新修改后的 ApisixRoute 對(duì)象如下所示,新增 plugins 屬性來(lái)配置插件:
- 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 路徑的請(qǐng)求都重寫(xiě)到了 / 跟路徑下,重新更新后再次訪問(wèn) http://ops.qikqiak.com/nexus 應(yīng)該就可以正常訪問(wèn)了:
只有最后一個(gè)小問(wèn)題了,從瀏覽器網(wǎng)絡(luò)請(qǐng)求中可以看出我們沒(méi)有去匹配 /service 這個(gè)路徑的請(qǐng)求,只需要配置上該路徑即可,如下所示:
- 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)在重新訪問(wèn)子路徑就完成正常了:
redirect
現(xiàn)在當(dāng)我們?cè)L問(wèn) http://ops.qikqiak.com/nexus 或者 http://ops.qikqiak.com/nexus/ 的時(shí)候都可以得到正常的結(jié)果,一般來(lái)說(shuō)我們可能希望能夠統(tǒng)一訪問(wèn)路徑,比如訪問(wèn) /nexus 子路徑的時(shí)候可以自動(dòng)跳轉(zhuǎn)到 /nexus/ 以 Splash 結(jié)尾的路徑上去。同樣要實(shí)現(xiàn)該需求我們只需要使用一個(gè)名為 redirect 的插件即可,該插件是 URI 重定向插件,可配置的屬性如下所示:
要實(shí)現(xiàn)我們的需求直接使用 regex_uri 這個(gè)屬性即可,只需要去匹配 /nexus 的請(qǐng)求,然后進(jìn)行跳轉(zhuǎn)即可,更新 ApisixRoute 對(duì)象:
- 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)訪問(wèn) /nexus 的時(shí)候會(huì)自動(dòng)跳轉(zhuǎn)到 /nexus/ 路徑下面去。
同樣如果我們想要重定向到 https,只需要在該插件下面設(shè)置 config.http_to_https=true 即可:
- # ... 其他部分省略
- - name: redirect
- enable: true
- config:
- http_to_https: true
tls
通過(guò)使用上面的 redirect 插件配置 http_to_https 可以將請(qǐng)求重定向到 https 上去,但是我們現(xiàn)在并沒(méi)有對(duì)我們的 ops.qikqiak.com 配置 https 證書(shū),這里我們就需要使用 ApisixTls 對(duì)象來(lái)進(jìn)行證書(shū)管理。
我們先使用 openssl 創(chuàng)建一個(gè)自簽名的證書(shū),當(dāng)然你有正規(guī) CA 機(jī)構(gòu)購(gòu)買(mǎi)的證書(shū)的話(huà)直接將證書(shū)下載下來(lái)使用即可:
- ➜ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=ops.qikqiak.com"
然后通過(guò) Secret 對(duì)象來(lái)引用上面創(chuàng)建的證書(shū)文件:
- # 要注意證書(shū)文件名稱(chēng)必須是 tls.crt 和 tls.key
- ➜ kubectl create secret tls ops-tls --cert=tls.crt --key=tls.key
然后就可以創(chuàng)建一個(gè) ApisixTls 資源對(duì)象,引用上面的 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)證的配置。上面的資源對(duì)象創(chuàng)建完成后,即可訪問(wèn) https 服務(wù)了(chrome 瀏覽器默認(rèn)會(huì)限制不安全的證書(shū),只需要在頁(yè)面上輸入 thisisunsafe 即可訪問(wèn)了):
而且當(dāng)訪問(wèn) http 的時(shí)候也會(huì)自動(dòng)跳轉(zhuǎn)到 https 上面去,此外我們還可以結(jié)合 cert-manager 來(lái)實(shí)現(xiàn)自動(dòng)化的 https。
完整的資源對(duì)象如下所示:
- 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 更多高級(jí)用法請(qǐng)繼續(xù)關(guān)注后續(xù)文章。