istio 是什麼
Istio 是一個開放原始碼的服務網格,它為基於微服務的應用程式提供了一種統一的方式來連線、保護、監控和管理服務。Istio 主要解決的是在微服務架構中的服務間通訊的複雜性問題,它透過提供服務間的負載均衡、服務到服務的認證、監控以及服務的彈性(例如重試、熔斷等)來實現。
sidecar 是什麼
sidecar 是一種設計模式,它將掛在業務容器旁邊作為輔助,當業務接受流量和傳出流量的時候,都先經過 sidecar 然後在到達業務容器或者發出。sidecar 可以看作是一個代理,或者是一個專門為我一個服務而工作的 gateway。這樣,服務的熔斷、限流、監控、日誌等功能都可以在 sidecar 中實現,而不需要在業務容器中實現。從而實現了業務容器的輕量化,只需要關注業務邏輯。
在 istio 中,sidecar 使用的是 envoy,envoy 是一個高效能的代理,它支援 http1.1, http2, grpc, tcp 等協議,支援負載均衡,熔斷,限流,監控等功能。envoy 是一個 c++ 專案,它的效能非常好。透過 istiod 控制平面,使用 grpc stream 的方式更新 envoy 的配置,從而實現了動態配置。
如果在 pod test 中訪問 test namespace 下的 nginx service,那麼流量會經過自己的 sidecar,然後到達 nginx 的 sidecar,最後到達 nginx 的容器。nginx 回覆同樣如此,先到達 sidecar,然後到達 test 的 sidecar,最後到達 test 的容器。
啟動方式
在 kubernetes 中,當 namespace 存在 istio-injection=enabled
label,那麼在該 namespace 中的 pod 在啟動的時候,istio 就會利用 mutating addmission webhook 的方式,自動修改 pod spec ,把 containers 中加入 sidecar 容器。當然,它也加入了一個 initcontainer,目的是做一些網路配置,能做到這個的原因是,kubernetes 的 pod 的多個 container 是使用同一個 linux network namespace, 所以 initcontainer 修改的網路配置對所有的 container 都生效。
流量劫持方式
在 test 訪問 nginx 的例子中,我們可以看到 nginx 的容器是啟動在 80 埠上的,流量也是訪問的 80, sidecar 是怎麼劫持到的呢?而且,在 test pod 中,我們訪問的是 nginx 的 service,流量又是怎麼劫持到 sidecar 的呢?
剛剛說過,pod 除了被插入了一個 sidecar 容器,還被插入了一個 initcontainer,我們啟動一個 nginx pod 和 service 看一下。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: test
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: test
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
kubectl create ns test
kubectl label namespace test istio-injection=enabled # 開啟 istio 注入
kubectl -n test apply -f nginx.yaml
現在我們看一下 nginx pod 被插入的 sidecar 和 initcontainer
## sidecar
- args:
- proxy
- sidecar
- --domain
- $(POD_NAMESPACE).svc.cluster.local
- --proxyLogLevel=warning
- --proxyComponentLogLevel=misc:error
- --log_output_level=default:info
# ...
## intcontainer
- args:
- istio-iptables
- -p
- "15001"
- -z
- "15006"
- -u
- "1337"
- -m
- REDIRECT
- -i
- '*'
- -x
- ""
- -b
- '*'
- -d
- 15090,15021,15020
- --log_output_level=default:info
可以看到,initcontainer 是自動執行了一系列的指令碼,這個指令碼我們並不知道是做啥的,但是從名字可以看出來是 iptables 的操作,那麼我們看一下 iptables 的規則
這裡我們容器內沒有 iptables,所以我們在宿主機上檢視 在nginx pod 所在的主機上檢視,先確定 nginx 這個container 的 pid。
# 從 pod 的 status 中的容器的 uid
kubectl get pod -n test nginx-7c79c4bf97-7985c -o jsonpath='{.status.containerStatuses[0].container
ID}'
docker://b0d6c9060661e0912a35d33ff220e67a628c9fc5300ca3c67dc30f9e40c9e0ce%
# 我這裡是用 docker 作為 container runtime 的
# 如果你是 containerd 的話 需要執行 ctr -n k8s.io info [container_id] |grep -i pod
docker inspect b0d6c9060661e0912a35d33ff220e67a628c9fc5300ca3c67dc30f9e40c9e0ce | grep -i pid # 在 nginx 所在的主機上執行
"Pid": 4652
# 在主機上使用 nseneter 進入容器的 network namespace 檢視 iptables 規則
nsenter -t 4652 -n -- iptables-save
# Warning: iptables-legacy tables present, use iptables-legacy-save to see them
# 說明這個容器使用的是 iptables-legacy 我們按提示執行
nsenter -t 4652 -n -- iptables-legacy-save
# Generated by iptables-save v1.8.7 on Sun May 12 05:53:29 2024
*nat
:PREROUTING ACCEPT [54:3240]
:INPUT ACCEPT [54:3240]
:OUTPUT ACCEPT [49:4198]
:POSTROUTING ACCEPT [49:4198]
:ISTIO_INBOUND - [0:0]
:ISTIO_IN_REDIRECT - [0:0]
:ISTIO_OUTPUT - [0:0]
:ISTIO_REDIRECT - [0:0]
# 所有入棧流量都走 ISTIO_INBOUND 鏈
-A PREROUTING -p tcp -j ISTIO_INBOUND
# 所有出棧流量都走 ISTIO_OUTPUT 鏈
-A OUTPUT -p tcp -j ISTIO_OUTPUT
# 忽略(也就是不劫持)目標埠是 15008 15090 15021 15020 的流量
# 15008:隧道埠 15090:prometheus 埠 15021:健康檢查 15020:管理埠
# 官方文件埠介紹 https://istio.io/latest/docs/ops/deployment/requirements/#ports-used-by-istio
-A ISTIO_INBOUND -p tcp -m tcp --dport 15008 -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
# 如果是 tcp 協議就走 ISTIO_IN_REDIRECT 鏈
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
# 如果是 tcp 就使用 dnat 把流量轉發到15006埠(也就是修改tcp的目標埠)也就是交給envoy處理
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
# 迴環地址 不處理
-A ISTIO_OUTPUT -s 127.0.0.6/32 -o lo -j RETURN
# 從 lo(迴環) 口出來的 目標不是本機 owner是 envoy(--uid-owner 1337) 目標埠是 15008 的 轉到 ISTIO_IN_REDIRECT 鏈處理
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -p tcp -m tcp ! --dport 15008 -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
# 從 lo 口出來的 owner 不是 envoy(不是 envoy 發出的) 不處理
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
# owner 是 envoy 的不處理 (不能劫持自己發出去的流量)
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
# 從 lo(迴環) 口出來的 目標不是本機 owner是 envoy(--gid-owner 1337) 目標埠是 15008 的 轉到 ISTIO_IN_REDIRECT 鏈處理
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -p tcp -m tcp ! --dport 15008 -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
# 從 lo(迴環) 口出來的 owner 不是 envoy 不處理
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
# owner 是 envoy 不處理
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
# 目標地址是 127.0.0.1 不處理
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
# 剩下轉到 ISTIO_REDIRECT 鏈
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
# 如果是 tcp 就使用 dnat 把流量轉發到 15001 埠(也就是修改tcp的目標埠)也就是交給envoy處理
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
COMMIT
# Completed on Sun May 12 05:53:29 2024
為什麼 --uid-owner 1337
和 --gid-owner 1337
就代表 owner 是 envoy 呢?
因為 envot (istio proxy) 是以 uid 和 gid 起來的。
kubectl get pod -n test nginx-7c79c4bf97-7985c -o jsonpath='{.spec.containers[1].name}'
istio-proxy
kubectl get pod -n test nginx-7c79c4bf97-7985c -o jsonpath='{.spec.containers[1].securityContext.ru
nAsGroup}'
1337
kubectl get pod -n test nginx-7c79c4bf97-7985c -o jsonpath='{.spec.containers[1].securityContext.runAsUser}'
1337
每個 pod 中的 iptables 都是一樣的,這樣我們就知道了 test pod 是怎麼劫持的,比如現在在 test pod container 中 curl nginx.test
首先查詢 dns nginx.test 對應的 ip 是 10.102.168.134
, 訪問也就是向 http://10.102.168.134:80
發請求。
- test pod 是發出去的包 所以 iptables 走 OUTPUT 鏈 http 是 tcp 協議的 所以走 ISTIO_OUTPUT 鏈
- 這個流量不是 lo 口的,目標地址不是 127.0.0.1, owner 也不是 envoy ,所以給 ISTIO_REDIRECT 鏈處理
- ISTIO_REDIRECT 中 我們是 tcp 所以 dnat 到埠 15001 (也就是 envoy)做處理
- test envoy gateway 會轉發到
http://10.244.0.73:80(pod ip)
(具體是怎麼轉發的後續會介紹到) - 流量是進入到 nginx pod 中 所以 iptables 的 PREROUTING 鏈 http 是 tcp 協議的,所以走 ISTIO_INBOUND 鏈
- 目標埠是 80 不是15008 15090 15021 15020 所以走 ISTIO_IN_REDIRECT 鏈
- ISTIO_IN_REDIRECT 會 dnat 到埠 15006 也就是 envoy 做處理
- envoy 會轉發到自己的 nginx container 容器中 (具體是怎麼轉發的後續會介紹到)
所以可以看到,流量從 test pod 的 test container 出來之後,會被自己的 envoy(istio-proxy sidecar) 劫持,然後7層轉發到 10.244.0.73 (nigix pod IP地址)。然後 nginx pod 中的 envoy container 會劫持這個流量交給自己,然後7層代理到 nginx container。流量回復回去是一個道理。
xDS
在上方的流程中 test envoy 劫持到 http://10.102.168.134:80
會轉發到 http://10.244.0.73:80
,那麼他是怎麼知道要轉發到這裡去的呢?如果是 nginx 我們會配置 upstream,然後執行 nginx -s reload
,這是 nginx 不支援動態載入方式。envoy 是支援動態載入的,對外提供 API,我們呼叫 API 就可以動態的修改配置。這個 API 就是 xDS API。它包括了以下API:
- CDS(Cluster Discovery Service): 用於發現叢集資訊,比如叢集的名字,叢集的地址等。
- EDS(Endpoint Discovery Service): 用於發現叢集中的 endpoint 資訊,比如叢集中的服務的地址,埠等。
- LDS(Listener Discovery Service): 用於發現監聽器資訊,比如監聽器的名字,監聽器的地址等。
- RDS(Route Discovery Service): 用於發現路由資訊,比如路由的名字,路由的規則等。
- SDS(Secret Discovery Service): 用於發現證書資訊,比如證書的名字,證書的內容等。
- HDS(Health Discovery Service): 用於發現健康檢查資訊,比如健康檢查的名字,健康檢查的規則等。
- ADS(Aggregated Discovery Service): 用於聚合以上所有的服務,提供一個統一的服務。
listener + route 是用來表達監聽哪個埠和哪些路由的,是 envoy 進入流量的入口。cluster + endpoint 是用來表達叢集和叢集中的服務的,是 envoy 轉發流量的目的地。
資料來源
那這些 xDS 的配置來自哪呢?
這些 envoy 配置都來自於 istiod,istiod 是 istio 的控制平面,它會使用 grpc stream 的方式,動態的更新 envoy 的配置。istiod 會監聽 kubernetes 的資源變化,比如 service, endpoint 和 istio 自己 CRD 等,組合成一個配置,然後定時的推送給 envoy。這樣就實現了動態配置。
比如我們這個 service 的配置,檢視 service 和 endpoints 就知道 service clusterIp 對應的 pod ip。
kubectl -n test get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.102.168.134 <none> 80/TCP 112m
kubectl -n test get endpoints nginx
NAME ENDPOINTS AGE
nginx 10.244.0.73:80 112m
這樣我們就知道了 nginx service 對應的 clusterIp 是 10.102.168.134
, 而對應的 pod ip 是 10.244.0.73
。然後 istiod 把這個配置推送給所有 sidecar,這樣 test pod 中的 envoy 就知道了要把流量轉發到 10.244.0.73
了。
流量流程圖
在 test pod 的 test 容器中 執行 curl http://nginx.test
流量的流程圖如下
配置檢視
我們可以透過呼叫 pod 中的 envoy 的 admin api 來檢視配置
kubectl port-forward pod/nginx-7c79c4bf97-7985c 15000:15000
curl http://localhost:15000/config_dump
列印出的 json 格式的配置檔案,它而很大看起來很不方便,幸好 istio 給我們提供了一個工具 istioctl,我們可以使用 istioctl 來檢視配置。
因為我們流量是從 test pod 到 nginx pod,所以所限我們檢視 test pod 中的 envoy 的配置。
1.首先我們看下 listerner 15001 的配置 因為從 iptables 我們知道 出去的流量會被劫持到 15001
istioctl -n test proxy-config listener test-f5b5d48b5-qdzft --port 15001
ADDRESSES PORT MATCH DESTINATION
0.0.0.0 15001 ALL PassthroughCluster
0.0.0.0 15001 Addr: *:15001 Non-HTTP/Non-TCP
首先會監聽 15001 埠,這個是真是監聽的埠。它會轉發到虛擬埠(Virtual Port),虛擬埠不會真是監聽作業系統埠,它只是envoy的邏輯埠。那我們怎麼知道流量轉發到哪個虛擬埠了?請求的埠是什麼,就轉發到哪個了。比如我們請求的是 nginx 80 埠,就會轉發到 80 虛擬埠
2.檢視 listener 的虛擬埠,nginx service ip 10.102.168.134 prot 80
istioctl -n test proxy-config listener test-f5b5d48b5-qdzft --port 80 --address 10.102.168.134
ADDRESSES PORT MATCH DESTINATION
10.102.168.134 80 Trans: raw_buffer; App: http/1.1,h2c Route: nginx.test.svc.cluster.local:80
10.102.168.134 80 ALL Cluster: outbound|80||nginx.test.svc.cluster.local
第一條是明文而且是 http/1.1 或者 h2c 無加密的 http/2)協議的流量會被轉發到 nginx.test.svc.cluster.local:80
3.檢視 route 配置
istioctl -n test proxy-config route test-f5b5d48b5-qdzft |grep nginx.test.svc.cluster.local
nginx.test.svc.cluster.local:80 nginx.test.svc.cluster.local:80 * /*
80 nginx.test.svc.cluster.local:80 nginx, nginx.test + 1 more... /*
這裡我們沒有指定 host 所以走第一條
# istioctl -n test proxy-config route test-f5b5d48b5-qdzft --name nginx.test.svc.cluster.local:80 -oyaml
- ignorePortInHostMatching: true
maxDirectResponseBodySizeBytes: 1048576
name: nginx.test.svc.cluster.local:80
validateClusters: false
virtualHosts:
- domains:
- '*'
includeRequestAttemptCount: true
name: nginx.test.svc.cluster.local:80
routes:
- decorator:
operation: nginx.test.svc.cluster.local:80/*
match:
prefix: /
name: default
route:
cluster: outbound|80||nginx.test.svc.cluster.local
maxGrpcTimeout: 0s
retryPolicy:
hostSelectionRetryMaxAttempts: "5"
numRetries: 2
retriableStatusCodes:
- 503
retryHostPredicate:
- name: envoy.retry_host_predicates.previous_hosts
typedConfig:
'@type': type.googleapis.com/envoy.extensions.retry.host.previous_hosts.v3.PreviousHostsPredicate
retryOn: connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes
timeout: 0s
可以看到,match 的路由是 prefix 是 /,也就是所有的請求都會走這個路由,這個路由會把流量轉發到 outbound|80||nginx.test.svc.cluster.local
這個 cluster 中。
4.我們檢視 cluster
# istioctl -n test proxy-config cluster test-f5b5d48b5-qdzft --fqdn "outbound|80||nginx.test.svc.cluster.local" -oyaml
- circuitBreakers:
thresholds:
- maxConnections: 4294967295
maxPendingRequests: 4294967295
maxRequests: 4294967295
maxRetries: 4294967295
trackRemaining: true
commonLbConfig:
localityWeightedLbConfig: {}
connectTimeout: 10s
edsClusterConfig:
edsConfig:
ads: {}
initialFetchTimeout: 0s
resourceApiVersion: V3
serviceName: outbound|80||nginx.test.svc.cluster.local
filters:
- name: istio.metadata_exchange
typedConfig:
'@type': type.googleapis.com/udpa.type.v1.TypedStruct
typeUrl: type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange
value:
enable_discovery: true
protocol: istio-peer-exchange
lbPolicy: LEAST_REQUEST
metadata:
filterMetadata:
istio:
services:
- host: nginx.test.svc.cluster.local
name: nginx
namespace: test
name: outbound|80||nginx.test.svc.cluster.local
transportSocketMatches:
- match:
tlsMode: istio
name: tlsMode-istio
transportSocket:
name: envoy.transport_sockets.tls
typedConfig:
'@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
commonTlsContext:
alpnProtocols:
- istio-peer-exchange
- istio
combinedValidationContext:
defaultValidationContext:
matchSubjectAltNames:
- exact: spiffe://cluster.local/ns/test/sa/default
validationContextSdsSecretConfig:
name: ROOTCA
sdsConfig:
apiConfigSource:
apiType: GRPC
grpcServices:
- envoyGrpc:
clusterName: sds-grpc
setNodeOnFirstMessageOnly: true
transportApiVersion: V3
initialFetchTimeout: 0s
resourceApiVersion: V3
tlsCertificateSdsSecretConfigs:
- name: default
sdsConfig:
apiConfigSource:
apiType: GRPC
grpcServices:
- envoyGrpc:
clusterName: sds-grpc
setNodeOnFirstMessageOnly: true
transportApiVersion: V3
initialFetchTimeout: 0s
resourceApiVersion: V3
tlsParams:
tlsMaximumProtocolVersion: TLSv1_3
tlsMinimumProtocolVersion: TLSv1_2
sni: outbound_.80_._.nginx.test.svc.cluster.local
- match: {}
name: tlsMode-disabled
transportSocket:
name: envoy.transport_sockets.raw_buffer
typedConfig:
'@type': type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer
type: EDS
typedExtensionProtocolOptions:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
'@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
useDownstreamProtocolConfig:
http2ProtocolOptions: {}
httpProtocolOptions: {}
可以看到,這個 cluster 是一個 EDS 型別的 cluster,它會從 edsConfig 中獲取配置。
5.檢視 endpoint
# istioctl -n test proxy-config endpoint test-f5b5d48b5-qdzft --cluster "outbound|80||nginx.test.svc.cluster.local" -oyaml
- addedViaApi: true
circuitBreakers:
thresholds:
- maxConnections: 4294967295
maxPendingRequests: 4294967295
maxRequests: 4294967295
maxRetries: 4294967295
- maxConnections: 1024
maxPendingRequests: 1024
maxRequests: 1024
maxRetries: 3
priority: HIGH
edsServiceName: outbound|80||nginx.test.svc.cluster.local
hostStatuses:
- address:
socketAddress:
address: 10.244.0.73
portValue: 80
healthStatus:
edsHealthStatus: HEALTHY
locality: {}
stats:
- name: cx_connect_fail
- name: cx_total
- name: rq_error
- name: rq_success
- name: rq_timeout
- name: rq_total
- name: cx_active
type: GAUGE
- name: rq_active
type: GAUGE
weight: 1
name: outbound|80||nginx.test.svc.cluster.local
observabilityName: outbound|80||nginx.test.svc.cluster.local
從 endpoint 中我們可以看到,流量會轉發到 10.244.0.73:80
這個地址。因為我們這個 service 只有一個 pod,如果多個 pod 的話,會有多個 address。
envoy 會向訪問 http://10.244.0.73:80
,那麼接下來就是 nginx pod 中的 envoy 會把流量轉發到 nginx container 中。
6.server 劫持到15006
istioctl -n test proxy-config listener nginx-7c79c4bf97-7985c --port 15006
ADDRESSES PORT MATCH DESTINATION
0.0.0.0 15006 Addr: *:15006 Non-HTTP/Non-TCP
0.0.0.0 15006 Trans: tls; App: istio-http/1.0,istio-http/1.1,istio-h2; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: raw_buffer; App: http/1.1,h2c; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; App: TCP TLS; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: raw_buffer; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; Addr: 0.0.0.0/0 InboundPassthroughClusterIpv4
0.0.0.0 15006 Trans: tls; App: istio-http/1.0,istio-http/1.1,istio-h2; Addr: *:80 Cluster: inbound|80||
0.0.0.0 15006 Trans: raw_buffer; App: http/1.1,h2c; Addr: *:80 Cluster: inbound|80||
0.0.0.0 15006 Trans: tls; App: TCP TLS; Addr: *:80 Cluster: inbound|80||
0.0.0.0 15006 Trans: raw_buffer; Addr: *:80 Cluster: inbound|80||
0.0.0.0 15006 Trans: tls; Addr: *:80 Cluster: inbound|80||
listener 的虛擬埠
istioctl -n test proxy-config listener nginx-7c79c4bf97-7985c --port 80 --address 0.0.0.0
ADDRESSES PORT MATCH DESTINATION
0.0.0.0 80 Trans: raw_buffer; App: http/1.1,h2c Route: 80
0.0.0.0 80 ALL PassthroughCluster
所以 DESTINATION 是 Route: 80
,所以 route 會匹配 inbound|80||
7.檢視 server route
# istioctl -n test proxy-config route nginx-7c79c4bf97-7985c --name "inbound|80||" -oyaml
- name: inbound|80||
validateClusters: false
virtualHosts:
- domains:
- '*'
name: inbound|http|80
routes:
- decorator:
operation: nginx.test.svc.cluster.local:80/*
match:
prefix: /
name: default
route:
cluster: inbound|80||
maxStreamDuration:
grpcTimeoutHeaderMax: 0s
maxStreamDuration: 0s
timeout: 0s
- name: inbound|80||
validateClusters: false
virtualHosts:
- domains:
- '*'
name: inbound|http|80
routes:
- decorator:
operation: nginx.test.svc.cluster.local:80/*
match:
prefix: /
name: default
route:
cluster: inbound|80||
maxStreamDuration:
grpcTimeoutHeaderMax: 0s
maxStreamDuration: 0s
timeout: 0s
會匹配到 cluster inbound|80||
,它是 inbound 型別的 route, 所以它會直接把流量轉發到 80 埠。也就是 pod 中 nginx container 中的 nigix 程序。
7.回覆
當 nginx 把靜態資源回覆給 test 的時候,流量的方式和請求的時候是一樣的,只是方向相反。