把网关与外部服务接起来
目标
掌握使用 Gateway 声明入口、使用 VirtualService 附加路由这一职责分工,并尝试使用 ServiceEntry 和 Sidecar 扩大及缩小服务网格的边界。
为什么重要
Ingress 是服务网格中最容易发生事故的位置。原因通常是以下三种之一:Gateway 的 hosts 与 VirtualService 的 hosts 没有交集;遗漏 gateways 字段,导致规则只应用于网格内部;或者 credentialName 指向的 Secret 与网关 Pod 位于不同的命名空间。这三种情况都会成功 apply,却让流量悄无声息地失败,因此读懂清单是唯一的防线。
ServiceEntry 与 Sidecar 是方向完全相反的工具。前者把网格外服务纳入网格,以便施加策略和可观测性;后者缩小 Sidecar 需要了解的范围,从而节省内存。在大型服务网格中,使用 Sidecar 资源是解决 Envoy 内存问题的标准办法,这一点在考试和实际工作中都会出现。
Kubernetes 基础资源需要实际 apply,Istio CRD 则写成 /root/ica-gateway/ 下的文件。
步骤
- 创建命名空间
ica-gateway,并添加标签istio-injection=enabled。 - 在命名空间
ica-gateway中部署 Deploymentshop-api,副本数为 2(镜像nginx:1.27-alpine,Pod 标签app=shop-api),并创建同名 Serviceshop-api,端口为8080,端口名称为http。 - 在命名空间
ica-gateway中创建 Secretshop-tls,类型为kubernetes.io/tls。其中包含tls.crt和tls.key两个键,值可以是占位字符串。 - 在
/root/ica-gateway/gw-shop.yaml中编写 Gatewayshop-gateway。spec.selector为istio: ingressgateway,并包含两个 servers。第一个使用端口443/ 协议HTTPS/ hostsshop.example.com/tls.mode: SIMPLE/tls.credentialName: shop-tls。第二个使用端口15443/ 协议TLS/ hostslegacy.example.com/tls.mode: PASSTHROUGH,且不设置 credentialName。 - 在
/root/ica-gateway/vs-shop.yaml中编写 VirtualService。hosts为shop.example.com,gateways为shop-gateway,http 路由目标是shop-api.ica-gateway.svc.cluster.local的端口8080。 - 在
/root/ica-gateway/se-payment.yaml中编写 ServiceEntryexternal-pg。hosts为api.pgprovider.example,location为MESH_EXTERNAL,resolution为DNS,ports 使用编号443/ 名称https/ 协议TLS。 - 在
/root/ica-gateway/sidecar-default.yaml中编写 Sidecar。metadata.name为default,metadata.namespace为ica-gateway,并且spec.egress[0].hosts中只能准确放置三个条目:当前命名空间(./*)、控制平面(istio-system/*),以及第 6 步注册的外部主机(*/api.pgprovider.example)。
参考
- 使用 YAML 创建 Secret 时,使用
stringData就不需要手动进行 base64 编码。 kubectl create secret tls需要真实的证书文件,因此在本环境中直接编写清单更快。- 常见错误 1:把 PASSTHROUGH server 的协议写成
HTTPS。既然不终止 TLS,就无法解析 HTTP。 - 常见错误 2:在 VirtualService 中遗漏
gateways。这样该规则只会应用于网格内部流量,对外部入口毫无影响。 - Sidecar 的 egress hosts 格式是
네임스페이스/호스트。对于不知道命名空间的外部主机,使用*/。
创建网关实验命名空间
创建命名空间 ica-gateway,并添加标签 istio-injection=enabled。
还必须添加自动注入标签,这样下一步的工作负载才能加入服务网格。
准备网关的后端目标
在命名空间 ica-gateway 中部署 Deployment shop-api,副本数为 2(镜像 nginx:1.27-alpine,Pod 标签 app=shop-api),并创建同名 Service shop-api,端口为 8080,端口名称为 http。
网关只负责接收流量。必须先有实际响应的工作负载以及把它组织起来的 Service,才能形成路由目标。
创建 TLS Secret
在命名空间 ica-gateway 中创建 Secret shop-tls,类型为 kubernetes.io/tls。其中包含 tls.crt 和 tls.key 两个键,值可以是占位字符串。
类型很重要。credentialName 只识别 kubernetes.io/tls 类型的 Secret,其中必须包含 tls.crt 和 tls.key 两个键。该实验环境没有 CA,因此可以填入占位字符串。
在一个 Gateway 中配置两种 TLS 模式
在 /root/ica-gateway/gw-shop.yaml 中编写 Gateway shop-gateway。spec.selector 为 istio: ingressgateway,并包含两个 servers。第一个使用端口 443 / 协议 HTTPS / hosts shop.example.com / tls.mode: SIMPLE / tls.credentialName: shop-tls。第二个使用端口 15443 / 协议 TLS / hosts legacy.example.com / tls.mode: PASSTHROUGH,且不设置 credentialName。
终止 TLS 的 server 与透传 TLS 的 server 使用不同的协议标记。不终止 TLS 的一侧不会解析 HTTP,因此协议不是 HTTPS,也不需要持有证书。
将 VirtualService 绑定到网关
在 /root/ica-gateway/vs-shop.yaml 中编写 VirtualService。hosts 为 shop.example.com,gateways 为 shop-gateway,http 路由目标是 shop-api.ica-gateway.svc.cluster.local 的端口 8080。
绑定必须同时满足两个条件:gateways 字段中必须包含名称,并且 hosts 必须与 Gateway 的 server hosts 有交集。destination 中也要写明端口号。
将外部支付 API 注册到服务网格
在 /root/ica-gateway/se-payment.yaml 中编写 ServiceEntry external-pg。hosts 为 api.pgprovider.example,location 为 MESH_EXTERNAL,resolution 为 DNS,ports 使用编号 443 / 名称 https / 协议 TLS。
由于这是网格外的服务,location 值是固定的;若未填写 endpoints,还必须说明如何解析名称。443 端口的协议为 TLS。
使用 Sidecar 缩小视野
在 /root/ica-gateway/sidecar-default.yaml 中编写 Sidecar。metadata.name 为 default,metadata.namespace 为 ica-gateway,并且 spec.egress[0].hosts 中只能准确放置三个条目:当前命名空间(./*)、控制平面(istio-system/*),以及第 6 步注册的外部主机(*/api.pgprovider.example)。
要成为命名空间的默认配置,名称是固定的。egress hosts 只保留当前命名空间、控制平面以及第 6 步注册的外部主机这三个条目。外部主机在命名空间位置使用通配符。