初識 Istio - 服務網格管理工具

What is a service mesh(服務網格)?

微服務在國內流行已經多年了,大多數公司選擇了基於容器化技術( Docker )以及容器編排管理平臺 ( Kubernetes )落地微服務 ,然而這僅僅是個開始,微服務的發展沒有停滯。nginx

相信在調研微服務開發框架的過程當中,會發現成熟的框架如 Spring Cloud ,Dubbo,Microprofile,它們都提供了諸如服務發現、負載均衡、故障恢復、度量和監控等方面的解決方案,可是都不一樣程度的產生了不少業務無關的代碼。運維層面,在 Kubernetes 平臺上要實現一些常見需求很不容易,例如 A/B 測試、金絲雀發佈、速率限制、訪問控制和端到端認證等。web

2016 年開發 Linkerd 的 Buoyant 公司提出,要在開發和運維中間增長一層基礎設施,提供對網絡流量的洞察和操做控制的能力,包括服務註冊發現、負載均衡、故障恢復、監控、權限控制等等,而這層基礎設施就稱做服務網格。api

What is Istio?

Istio 是谷歌對於服務網格的實現,支持 Kubernetes,Consul,VMs等多種環境,並做爲透明的一層接入到現有的微服務應用程序裏,提供了以下功能:安全

  • 爲 HTTP、gRPC、WebSocket 和 TCP 流量自動負載均衡。
  • 經過豐富的路由規則、重試、故障轉移和故障注入對流量行爲進行細粒度控制。
  • 可插拔的策略層和配置 API,支持訪問控制、速率限制和配額。
  • 集羣內(包括集羣的入口和出口)全部流量的自動化度量、日誌記錄和追蹤。
  • 在具備強大的基於身份驗證和受權的集羣中實現安全的服務間通訊。

How istio work?

Istio 的架構圖以下,istio 服務網格,分爲控制面和數據面,全部流量都從 istio 的 ingress 進,從 egress出,以 Kubernetes 爲例,上圖的兩個 Service 對應 Kubernetes 中的 Pod,istio 使用 sidecar 模式,給每一個 Pod 加了一層代理,實際請求統統路由到代理,知足條件才路由給 Pod,至於控制面很簡單,就是把路由規則同步給各個代理,而且完成一些管理,安全,遙測工做。能夠發現網格中 Kubernetes 的網絡徹底被 istio 接管了,每一個 Pod 和其代理構成了一個個對外零信任的高內聚的小格子。bash

圖1

插一句,Docker 提倡每一個進程一個容器,Kubernetes 提倡每一個容器一個 Pod,istio 又提倡給每一個 Pod 一個格子,最小單元變的愈來愈大了,每一個格子外面還會接着套麼?網絡

探祕 Istio 流量管理

流量管理無疑是 Istio 的核心,流量管理的核心又是 sidecar 代理,正是經過一個個 sidecar 代理,istio 能清晰的知道流量從哪來到哪去,從而很方便的實現,日誌收集,遙測,追蹤,監控,限流等功能。下面讓咱們一塊兒近距離體驗一下 Istio 的流量管理功能。架構

安裝

參照 官方教程 安裝 Isito demo profile,以下所示 Istio 相關的服務全裝到了 istio-system 的 namespace。其中 istiod 是 istio 的核心服務,Pilot(服務發現),Galley(配置管理),Citadel(證書管理)等服務被統一成了 istiod,istiod 中 跑着 discovery 進程,用於監聽 Kubernetes 的 ApiServer 而且實時把配置跟新到各個 sidecar 代理中。istio-ingressgateway 以及 istio-egressgateway 是 demo 模式下默認安裝,運行中 Pilot 的客戶端,接受配置實時跟新規則,envoy 是相似 ngnix 的輕量級代理工具。istio-ingressgateway 和Kubernetes 平臺中的 nginx-ingress 組建起相同做用,做爲平臺外部請求進入網格的入口。其餘 grafana,jaeger,kiali,prometheus爲 istio 集成的可觀察性相關的組件。併發

chenling@ChendeMacBook-Pro ~ % kubectl get pod -n istio-system
NAME                                    READY   STATUS    RESTARTS   AGE
grafana-767c5487d6-j5l92                1/1     Running   0          5d5h
istio-egressgateway-55856f9f8f-s78md    1/1     Running   0          5d21h
istio-ingressgateway-85fbcc77b8-8rsfk   1/1     Running   0          5d21h
istiod-6dc785c4b9-z8v9v                 1/1     Running   0          5d21h
jaeger-566c547fb9-zbhn7                 1/1     Running   0          5d5h
kiali-89fd7f87b-r64dw                   1/1     Running   0          5d21h
prometheus-788c945c9c-xn8mz             2/2     Running   0          5d5h
chenling@ChendeMacBook-Pro ~ % kubectl exec -it istiod-6dc785c4b9-z8v9v -n istio-system -- ps -ef              
UID        PID  PPID  C STIME TTY          TIME CMD
istio-p+     1     0  3 Sep27 ?        00:28:28 /usr/local/bin/pilot-discovery d
istio-p+    34     0  0 00:41 pts/0    00:00:00 sh
istio-p+   112     0  0 08:04 pts/1    00:00:00 ps -ef
chenling@ChendeMacBook-Pro ~ % kubectl exec -it istio-ingressgateway-85fbcc77b8-8rsfk -n istio-system -- ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
istio-p+     1     0  0 Sep27 ?        00:01:38 /usr/local/bin/pilot-agent proxy
istio-p+    14     1  1 Sep27 ?        00:08:48 /usr/local/bin/envoy -c etc/isti
istio-p+    65     0  0 08:04 pts/0    00:00:00 ps -ef

注入

經過給 default namespace 打以下標籤,pod 建立時會自動注入 sidecar負載均衡

$ kubectl label namespace default istio-injection=enabled

當咱們經過 Kubernetes 的客戶端工具給 ApiServer 發送指令時,平臺的 Scheduler 調度服務,會監聽建立請求,並找到合適的機器,把相關信息傳給 ApiServer 並把原數據寫入 etcd,Isito 的 Pilot 採用相似機制監聽ApiServer ,當 namespace 被打上自動注入標籤,就會修改建立 pod 的原數據,增長 sidecar 代理容器到 pod 中,而且監聽到 Istio 自定義的資源變更,通知到相關的 sidecar。框架

固然也能夠手動注入 sidecar,手動注入會啓動新的 pod

istioctl kube-inject -f deployment.yaml -o deployment-injected.yaml

書寫 deployment 資源文件,注入完成以後以下所示,爲啥 Pod 中有 2 個容器?

chenling@ChendeMacBook-Pro ~ % kubectl get pod
NAME                         READY   STATUS    RESTARTS   AGE
client-6b495f748b-tgt97      2/2     Running   2          23h
hello-bc8bb7cd6-pvvkv        2/2     Running   0          24h
hello-new-5b7cbf7df4-ksxtg   2/2     Running   0          24h

默認容器是咱們聲明的,運行着一個 httpd 服務

chenling@ChendeMacBook-Pro ~ % kubectl exec -it hello-bc8bb7cd6-pvvkv -- ps -ef
Defaulting container name to hello.
Use 'kubectl describe pod/hello-bc8bb7cd6-pvvkv -n default' to see all of the containers in this pod.
PID   USER     TIME  COMMAND
    1 root      0:00 httpd -f -p 8080 -h /var/www
  435 root      0:00 ps -ef

查看 pod 中另一個容器,能夠發現和 istio-gateway 同樣,其實運行着一個 envoy 代理服務,經過 pilot-agent 接受控制面信息。

chenling@ChendeMacBook-Pro ~ % kubectl exec -it hello-bc8bb7cd6-pvvkv -c istio-proxy -- ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
istio-p+     1     0  0 Sep27 ?        00:01:50 /usr/local/bin/pilot-agent proxy
istio-p+    15     1  1 Sep27 ?        00:05:24 /usr/local/bin/envoy -c etc/isti
istio-p+   140     0  0 08:13 pts/0    00:00:00 ps -ef

注入流程

下面咱們看看注入過程,首先被注入的pod中增長了名爲 istio-init 的 initContainer,以下日誌顯示初始化過程,經過在容器 iptables nat 表中增長規則,把全部非 Istio 的入站流量重定向到 15006 端口,全部非 Istio 的出站流量定向到 15001 端口

chenling@ChendeMacBook-Pro ~ % kubectl logs --tail=32 hello-bc8bb7cd6-pvvkv -c istio-init
iptables-save 
# Generated by iptables-save v1.6.1 on Sun Sep 27 07:20:03 2020
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:ISTIO_INBOUND - [0:0]
:ISTIO_IN_REDIRECT - [0:0]
:ISTIO_OUTPUT - [0:0]
:ISTIO_REDIRECT - [0:0]
-A PREROUTING -p tcp -j ISTIO_INBOUND
-A OUTPUT -p tcp -j ISTIO_OUTPUT
-A ISTIO_INBOUND -p tcp -m tcp --dport 15008 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 22 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15090 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15021 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15020 -j RETURN
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
-A ISTIO_OUTPUT -s 127.0.0.6/32 -o lo -j RETURN
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
COMMIT
# Completed on Sun Sep 27 07:20:03 2020

以下所示 ,15006 和 15001 端口都是 envoy 提供

chenling@ChendeMacBook-Pro ~ % kubectl exec -it hello-bc8bb7cd6-pvvkv -c istio-proxy -- netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:15021           0.0.0.0:*               LISTEN      15/envoy            
tcp        0      0 0.0.0.0:15090           0.0.0.0:*               LISTEN      15/envoy            
tcp        0      0 127.0.0.1:15000         0.0.0.0:*               LISTEN      15/envoy            
tcp        0      0 0.0.0.0:15001           0.0.0.0:*               LISTEN      15/envoy            
tcp        0      0 0.0.0.0:15006           0.0.0.0:*               LISTEN      15/envoy            
tcp6       0      0 :::15020                :::*                    LISTEN      1/pilot-agent       
tcp6       0      0 :::8080                 :::*                    LISTEN      -

綜上所述,istio流量管理的實現大體以下

  • 經過自動注入,給 pod 增長 iptables,把全部進出流量指向 envoy
  • 控制面的 pilot 監控 istio 自定義資源變化,把規則發送給各個 sidecar
  • sidecar 中的 pilot-agent 接受 pilot 的信息,熱更新 envoy 代理規則,無需重啓 pod便可改變流量路徑

配置

實踐一下配置網格行爲

  • 配置名爲 xingren-gateway 的 Istio Gateway 接受全部 host爲 xingren.upup 的外部流量
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: xingren-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - xingren.upup
  • 配置 VirtualService 接受全部來自 ingren-gateway,host 爲 xingren.upup 或者 hello 的流量
  • 若是 http header 中 version 字段爲 new,流量轉到 new 子集,而且設置了 5 秒的超時時間,而且以 10% 的比例,注入一個10秒的請求延遲,已驗證服務的容錯能力
  • 若是 http header 中 version 字段不存在,或者不是 new,則 70% 流量轉到 latest 子集, 30% 流量轉到 new 子集
  • 配置可複用的 DestinationRule,定義了 latest 子集和 new 子集,按照 version 標籤匹配到 Kubernetes hello 服務下的真實pod,同時設置了併發請求不能大於1的熔斷規則
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: hello-virtualservice
spec:
  hosts:
    - hello
    - xingren.upup
  gateways:
    - xingren-gateway
  http:
    - match:
        - headers:
            version:
              exact: new
      route:
        - destination:
            host: hello
            subset: new
      fault:
        delay:
          percentage:
            value: 10
          fixedDelay: 10s
      timeout: 5s
    - route:
        - destination:
            host: hello
            subset: latest
          weight: 70
        - destination:
            host: hello
            subset: new
          weight: 30

---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: hello-destinationrule
spec:
  host: hello
  trafficPolicy:
    connectionPool:
      http:
        http1MaxPendingRequests: 1
        maxRequestsPerConnection: 1
      tcp:
        maxConnections: 1
  subsets:
    - name: latest
      labels:
        version: latest
    - name: new
      labels:
        version: new

固然 istio 的功能遠遠不止這些,詳見 官網案例

可視化

能夠經過以下命令觀察服務網格,固然也能夠經過網關暴露出去

chenling@ChendeMacBook-Pro ~ % istioctl dashboard --help
Access to Istio web UIs

Usage:
  istioctl dashboard [flags]
  istioctl dashboard [command]

Aliases:
  dashboard, dash, d

Available Commands:
  controlz    Open ControlZ web UI
  envoy       Open Envoy admin web UI
  grafana     Open Grafana web UI
  jaeger      Open Jaeger web UI
  kiali       Open Kiali web UI
  prometheus  Open Prometheus web UI
  zipkin      Open Zipkin web UI

向服務中注入一些流量

chenling@ChendeMacBook-Pro ~ % for i in `seq 1000`; do wget -q -O - http://xingren.upup; sleep 0.2;done
 Hello World(new) 
 Hello World 
 Hello World 
 Hello World 
 Hello World 
 Hello World 
 Hello World(new) 
 Hello World 
 Hello World 
 Hello World 
 Hello World(new) 
 Hello World 
 Hello World 
 Hello World 
 Hello World(new) 
 Hello World 
 ...

觀察 istio 的可視化界面 kiali,能夠看到流量從外部經過 hello 虛擬服務進入 pod,而且權重 大體 7比3

總結

Istio 出色的完成了服務網格該有的功能,且有很強的可擴展性,能夠方便的整合 prometheus,jaeger 等工具,隨着迭代易用性也有所提升。雖然 Istio 尚未被大規模用於生產環境 ,而且有質疑其佔用了過多的資源,總的來講利大於弊,經實驗,沒有被 Istio 注入的 pod 訪問被注入的資源,不會受到任何影響,會直接透傳給真實pod,因此仍是能夠小範圍嚐鮮 Istio 的。

相關文章
相關標籤/搜索