前面我们了解了 APISIX Ingress 的基本使用,同样我们来介绍下如何使用 APISIX 来实现 URL Rewrite 操作,还是以前面测试用过的 Nexus 应用为例进行说明,通过 ApisixRoute 对象来配置服务路由.
正文
APISIX Ingress 高级使用之 Url Rewrite
前面我们了解了 APISIX Ingress 的基本使用,同样我们来介绍下如何使用 APISIX 来实现 URL Rewrite 操作,还是以前面测试用过的 Nexus 应用为例进行说明,通过 ApisixRoute 对象来配置服务路由,对应的资源清单如下所示:
- # 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
直接创建上面的资源对象即可:
- ➜ 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
部署完成后,我们根据 ApisixRoute 对象中的配置,只需要将域名 ops.qikqiak.com 解析到 node2 节点(上面通过 port-forward 暴露了 80 端口)即可访问:
url rewrite
同样如果现在需要通过一个子路径来访问 Nexus 应用的话又应该怎么来实现呢?比如通过 http://ops.qikqiak.com/nexus 来访问我们的应用,首先我们肯定需要修改 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 访问应用:
仔细分析发现很多静态资源404了,这是因为现在我们只匹配了 /nexus 的请求,而我们的静态资源是 /static 路径开头的,当然就匹配不到了,所以就出现了404,所以我们只需要加上这个 /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
更新后发现虽然静态资源可以正常访问了,但是当我们访问 http://ops.qikqiak.com/nexus 的时候依然会出现 404 错误。
这是因为我们这里是将 /nexus 路径的请求直接路由到后端服务去了,而后端服务没有对该路径做任何处理,所以也就是404的响应了,在之前 ingress-nginx 或者 traefik 中我们是通过 url 重写来实现的,而在 APISIX 中同样可以实现这个处理,相当于在请求在真正到达上游服务之前将请求的 url 重写到根目录就可以了,这里我们需要用到 proxy-rewrite 这个插件(需要确保在安装的时候已经包含了该插件),proxy-rewrite 是上游代理信息重写插件,支持对 scheme、uri、host 等信息的重写,该插件可配置的属性如下表所示:
我们现在的需求是希望将所有 /nexus 下面的请求都重写到根路径 / 下面去,所以我们应该使用 regex_uri 属性,转发到上游的新 uri 地址, 使用正则表达式匹配来自客户端的 uri,当匹配成功后使用模板替换转发到上游的 uri, 未匹配成功时将客户端请求的uri 转发至上游,重新修改后的 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
这里我们启用一个 proxy-rewrite 插件,并且将所有 /nexus 路径的请求都重写到了 / 跟路径下,重新更新后再次访问 http://ops.qikqiak.com/nexus 应该就可以正常访问了:
只有最后一个小问题了,从浏览器网络请求中可以看出我们没有去匹配 /service 这个路径的请求,只需要配置上该路径即可,如下所示:
- 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
现在重新访问子路径就完成正常了:
redirect
现在当我们访问 http://ops.qikqiak.com/nexus 或者 http://ops.qikqiak.com/nexus/ 的时候都可以得到正常的结果,一般来说我们可能希望能够统一访问路径,比如访问 /nexus 子路径的时候可以自动跳转到 /nexus/ 以 Splash 结尾的路径上去。同样要实现该需求我们只需要使用一个名为 redirect 的插件即可,该插件是 URI 重定向插件,可配置的属性如下所示:
要实现我们的需求直接使用 regex_uri 这个属性即可,只需要去匹配 /nexus 的请求,然后进行跳转即可,更新 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
我们新启用了一个 redirect 插件,并配置 regex_uri: ["^(/nexus)$", "$1/"],这样当访问 /nexus 的时候会自动跳转到 /nexus/ 路径下面去。
同样如果我们想要重定向到 https,只需要在该插件下面设置 config.http_to_https=true 即可:
- # ... 其他部分省略
- - name: redirect
- enable: true
- config:
- http_to_https: true
tls
通过使用上面的 redirect 插件配置 http_to_https 可以将请求重定向到 https 上去,但是我们现在并没有对我们的 ops.qikqiak.com 配置 https 证书,这里我们就需要使用 ApisixTls 对象来进行证书管理。
我们先使用 openssl 创建一个自签名的证书,当然你有正规 CA 机构购买的证书的话直接将证书下载下来使用即可:
- ➜ openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=ops.qikqiak.com"
然后通过 Secret 对象来引用上面创建的证书文件:
- # 要注意证书文件名称必须是 tls.crt 和 tls.key
- ➜ kubectl create secret tls ops-tls --cert=tls.crt --key=tls.key
然后就可以创建一个 ApisixTls 资源对象,引用上面的 Secret 即可:
- apiVersion: apisix.apache.org/v1
- kind: ApisixTls
- metadata:
- name: ops-tls
- spec:
- hosts:
- - ops.qikqiak.com
- secret:
- name: ops-tls
- namespace: default
同时 APISIX TLS 还可以配置 spec.client,用于进行 mTLS 双向认证的配置。上面的资源对象创建完成后,即可访问 https 服务了(chrome 浏览器默认会限制不安全的证书,只需要在页面上输入 thisisunsafe 即可访问了):
而且当访问 http 的时候也会自动跳转到 https 上面去,此外我们还可以结合 cert-manager 来实现自动化的 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
关于 APISIX Ingress 更多高级用法请继续关注后续文章。
原文链接:https://mp.weixin.qq.com/s/P6I_27d3rjmN0Ls_aZMHUA
发表评论