Skip to content

流量、卷、身份:沿三条路径查隔离边界 ​

Service 的 selector 匹配 Pod 后由 EndpointSlice 发布端点和就绪状态;kube-proxy 或其替代实现把虚拟 IP 流量转到端点。CoreDNS 从服务和命名空间解析名字。排障按 DNS → Service 端口和 targetPort → EndpointSlice → Pod 监听地址 → NetworkPolicy 顺序,能把“不可达”缩到具体层。NetworkPolicy 需 CNI 支持;namespace 本身不是网络边界。Ingress/Gateway API 负责入站路由,不等同于集群内的 Service。

readiness 决定接流量,liveness 决定重启,startup probe 给慢启动留时间。模型尚在加载时重复 liveness 重启会制造永不就绪的循环。StorageClass 指定供应策略,PVC 绑定 PV;模型缓存若挂在节点本地,换节点即冷启动,若共享 PVC 则要考虑访问模式和拉取并发。rolling update 期间新旧 Pod 可能同时占卡,容量应含 maxSurge。PDB 约束使用 eviction API 的自愿中断,不能替代故障容灾或约束所有滚动更新。ResourceQuota 管 namespace 总量,LimitRange 管单对象默认值/范围;RBAC 管 API 权限,这三者不能替代推理网关的租户授权。

请求究竟走哪条路 ​

Pod IP 由集群网络实现连接;Service 是稳定的逻辑入口,EndpointSlice 提供后端及就绪条件。Linux 上代理可用 iptables 规则做目的地址转换;IPVS 以虚拟服务/真实后端组织转发,但并非所有 Service 语义都能自然映射,较新版本已将 IPVS 标记弃用。也有 nftables 或由 CNI 实现替代的数据面。不要在 Mac 宿主网络里找 Linux 节点规则。先依据所用 Kubernetes 版本的代理模式核对集群实现。

sh
kubectl -n kube-system get configmap kube-proxy -o yaml
kubectl -n modeldock-lab describe svc chart-demo
kubectl -n modeldock-lab get endpointslice -l kubernetes.io/service-name=chart-demo -o yaml
kubectl -n kube-system get svc kube-dns
kubectl api-resources | grep -E 'httproutes|networkpolicies|storageclasses'

单测 Service 可以 port-forward,但它绕过了普通客户端的 DNS/ClusterIP 路径;只有从实际客户端所在网络请求才验证服务发现。NetworkPolicy 要 CNI 支持:默认拒绝出站后要允许 DNS 和所需目的端口;Ingress/Gateway API 还需要实际安装的 controller,Route 的 Accepted 不等于所有 backendRefs 有效。

存储与身份也是控制循环 ​

PVC 声明容量、访问模式和 StorageClass;控制器匹配已有 PV 或调用 CSI provisioner 创建,kubelet 再经节点插件挂卷。WaitForFirstConsumer 能把卷区位与 Pod 调度放到同一决策中。ReadWriteOnce 是单节点读写,并非限制一个 Pod。跨节点调度恢复时,旧节点未卸载可能导致 Multi-Attach;先核对 VolumeAttachment 和节点状态,不能为了加速恢复盲删卷。下面是 GPU 模型缓存的真实使用清单。

完整源码:deploy/gpu/modelservice.yaml · 第 1–9 行

yaml
apiVersion: lab.modeldock.dev/v1alpha1
kind: ModelService
metadata: {name: qwen-runtime, namespace: modeldock-lab}
spec:
  image: vllm/vllm-openai:v0.10.2
  runtime: vllm
  model: Qwen/Qwen2.5-1.5B-Instruct
  gpuPerReplica: 1
  replicas: 1

命名空间约束名字、可见范围和配额,不天然隔离流量;ServiceAccount 标识进程,Role/RoleBinding 决定动词、资源和对象名。Pod Security Admission 的 enforce/warn/audit 针对 Pod 规范,不替代 RBAC。Secret 用环境变量或挂载传入,避免打入镜像和日志;更强边界需静态加密与外部密钥管理。用一读一写两个身份做下面的验证,预期依次 no、yes:

sh
for sa in observe repair; do
 kubectl auth can-i patch deployments.apps/pending-lab -n opspilot-lab --as="system:serviceaccount:opspilot-lab:$sa"
done

追问。 诊断助手可以读日志,是否就应该给它 patch 全部 Deployment 的权限?工具实现只允许特定对象和特定动作;API 权限与工具参数限制需要同时成立。

三个容易混淆的配置片段 ​

模型加载目录由 PVC 提供。先请求空间,再在 Pod template 的 volumes 里引用 claimName,容器通过 volumeMounts 挂载。下面是可部署配置的开头;当 StorageClass 没有 provisioner 或节点拓扑不匹配,PVC 与 Pod 都可能等待。确认事件指向哪一个,而不是直接删除 PVC。

完整源码:deploy/gpu/vllm.yaml · 第 1–10 行

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata: {name: model-weights, namespace: modeldock-lab}
spec:
  accessModes: [ReadWriteOnce]
  resources: {requests: {storage: 20Gi}}
---
apiVersion: apps/v1
kind: Deployment
metadata: {name: qwen-gpu, namespace: modeldock-lab}

实验网关把 TENANT_KEYS_JSON 放在 Secret 的同名键中,容器从 secretKeyRef 读取,变更后按发布策略滚动重启。生产可以将外部 Gateway/HTTPRoute 指到已鉴权的 Service;下面是已有 Gateway API CRD、名为 public 的 Gateway 且 listener 允许本 namespace时的示例。单独提交 Route 不会创建云负载均衡器。

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: {name: modeldock, namespace: modeldock-lab}
spec:
  parentRefs: [{name: public, namespace: ingress-system}]
  rules:
    - matches: [{path: {type: PathPrefix, value: /v1}}]
      backendRefs: [{name: modeldock-gateway, port: 8080}]

用 kubectl -n modeldock-lab get httproute modeldock -o yaml 看 parents.conditions 的 Accepted 与 ResolvedRefs,再以正确租户身份测试 SSE。该 Route 是可选接入方案;线上 Cloudflare 仅托管教程。

反例:port-forward 能用,用户仍连不上 ​

port-forward 可以证明选中的后端监听着某个端口,却绕开了普通客户端的域名解析和 ClusterIP 转发。先从故障客户端验证同一个名字、端口和身份,再对照 EndpointSlice 中地址与 ready 条件。如果直连端点成功而 Service 名称失败,证据才开始指向 DNS 或 Service 数据面;如果端点本身也失败,先查容器监听与策略。不要把一次本地成功请求提交为整个多租户网络隔离的验收。