我是 LEE,老李,一個(gè)在 IT 行業(yè)摸爬滾打 16 年的技術(shù)老兵。
事件背景
忙完了公司的雙 11 項(xiàng)目后,整個(gè)公司的大項(xiàng)目基本都結(jié)束了。整個(gè)生產(chǎn)系統(tǒng)進(jìn)入了一年一度的維護(hù)和升級(jí)階段,那么主要底層系統(tǒng)也進(jìn)入了版本更新和維護(hù)的階段。寫一篇文章的目的是解決前幾個(gè)星期我們要對(duì)承載租戶流量的服務(wù)網(wǎng)格 Istio 做整體升級(jí),但是翻閱了整個(gè)網(wǎng)絡(luò)資料后,發(fā)現(xiàn)沒有一篇完整的能夠提供 Istio 平滑升級(jí)的文章以及可行的操作手冊的問題。所以決定根據(jù)自己在實(shí)際工作中碰到的問題以及實(shí)際操作整理一篇文章,希望能夠?qū)ζ渌谑褂?Istio 的小伙伴提供一種“無損平滑”升級(jí)的技術(shù)參考。
升級(jí)要求
- 租戶應(yīng)用與服務(wù)不能中斷。
- 租戶在升級(jí)期間能夠正常使用原有系統(tǒng),對(duì)升級(jí)無感。
- 升級(jí)過程支持平滑回退,有完善的過濾流程和時(shí)間。
- 方案可持續(xù),對(duì) Istio 系統(tǒng)沒有侵入,利用社區(qū)內(nèi)資源和資料。
- 操作可規(guī)范和流程化,方便后續(xù)人參考和使用。
有了上面的升級(jí)要求,那么我們也就有尋求“無損平滑”解決方案的需求,但是事實(shí)總是殘酷的,沒有找到復(fù)合我們需要的方案,哪怕官方文檔提供的升級(jí)方案都是有損的。我就很擔(dān)心如果按照現(xiàn)在網(wǎng)絡(luò)提供的資料和信息制作升級(jí)方案和操作 SOP,滿足不了升級(jí)要求。怎么辦?看來不得不有一次技術(shù)攻堅(jiān)、方案設(shè)計(jì)、可行性驗(yàn)證了。我想要平滑升級(jí) Istio,那么就要回到源頭,研究 Istio 的結(jié)構(gòu),制定真正可行的方案。
廢話不多說,我們一起進(jìn)入“技術(shù)探索”環(huán)節(jié)。
技術(shù)探索
既然要制定 Istio “無損平滑”升級(jí)方案,就要知道為什么 Istio 升級(jí)會(huì)有損。有一種頭痛醫(yī)頭,腳痛醫(yī)腳的感覺,這個(gè)是最有效的辦法,不妨我們耐心繼續(xù)往下看。
我們先看下 Istio 的架構(gòu)簡圖:

實(shí)際 Pod 的 sidecar 和 IngressGateway 底層都是 Envoy,都是通過 Istiod 分發(fā)的 Dynamic config,也就是這些 envoy 都是注冊在 Istiod 上的,由 Istiod 統(tǒng)一管理。
補(bǔ)充說明:Istio sidecar 注入是因?yàn)?MutatingWebhookConfigurations 的配置。在擁有 label 為 istio-injection=enabled 的 namespace 中創(chuàng)建 pod 會(huì)自動(dòng)注入 pod 啟動(dòng)中。
我們做一個(gè)假設(shè),現(xiàn)在生產(chǎn)的 Istio 版本是 1.7,然后再把 Istio 版本升級(jí)到了 1.11 這個(gè)版本。 Istiod 版本發(fā)生了變化,Istiod 版本成為了 1.11,而業(yè)務(wù) Pod 的 sidecar 版本還是 1.7,怎么辦?
小伙伴第一反應(yīng)就是重啟 pod,讓業(yè)務(wù) Pod 的 sidecar 重新注冊到 1.11 上,看上去是那么回事,但是別忘了,你重啟了業(yè)務(wù) Pod,租戶的請(qǐng)求此時(shí)因?yàn)橹貑?huì)出現(xiàn)中斷或者服務(wù)不可用的情況。如果我不重啟業(yè)務(wù) Pod,就讓 1.7 的 Pod sidecar 連接 1.11 的 Istiod 不就好了,事實(shí)真的是你想的嗎? No,No,No,太天真。 Pod sidecar 會(huì)因?yàn)榘姹静患嫒?,丟失配置,導(dǎo)致 Pod 因?yàn)榻】当O(jiān)測失敗而重啟。

由于 Istio sidecar 的配置丟失。如果你的 Istio-agent sidecar 無法與 Istiod 通信,或與發(fā)送的配置不兼容,你的工作負(fù)載將無法加入網(wǎng)格或與網(wǎng)格通信。這甚至?xí)绊懍F(xiàn)有的工作負(fù)載,導(dǎo)致你可能會(huì)嘗試訪問不再存在的工作負(fù)載,新的工作負(fù)載也將無法加入。
TIPS: 由于這種類型的中斷,建議 istio-agents 匹配并保留與控制平面 (Istiod) 相同的版本。在升級(jí)過程中,現(xiàn)有的控制平面部署保持原位而不是直接升級(jí)。
如果有小伙伴想探索究竟,可以參閱我之前公開的資料 《Istio Pilot 結(jié)構(gòu)解析 PPT (已脫敏)》
既然有直接升級(jí)不行,而且會(huì)斷流,有沒有其他的解決方案呢?
有,灰度升級(jí)。官方文檔:https://istio.io/latest/docs/setup/upgrade/canary/
但是這個(gè)就是真的我們想要的嗎?不。在官方文檔中有這么一步操作:
After the namespace updates, you need to restart the pods to trigger re-injection. One way to do this is using:
$ kubectl rollout restart deployment -n test-ns
看到這里,很多人跟我一樣,木了。。。 重啟 pod ? 真實(shí)生產(chǎn)環(huán)境,你去重啟生產(chǎn) pod?就因?yàn)?Istio 軟件升級(jí)? 這個(gè)是平滑升級(jí)方案?技術(shù)委員會(huì)能通過你的方案? 這么多問號(hào)都擺在面前,那么我們該怎么做? 不著急, 我們一起進(jìn)入“技術(shù)方案”環(huán)節(jié)。
技術(shù)方案
技術(shù)挑戰(zhàn)
- 直接升級(jí) Istio 會(huì)導(dǎo)致 Istio-agent sidecar 與 Istiod 不兼容,最后導(dǎo)致業(yè)務(wù) Pod 重啟。
- 為了保證 Istio-agent 和 Istiod 之間的兼容性,必須要手動(dòng)重啟業(yè)務(wù) Pod。
- 系統(tǒng)需要平滑過渡和升級(jí),業(yè)務(wù) Pod 非到不必要,絕對(duì)不能重啟。
其中 1,2 和 3 點(diǎn)之間是相悖的。
方案猜想
- Istio-agent sidecar 與 Istiod 兼容問題,可不可以老版本的 Istio-agent sidecar 與 Istiod 連接,新版本的 Istio-agent sidecar 與 Istiod 連接?
- 如果各個(gè)版本的 Istio-agent sidecar 與 Istiod 連接,如何讓老版本的 sidecar 的業(yè)務(wù) pod 自然過渡到新版本的 sidecar 上?
- 如何保證真正的“無損平滑”升級(jí)?
解決方式
帶著這么多問題和技術(shù)挑戰(zhàn),當(dāng)時(shí)確實(shí)真的把我難道了,但是經(jīng)過差不多的 2 周的左右的方案設(shè)計(jì)以及技術(shù)驗(yàn)證,發(fā)現(xiàn)是完全可以做到真正的“無損平滑”升級(jí)的。那么在這里我就分享下當(dāng)時(shí)我的思考方式和定位方案的過程。
兼容問題
這個(gè)問題好辦,創(chuàng)建兩個(gè)獨(dú)立的 Istio 系統(tǒng)在一個(gè) k8s 中,只需要在 istioctl 新安裝的 Istio 加入一個(gè)參數(shù) --set revision=xxx。 istioctl 安裝時(shí)候就不會(huì)覆蓋原有的 Istio 版本,而是啟用一個(gè)全新的控制面和部分?jǐn)?shù)據(jù)面(為什么是部分,后面會(huì)看到)。這樣我們就很好的做到了老版本的 Istio-agent sidecar 與 Istiod 連接,新版本的 Istio-agent sidecar 與 Istiod 連接。
過渡問題
首先我們不能手動(dòng)重啟正在運(yùn)行的業(yè)務(wù) Pod,但是不代表業(yè)務(wù) Pod 不會(huì)迭代和發(fā)版,只要他們重新發(fā)版,Pod 自然就完成了重啟。只要經(jīng)過一段足夠長的時(shí)間就能讓使用老版本的 sidecar 的業(yè)務(wù) pod 自然過渡到新版本的 sidecar 上。
說到這里,有小伙伴覺得還是沒有說到重點(diǎn),那么我覺得有必要來看看 MutatingWebhookConfigurations 的配置。
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
annotations:
creationTimestamp: "2022-11-30T10:41:51Z"
generation: 5
labels:
app: sidecar-injector
install.operator.istio.io/owning-resource: installed-state
install.operator.istio.io/owning-resource-namespace: istio-system
istio.io/rev: default
operator.istio.io/component: Pilot
operator.istio.io/managed: Reconcile
operator.istio.io/version: 1.7.8
release: istio
name: istio-sidecar-injector
resourceVersion: "9640"
selfLink: /apis/admissionregistration.k8s.io/v1/mutatingwebhookconfigurations/istio-sidecar-injector
uid: b66c986a-9ad9-469f-bf14-eea3df74c876
webhooks:
- admissionReviewVersions:
- v1beta1
- v1
clientConfig:
caBundle: <Secret>
service:
name: istiod ## 這里很重要,就是在 Pod 創(chuàng)建時(shí)候,訪問 k8s istiod service 的 443 端口,然后注冊自己,然后拉取 sidecar 啟動(dòng)配置
namespace: istio-system
path: /inject
port: 443
failurePolicy: Fail
matchPolicy: Exact
name: sidecar-injector.istio.io
namespaceSelector:
matchLabels:
istio-injection: enabled
objectSelector: {}
reinvocationPolicy: Never
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE ## 創(chuàng)建動(dòng)作
resources:
- pods ## 只關(guān)注 Pod
scope: "*"
sideEffects: None
timeoutSeconds: 30
(★) 在此看到 yaml 文件中 service 字段下有一個(gè) name 為 istiod,我們只要把這個(gè)值改成新版本的 Istiod 的 service 名稱即可。 就可以讓重啟的 Pod 使用新版本的 Istio sidecar 啟動(dòng)了。
舉個(gè)栗子:
[root@localhost ops]# kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.126.118.148 10.111.251.17 15021:30082/TCP,80:30080/TCP 2d21h
istiod ClusterIP 10.126.118.150 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP,853/TCP 2d21h
istiod-1-11-8 ClusterIP 10.126.118.241 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 2d21h
這里我已經(jīng)安裝了一個(gè) 1.11.8 的新版本的 Istio 與老版本的并行,相互不沖突。 修改 MutatingWebhookConfiguration 中配置 sevice name 為 istiod-1-11-8,隨后通過模擬“發(fā)布”新版本的應(yīng)用,重啟了業(yè)務(wù) Pod,讓其注冊到了新版本的 Istio 上。
[root@localhost 1.11.8]# istioctl proxy-status
NAME CDS LDS EDS RDS ISTIOD VERSION
istio-ingressgateway-59b5b798d4-v9d98.istio-system SYNCED SYNCED SYNCED SYNCED istiod-1-11-8-866bf44db-2wbqx 1.11.8
nginx-app-7b88698d6f-brhc4.nginx SYNCED SYNCED SYNCED SYNCED istiod-1-11-8-866bf44db-2wbqx 1.11.8
nginx-app-7b88698d6f-jhwr8.nginx2 SYNCED SYNCED SYNCED SYNCED istiod-879f4d9bf-c5xz6 1.7.8
這個(gè)時(shí)候讓我們將目光關(guān)注到 VERSION 這個(gè)字段下,我們發(fā)現(xiàn) nginx-app-7b88698d6f-jhwr8.nginx2 這個(gè) Pod 還是在使用版本 Istio 1.7 并與老的 istiod-879f4d9bf-c5xz6 建立著連接。而 nginx-app-7b88698d6f-brhc4.nginx 這個(gè) Pod 在重啟后就與新版本 Istio 1.11 的 istiod-1-11-8-866bf44db-2wbqx 建立著連接。
到了這里基本上我們實(shí)現(xiàn)了 Istio 平滑升級(jí),通過自然迭代的方式重啟 Pod,緩慢遷移到新版本 Istio 上。
平穩(wěn)過渡
- 新版本 Istio 使用灰度安裝升級(jí)的方式部署
- 切換 Istio sidecar 注冊方式 (MutatingWebhookConfiguration)
- 等待業(yè)務(wù) Pod 自然迭代重啟,如果長期沒有切換重啟的 Pod,可以組織適當(dāng)?shù)耐C(jī)時(shí)間,完成切換
- 卸載老版本 Istio
實(shí)操步驟
安裝新版 Istio
演示的 operator.yaml 文件內(nèi)容
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
accessLogFile: /dev/stdout
accessLogEncoding: JSON
outboundTrafficPolicy:
mode: REGISTRY_ONLY
defaultConfig:
holdApplicationUntilProxyStarts: true
components:
ingressGateways:
- name: istio-ingressgateway
enabled: true
k8s:
service:
ports:
- port: 15021
targetPort: 15021
nodePort: 30082
name: status-port
- port: 80
targetPort: 8080
nodePort: 30080
name: http2
values:
global:
proxy:
excludeIPRanges: "10.126.118.0/24"
gateways:
istio-ingressgateway:
type: LoadBalancer
autoscaleMin: 1
autoscaleMax: 3
resources:
requests:
cpu: 1500m
memory: 1Gi
limits:
cpu: "4"
memory: 8Gi
addonComponents:
prometheus:
enabled: false
執(zhí)行命令:
# istioctl install -f operator.yaml -s revision=1-11-8
切換注冊到新版 Istio
切換 MutatingWebhookConfigurations ,完成 Namespace 中 Pod 啟動(dòng)自動(dòng)注入 Sidecar 到 1.11.8 上,而不是用老的 1.7.8 (其中 istiod-1-11-8 是 k8s service 的名稱,可以通過 kubectl get svc 獲得)
執(zhí)行命令:
# kubectl get mutatingwebhookconfigurations -n istio-system istio-sidecar-injector -o json | jq '.webhooks[0].clientConfig.service.name="istiod-1-11-8"' | kubectl replace -f -
(可選)卸載老版本 Istio
直接卸載可能導(dǎo)致默認(rèn)的 mutatingwebhookconfigurations 配置丟失,所以這里要注意有備份和恢復(fù)。
備份 MutatingWebhookConfigurations 配置
# kubectl get mutatingwebhookconfigurations -n istio-system istio-sidecar-injector -o yaml > /tmp/mutatingwebhookconfigurations.backup.yaml
刪除老版本的 Istio
# istioctl x uninstall -f operator.yaml
恢復(fù) MutatingWebhookConfigurations 配置
# kubectl apply -f /tmp/mutatingwebhookconfigurations.backup.yaml
最終效果
這里通過模擬集群演示來展現(xiàn)我們線上遷移整體效果,方法是一致的。
并行狀態(tài)
[root@localhost 1.11.8]# istioctl proxy-status
NAME CDS LDS EDS RDS ISTIOD VERSION
istio-ingressgateway-59b5b798d4-v9d98.istio-system SYNCED SYNCED SYNCED SYNCED istiod-1-11-8-866bf44db-2wbqx 1.11.8
nginx-app-7b88698d6f-brhc4.nginx SYNCED SYNCED SYNCED SYNCED istiod-1-11-8-866bf44db-2wbqx 1.11.8
nginx-app-7b88698d6f-jhwr8.nginx2 SYNCED SYNCED SYNCED SYNCED istiod-879f4d9bf-c5xz6 1.7.8
日志檢測
已經(jīng)遷移到新版本 Istio 的業(yè)務(wù) Pod 日志
[root@localhost 1.11.8]# kubectl logs -n nginx nginx-app-7b88698d6f-brhc4
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/12/02 07:34:59 [notice] 1#1: using the "epoll" event method
2022/12/02 07:34:59 [notice] 1#1: nginx/1.23.2
2022/12/02 07:34:59 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2022/12/02 07:34:59 [notice] 1#1: OS: Linux 5.18.19-051819-generic
2022/12/02 07:34:59 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 64000:64000
2022/12/02 07:34:59 [notice] 1#1: start worker processes
2022/12/02 07:34:59 [notice] 1#1: start worker process 29
2022/12/02 07:34:59 [notice] 1#1: start worker process 30
2022/12/02 07:34:59 [notice] 1#1: start worker process 31
2022/12/02 07:34:59 [notice] 1#1: start worker process 32
2022/12/02 07:34:59 [notice] 1#1: start worker process 33
2022/12/02 07:34:59 [notice] 1#1: start worker process 34
2022/12/02 07:34:59 [notice] 1#1: start worker process 35
2022/12/02 07:34:59 [notice] 1#1: start worker process 36
127.0.0.6 - - [02/Dec/2022:08:02:46 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:46 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:47 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:48 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:48 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:49 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:49 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:50 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:50 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:51 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:51 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.6 - - [02/Dec/2022:08:02:52 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
繼續(xù)使用老版本 Istio 的業(yè)務(wù) Pod 日志
[root@localhost 1.11.8]# kubectl logs -n nginx2 nginx-app-7b88698d6f-jhwr8 -c app
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/11/30 11:22:37 [notice] 1#1: using the "epoll" event method
2022/11/30 11:22:37 [notice] 1#1: nginx/1.23.2
2022/11/30 11:22:37 [notice] 1#1: built by gcc 10.2.1 20210110 (Debian 10.2.1-6)
2022/11/30 11:22:37 [notice] 1#1: OS: Linux 5.4.185-1.el7.elrepo.x86_64
2022/11/30 11:22:37 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 64000:64000
2022/11/30 11:22:37 [notice] 1#1: start worker processes
2022/11/30 11:22:37 [notice] 1#1: start worker process 28
2022/11/30 11:22:37 [notice] 1#1: start worker process 29
2022/11/30 11:22:37 [notice] 1#1: start worker process 30
2022/11/30 11:22:37 [notice] 1#1: start worker process 31
2022/11/30 11:22:37 [notice] 1#1: start worker process 32
2022/11/30 11:22:37 [notice] 1#1: start worker process 33
2022/11/30 11:22:37 [notice] 1#1: start worker process 34
2022/11/30 11:22:37 [notice] 1#1: start worker process 35
127.0.0.1 - - [03/Dec/2022:08:31:17 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.1 - - [03/Dec/2022:08:31:18 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.1 - - [03/Dec/2022:08:31:19 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.1 - - [03/Dec/2022:08:31:20 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.1 - - [03/Dec/2022:08:31:20 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.1 - - [03/Dec/2022:08:31:21 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.1 - - [03/Dec/2022:08:31:21 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.1 - - [03/Dec/2022:08:31:22 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.1 - - [03/Dec/2022:08:31:23 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
127.0.0.1 - - [03/Dec/2022:08:31:23 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "10.11.251.5"
通過上面的日志,我們可以確認(rèn),兩套 Istio 已經(jīng)完成并行,而且兩個(gè)應(yīng)用 Pod 請(qǐng)求相應(yīng)正常。