1. 程式人生 > 實用技巧 >Istio入門實戰與架構原理——使用Docker Compose搭建Service Mesh

Istio入門實戰與架構原理——使用Docker Compose搭建Service Mesh

本文將介紹如何使用Docker Compose搭建Istio。Istio號稱支援多種平臺(不僅僅Kubernetes)。然而,官網上非基於Kubernetes的教程彷彿不是親兒子,寫得非常隨便,不僅缺了一些內容,而且還有坑。本文希望能補實這些內容。我認為在學習Istio的過程中,相比於Kubernetes,使用Docker Compose部署更能深刻地理解Istio各個元件的用處以及他們的互動關係。在理解了這些後,可以在其他環境,甚至直接在虛擬機器上部署Istio。當然,生產環境建議使用Kubernetes等成熟的容器框架


本文使用官方的Bookinfo示例。通過搭建Istio控制平面,部署Bookinfo應用,最後配置路由規則,展示Istio基本的功能和架構原理。


本文涉及的名詞、用到的埠比較多。Don't panic.



為了防止不提供原網址的轉載,特在這裡加上原文連結:
https://www.cnblogs.com/skabyy/p/10668079.html



準備工作



  1. 安裝Docker和Docker Compose。

  2. 安裝kubectl(Kubernetes的客戶端)。

  3. 下載Istio release 1.1.0並解壓。注意,這裡下載的是Linux的版本。即使你用的Windows或者OSX作業系統,也應該下載Linux版本的Istio,因為我們要放到Docker容器裡去執行的。


Service Mesh架構


在微服務架構中,通常除了實現業務功能的微服務外,我們還會部署一系列的基礎元件。這些基礎元件有些會入侵微服務的程式碼。比如服務發現需要微服務啟動時註冊自己,鏈路跟蹤需要在HTTP請求的headers中插入資料,流量控制需要一整套控制流量的邏輯等。這些入侵的程式碼需要在所有的微服務中保持一致。這導致了開發和管理上的一些難題。


為了解決這個問題,我們再次應用抽象和服務化的思想,將這些需要入侵的功能抽象出來,作為一個獨立的服務。這個獨立的服務被稱為sidecar,這種模式叫Sidecar模式。對每個微服務節點,都需要額外部署一個sidecar來負責業務邏輯外的公共功能。所有的出站入站的網路流量都會先經過sidecar進行各種處理或者轉發。這樣微服務的開發就不需要考慮業務邏輯外的問題。另外所有的sidecar都是一樣的,只需要部署的時候使用合適的編排工具即可方便地為所有節點注入sidecar。



Sidecar不會產生額外網路成本。Sidecar會和微服務節點部署在同一臺主機上並且共用相同的虛擬網絡卡。所以sidecar和微服務節點的通訊實際上都只是通過記憶體拷貝實現的。





圖片來自:Pattern: Service Mesh



Sidecar只負責網路通訊。還需要有個元件來統一管理所有sidecar的配置。在Service Mesh中,負責網路通訊的部分叫資料平面(data plane),負責配置管理的部分叫控制平面(control plane)。資料平面和控制平面構成了Service Mesh的基本架構。




圖片來自:Pattern: Service Mesh



Istio的資料平面主要由Envoy實現,控制平面則主要由Istio的Pilot元件實現。


部署控制平面


如果你使用Linux作業系統,需要先配置DOCKER_GATEWAY環境變數。非Linux系統不要配。


$ export DOCKER_GATEWAY=172.28.0.1:

install/consul目錄下,使用istio.yaml檔案啟動控制平面:



根據自己的網路情況(你懂得),可以把istio.yaml中的映象gcr.io/google_containers/kube-apiserver-amd64:v1.7.3換成mirrorgooglecontainers/kube-apiserver-amd64:v1.7.3



$ docker-compose -f istio.yaml up -d

用命令docker-compose -f istio.yaml ps看一下是不是所有元件正常執行。你可能(大概率)會看到pilot的狀態是Exit 255。使用命令docker-compose -f istio.yaml logs | grep pilot檢視日誌發現,pilot啟動時訪問istio-apiserver失敗。這是因為Docker Compose是同時啟動所有容器的,在pilot啟動時,istio-apiserver也是處於啟動狀態,所以訪問istio-apiserver就失敗了。


istio-apiserver啟動完成後,重新執行啟動命令就能成功啟動pilot了。你也可以寫一個指令碼來自動跑兩次命令:


docker-compose -f istio.yaml up -d
# 有些依賴別人的第一次啟動會掛
sec=10 # 根據你的機器效能這個時間可以修改
echo 'Wait $sec seconds...'
sleep $sec
docker-compose -f istio.yaml up -d
docker-compose -f istio.yaml ps

配置kubectl,讓kubectl使用我們剛剛部署的istio-apiserver作為服務端。我們後面會使用kubectl來執行配置管理的操作。


$ kubectl config set-context istio --cluster=istio
$ kubectl config set-cluster istio --server=http://localhost:8080
$ kubectl config use-context istio

部署完成後,使用地址localhost:8500可以訪問consul,使用地址localhost:9411可以訪問zipkin


控制平面架構


在下一步之前,我們先來看一下控制平面都由哪些元件組成。下面是istio.yaml檔案的內容:


# GENERATED FILE. Use with Docker-Compose and consul
# TO UPDATE, modify files in install/consul/templates and run install/updateVersion.sh
version: '2'
services:
etcd:
image: quay.io/coreos/etcd:latest
networks:
istiomesh:
aliases:
- etcd
ports:
- '4001:4001'
- '2380:2380'
- '2379:2379'
environment:
- SERVICE_IGNORE=1
command: ['/usr/local/bin/etcd', '-advertise-client-urls=http://0.0.0.0:2379', '-listen-client-urls=http://0.0.0.0:2379']

istio-apiserver:
# 如果這個映象下載不了的話,可以換成下面的地址:
# image: mirrorgooglecontainers/kube-apiserver-amd64:v1.7.3
image: gcr.io/google_containers/kube-apiserver-amd64:v1.7.3
networks:
istiomesh:
ipv4_address: 172.28.0.13
aliases:
- apiserver
ports:
- '8080:8080'
privileged: true
environment:
- SERVICE_IGNORE=1
command: ['kube-apiserver', '--etcd-servers', 'http://etcd:2379', '--service-cluster-ip-range', '10.99.0.0/16', '--insecure-port', '8080', '-v', '2', '--insecure-bind-address', '0.0.0.0']

consul:
image: consul:1.3.0
networks:
istiomesh:
aliases:
- consul
ports:
- '8500:8500'
- '${DOCKER_GATEWAY}53:8600/udp'
- '8400:8400'
- '8502:8502'
environment:
- SERVICE_IGNORE=1
- DNS_RESOLVES=consul
- DNS_PORT=8600
- CONSUL_DATA_DIR=/consul/data
- CONSUL_CONFIG_DIR=/consul/config
entrypoint:
- 'docker-entrypoint.sh'
command: ['agent', '-bootstrap', '-server', '-ui',
'-grpc-port', '8502'
]
volumes:
- ./consul_config:/consul/config

registrator:
image: gliderlabs/registrator:latest
networks:
istiomesh:
volumes:
- /var/run/docker.sock:/tmp/docker.sock
command: ['-internal', '-retry-attempts=-1', 'consul://consul:8500']

pilot:
image: docker.io/istio/pilot:1.1.0
networks:
istiomesh:
aliases:
- istio-pilot
expose:
- '15003'
- '15005'
- '15007'
ports:
- '8081:15007'
command: ['discovery',
'--httpAddr', ':15007',
'--registries', 'Consul',
'--consulserverURL', 'http://consul:8500',
'--kubeconfig', '/etc/istio/config/kubeconfig',
'--secureGrpcAddr', '',
]
volumes:
- ./kubeconfig:/etc/istio/config/kubeconfig

zipkin:
image: docker.io/openzipkin/zipkin:2.7
networks:
istiomesh:
aliases:
- zipkin
ports:
- '9411:9411'

networks:
istiomesh:
ipam:
driver: default
config:
- subnet: 172.28.0.0/16
gateway: 172.28.0.1

控制平面部署了這幾個元件(使用istio.yaml裡寫的名稱):



  • etcd:分散式key-value儲存。Istio的配置資訊存在這裡。

  • istio-apiserver:實際上是一個kube-apiserver,提供了Kubernetes格式資料的讀寫介面。

  • consul:服務發現。

  • registrator:監聽Docker服務程序,自動將容器註冊到consul

  • pilot:從consulistio-apiserver收集主機資訊與配置資料,並下發到所有的sidecar。

  • zipkin:鏈路跟蹤元件。與其他元件的關係相對獨立。


這些元件間的關係如下圖:



控制平面主要實現了以下兩個功能:



  • 借用Kubernetes API管理配置資料etcdkube-apiserver的組合可以看作是一個物件儲存系統,它提供了讀寫介面和變更事件,並且可以直接使用kubectl作為客戶端方便地進行操作。Istio直接使用這個組合作為控制平面的持久化層,節省了重複開發的麻煩,另外也相容了Kubernetes容器框架。

  • 使用Pilot-discovery將主機資訊與配置資料同步到Envoypilot容器中實際執行的是pilot-discovery(發現服務)。它從consul收集各個主機的域名和IP的對應關係,從istio-apiserver獲取流量控制配置,然後按照Envoy的xDS API規範生成Envoy配置,下發到所有sidecar。


部署微服務和sidecar


接下來我們開始部署微服務。這裡我們使用Istio提供的例子,一個Bookinfo應用


Bookinfo 應用分為四個單獨的微服務:



  • productpageproductpage微服務會呼叫detailsreviews兩個微服務,用來生成頁面。

  • details:這個微服務包含了書籍的資訊。

  • reviews:這個微服務包含了書籍相關的評論。它還會呼叫ratings微服務。

  • ratingsratings微服務中包含了由書籍評價組成的評級資訊。


reviews微服務有3個版本:



  • v1版本不會呼叫ratings服務。

  • v2版本會呼叫ratings服務,並使用1到5個黑色星形圖示來顯示評分資訊。

  • v3版本會呼叫ratings服務,並使用1到5個紅色星形圖示來顯示評分資訊。


Bookinfo應用的架構如下圖所示:




圖片來自:Bookinfo應用



首先,我們切換到這個示例的目錄samples/bookinfo/platform/consul下。


使用bookinfo.yaml檔案啟動所有微服務:


$ docker-compose -f bookinfo.yaml up -d

這裡只啟動了微服務,還需使用bookinfo.sidecar.yaml檔案啟動所有sidecar:


$ docker-compose -f bookinfo.sidecars.yaml up -d

部署完畢。但是當我們訪問時……


Bookinfo暴露到外面的埠是9081,使用地址localhost:9081/productpage訪問productpage頁面。


Emmm……出錯了:



本來應該顯示reviews的部分報錯了,而details還是正常的。經過一番排查,我們發現,在所有微服務的容器上,不管你訪問的是productpagedetailsreviews還是ratings,網路請求都會跑到details



你的情況不一定是details,也有可能所有流量都跑到另外的某個服務。這是隨機的。



# 到reviews查reviews,返回404
$ docker exec -it consul_ratings-v1_1 curl reviews.service.consul:9080/reviews/0
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0//EN'>
<HTML>
<HEAD><TITLE>Not Found</TITLE></HEAD>
<BODY>
<H1>Not Found</H1>
`/reviews/0' not found.
<HR>
<ADDRESS>
WEBrick/1.3.1 (Ruby/2.3.8/2018-10-18) at
reviews.service.consul:9080
</ADDRESS>
</BODY>
</HTML>

# 到reviews查details,反倒能查出資料,詭異的路由……
$ docker exec -it consul_ratings-v1_1 curl reviews.service.consul:9080/details/0
{'id':0,'author':'William Shakespeare','year':1595,'type':'paperback','pages':200,'publisher':'PublisherA','language':'English','ISBN-10':'1234567890','ISBN-13':'123-1234567890'}

不用懷疑部署的時候哪裡操作失誤了,就是官方的部署檔案有坑……


要解決這個問題,我們來看看sidecar的原理。


Istio Sidecar模式的原理


首先看看兩個部署用的yaml檔案都做了什麼。由於每個微服務的部署都大同小異,這裡只貼出productpage相關的內容。


bookinfo.yaml


version: '2'
services:
……
productpage-v1:
image: istio/examples-bookinfo-productpage-v1:1.10.1
networks:
istiomesh:
ipv4_address: 172.28.0.14
dns:
- 172.28.0.1
- 8.8.8.8
dns_search:
- service.consul
environment:
- SERVICE_NAME=productpage
- SERVICE_TAGS=version|v1
- SERVICE_PROTOCOL=http
ports:
- '9081:9080'
expose:
- '9080'
……


  • dns_search: - search.consul。Docker Compose部署的這套樣例對短服務主機名的解析可能會有問題,所以這裡需要加個字尾。

  • environment環境變數的幾個設定。registrator會以這些環境變數為配置將服務註冊到consulSERVICE_NAME是註冊的服務名,SERVICE_TAGS是註冊服務的ServiceTags,而SERVICE_PROTOCOL=http則會將protocol: http加入到ServiceMeta


bookinfo.sidecar.yaml


version: '2'
services:
……
productpage-v1-init:
image: docker.io/istio/proxy_init:0.7.1
cap_add:
- NET_ADMIN
network_mode: 'container:consul_productpage-v1_1'
command:
- -p
- '15001'
- -u
- '1337'
productpage-v1-sidecar:
image: docker.io/istio/proxy_debug:1.1.0
network_mode: 'container:consul_productpage-v1_1'
entrypoint:
- su
- istio-proxy
- -c
- '/usr/local/bin/pilot-agent proxy --serviceregistry Consul --serviceCluster productpage-v1 --zipkinAddress zipkin:9411 --configPath /var/lib/istio >/tmp/envoy.log'
……


  • sidecar由兩部分組成,一個是負責初始化的proxy_init,這個容器執行完就退出了;另一個是實際的sidecar程式proxy_debug

  • 注意這兩個容器的network_mode,值為container:consul_productpage-v1_1。這是Docker的容器網路模式,意思是這兩個容器和productpage-v1共用同一個虛擬網絡卡,即它們在相同網路棧上。


proxy_init


sidecar的網路代理一般是將一個埠轉發到另一個埠。所以微服務使用的埠就必須和對外暴露的埠不一樣,這樣一來sidecar就不夠透明。


為了使sidecar變得透明,以Istio使用proxy_init設定了iptables的轉發規則(proxy_initproxy_debugproductpage-v1在相同的網路棧上,所以這個配置對這三個容器都生效)。新增的規則為:



  1. 迴環網路的流量不處理。

  2. 使用者ID為1337的流量不處理。1337是Envoy程序的使用者ID,這條規則是為了防止流量轉發死迴圈。

  3. 所有出站入站的流量除了規則1和規則2外,都轉發到15001埠——這是Envoy監聽的埠。


比如productpage服務使用的9080埠,當其他服務通過9080埠訪問productpage是,請求會先被iptables轉發到15001埠,Envoy再根據路由規則轉發到9080埠。這樣訪問9080的流量實際上都在15001繞了一圈,但是對外部來說,這個過程是透明的。



proxy_debug


proxy_debug有兩個程序:pilot-agentenvoyproxy_debug啟動時,會先啟動pilot-agentpilot-agent做的事很簡單,它生成了envoy的初始配置檔案/var/lib/istio/envoy-rev0.json,然後啟動envoy。後面的事就都交給envoy了。


使用下面命令匯出初始配置檔案:


$ docker exec -it consul_productpage-v1-sidecar_1 cat /var/lib/istio/envoy-rev0.json > envoy-rev0.json

使用你心愛的編輯器開啟初始配置檔案,可以看到有這麼一段:


……
'name': 'xds-grpc',
'type': 'STRICT_DNS',
'connect_timeout': '10s',
'lb_policy': 'ROUND_ROBIN',

'hosts': [
{
'socket_address': {'address': 'istio-pilot', 'port_value': 15010}
}
],
……

這一段的意思是envoy會連線到pilot(控制平面的元件,忘記了請往上翻翻)的15010埠。這倆將按照xDS的API規範,使用GRPC協議實時同步配置資料。



xDS是Envoy約定的一系列發現服務(Discovery Service)的統稱。如CDS(Cluster Discovery Service),EDS(Endpoint Discovery Service),RDS(Route Discovery Service)等。Envoy動態配置需要從實現了xDS規範的介面(比如這裡的pilot-discovery)獲取配置資料。



總結一下,Envoy配置初始化流程為:




圖片來自:Istio流量管理實現機制深度解析



那麼說envoy實際使用的路由配置並不在初始配置檔案中,而是pilot生成並推送過來的。如何檢視envoy的當前配置呢?還好envoy暴露了一個管理埠15000:


$ docker exec -it consul_productpage-v1-sidecar_1 curl localhost:15000/help
admin commands are:
/: Admin home page
/certs: print certs on machine
/clusters: upstream cluster status
/config_dump: dump current Envoy configs (experimental)
/contention: dump current Envoy mutex contention stats (if enabled)
/cpuprofiler: enable/disable the CPU profiler
/healthcheck/fail: cause the server to fail health checks
/healthcheck/ok: cause the server to pass health checks
/help: print out list of admin commands
/hot_restart_version: print the hot restart compatibility version
/listeners: print listener addresses
/logging: query/change logging levels
/memory: print current allocation/heap usage
/quitquitquit: exit the server
/reset_counters: reset all counters to zero
/runtime: print runtime values
/runtime_modify: modify runtime values
/server_info: print server version/status information
/stats: print server stats
/stats/prometheus: print server stats in prometheus format

我們可以通過/config_dump介面匯出envoy的當前配置:


$ docker exec -it consul_productpage-v1-sidecar_1 curl localhost:15000/config_dump > envoy.json

開啟這個配置,看到這麼一段:


……
'listener': {
'name': '0.0.0.0_9080',
'address': {
'socket_address': {
'address': '0.0.0.0',
'port_value': 9080
}
},
'filter_chains': [
{
'filters': [
{
'name': 'envoy.tcp_proxy',
'typed_config': {
'@type': 'type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy',
'stat_prefix': 'outbound|9080||details.service.consul',
'cluster': 'outbound|9080||details.service.consul',
……

猜一下也能知道,這一段的意思是,訪問目標地址9080埠的出站流量,都會被路由到details。太坑了!!!


解決問題


從上面原理分析可知,這個問題的根源應該在於pilot給Envoy生成的配置不正確。


檢視pilot原始碼得知,pilot在生成配置時,用一個map儲存Listener資訊。這個map的key為<ip>:<port>。如果服務註冊的時候,沒有指明埠<port>上的協議的話,預設認為TCP協議。pilot會將這個Listener和路由寫入到這個map,並拒絕其他相同地址埠再來監聽。於是只有第一個註冊的服務的路由會生效,所有流量都會走到那個服務。如果這個埠有指定使用HTTP協議的話,Pilot-discovery這裡生成的是一個RDS的監聽,這個RDS則根據域名路由到正確的地址。


簡單說就是所有微服務在註冊到consul時應該在ServiceMeta中說明自己9080埠的協議是http


等等,前面的bookinfo.yaml配置裡,有指定9080埠的協議是了呀。我們訪問一下consul的介面看下ServiceMeta是寫入了沒有:



果然沒有……看來Registrator註冊的時候出了岔子。網上搜了下,確實有Issue提到了這個問題:gliderlabs/registrator#633istio.yaml中使用的latest版本的Registrator不支援寫入Consul的ServiceMeta。應該改為master版本


修改一下istio.yaml配置。按照部署倒敘關閉sidecar、微服務,重新啟動控制平面,等registrator啟動完畢後,重新部署微服務和sidecar。


# /samples/bookinfo/platform/consul
$ docker-compose -f bookinfo.sidecars.yaml down
$ docker-compose -f bookinfo.yaml down
# /install/consul
$ docker-compose -f istio.yaml up -d
# /samples/bookinfo/platform/consul
$ docker-compose -f bookinfo.yaml up -d
$ docker-compose -f bookinfo.sidecars.yaml up -d

再訪問consul的介面試試,有了(沒有的話可能是registrator沒啟動好導致沒註冊到consul,再新部署下微服務和sidecar):



再訪問頁面,OK了。目前沒有配置路由規則,reviews的版本是隨機的。多重新整理幾次頁面,可以看到打星在“沒有星星”、“黑色星星”和“紅色星星”三種效果間隨機切換。


使用地址http://localhost:9411能訪問Zipkin鏈路跟蹤系統,檢視微服務請求鏈路呼叫情況。


我們來看看正確的配置是什麼內容。再取出Envoy的配置,0.0.0.0_9080的Listener內容變為:


……
'listener': {
'name': '0.0.0.0_9080',
'address': {
'socket_address': {
'address': '0.0.0.0',
'port_value': 9080
}
},
'filter_chains': [
{
'filters': [
{
'name': 'envoy.http_connection_manager',
'typed_config': {
'@type': 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager',
'stat_prefix': '0.0.0.0_9080',
'rds': {
'config_source': {
'ads': {}
},
'route_config_name': '9080'
},
……

9080埠的出站路由規則由一個名稱為'9080'route_config定義。找一下這個route_config


……
'route_config': {
'name': '9080',
'virtual_hosts': [
{
'name': 'details.service.consul:9080',
'domains': [
'details.service.consul',
'details.service.consul:9080',
'details',
'details:9080',
'details.service',
'details.service:9080'
],
'routes': [
{
'match': {
'prefix': '/'
},
'route': {
'cluster': 'outbound|9080|v1|details.service.consul',
……
},
……
}
]
},
{
'name': 'productpage.service.consul:9080',
'domains': [
'productpage.service.consul',
'productpage.service.consul:9080',
'productpage',
'productpage:9080',
'productpage.service',
'productpage.service:9080'
],
'routes': [
{
'match': {
'prefix': '/'
},
'route': {
'cluster': 'outbound|9080|v1|productpage.service.consul',
……
},
……
}
]
},
……

由於內容太長,這裡只貼detailsproductpage的關鍵內容。可以看到,9080埠的出站流量會根據目標地址的域名正確地轉發到對應的微服務。


Istio路由控制


注意:本節工作目錄為/samples/bookinfo/platform/consul


最後我們嘗試一下Istio的路由控制能力。在配置路由規則之前,我們要先使用DestinationRule定義各個微服務的版本:


$ kubectl apply -f destination-rule-all.yaml


DestinationRule:DestinationRule定義了每個服務下按照某種策略分割的子集。在本例子中按照版本來分子集,reviews分為v1、v2、v3三個版本的子集,其他微服務都只有v1一個子集。



使用命令kubectl get destinationrules -o yaml可以檢視已配置的DestinationRule。


接下來我們使用VirtualService來配置路由規則。virtual-service-all-v1.yaml配置會讓所有微服務的流量都路由到v1版本。


$ kubectl apply -f virtual-service-all-v1.yaml


VirtualService:定義路由規則,按照這個規則決定每次請求服務應該將流量轉發到哪個子集。



使用命令kubectl get virtualservices -o yaml可以檢視已配置的VirtualService。


再重新整理頁面,現在不管重新整理多少次,reviews都會使用v1版本,也就是頁面不會顯示星星。


下面我們試一下基於使用者身份的路由規則。配置檔案virtual-service-reviews-test-v2.yaml配置了reviews的路由,讓使用者jason的流量路由到v2版本,其他情況路由到v1版本。


$ kubectl apply -f virtual-service-reviews-test-v2.yaml

執行命令後重新整理頁面,可以看到reviews都使用的v1版本,頁面不會顯示星星。點選右上角的Sign in按鈕,以jason的身份登入(密碼隨便),可以看到reviews切換到v2版本了,頁面顯示了黑色星星。


檢視virtual-service-reviews-test-v2.yaml檔案內容可以看到,基於身份的路由是按照匹配HTTP的headers實現的。當HTTP的headers有end-user: jason的內容時路由到v2版本,否則路由到v1版本。


apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews.service.consul
http:
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews.service.consul
subset: v2
- route:
- destination:
host: reviews.service.consul
subset: v1

幾點注意事項的總結



  1. istio.yaml引用的Registrator的latest版本不支援consul的ServiceMeta。要改為master版本。

  2. 第一次啟動istio.yaml後,因為啟動時pilot連不上istio-apiserverpilot會失敗退出。等待istio-apiserver啟動完畢後再跑一次istio.yaml

  3. 配置kubectlcontext,讓kubectl使用istio-apiserver提供的Kubernetes API介面。

  4. 使用bookinfo.yaml啟動各個微服務後,還要執行bookinfo.sidecar.yaml以初始化和啟動sidecar。


整體架構圖



參考資料