service mesh istio-0.8微服務實驗

簡介

本實驗經過在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

  • vue/react
  • python2/3
  • node8/10
  • openresty1.11 /1.13
  • go1.10/1.9

架構圖以下:git

istio-0.8版本配置發生很大的變化,由原來的v1alpha1升級到了v1alpha3,主要變化以下github

  • 使用virtualservicedestinationrule 代替原來的routerule
  • 使用gateway代替了原來的ingress

每一個virtualservice都要指定要去向哪個destinationrulevirtualservice指定訪問哪一個地址時會使用這個路由,至關於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
複製代碼

建立Gateway

# 使用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並不能正常加載
複製代碼

流量管理

根據請求的信息,把流量路由到服務的不一樣版本。實驗過程若是沒有達到預期效果,頗有多是由於存在路由規則衝突,並且沒有設置優先級,能夠先刪除以前設置的路由規則或者把優先級設置高一點。

把全部流量導向v1版本

# 清理以前建立的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
複製代碼

根據請求把流量導向不一樣版本(A/B測試)

# 建立路由規則
# 根據瀏覽器的不一樣返回不一樣內容
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
複製代碼

超時模擬

設置重試與模擬服務500故障

# 先建立以下路由方便測試訪問
# 根據瀏覽器的不一樣返回不一樣內容
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
複製代碼

模擬服務500故障

超時和服務故障模擬配合使用

# 全部請求延遲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}')
複製代碼

參考文檔

相關文章
相關標籤/搜索