使用KubernetesIngress來實現類似Istio條件路由
微服務 Istio / SpringCloud日益被越來越多的客戶關注,Istio提供了各種酷炫的流量控制功能,但Istio距離生產部署可用仍然還有差距。條件路由是否可以在已有的Kubernetes Ingress架構中實現,以最小的代價實現應用的微服務化遷移。答案是肯定的,通過對ingress自定義location/server塊的定義,以及upsteam自動生產的規則,可以實現複雜條件路由的支援,類似istio, match。
[不滿足] 1. 嘗試一, 修改Ingress的server-snippet/location-snippet屬性來重定向請求到後臺服務, 不能按期望跳轉
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/load-balance: ip_hash
nginx.ingress.kubernetes.io/server-snippet: |
set $agentflag 0;
if ($http_user_agent ~* "(Mobile)" ){
set $agentflag 1;
}
if ( $agentflag = 1 ) {
. return 301 http://default-cardinfo-homepage-80;
}
nginx.ingress.kubernetes.io/upstream-hash-by: ip_hash
nginx.ingress.kubernetes.io//location-snippet: |
if ( $agentflag = 1 ) {
proxy_pass http://default-cardinfo-homepage-80;
}
creationTimestamp: 2018-08-27T12:06:32Z
generation: 2
name: nginx-test
namespace: default
resourceVersion: "43290755"
selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/nginx-test
uid: a310ca06-a9f1-11e8-a613-00163e0c87f1
spec:
rules:
- host: stickyingress.example.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
- host: mobile.example.com
http:
paths:
- backend:
serviceName: cardinfo-homepage
servicePort: 80
path: /
status:
loadBalancer:
ingress:
- {}
檢查ingressController自動生成的nginx server定義, 僅僅依靠server-snippet 以及location-snippet是不能完成請求的自動跳轉。server-snippet at ingress level does not work for reverse proxy server-snippet spec
[不滿足] 嘗試二, 使用IngressController級別的定義 location-snippet, location-snippet會傳播到所有的location-block, 不滿足期望。
location-snippet of ingress controller is applied to all location block, it does not work as expected
location-snippet
apiVersion: v1
data:
location-snippet: |
if ( $agentflag = 1 ) {
proxy_pass http://default-cardinfo-homepage-80;
}
proxy-body-size: 20m
kind: ConfigMap
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","data":{"proxy-body-size":"20m"},"kind":"ConfigMap","metadata":{"annotations":{},"labels":{"app":"ingress-nginx"},"name":"nginx-configuration","namespace":"kube-system"}}
creationTimestamp: 2018-02-07T09:06:33Z
labels:
app: ingress-nginx
name: nginx-configuration
namespace: kube-system
resourceVersion: "43308775"
selfLink: /api/v1/namespaces/kube-system/configmaps/nginx-configuration
uid: 312dd92f-0be6-11e8-856b-00163e0c87f1
[解決] 嘗試三, 使用configuration-snippet + server-snippet + upstream default name 來實現路由跳轉到不同的kubernetes service服務。
configuration-snippet is alternative of location snippet, combination configuration-snippet and server-snippet to parse header, set global variable, then proxy specific backend service with upstream name created by IngressController. e.g. default-cardinfo-homepage-80
metadata:
annotations:
nginx.ingress.kubernetes.io/server-snippet: |
set $agentflag 0;
if ($http_user_agent ~* "(Mobile)" ){
set $agentflag 1;
}
nginx.ingress.kubernetes.io/configuration-snippet: |
if ( $agentflag = 1 ) {
proxy_pass http://default-cardinfo-homepage-80;
}
Put everything together
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/load-balance: ip_hash
nginx.ingress.kubernetes.io/server-snippet: |
set $agentflag 0;
if ($http_user_agent ~* "(Mobile)" ){
set $agentflag 1;
}
nginx.ingress.kubernetes.io/upstream-hash-by: ip_hash
nginx.ingress.kubernetes.io/configuration-snippet: |
if ( $agentflag = 1 ) {
proxy_pass http://default-cardinfo-homepage-80;
}
name: nginx-condition
namespace: default
spec:
rules:
- host: stickyingress.example.com
http:
paths:
- backend:
serviceName: cardinfo-recommendation
servicePort: 80
path: /
- host: mobile.example.com
http:
paths:
- backend:
serviceName: cardinfo-homepage
servicePort: 80
path: /
status:
loadBalancer:
ingress:
- {}
測試
使用不同的Header 模擬不同使用者瀏覽器請求,使用者請求根據瀏覽器的型別被重定向到不同的後臺服務和入口。以stickyingress.example.com為入口的使用者使用”user-agent: (Mobile)”的使用者,自動跳轉到後臺服務cardinfo-homepage,其他使用者仍然進入cardinfo-recommendation。
curl stickyingress.example.com:32619 -v
* Rebuilt URL to: stickyingress.example.com:32619/
* Hostname was NOT found in DNS cache
* Trying 192.168.33.239...
* Connected to stickyingress.example.com (192.168.33.239) port 32619 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.37.0
> Host: stickyingress.example.com:32619
> Accept: */*
>
< HTTP/1.1 200
* Server nginx/1.13.7 is not blacklisted
< Server: nginx/1.13.7
< Date: Wed, 14 Nov 2018 04:46:19 GMT
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 17
< Connection: keep-alive
<
* Connection #0 to host stickyingress.example.com left intact
recommendation v2
dns:~ # curl stickyingress.example.com:32619 -v -H "user-agent: (Mobile)"
* Rebuilt URL to: stickyingress.example.com:32619/
* Hostname was NOT found in DNS cache
* Trying 192.168.33.239...
* Connected to stickyingress.example.com (192.168.33.239) port 32619 (#0)
> GET / HTTP/1.1
> Host: stickyingress.example.com:32619
> Accept: */*
> user-agent: (Mobile)
>
< HTTP/1.1 200
* Server nginx/1.13.7 is not blacklisted
< Server: nginx/1.13.7
< Date: Wed, 14 Nov 2018 04:46:31 GMT
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 26
< Connection: keep-alive
< Vary: Accept-Encoding
<
* Connection #0 to host stickyingress.example.com left intact
OK. Vist /cardinfo please.
Conclusion 總結
使用Ingress的自定義location/server block,以及upstream的隱含定義,依然可以實現類似Istio的自動流量路由功能,後臺Pod出現更新升級並不會影響到條件跳轉。 使用者可以使用最小的代價通過Kubernetes Ingress實現ABTest,灰度,流量路由,並且享受到Kubernetes服務發現,和滾動更新帶來的優勢。
相關文章
- JS實現類似於微博秀的GitHub掛件JSGithub
- Laravel 小技巧 - 讓路由實現類似 Model::query 的效果Laravel路由
- where條件中使用case when來實現不同列的join
- 自研ORM框架 實現類似EF Core Include 拆分查詢 支援自定義條件、排序、選擇ORM框架排序
- gorm 使用map實現in 條件查詢用法GoORM
- Android中使用RecyclerView + SnapHelper實現類似ViewPager效果AndroidViewpager
- React 提供了幾種方式來實現條件渲染React
- 使用 LDAP 目錄協議實現 Domino 郵件路由LDA協議路由
- PostgreSQL類似OracleMERGE功能的實現SQLOracle
- 類似咻一咻,水波紋實現
- SQLite中中實現 if not exist 類似功能SQLite
- Vue.js+cube-ui(Scroll元件)實現類似頭條效果的橫向滾動導航條Vue.jsUI元件
- 簡單實現類似Spring的Aop原理實現Spring
- 用 GoLang 編寫類似 Apache Camel 路由引擎GolangApache路由
- Flutter 實現類似TabPicker省市區選擇Flutter
- flutter實現類似優惠券樣式Flutter
- 在鴻蒙中實現類似瀑布流效果鴻蒙
- Autofac實現有條件的DI
- Aspectj 實現Method條件執行
- 如何實現條件組合元件元件
- 使用.net standard實現不同內網埠的互通(類似花生殼)內網
- LiveKit:使用Go與WebRTC實現類似Zoom高影片質量GoWebOOM
- WinForm使用DataGridView實現類似Excel表格的查詢替換ORMViewExcel
- 用Java 19實現類似Go併發 - mccueJavaGo
- MySQL的字首索引及Oracle的類似實現MySql索引Oracle
- go如何實現類似java的動態代理GoJava
- JS實現 類似圖片3D效果JS3D
- 實現類似IE的列印網頁功能 (轉)網頁
- Java多型實現的必要條件Java多型
- C# SQLiteHelper類似SqlHelper類實現存取Sqlite資料庫C#SQLite資料庫
- 使用條件型別實現TypeScript中的函式過載型別TypeScript函式
- 用if條件語句來實現瀏覽器相容簡單介紹瀏覽器
- 使用Istio服務網格實現流量映象
- 使用Kubernetes和Istio實現藍綠部署
- 乾貨分享|使用 Istio 實現灰度釋出
- Node.js 實現類似於.php,.jsp的伺服器頁面技術,自動路由Node.jsPHP伺服器路由
- div顯示滾動條(類似合同閱讀)
- 用 golang 去實現類似 swoole 的 websocket 服務 ?GolangWeb