服务网格 E04:虚拟机与 Kubernetes 怎样混合接入
库存在集群外,orders 找到的到底是谁
同一个 orders → inventory 报价,如果库存从 Kubernetes Pod 迁到独立虚拟机,应用的 URL 不一定需要变,但服务发现必须把 VM 地址纳入目标集合,且 VM 上的数据面要拿到可信身份。把一个普通 Pod 标注 vm=true,依然是 Pod、Kubernetes 身份与 Pod 网络,并没有验证跨边界注册。本文以 Istio 1.27 文档快照设计双端点用例;并未在当前机器安装 Istio。
图上 orders → 源代理 →(视网络拓扑经网关)→ VM 代理 → inventory 是数据通道;Istiod → VM 的注册发现与证书/配置是独立的启动依赖。若 VM 在同网络且直接可达,不应无证据地画成必经东西向网关。反过来,仅在控制面看到 WorkloadEntry,也不能证明真实入口端口/防火墙可达。相关基础见 19 身份、29 控制面失效 和 32 多集群。
谁注册,谁发证,谁连接
VM 启动和接收请求之间存在依赖,不是一个“已注册”布尔值:
1 | |
| 注入的故障 | orders 端可能看到 | 需要定位的边界 |
|---|---|---|
| 撤掉发现条目 | 新请求无 VM 候选 | 服务注册/端点收敛 |
| 错误 VM 凭据 | 地址可见,代理可能尚未就绪 | 身份签发、SDS 与对等验证分别检查 |
| 网络不通 | 有地址,连接超时/失败 | 防火墙/网关可达性 |
在受控 VM/独立宿主上运行 inventory 与 Istio 代理。按 Istio 1.27 VM 安装指南配置 WorkloadGroup 或 WorkloadEntry、服务关联、网络和代理启动参数;WorkloadEntry 是向网格描述非 Pod 工作负载的资源,应用进程仍须真的在独立地址提供 /quote。身份引导材料须通过合适的秘密分发机制进入 VM,代理在控制面可达时申请/轮换短期证书;不得提交引导 token、私钥或把测试证书复制进文章。先确认代理有有效身份和端点,再确认 orders 连接目标确实是 VM,而不是同名 Service 中仍在运行的 Pod。
对相同 sku=paper,正常路径保存注册资源、证书公开身份、代理端点视图、客户端带 ID 原始响应、VM inventory 应用日志和网络连接目标;失败路径先移除隔离实验里的 VM 发现条目,核对旧连接与新建连接是否仍能发出请求,再恢复。另一组以错误身份或过期凭据测试认证拒绝:发现失败与 TLS 拒绝是两种不同故障,不能只看“请求失败”混为一谈。VM 启动时若控制面/身份发放端暂不可达,新旧代理状态也不同;只有实际启动日志和证书状态能解释差异。
当前累计工程的 inventory-v1/v2 都是本机应用进程基线;它们既没有 VM 引导身份,也没有跨 Kubernetes 发现。宿主无 kubectl/context、VM 测试环境或可验证代理,因此 VM 注册、证书与连接实验 NOT_RUN;源码和官方配置阅读只支撑设计。复跑前分别核对隔离集群 context、独立宿主所有权及网络可达性,不操作生产 VM。
单网络实验:先固定连接地址,再启用身份
工程目录 examples/service-mesh/electives/E04/ 提供完整的 WorkloadGroup、ServiceEntry、WorkloadEntry 模板、入站与出站 TLS 策略,以及 VM 安装脚本。基线选择单网络:Kubernetes Pod 能直接连接独立 Linux VM 的 8080,VM 能连接暴露的 Istiod。跨网络部署还要增加网关与 network 映射,不能只把模板里的空字符串改掉就算完成。
inventory.vm.mesh:8080 是实验服务名,240.0.0.10 是代理捕获用的专用 VIP。VIP 不等于 VM 的物理地址。客户端使用 curl --resolve 明确把域名解析到 VIP,避免依赖宿主 DNS 配置;源 sidecar 再按 ServiceEntry 选择 VM 的真实地址。部署前必须保证这个 VIP 没有与实验网络其他用途冲突。
四种资源的责任不同:WorkloadGroup 给出一组 VM 的身份与标签模板;WorkloadEntry 登记某一台 VM 的地址;ServiceEntry 用选择器将条目组成服务;DestinationRule 指定源端如何发起 TLS。注册资源不会在 VM 上安装代理、启动 inventory,也不会自动放通防火墙。
在已安装 Istio 1.27.0 的隔离集群操作,SM_CONTEXT 必须是该集群的显式 context,ISTIO_DIR 是对应版本发行包目录。先暴露控制面,再建立服务资源:
1 | |
192.0.2.10 是文档地址,运行时换成实际 VM 地址;这里没有声称它可以连通。该基线采用手工 WorkloadEntry,不启用自动注册,因而删除条目的故障不会被 agent 立即重新注册所掩盖。若改用 --autoregister,还必须启用控制面的自动注册能力,并把健康检查作为独立条件。
引导文件如何变成工作负载证书
从集群导出 WorkloadGroup,并生成引导材料。E04_PRIVATE_DIR 放在仓库之外,只允许当前用户读取;材料中包含短期 ServiceAccount token,不进入证据目录。
1 | |
--clusterID 必须等于控制面安装时的 clusterName;Kubernetes 只对应官方单集群默认例子。生成的 cluster.env 定义 namespace、ServiceAccount 和捕获端口,mesh.yaml 指向发现地址,hosts 提供 Istiod 名称解析,root-cert.pem 验证控制面,istio-token 用于申请工作负载证书。引导 token 与后来经 SDS 下发的证书不是同一份凭据。
在独立 Debian/Ubuntu VM 安装固定版本运行包,再通过受控通道传入 bootstrap 目录:
1 | |
mesh-demo 来自累计工程的 apps/mesh-demo,应按 VM 架构交叉编译、传输并记录哈希。运行包也要记录来源、包信息和 SHA-256。应用不要以 istio-proxy 用户运行,否则它的流量可能落入用于避免代理回环的排除规则。VM 实际可接入的操作系统、内核权限和 iptables 行为需要现场核对。
TLS 失败的三个不同时间点
资源文件同时设置入站 PeerAuthentication STRICT、出站 DestinationRule ISTIO_MUTUAL,并把 SAN 约束为 spiffe://cluster.local/ns/vm-lab/sa/inventory-vm。这里用默认 trust domain;修改 trust domain 时要同步身份约束。STRICT 表示受策略覆盖的入站连接要求 mTLS;ISTIO_MUTUAL 表示源代理使用 Istio 管理的证书发起 mTLS,不能把它理解成已经握手成功。
如果错误 token 导致 VM 尚未取得证书,SDS 依赖的 listener 或 cluster 可能仍在 warming,代理也可能没有就绪,源端最终表现为连接失败或超时。此时没有证据说明对端收到证书后拒绝了身份。只有双方已经取得证书、实际发生握手,且错误链/SAN 被校验失败,才属于 TLS 身份验证拒绝。握手之后再被 AuthorizationPolicy 拒绝,则又是授权阶段。
三个检查应分别保存:istioctl proxy-status 的配置同步状态,VM agent 日志中 SDS 密钥对和 ROOTCA 的加载状态,以及真实请求的连接/握手错误。curl localhost:15021/healthz/ready 只证明 readiness 端点;仍需结合 curl localhost:15000/certs 的公开证书元数据确认有效期与身份,不导出私钥。源端 proxy-config secret 只说明源代理持有证书,不证明 VM 持有证书。
正常、撤销与恢复
在 vm-lab 部署发行包的 samples/curl/curl.yaml,其 namespace 已启用 sidecar 注入。先检查 Pod 确有 istio-proxy,再设置 SM_CLIENT_POD 并执行 bash scripts/run-E04.sh。脚本保存资源、客户端 SDS 摘要、端点视图和请求,VM 上另外保存 inventory 的 E04-probe 请求日志、代理 readiness 和证书摘要。成功条件是响应版本为 vm,源端选中的地址是 VM,VM 应用确有相同 ID,三者一致。
从同一隔离集群删除 inventory-vm-1,等待源端 EDS 不再包含其地址,然后发起新 curl 进程;恢复用原 /tmp/e04-entry.yaml。旧连接可能短暂继续使用旧状态,因此“删除对象后立即请求成功”不能直接判定策略无效。接着单独测试 VM 启动时错误 token,保存代理未就绪与 SDS 错误;恢复正确 token 并重启 agent,等待证书与 readiness 恢复后再请求。已经取得的证书不会因 bootstrap token 文件变化而瞬间消失,不应通过替换 token 假装完成证书撤销。
| 需求关键词 | 可迁移原则 | 本例执行点 |
|---|---|---|
| 地址有了但请求失败 | 分开检查发现、就绪、握手与应用执行 | WorkloadEntry、SDS、代理、请求 ID |
| 引导凭据更新 | 引导与持续身份分别管理 | token 申请证书,证书有独立生命周期 |
| 撤销端点 | 区分控制面删除和数据面收敛 | EDS 新视图及新连接 |
练习与参考解答
- 画出 WorkloadEntry 存在但 VM 代理未取得证书时,新请求会停在何处。参考解答:先核对 STRICT、ISTIO_MUTUAL 及流量是否被代理捕获;代理可能等待 SDS、listener 未就绪,也可能在连接阶段失败。不能直接写成对端身份拒绝。只有握手日志才支持握手归因,业务执行必须由 VM 的请求 ID 日志证明。
- 把 Pod 的 hostname 改成
inventory-vm,可以代替身份失败对照吗?参考解答:不能。Pod 仍由 Kubernetes 调度且走原工作负载身份/网络;应使用独立宿主的 WorkloadEntry 和 VM 代理,显式验证实际连接地址及证书身份。
资料与系列导航
Istio 1.27 VM 安装、WorkloadEntry API;源码入口 Istio 1.27.0 serviceentry registry。研究记录 writing-plans/service-mesh/research/E04.md。
系列导航:E03 Proxyless gRPC → E04 VM 接入(本文) → E05 Envoy 外部授权。
