Istio在服務網絡中統一提供了許多關鍵功能:
-
流量管理:控制服務之間的流量和API調用的流向,使得調用更可靠,並使網絡在惡劣情況下更加健壯。
-
可觀察性:了解服務之間的依賴關系,以及它們之間流量的本質和流向,從而提供快速識別問題的能力。
-
策略執行:將組織策略應用於服務之間的互動,確保訪問策略得以執行,資源在消費者之間良好分配。策略的更改是通過配置網格而不是修改應用程序代碼。
-
服務身份和安全:為網格中的服務提供可驗證身份,並提供保護服務流量的能力,使其可以在不同可信度的網絡上流轉。
Istio針對可擴展性進行了設計,以滿足不同的部署需要:
-
平台支持:Istio旨在在各種環境中運行,包括跨雲, 預置,Kubernetes,Mesos等。最初專注於Kubernetes,但很快將支持其他環境。
-
集成和定制:策略執行組件可以擴展和定制,以便與現有的ACL,日志,監控,配額,審核等解決方案集成。
Envoy:
istio 使用Envoy 代理的擴展版本,Envoy是以c++開發的高性能代理,用於解釋服務網格中所有服務的所有入站和出站的流量,Envoy的許多內置功能被iosio發揚光大,例如動態發現,負載均衡,TLS終止,HTTP1/2&Grpc代理,熔斷器,健康檢查,基於百分比流量拆分的分段推出,故障注入和豐富指標。
Envoy被部署為邊車,和對應服務在同一個pod中,這允許istio將大量關於流量行為的型號作為屬性提取出來,而這些屬性又可以在Mixer中用於執行策略決策,並發送到監控系統,以提供整個網格行為的信息
Mixer:
負責在服務網格上執行訪問控制和使用策略,並從Envoy代理和其他服務收集遙測數據,代理提取請求級屬性,發送到Mixer進行評估。
Pilot
負責手機和驗證配置,並將其傳播到各種istio組件,它從Mixer和Envoy中提取環境特定的實現細節,為他們提供用戶服務的抽象表示,獨立於底層平台,此外,流量管理規則可以在運行時通過pilot進行編程。
lstio-auth
提供強大的服務間認證和終端用戶認證,使用交互tls,內置身份和證書管理,可以升級服務網格中的未加密流量,並為運維人員提供基於服務身份而不是網絡控制來執行策略的能力。
安裝Istio Sidecar
在Kubernetes 1.9及更高版本中默認啟用。從Istio 0.5.0開始,自動代理注入使用突變webhooks,並且已經刪除了對初始化程序注入的支持。無法升級到Kubernetes 1.9的用戶應使用手動注入。
自動把 sidecar 插入到 pod中, 需要在api中打開
[root@master1 addons]# cat /lib/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server Documentation=https://github.com/GoogleCloudPlatform/kubernetes After=network.target [Service] User=root ExecStart=/usr/local/bin/kube-apiserver \ --admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota,,MutatingAdmissionWebhook,ValidatingAdmissionWebhook \ --advertise-address=192.168.200.51 \ --allow-privileged=true \ --anonymous-auth=false \ --apiserver-count=1 \ --audit-policy-file=/etc/kubernetes/audit-policy.yaml \ --audit-log-maxage=30 \ --audit-log-maxbackup=3 \ --audit-log-maxsize=100 \ --audit-log-path=/var/log/kubernetes/audit.log \ --authorization-mode=Node,RBAC \ --bind-address=0.0.0.0 \ --secure-port=6443 \ --client-ca-file=/etc/kubernetes/ssl/ca.pem \ --enable-swagger-ui=true \ --etcd-cafile=/etc/kubernetes/ssl/ca.pem \ --etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem \ --etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem \ --etcd-servers=https://192.168.200.51:2379,https://192.168.200.52:2379,https://192.168.200.53:2379 \ --event-ttl=1h \ --kubelet-https=true \ --insecure-bind-address=192.168.200.51 \ --insecure-port=8080 \ --service-account-key-file=/etc/kubernetes/ssl/ca-key.pem \ --service-cluster-ip-range=10.254.0.0/16 \ --service-node-port-range=30000-32000 \ --tls-cert-file=/etc/kubernetes/ssl/kubernetes.pem \ --tls-private-key-file=/etc/kubernetes/ssl/kubernetes-key.pem \ --enable-bootstrap-token-auth=true \ --token-auth-file=/etc/kubernetes/token.csv \ --requestheader-client-ca-file=/etc/kubernetes/ssl/front-proxy-ca.pem \ --proxy-client-cert-file=/etc/kubernetes/ssl/front-proxy-client.pem \ --proxy-client-key-file=/etc/kubernetes/ssl/front-proxy-client-key.pem \ --requestheader-allowed-names=aggregator \ --requestheader-group-headers=X-Remote-Group \ --requestheader-extra-headers-prefix=X-Remote-Extra- \ --requestheader-username-headers=X-Remote-User \ --runtime-config=admissionregistration.k8s.io/v1alpha1 \ --runtime-config=api/all=true \ --enable-aggregator-routing=true \ --v=0 Restart=on-failure RestartSec=5 Type=notify LimitNOFILE=65536 [Install] WantedBy=multi-user.target
Pod規格要求
1.服務關聯
2.命名端口
服務端口必須命名。端口名稱必須是形式<protocol>[-<suffix>]
與 HTTP, http2, GRPC,或 Redis的作為<protocol>
,以便采取的Istio的路由功能。例如,name: http2-foo
或者name: http
是有效的端口名稱,但name: http2foo
不是。如果端口名稱未以可識別的前綴開頭,或者端口未命名,則端口上的流量將被視為純TCP流量(除非端口明確用於Protocol: UDP
表示UDP端口
3. 使用應用標簽進行部署:建議使用Kubernetes部署的Pod在部署規范中Deployment
具有明確的app
標簽。每個部署規范都應該有一個明確的app
標簽,其中有一個值表示有意義的值 該app
標簽用於在分布式跟蹤中添加上下文信息
自動邊車注入
使用webhook准入控制器,可將Sidecars自動添加到適用的Kubernetes Pod中。此功能需要Kubernetes 1.9或更高版本。驗證kube-apiserver進程是否已設置admission-control
標記,MutatingAdmissionWebhook
並ValidatingAdmissionWebhook
按照正確的順序添加並准許控制器,並且啟用許可注冊API。
kubectl api-versions | grep admissionregistration
admissionregistration.k8s.io/v1beta1
安裝webhook
kubectl apply -f install/kubernetes/istio.yaml
Webhooks需要簽名的證書/密鑰對。使用install/kubernetes/webhook-create-signed-cert.sh
來產生由Kubernetes' CA簽名的證書/密鑰對 生成的證書/密鑰文件作為Kubernetes機密文件存儲,供邊車注入器webhook使用。
注意:Kubernetes CA批准需要創建和批准CSR的權限
./install/kubernetes/webhook-create-signed-cert.sh \ --service istio-sidecar-injector \ --namespace istio-system \ --secret sidecar-injector-certs
安裝邊車注入配置圖。
kubectl apply -f install/kubernetes/istio-sidecar-injector-configmap-release.yaml
Set the caBundle
in the webhook install YAML that the Kubernetes api-server uses to invoke the webhook.
cat install/kubernetes/istio-sidecar-injector.yaml | \ ./install/kubernetes/webhook-patch-ca-bundle.sh > \ install/kubernetes/istio-sidecar-injector-with-ca-bundle.yaml
Install the sidecar injector webhook.
kubectl apply -f install/kubernetes/istio-sidecar-injector-with-ca-bundle.yaml
The sidecar injector webhook should now be running.
kubectl -n istio-system get deployment -listio=sidecar-injector NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE istio-sidecar-injector 1 1 1 1 1d
NamespaceSelector根據該對象的名稱空間是否與選擇器匹配來決定是否在對象上運行webhook,默認的webhook配置使用istio-injection=enabled
。
查看顯示istio-injection
標簽的default
名稱空間並驗證名稱空間未被標記。
kubectl get namespace -L istio-injection NAME STATUS AGE ISTIO-INJECTION default Active 1h istio-system Active 1h kube-public Active 1h kube-system Active 1h
用default
名稱空間標簽istio-injection=enabled
kubectl label namespace default istio-injection=enabled
kubectl get namespace -L istio-injection NAME STATUS AGE ISTIO-INJECTION default Active 1h enabled istio-system Active 1h kube-public Active 1h kube-system Active 1h
部署一個應用程序
kubectl apply -f samples/sleep/sleep.yaml
禁用default
名稱空間的注入
kubectl label namespace default istio-injection-
卸載webhook
kubectl delete -f install/kubernetes/istio-sidecar-injector-with-ca-bundle.yaml
kubectl -n istio-system delete secret sidecar-injector-certs kubectl delete csr istio-sidecar-injector.istio-system kubectl label namespace default istio-injection-
流量管理
介紹演示Istio服務網格的流量路由功能的任務。
配置請求路由: 此任務向您展示如何根據權重和HTTP標頭配置動態請求路由。
故障注入 : 此任務顯示如何注入延遲並測試應用程序的彈性。
交通轉移 : 此任務向您顯示如何將流量從舊版本遷移到新版本的服務。
設置請求超時: 本任務向您展示如何使用Istio在Envoy中設置請求超時。
Istio Ingress : 介紹如何在Kubernetes上配置Istio Ingress。
控制出口流量: 介紹如何配置Istio以將流量從網格中的服務路由到外部服務。
控制出口TCP流量:介紹如何配置Istio以將TCP流量從網格中的服務路由到外部服務。
斷路 : 這項任務演示了彈性應用的斷路能力
鏡像 : 演示Istio的流量投影/鏡像功能
deployment 和 service 模版 ,使用標簽 app version, 一個服務對應不同的deployment
apiVersion: v1 kind: Service metadata: name: reviews labels: app: reviews spec: type: NodePort ports: - port: 9080 name: http selector: app: reviews --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: reviews-v1 spec: replicas: 1 template: metadata: labels: app: reviews version: v1 spec: containers: - name: reviews image: 192.168.200.10/istio/examples-bookinfo-reviews-v1:1.5.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: reviews-v2 spec: replicas: 1 template: metadata: labels: app: reviews version: v2 spec: containers: - name: reviews image: 192.168.200.10/istio/examples-bookinfo-reviews-v2:1.5.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: reviews-v3 spec: replicas: 1 template: metadata: labels: app: reviews version: v3 spec: containers: - name: reviews image: 192.168.200.10/istio/examples-bookinfo-reviews-v3:1.5.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080
配置請求路由
原理: 首先使用istio將100%的請求流量路由到了 v1 版本上, 然后設置了一條路由規則, 該規則基於請求header(一個用戶的cookie)將流量路由到了 v2 版本, 如果v2 版本經過測試后滿足要求,我們就可以一次性
或者漸進的路由到v2版本上。
1. 默認訪問 version v1 版本
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: reviews-default spec: destination: name: reviews precedence: 1 route: - labels: version: v1
2. 將特定用戶的請求路由到 version v2上
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: reviews-test-v2 spec: destination: name: reviews precedence: 2 match: request: headers: cookie: regex: "^(.*?;)?(user=jason)(;.*)?$" route: - labels: version: v2
故障注入
istio 注入延遲 測試應用彈性
2個服務, serverA 和 serverB
serverA 用戶(feng) 和 serverB 之間 注入7秒延遲, serverA 針對 serverB 服務設置了10秒超時,期望 端對端的流程能無錯持續。
注意: 其他用戶沒有注入7秒延遲。
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: ratings-test-delay spec: destination: name: ratings precedence: 2 match: request: headers: cookie: regex: "^(.*?;)?(user=jason)(;.*)?$" route: - labels: version: v1 httpFault: delay: percent: 100 fixedDelay: 7s
使用賬戶 feng 登錄, 如果應用首頁已經設置了正確處理延遲,那么首頁將會在 7秒加載完成,但是 serverA 到 serverB 需要等待10秒,那么將超時。
流量轉移:
應用流量 逐步有舊版本的服務 遷移到新版本, 通過istio 可以使用不同權重的規則,將流量平穩的從舊版本服務 遷移到新版本上, 金絲雀 灰度發布。
1. 請求v1 版本
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: reviews-default spec: destination: name: reviews precedence: 1 route: - labels: version: v1
2. 把50% 的流量從 v1 版本 轉移到 v3版本
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: reviews-default spec: destination: name: reviews precedence: 1 route: - labels: version: v1 weight: 50 - labels: version: v3 weight: 50
用 kubectl apply/ replace 替換
3. v3 和 v1 版本交替出現后, 將100%的流量路由到v3 版本中
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: name: reviews-default spec: destination: name: reviews precedence: 1 route: - labels: version: v3 weight: 100
###################################################################################################
實戰:
一個服務,對應3個deployment, 最后通過istio-ingress 映射域名
nginx.yaml
apiVersion: v1 kind: Service metadata: namespace: fengjian name: nginx labels: app: nginx spec: type: NodePort ports: - port: 80 name: http protocol: TCP targetPort: 80 selector: app: nginx --- apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: fengjian name: nginx-v1 spec: replicas: 1 template: metadata: labels: app: nginx version: v1 spec: containers: - name: nginx image: 192.168.200.10/test/nginx:v1 imagePullPolicy: IfNotPresent ports: - containerPort: 80 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: fengjian name: nginx-v2 spec: replicas: 1 template: metadata: labels: app: nginx version: v2 spec: containers: - name: nginx image: 192.168.200.10/test/nginx:v2 imagePullPolicy: IfNotPresent ports: - containerPort: 80 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: namespace: fengjian name: nginx-v3 spec: replicas: 1 template: metadata: labels: app: nginx version: v3 spec: containers: - name: nginx image: 192.168.200.10/test/nginx:v3 imagePullPolicy: IfNotPresent ports: - containerPort: 80
2. 通過istio-ingress 讓外網訪問,注意: pod 注入 enovy后,nodeport 不起作用了,服務無法訪問。
istio-ingress-bookinfo.yaml
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: gatewayfengjian namespace: fengjian annotations: kubernetes.io/ingress.class: "istio" spec: rules: - http: paths: - path: / backend: serviceName: nginx servicePort: 80
創建執行
[root@master1 nginx-istio]# kubectl create -f booktest.yaml -f istio-ingress-bookinfo.yaml
默認情況, 訪問應該輪訓到 3個deployment的上的nginx , 通過流量管理中的 配置請求路由規則,指定到 deployment nginx:v1 版本上
vim rule-choice-deployment-nginx-v1.yaml
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: namespace: fengjian name: nginx-default spec: destination: name: nginx precedence: 1 route: - labels: version: v1
創建規則
kubectl create -f rule-choice-deployment-nginx-v1.yaml
訪問istio-ingress
注意的問題:
流量轉移
流量從 舊版本中遷移到新版本中, 通過istio,可以使用一系列不同權重的規則(10%,20%.....100%),將流量平穩的遷移到新版本中
1. 遷移50%到新版本中
route-rule-reviews-50.yaml
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: namespace: fengjian name: nginx-50 spec: destination: name: nginx precedence: 1 route: - labels: version: v1 weight: 50 - labels: version: v3 weight: 50
通過訪問頁面,基本上是50%的輪訓到頁面。
2. 遷移100%到新版本中
route-rule-reviews-100.yaml
apiVersion: config.istio.io/v1alpha2 kind: RouteRule metadata: namespace: fengjian name: nginx-50 spec: destination: name: nginx precedence: 1 - labels: version: v3 weight: 100
是更新,不是創建
kubectl apply -f route-rule-reviews-100.yaml
注意該方式和使用容器編排平台的部署特點來進行版本遷移是完全不同的,容器編排平台使用了實例scaling來對流量進行管理,而通過istio,兩個版本的的服務可以獨立進行
scale up 和 scale down,並不會影響這兩個版本的服務之間的流量分發。
熔斷
限制因為故障、延遲高峰以及其他預計外的網絡異常所造成的影響范圍。
服務端使用 nginx
配置目的策略,對nginx 的調用過程進行斷路設置。
nginx-destinaionpolicy.yaml
apiVersion: config.istio.io/v1beta1 kind: DestinationPolicy metadata: name: nginx-circuit-breaker spec: destination: name: nginx labels: version: v1 circuitBreaker: simpleCb: maxConnections: 1 httpMaxPendingRequests: 1 sleepWindow: 3m httpDetectionInterval: 1s httpMaxEjectionPercent: 100 httpConsecutiveErrors: 1 httpMaxRequestsPerConnection: 1
kubectl create -f nginx-destinaionpolicy.yaml istioctl get destinationpolicy NAME KIND NAMESPACE nginx-circuit-breaker DestinationPolicy.v1alpha2.config.istio.io istio-samples
設置客戶端
客戶端調用ginx服務的規則, 創建一個客戶端,向服務端發送流量, 使用負載測試工具fortio, 使用fortio 可以控制連接數量,並發數以及外發http調用的延遲。
kubectl apply -f <(istioctl kube-inject -f samples/httpbin/sample-client/fortio-deploy.yaml)
使用-curl 指定只執行一次調用。
FORTIO_POD=$(kubectl get pod | grep fortio | awk '{ print $1 }') kubectl exec -it $FORTIO_POD -c fortio /usr/local/bin/fortio -- load -curl http://nginx:8000
測試斷路器
在斷路器設置中,我們指定maxConnections: 1
以及httpMaxPendingRequests: 1
。這樣的設置下,如果我們並發超過一個連接和請求,istio-proxy就會斷掉后續的請求和連接。設置兩個並發鏈接(-c 2
),發送20個請求(-n 20
):
[root@master1 httpbin]# kubectl exec -it fortio-deploy-d86464f9d-ks4hm -c fortio /usr/local/bin/fortio -- load -c 2 -qps 0 -n 20 -loglevel Warning http://nginx.fengjian 08:10:21 I logger.go:97> Log level is now 3 Warning (was 2 Info) Fortio 0.9.0 running at 0 queries per second, 4->4 procs, for 20 calls: http://nginx.fengjian Starting at max qps with 2 thread(s) [gomax 4] for exactly 20 calls (10 per thread + 0) Ended after 18.157183ms : 20 calls. qps=1101.5 Aggregated Function Time : count 20 avg 0.0016854434 +/- 0.0008323 min 0.000847509 max 0.004309432 sum 0.033708867 # range, mid point, percentile, count >= 0.000847509 <= 0.001 , 0.000923755 , 15.00, 3 > 0.001 <= 0.002 , 0.0015 , 65.00, 10 > 0.002 <= 0.003 , 0.0025 , 95.00, 6 > 0.004 <= 0.00430943 , 0.00415472 , 100.00, 1 # target 50% 0.0017 # target 75% 0.00233333 # target 90% 0.00283333 # target 99% 0.00424755 # target 99.9% 0.00430324 Sockets used: 2 (for perfect keepalive, would be 2) Code 200 : 20 (100.0 %) Response Header Sizes : count 20 avg 237 +/- 0 min 237 max 237 sum 4740 Response Body/Total Sizes : count 20 avg 246 +/- 0 min 246 max 246 sum 4920 All done 20 calls (plus 0 warmup) 1.685 ms avg, 1101.5 qps
設置兩個並發鏈接(-c 100000
),發送20個請求(-n 200000
)
kubectl exec -it fortio-deploy-d86464f9d-ks4hm -c fortio /usr/local/bin/fortio -- load -c 100000 -qps 0 -n 20000 -loglevel Warning http://nginx.fengjian > 50 <= 75 , 62.5 , 42.37, 12001 > 75 <= 100 , 87.5 , 47.88, 5515 > 100 <= 283.465 , 191.733 , 100.00, 52118 # target 50% 107.452 # target 75% 195.459 # target 90% 248.263 # target 99% 279.945 # target 99.9% 283.113 Sockets used: 100001 (for perfect keepalive, would be 100000) Code -1 : 62857 (62.9 %) Code 200 : 19587 (19.6 %) Code 503 : 17558 (17.6 %) Response Header Sizes : count 100002 avg 46.731345 +/- 94.69 min 0 max 240 sum 4673228 Response Body/Total Sizes : count 100002 avg 86.594238 +/- 113 min 0 max 249 sum 8659597 All done 100002 calls (plus 0 warmup) 123391.636 ms avg, 352.1 qps
策略實施
限流
如果是一個外部付費API服務, 限制1 qps免費, 使用istio 控制。