本實驗經過在k8s上部署istio,實現微服務的基礎功能。其中會涉及到服務的限流,超時,熔斷,降級,流量分隔,A/B測試等功能。實驗以前須要安裝k8s和istio,請參考以前文章。注意開啓istio的自動注入功能,並在 default namespace 啓用自動注入功能。css
本實驗的服務間調用關係以下:html
本實驗採用時下流行的先後端分離模式前端
前端項目基於vue/react實現vue
前端調用python實現的API接口node
python服務調用後端node實現的服務和lua實現的服務python
node服務調用go實現的服務react
- ---->service-js
- ---->service-python
- ---->service-lua
- ---->service-node
- ---->service-go
本實驗使用的語言技術棧:nginx
架構圖以下:git
istio-0.8
版本配置發生很大的變化,由原來的v1alpha1
升級到了v1alpha3
,主要變化以下github
virtualservice
和destinationrule
代替原來的routerule
gateway
代替了原來的ingress
每一個virtualservice
都要指定要去向哪個destinationrule
,virtualservice
指定訪問哪一個地址時會使用這個路由,至關於nginx
上配置的vhosts
git clone https://github.com/mgxian/istio-test
cd istio-test && git checkout v2
複製代碼
kubectl apply -f service/go/v1/go-v1.yml
kubectl apply -f service/go/v2/go-v2.yml
kubectl apply -f service/python/v1/python-v1.yml
kubectl apply -f service/python/v2/python-v2.yml
kubectl apply -f service/js/v1/js-v1.yml
kubectl apply -f service/js/v2/js-v2.yml
kubectl apply -f service/node/v1/node-v1.yml
kubectl apply -f service/node/v2/node-v2.yml
kubectl apply -f service/lua/v1/lua-v1.yml
kubectl apply -f service/lua/v2/lua-v2.yml
複製代碼
# 使用istio提供的Gateway功能
# 暴露js和python服務讓k8s集羣外部訪問
istioctl create -f istio/gateway.yml
istioctl create -f istio/gateway-virtualservice.yml
# 查看
istioctl get gateway
istioctl get virtualservice
# 測試訪問
INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}')
NODE_NAME=$(kubectl get no | grep '<none>' | head -1 | awk '{print $1}')
NODE_IP=$(ping -c 1 $NODE_NAME | grep PING | awk '{print $3}' | tr -d '()')
export GATEWAY_URL=$NODE_IP:$INGRESS_PORT
echo "curl -I http://$GATEWAY_URL/"
echo "curl -I http://$NODE_IP/"
# 訪問返回404表示正確
複製代碼
# 配置hosts解析
# 11.11.11.112爲其中一個node的ip
11.11.11.112 istio-test.will
curl -I http://istio-test.will/
# 使用curl
curl -I istio-test.will
curl -s istio-test.will | egrep "vue|React"
# 此時若是用瀏覽器,可能會出會頁面顯示不正常的狀況。
# 由於此時請求會輪流分發到後端js服務的v1/v2版本,所以css/js並不能正常加載
複製代碼
根據請求的信息,把流量路由到服務的不一樣版本。實驗過程若是沒有達到預期效果,頗有多是由於存在路由規則衝突,並且沒有設置優先級,能夠先刪除以前設置的路由規則或者把優先級設置高一點。
# 清理以前建立的gateway相關的路由規則
istioctl delete -f istio/gateway-virtualservice.yml
# 建立路由規則
istioctl create -f istio/gateway-virtualservice-v1.yml
istioctl create -f istio/route-rule-all-v1.yml
# 查看路由規則
istioctl get virtualservice
istioctl get destinationrule
# 訪問瀏覽器測試
http://istio-test.will/
# 此時你會看到react app的界面
# 點擊發射按鈕,會發送ajax請求到python服務
# 因爲把全部流量都導向了v1版本
# 屢次點擊發射按鈕會獲得同樣的內容
# react----->Python2.7.15----->Gogo1.9.6
# 清除路由規則
istioctl delete -f istio/route-rule-all-v1.yml
istioctl delete -f istio/gateway-virtualservice-v1.yml
複製代碼
# 建立路由規則
# 根據瀏覽器的不一樣返回不一樣內容
istioctl create -f istio/route-rule-js-by-agent.yml
# 查看路由規則
istioctl get virtualservice
istioctl get destinationrule
# 使用訪問瀏覽器
# 若是你用chrome瀏覽器你會看到react app的界面
# 若是你用firefox瀏覽器你會看到vue app的界面
# 屢次點擊發射按鈕,會獲取到不一樣的內容
# 清除路由規則
istioctl delete -f istio/route-rule-js-by-agent.yml
# 根據前端app不一樣使用不一樣版本的python服務
istioctl create -f istio/route-rule-python-by-header.yml
# 清除路由規則
istioctl delete -f istio/route-rule-python-by-header.yml
複製代碼
# 先建立以下路由方便測試訪問
# 根據瀏覽器的不一樣返回不一樣內容
istioctl create -f istio/route-rule-js-by-agent.yml
# 建立路由規則
istioctl create -f istio/route-rule-go-by-source.yml
# 清除路由規則
istioctl delete -f istio/route-rule-js-by-agent.yml
istioctl delete -f istio/route-rule-go-by-source.yml
複製代碼
# 指定權重把流量分隔
# 25%流量路由到v1版本
# 75%流量路由到v2版本
# 先建立以下路由方便測試訪問
# 根據瀏覽器的不一樣返回不一樣內容
istioctl create -f istio/route-rule-js-by-agent.yml
# 建立路由規則
istioctl create -f istio/route-rule-go-v1-v2.yaml
# 清除路由規則
istioctl delete -f istio/route-rule-js-by-agent.yml
istioctl delete -f istio/route-rule-go-v1-v2.yaml
複製代碼
# 默認狀況下,啓用了istio的服務是沒法訪問外部url的
# 若是須要訪問外部url,須要使用egress進行配置
# egress一樣支持設置路由規則
# http
istioctl create -f istio/egress-rule-http-bin.yml
# tcp
istioctl create -f istio/egress-rule-tcp-wikipedia.yml
# 查看
istioctl get serviceentry
# 測試
# 使用exec進入做爲測試源使用的pod
kubectl apply -f istio/sleep.yaml
kubectl get pods
export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
kubectl exec -it $SOURCE_POD -c sleep bash
# http測試
curl http://httpbin.org/headers
curl http://httpbin.org/delay/5
# tcp測試
curl -o /dev/null -s -w "%{http_code}\n" https://www.wikipedia.org
curl -s https://en.wikipedia.org/wiki/Main_Page | grep articlecount | grep 'Special:Statistics'
# 清理
istioctl delete -f istio/egress-rule-http-bin.yml
istioctl delete -f istio/egress-rule-tcp-wikipedia.yml
kubectl delete -f istio/sleep.yaml
複製代碼
# 先建立以下路由方便測試訪問
# 根據瀏覽器的不一樣返回不一樣內容
istioctl create -f istio/route-rule-js-by-agent.yml
# 設置python服務超時時間
istioctl create -f istio/route-rule-node-timeout.yml
# 模擬go服務超時故障
istioctl create -f istio/route-rule-go-delay.yml
# 使用瀏覽器訪問並打開調試面板查看網絡標籤(按F12鍵)
# 屢次點擊發射按鈕觀察響應時間
# 會看到部分50%的請求會返回500錯誤
# 清除路由規則
istioctl delete -f istio/route-rule-js-by-agent.yml
istioctl delete -f istio/route-rule-node-timeout.yml
istioctl delete -f istio/route-rule-go-delay.yml
複製代碼
# 先建立以下路由方便測試訪問
# 根據瀏覽器的不一樣返回不一樣內容
istioctl create -f istio/route-rule-js-by-agent.yml
# 設置python服務超時時間
istioctl create -f istio/route-rule-node-retry.yml
# 模擬go服務超時故障
istioctl create -f istio/route-rule-go-abort.yml
# 使用瀏覽器訪問並打開調試面板查看網絡標籤(按F12鍵)
# 屢次點擊發射按鈕觀察響應時間
# 會看到部分請求會返回500錯誤
# 清除路由規則
istioctl delete -f istio/route-rule-js-by-agent.yml
istioctl delete -f istio/route-rule-node-retry.yml
istioctl delete -f istio/route-rule-go-abort.yml
複製代碼
# 全部請求延遲5秒鐘,而後失敗其中的10%
...
route:
- labels:
version: v1
httpFault:
delay:
fixedDelay: 5s
abort:
percent: 10
httpStatus: 400
複製代碼
# 設置熔斷規則
istioctl create -f istio/route-rule-go-cb.yml
# 查看規則
istioctl get destinationrule
# 建立測試用的fortio
kubectl apply -f istio/fortio-deploy.yaml
# 正常訪問測試
FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
kubectl exec -it $FORTIO_POD -c fortio /usr/local/bin/fortio -- load -curl http://service-go/env
# 測試熔斷 2併發
kubectl exec -it $FORTIO_POD -c fortio /usr/local/bin/fortio -- load -c 2 -qps 0 -n 20 -loglevel Warning http://service-go/env
# 測試熔斷 3併發
kubectl exec -it $FORTIO_POD -c fortio /usr/local/bin/fortio -- load -c 3 -qps 0 -n 20 -loglevel Warning http://service-go/env
# 增長併發會看到失敗的請求佔比增高
# 查看狀態
# upstream_rq_pending_overflow 表示被熔斷的請求數
kubectl exec -it $FORTIO_POD -c istio-proxy -- sh -c 'curl localhost:15000/stats' | grep service-go | grep pending
# 清理
kubectl delete -f istio/fortio-deploy.yaml
istioctl delete -f istio/route-rule-go-cb.yml
複製代碼
動態設置服務qps
# 配置 memquota, quota, rule, QuotaSpec, QuotaSpecBinding 啓用限速
# 默認設置500qps
istioctl create -f istio/ratelimit-handler.yaml
# 配置速率限制實例和規則
istioctl create -f istio/ratelimit-rule-service-go.yaml
# 查看
kubectl get memquota -n istio-system
kubectl get quota -n istio-system
kubectl get rule -n istio-system
kubectl get quotaspec -n istio-system
kubectl get quotaspecbinding -n istio-system
# 建立測試用的fortio
kubectl apply -f istio/fortio-deploy.yaml
# 正常訪問測試
FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
kubectl exec -it $FORTIO_POD -c fortio /usr/local/bin/fortio -- load -curl http://service-node/env
# 測試
# 會出現部分請求不正常
# node 返回 code 500
# go 返回 code 429
kubectl exec -it $FORTIO_POD -c fortio /usr/local/bin/fortio -- load -qps 20 -n 100 -loglevel Warning http://service-node/env
kubectl exec -it $FORTIO_POD -c fortio /usr/local/bin/fortio -- load -qps 50 -n 100 -loglevel Warning http://service-go/env
# 清理
istioctl delete -f istio/ratelimit-handler.yaml
istioctl delete -f istio/ratelimit-rule-service-go.yaml
kubectl delete -f istio/fortio-deploy.yaml
# 帶條件的速率限制
apiVersion: config.istio.io/v1alpha2
kind: rule
metadata:
name: quota
namespace: istio-system
spec:
match: source.namespace != destination.namespace
actions:
- handler: handler.memquota
instances:
- requestcount.quota
複製代碼
複製服務的流量到別一個鏡像服務,通常用於線上新上服務的測試。
# 建立測試用的fortio
kubectl apply -f istio/fortio-deploy.yaml
# 正常訪問測試
FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }')
kubectl exec -it $FORTIO_POD -c fortio /usr/local/bin/fortio -- load -curl http://service-go/env
# 查看v1的日誌
kubectl logs -f $(kubectl get pods | grep service-go-v1 | awk '{print $1}'| head -n 1) -c service-go
# 查看v2的日誌
# 再開一個終端查看日誌
kubectl logs -f $(kubectl get pods | grep service-go-v2 | awk '{print $1}'| head -n 1) -c service-go
# 建立鏡像規則
istioctl create -f istio/route-rule-go-mirror.yml
# 測試屢次訪問
kubectl exec -it $FORTIO_POD -c fortio /usr/local/bin/fortio -- load -c 10 -qps 0 -t 10s -loglevel Warning http://service-go/env
# 清理
kubectl delete -f istio/fortio-deploy.yaml
istioctl delete -f istio/route-rule-go-mirror.yml
複製代碼
# 刪除相關deploy和svc
kubectl delete -f service/go/v1/go-v1.yml
kubectl delete -f service/go/v2/go-v2.yml
kubectl delete -f service/python/v1/python-v1.yml
kubectl delete -f service/python/v2/python-v2.yml
kubectl delete -f service/js/v1/js-v1.yml
kubectl delete -f service/js/v2/js-v2.yml
kubectl delete -f service/node/v1/node-v1.yml
kubectl delete -f service/node/v2/node-v2.yml
kubectl delete -f service/lua/v1/lua-v1.yml
kubectl delete -f service/lua/v2/lua-v2.yml
# 清除路由規則
kubectl delete -f istio/gateway.yml
kubectl delete -f istio/gateway-virtualservice.yml
istioctl delete destinationrule $(istioctl get destinationrule | grep 'service-' | awk '{print $1}')
istioctl delete virtualservice $(istioctl get virtualservice | grep 'service-' | awk '{print $1}')
複製代碼