Service Mesh 到底解决什么问题?从请求链路到 Istio 灰度、mTLS 与故障排查

同一个接口,Java 服务重试三次,Go 服务重试一次,另一个服务干脆没有超时。新版本想先放一点流量,客户端却各自维护地址。出了故障,应用日志都说“下游调用失败”,链路到哪一跳开始慢,没人能马上对齐。

这才是 Service Mesh 值得讨论的现场。它把服务间通信的一部分共性能力放到基础设施里,让不同语言的服务使用相近的流量规则、身份机制和观测入口。

但我不会因为 Pod 多了一个代理,就宣布治理完成。流量有没有经过代理、身份有没有被验证、调用链有没有串起来,都要逐项核验;配置写进 Kubernetes,也不等于每个代理已经收到并执行。

Service Mesh 统一的是通信规则,应用仍要对业务语义负责。 下面把架构、适用边界和一个可复现的 Istio 实验接起来,读完能知道怎么配置,也能知道配置失败该往哪查。

一次请求怎么走,控制面在哪里?

Service Mesh 是治理服务间通信的基础设施层,常用于处理微服务的东西向流量。在典型 Istio sidecar 模式下,被纳入网格的工作负载旁有 Envoy 代理。

应用发起请求,代理根据配置处理路由、连接、超时、重试、加密等,再把请求送往接收端代理和应用。

应用 A → 代理 A → 代理 B → 应用 B
          ↑         ↑
          └── istiod 下发配置、身份材料等 ──┘

Envoy 是这个模式的数据面,istiod 是控制面。两者的区别可以理解为:

  • 数据面处理实际请求:转发流量、选择上游、执行访问控制、产生通信指标。
  • 控制面管理规则和身份:发现服务、生成并下发代理配置、参与工作负载证书管理。

正常请求沿数据面传输,不需要每次先去问 istiod。控制面不可用时,已配置代理通常还能使用最后收到的配置继续处理流量,但新 Pod 获取配置、端点变化、规则更新、证书轮换等可能受影响。

所以,“老请求还通”不能证明控制面健康。

Mesh 不必都用 sidecar。Istio ambient 模式以 ztunnel 提供四层安全与连接能力,需要七层治理时可使用 waypoint。两种模式的流量路径、能力落点和排障方法不同,本文的实验只讨论 sidecar。

代理也不是天然接管所有流量。实际捕获范围、排除端口/IP、hostNetwork、注入与平台配置都会影响路径;绕过代理的流量不自动得到同样的治理。

手工在 Pod YAML 里增加一个 istio-proxy 容器,也不等于完成网格接入。完整注入还涉及代理启动配置、工作负载身份、网络重定向等;网络重定向可能由初始化容器或平台部署的 Istio CNI 配合完成。

我会用这张表划清职责:

能力通常解决的问题需要另外解决的问题
Kubernetes Service 与具体 kube-proxy/CNI 实现服务发现、稳定访问地址、四层连接选择按 HTTP 请求进行版本灰度、工作负载身份授权
Service Mesh纳管通信的身份、流量与观测治理业务幂等、业务权限、应用内部计算与数据库瓶颈
API 网关常见于北南入口路由、认证、限流等内部服务每一跳的通信治理,具体能力取决于实现

这些职责会交叉,关键是规则由谁拥有、在哪里生效。

Istio Gateway 能处理特定入口流量,但不等于完整 API 管理平台。开发者门户、API 产品管理、计费和业务认证等,需要根据系统需求补充。

还要分清应用 TLS 与 mesh mTLS:后者在代理之间加密原本的 HTTP,代理仍可处理七层信息;前者若只被透传,代理无法凭空看到 HTTP 路径、状态和请求内容,相关路由与观测能力就会受到限制。

先算收益与成本,再决定要不要引入

我会优先看通信规则是否频繁重复:

  • 多语言服务需要统一超时、灰度和身份策略。
  • 发布新版本需要协调多个调用方。
  • 证书管理已经成为长期维护负担。
  • 故障定位经常卡在“哪个服务调用哪个服务失败”。
  • 相同治理能力散落在多个客户端库里,配置和行为难以统一。

这些信号比“达到几十个服务”更有用,服务数量没有统一入场门槛。

收益来自规则集中下发、跨语言一致性和可观测性,成本则落在代理 CPU/内存、额外网络处理、配置复杂度与控制面的运维上。

不能承诺固定增加 1~5ms 延迟。必须在代表性并发、报文大小、连接复用与加密条件下测量 P99、吞吐、代理 CPU/内存、应用 GC 和节点争用,再决定资源预算。

观测也要配置。指标端点、访问日志、采样和后端采集需要按部署核查;采集不到不能当作没有请求。

代理能够提供通信层信息,但完整分布式调用链通常仍需要应用传播追踪上下文。上下文中断时,一个请求在不同服务里可能变成多段互不相连的链路。使用哪种传播格式,应与当前追踪系统和应用配置一致。

超时与重试尤其要保留业务判断。调用方总截止时间要覆盖合理的单次尝试与排队预算,并与上游剩余时间协调;叠加应用重试和代理重试会放大请求量。

非幂等写入可能产生重复副作用,不能见到错误就给全部 POST 加重试。

选型时也别只问 Istio 和 Linkerd 谁“更轻”。两者在数据面、功能覆盖和配置方式上有差异,应按当前受支持版本比较必需功能、升级路径、故障定位能力与团队经验,再用相同业务负载测资源和延迟。

团队没人能解释生效策略、证书和回退流程时,再多功能也会成为新的不确定性。

在独享实验空间,把两个版本跑起来

以下 Bash 命令在有权限的 Linux 运维终端执行,所有 <...> 必须先替换,不能原样运行。

实验前提是已有受支持的 Istio sidecar 安装,终端 istioctl 与控制面版本匹配。确认 PodSecurity、准入策略与平台的网络重定向方式兼容;受限环境按既有 Istio CNI/注入方案运行。

镜像为固定版本演示,正式使用应经过扫描并锁定 digest。仓库访问、准入或权限失败时,按平台流程处理。

先做只读确认:

kubectl config current-context
kubectl version
istioctl version
istioctl proxy-status

kubectl -n  get pods -l app=istiod

kubectl get peerauthentication,authorizationpolicy -A

istioctl analyze --help
istioctl proxy-config --help

kubectl get crd \
  virtualservices.networking.istio.io \
  destinationrules.networking.istio.io \
  peerauthentications.security.istio.io \
  authorizationpolicies.security.istio.io \
  -o jsonpath='{range .items[*]}{.metadata.name}{" "}{range .spec.versions[*]}{.name}{" served="}{.served}{" "}{end}{"\n"}{end}'

重点确认目标集群与版本、控制面状态,以及四种 CRD 的 v1 是否 served=true。

控制面 namespace、修订版和根命名空间策略由平台确认;不能把 istio-system 当成所有安装的固定位置。已有全局策略可能影响实验流量,即便新建 namespace 也不能跳过检查。

本文 YAML 使用这些 v1 API;版本不支持时,应对照该版本文档调整。帮助输出用于核对后面命令在当前版本的参数。

本文服务 FQDN 假设 Kubernetes 的 clusterDomain,也就是服务 DNS 后缀,为 cluster.local。若实际不同,替换全文 Service host、路由目标和 curl URL 中的后缀。

它与后面 Istio 工作负载身份的 trustDomain 是两个独立配置,示例值相同不能证明实际相同。

实验会创建新 namespace,并在其中部署工作负载和策略,属于有状态变更。先确认 mesh-lab 不存在:

kubectl get namespace mesh-lab

只有服务器明确返回该 namespace NotFound 才继续。权限、网络或其他错误不能解释成不存在。

如果已有 namespace,就换新独享名字,并替换全文。确认 NotFound 后执行:

kubectl create namespace mesh-lab &&
kubectl label namespace mesh-lab istio-injection=enabled

&& 确保创建成功才贴标签;任一步失败就停止,先查原因。

上面的方式适用于平台允许使用默认注入标签的安装。修订版安装将标签改为平台指定的 istio.io/rev=,仍保留创建成功的保护。两种标签二选一,不同时设置。

注入发生于新 Pod 创建时。已有 Pod 不会热加代理;共享业务滚动重建还需容量、可用性与回退准备,本文用新空间进行实验。

把下面内容保存为 mesh-apps.yaml,一次建立应用和两个客户端身份:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: echo
  namespace: mesh-lab
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: echo-client
  namespace: mesh-lab
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: echo-denied
  namespace: mesh-lab
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-v1
  namespace: mesh-lab
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo
      version: v1
  template:
    metadata:
      labels:
        app: echo
        version: v1
    spec:
      serviceAccountName: echo
      containers:
      - name: echo
        image: hashicorp/http-echo:1.0.0
        args: ["-listen=:5678", "-text=v1"]
        ports:
        - containerPort: 5678
        readinessProbe:
          httpGet:
            path: /
            port: 5678
        resources:
          requests:
            cpu: 50m
            memory: 32Mi
          limits:
            cpu: 200m
            memory: 64Mi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: echo-v2
  namespace: mesh-lab
spec:
  replicas: 1
  selector:
    matchLabels:
      app: echo
      version: v2
  template:
    metadata:
      labels:
        app: echo
        version: v2
    spec:
      serviceAccountName: echo
      containers:
      - name: echo
        image: hashicorp/http-echo:1.0.0
        args: ["-listen=:5678", "-text=v2"]
        ports:
        - containerPort: 5678
        readinessProbe:
          httpGet:
            path: /
            port: 5678
        resources:
          requests:
            cpu: 50m
            memory: 32Mi
          limits:
            cpu: 200m
            memory: 64Mi
---
apiVersion: v1
kind: Service
metadata:
  name: echo
  namespace: mesh-lab
spec:
  selector:
    app: echo
  ports:
  - name: http
    port: 80
    targetPort: 5678
---
apiVersion: v1
kind: Pod
metadata:
  name: echo-client
  namespace: mesh-lab
  labels:
    app: echo-client
spec:
  serviceAccountName: echo-client
  containers:
  - name: curl
    image: curlimages/curl:8.12.1
    command: ["sh", "-c", "sleep 86400"]
    resources:
      requests:
        cpu: 25m
        memory: 16Mi
      limits:
        cpu: 100m
        memory: 64Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: echo-denied
  namespace: mesh-lab
  labels:
    app: echo-denied
spec:
  serviceAccountName: echo-denied
  containers:
  - name: curl
    image: curlimages/curl:8.12.1
    command: ["sh", "-c", "sleep 86400"]
    resources:
      requests:
        cpu: 25m
        memory: 16Mi
      limits:
        cpu: 100m
        memory: 64Mi

这里有几个不能忽略的细节:

  • 两个 Deployment 的 selector 与各自 Pod 标签一致。
  • Service 只按 app: echo 选择,所以包含两个版本。
  • Service 访问端口是 80,应用实际监听端口是 5678。
  • 服务端口命名为 http,帮助明确协议。
  • 两个客户端使用不同 ServiceAccount,后面才能验证身份授权。

资源值仅适用于轻量演示,未包含注入代理自身的资源,以实际注入模板与集群预算为准。两个客户端是用裸 Pod 和长时间 sleep 保活的实验工具,不是生产部署模板。

预览校验通过后,再创建并确认:

kubectl apply --dry-run=server -f mesh-apps.yaml
kubectl apply -f mesh-apps.yaml

kubectl -n mesh-lab rollout status deployment/echo-v1 --timeout=3m
kubectl -n mesh-lab rollout status deployment/echo-v2 --timeout=3m

kubectl -n mesh-lab wait \
  --for=condition=Ready \
  pod/echo-client pod/echo-denied \
  --timeout=3m

kubectl -n mesh-lab get pods
istioctl proxy-status

kubectl -n mesh-lab exec echo-client -c curl -- \
  curl -fsS --max-time 3 http://echo.mesh-lab.svc.cluster.local/

预期响应是 v1 或 v2。

常见 sidecar 布局显示应用容器和 istio-proxy 均就绪,即 2/2;还要查看实际容器与代理同步状态。若启用了原生 sidecar,代理可能位于 initContainers,不能固定用 2/2 判断注入。

kubectl -n mesh-lab get pod echo-client -o yaml

kubectl -n mesh-lab get pod echo-client \
  -o jsonpath='{.spec.containers[*].name}{"\n"}{.spec.initContainers[*].name}{"\n"}'

kubectl -n mesh-lab get pods -l app=echo -o yaml

Istio 通常会改写 HTTP 健康探针,核查实际 Pod 的 probe 与事件。Pending、注入失败或首次调用失败时,先采事件与代理状态,未通过就不要继续增加策略。

90/10 是路由规则,先用配置和响应一起证明

Service 选择两个版本的 Pod,DestinationRule 按 version 标签定义 subset,VirtualService 把到这个服务的请求分配给不同 subset。

Service、subset 与 Pod 标签必须对齐,写了 v2 不会凭空生成一个 v2 端点。

保存为 mesh-routing.yaml:

apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
  name: echo
  namespace: mesh-lab
spec:
  host: echo.mesh-lab.svc.cluster.local
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: echo
  namespace: mesh-lab
spec:
  hosts:
  - echo.mesh-lab.svc.cluster.local
  gateways:
  - mesh
  http:
  - timeout: 2s
    route:
    - destination:
        host: echo.mesh-lab.svc.cluster.local
        subset: v1
        port:
          number: 80
      weight: 90
    - destination:
        host: echo.mesh-lab.svc.cluster.local
        subset: v2
        port:
          number: 80
      weight: 10

gateways: [mesh] 明确这条规则作用于网格内流量;这份实验没有配置入口网关。

先将两个 weight 设置为 100/0,按下方步骤建立全量 v1 基线,再恢复文件中的 90/10 重复验证。这样能比较变更前后,也有明确的回退目标。

这里只给幂等 GET 做验证,暂不加重试。若确需一次 GET 重试,可按当前版本文档增加 retries.attempts: 1 与 perTryTimeout: 500ms,并验证总截止时间、重试触发条件和实际请求放大量。

这份 echo 服务响应很快,实验能证明路由下发与版本响应,不能证明 2s 超时已经实测生效。超时需另用可控慢服务验证,也不要在同一 HTTP 规则混入故障注入来推断 timeout/retry 行为。

kubectl apply --dry-run=server -f mesh-routing.yaml
kubectl apply -f mesh-routing.yaml

istioctl analyze -n mesh-lab
istioctl proxy-config routes echo-client -n mesh-lab

分析没有配置错误、路由下发后,执行统计:

kubectl -n mesh-lab exec echo-client -c curl -- sh -c '
attempted=0
v1=0
v2=0
failed=0
unexpected=0

while [ "$attempted" -lt 100 ]; do
  attempted=$((attempted+1))

  if body=$(curl -fsS --max-time 3 http://echo.mesh-lab.svc.cluster.local/); then
    case "$body" in
      v1) v1=$((v1+1)) ;;
      v2) v2=$((v2+1)) ;;
      *) unexpected=$((unexpected+1)) ;;
    esac
  else
    failed=$((failed+1))
  fi
done

sum=$((v1+v2+failed+unexpected))

printf "attempted=%s sum=%s v1=%s v2=%s failed=%s unexpected=%s\n" \
  "$attempted" "$sum" "$v1" "$v2" "$failed" "$unexpected"

[ "$attempted" -eq 100 ] &&
[ "$sum" -eq "$attempted" ] &&
[ "$failed" -eq 0 ] &&
[ "$unexpected" -eq 0 ] || exit 1
'

脚本完成 100 次尝试:

  • 超时、连接错误和 HTTP 错误计入 failed。
  • 成功但正文不是 v1/v2 的响应计入 unexpected。
  • 任一异常让脚本以非零状态退出。
  • 外层没有管道覆盖 kubectl exec 的退出码。

先确认 attempted 与四项之和均为 100,再看版本分配。

100/0 基线应全为 v1 且异常计数为零;90/10 下的 100 次请求只是低负载概率演示,不保证恰好 90/10。若未见 v2,增加受控样本并核对路由。

生产灰度应观测两个版本的实际 QPS、错误率、P99 与资源,并匹配请求类型和单 Pod 负载后比较。不能用 port-forward 直连某个 Pod 来证明服务路由有效。

连接池限制与异常实例驱逐常被统称为“熔断”,但具体行为不同:

  • connectionPool 限制连接、待处理请求等。
  • outlierDetection 根据错误驱逐异常上游端点。

它们不能自动理解余额不足、库存不足等业务语义。阈值应按服务、端口和并发压测确定;过紧会主动制造溢出或减少可用实例。

加密证明身份,授权决定谁能调用

mTLS 同时提供通信加密与对端工作负载身份验证,业务用户身份仍由应用处理。

PeerAuthentication 定义接收端接受的传输要求;AuthorizationPolicy 定义身份和请求是否允许。namespace 隔离或 NetworkPolicy 不是同一层次的替代品。

下面独立假设 Istio 身份信任域 trustDomain 为 cluster.local。其他值只替换 principal 中的信任域,不据此改服务 DNS。

保存为 mesh-security.yaml,只选择 app: echo 的实验工作负载:

apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: echo-strict
  namespace: mesh-lab
spec:
  selector:
    matchLabels:
      app: echo
  mtls:
    mode: STRICT
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: echo-allow-client
  namespace: mesh-lab
spec:
  selector:
    matchLabels:
      app: echo
  action: ALLOW
  rules:
  - from:
    - source:
        principals:
        - cluster.local/ns/mesh-lab/sa/echo-client
    to:
    - operation:
        methods:
        - GET
        paths:
        - /

这里允许的是持有 echo-client ServiceAccount 工作负载身份、访问 / 的 GET。请求 principal 需要 mTLS 才能建立。

规则不是“同 namespace 都能访问”。

适用的 ALLOW 策略存在时,请求至少要匹配一条允许规则;多个 ALLOW 组成允许集合,因此其他策略也可能放行。匹配的 DENY 会优先阻断,其他高级 action 按当前版本文档核对。

已有上层策略也可能影响最终结果,执行前要检查实际生效范围。

kubectl get peerauthentication,authorizationpolicy -A

kubectl apply --dry-run=server -f mesh-security.yaml
kubectl apply -f mesh-security.yaml

istioctl analyze -n mesh-lab
istioctl proxy-status

istioctl proxy-config clusters echo-client -n mesh-lab -o json
istioctl proxy-config secret echo-client -n mesh-lab

kubectl -n mesh-lab exec echo-client -c curl -- \
  curl -sS -o /dev/null -w '%{http_code}\n' \
  --max-time 3 http://echo.mesh-lab.svc.cluster.local/

kubectl -n mesh-lab exec echo-denied -c curl -- \
  curl -sS -o /dev/null -w '%{http_code}\n' \
  --max-time 3 http://echo.mesh-lab.svc.cluster.local/

等待代理同步后,允许身份预期得到 200,另一个已经注入 sidecar、使用 echo-denied 身份的客户端预期得到 403。

若返回连接错误,不能当作授权拒绝成功;应检查 mTLS、端点与路由。两个客户端都要确认代理存在和就绪,避免把“未进入网格”误解成“身份策略起作用”。

clusters 输出中核对目标 echo subset 的 TLS 传输配置与证书引用;secret 默认摘要查看证书状态和有效期,不导出私钥或整份敏感 secret。

证书存在也不能独立证明这一跳用了它,需要结合目标 cluster、接收端 STRICT 生效与现有安全观测。

403 则要与实际 ServiceAccount 和生效授权规则对应,排除应用返回的同名状态。成功返回 200,也不能证明整个网络都已加密。

出现 503,先把应用端点与代理端点对上

下面用一个脱敏后的典型场景说明。以下时间、比例、状态和配置差异均为机制推演示例,不对应真实事故。

示例中,15:00 将流量从全量 v1 调到 90/10 后出现一部分 503,v1 请求仍正常。

初判是 v2 应用坏了,但两个 Deployment 都就绪,Service 的 EndpointSlice 也能看到两个版本的地址,应用健康检查正常。

这个证据只能说明 Service 有端点,不能证明 v2 subset 有端点。

检查客户端代理配置后,路由确实指向 v2 cluster,但 v2 cluster 没有可用 endpoint。再对照 YAML:v2 Pod 的版本标签是 v2-canary,DestinationRule 却筛选 version: v2。

根因在 subset 标签不匹配。

修正 DestinationRule 的筛选标签、通过预览和分析、等待代理同步后,v2 endpoint 出现,受控请求恢复。不要为复现故障而修改 Deployment 不可变 selector;这里用配置差异说明排查路径。

我会沿这组只读命令缩小范围。日志和输出可能含地址与请求信息,只取故障时间附近,分享前脱敏:

kubectl -n mesh-lab get pods -o wide --show-labels
kubectl -n mesh-lab get service echo -o yaml

kubectl -n mesh-lab get endpointslice \
  -l kubernetes.io/service-name=echo -o yaml

kubectl -n mesh-lab get networkpolicy -o yaml
kubectl get nodes

istioctl proxy-status
istioctl analyze -n mesh-lab

istioctl proxy-config routes echo-client -n mesh-lab
istioctl proxy-config clusters echo-client -n mesh-lab
istioctl proxy-config endpoints echo-client -n mesh-lab
istioctl proxy-config listeners echo-client -n mesh-lab

kubectl -n mesh-lab logs echo-client -c istio-proxy \
  --since=5m --tail=200

应用与节点异常、Service selector 错或 EndpointSlice 无地址时,先修基础层;基础层正常,再核对代理同步和配置。

各类代理配置分别回答不同问题:

检查对象重点判断
routes请求命中了哪个路由,指向哪个上游 cluster
clusterssubset、上游协议、连接与 TLS 传输设置
endpoints代理实际得到哪些目标地址,是否可用
listeners流量捕获、监听与协议识别是否符合预期

必要时对接收端 Pod 做相同检查。输出格式随版本变化,要用当前帮助与文档解释。

Envoy 响应标志能给方向:NR 常见于找不到路由,UF 指向上游连接失败,UO 指向上游溢出,UT 指向上游超时;无健康上游还可能看到 UH。

实际可见字段依赖日志配置与版本,具体 response_flags 与 response_code_details 按当前 Envoy 文档解释。

503 不唯一对应 mTLS。看到 UF,也要检查端点、网络与证书;看到 403,要结合授权拒绝原因。

临时止损是停止继续扩流量,把 VirtualService 权重恢复为 v1=100、v2=0,并确认 v1 容量可承接;再按原发布管道修正并验证标签。

保存故障时间、配置差异、代理端点前后输出和版本指标,才有完整复盘。若修正后仍不通,应回到证据分支,而不是继续加重试。

回退和清理也要有边界

正式变更前保存声明式来源与生效配置。GitOps/Helm 通过原管道恢复;手工实验则保留文件版本。

需要把本实验退回全量 v1,可复制 mesh-routing.yaml 为回退文件,将两项 weight 改成 100 和 0,服务端预览、应用、等待同步,再做请求与基线容量核验。

生产灰度的停止条件应在放流量前写清:例如错误率或 P99 越过服务 SLO、v2 资源异常、同节点其他服务恶化。apply 成功只证明配置写入,不证明流量已经按预期恢复。

安全策略的生产回退要恢复此前获准配置,不能靠删掉所有 ALLOW 或解除 STRICT 获得“恢复”。

本实验中的策略都新建在独享空间。若单独研究策略行为,可以在保存配置后删除明确的 echo-allow-client 实验对象;这可能放宽访问,删除后不等于恢复此前获准的安全基线。

实验结束后,先核对 namespace 仍是本次独享对象,再清理:

kubectl get namespace mesh-lab --show-labels

kubectl -n mesh-lab get \
  deployment,pod,service,virtualservice,destinationrule,peerauthentication,authorizationpolicy

kubectl delete namespace mesh-lab

最后一条会删除该 namespace 内的全部资源。执行前保存需要的实验记录,确认没有混入其他人的工作负载。

删除 namespace 注入标签不会让已有 Pod 热移除 sidecar。生产退出网格通常还涉及滚动重建、路由、身份策略与容量验证。

这份检查清单可以直接带到评审和排障现场:

  • 务必确认版本、CRD 与流量模式,sidecar 和 ambient 的能力落点不同。
  • 不要把注入成功当作治理完成,捕获范围、同步状态、加密和授权分别核验。
  • 务必对齐 Service selector、subset 标签与代理 endpoint,否则就绪 Pod 仍可能接不到指定路由。
  • 不要给非幂等请求盲加重试,多层重试会放大故障并制造重复写入。
  • 务必分别确认服务 DNS 域与身份信任域,示例值相同不代表实际配置相同。
  • 务必核对 ServiceAccount 和已有策略,身份字符串写错可能阻断合法调用。
  • 不要只看 HTTP 状态,应用、代理响应标志、端点与传输配置一起判断。
  • 务必实测 P99、代理资源与节点争用,固定延迟和服务数量门槛不能替你做容量决策。
  • 务必保留版本配置、停止条件与容量退路,流量和安全策略的回退都要验证实际效果。

我建议你先在独享实验空间跑完“两个版本返回不同内容、代理路由可查、允许身份成功、未授权身份被拒绝”这四个验证,再讨论推广。

能把规则与结果对上,Service Mesh 才开始成为可管理的基础设施。

如果这份实操让你更清楚地判断何时需要网格、故障时先查哪一层,可以关注、点赞、点个在看,也转给一起维护服务链路的同事。

公众号:耕云躬行录

个人博客:躬行笔记

添加评论
点赞收藏
点踩分享查看原文
评论
?
参与讨论