使用通配符主机进行出口流量
该访问外部服务任务和配置出口网关示例描述了如何为特定主机名(如 edition.cnn.com
)配置出口流量。此示例显示了如何为公共域中的一组主机(例如 *.wikipedia.org
)启用出口流量,而不是分别配置每个主机。
背景
假设您希望在 Istio 中为所有语言的 wikipedia.org
站点启用出口流量。特定语言的每个 wikipedia.org
版本都有自己的主机名,例如,英语和德语分别为 en.wikipedia.org
和 de.wikipedia.org
。您希望通过所有维基百科站点的通用配置项启用出口流量,而无需分别指定每种语言的站点。
开始之前
- 安装 Istio,并启用访问日志记录以及默认阻止出站流量策略。
$ istioctl install --set profile=demo --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY
$ istioctl install --set profile=minimal -y \
--set values.pilot.env.PILOT_ENABLE_ALPHA_GATEWAY_API=true \
--set meshConfig.accessLogFile=/dev/stdout \
--set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY
部署curl示例应用程序作为发送请求的测试源。如果您启用了自动 sidecar 注入,请运行以下命令来部署示例应用程序
$ kubectl apply -f @samples/curl/curl.yaml@
否则,在使用以下命令部署 `curl` 应用程序之前,手动注入 sidecar
$ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@)
将 `SOURCE_POD` 环境变量设置为源 Pod 的名称。
$ export SOURCE_POD=$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})
配置到通配符主机的直接流量
访问公共域名内一组主机的第一种也是最简单的方法是,通过配置一个带有通配符主机名的简单 `ServiceEntry`,并直接从 sidecar 调用服务。当直接调用服务(即,不通过出站网关)时,通配符主机的配置与任何其他(例如,完全限定的)主机没有什么不同,只是在公共域名内有多个主机时,这种方式更加方便。
为 `*.wikipedia.org` 定义一个 `ServiceEntry`。
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: ServiceEntry metadata: name: wikipedia spec: hosts: - "*.wikipedia.org" ports: - number: 443 name: https protocol: HTTPS EOF
向https://en.wikipedia.org和https://de.wikipedia.org发送 HTTPS 请求。
$ kubectl exec "$SOURCE_POD" -c curl -- sh -c 'curl -s https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"; curl -s https://de.wikipedia.org/wiki/Wikipedia:Hauptseite | grep -o "<title>.*</title>"' <title>Wikipedia, the free encyclopedia</title> <title>Wikipedia – Die freie Enzyklopädie</title>
清理到通配符主机的直接流量
$ kubectl delete serviceentry wikipedia
配置到通配符主机的出口网关流量
当所有通配符主机都由单个服务器提供服务时,基于出站网关访问通配符主机的配置与任何主机的配置非常相似,只有一个例外:配置的路由目标将与配置的主机(即,通配符)不同。相反,它将使用一组域的单个服务器的主机进行配置。
- 为 *.wikipedia.org 创建一个出站 `Gateway`,并创建路由规则以将流量通过出站网关转发,以及从出站网关转发到外部服务。
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: istio-egressgateway
spec:
selector:
istio: egressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "*.wikipedia.org"
tls:
mode: PASSTHROUGH
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: egressgateway-for-wikipedia
spec:
host: istio-egressgateway.istio-system.svc.cluster.local
subsets:
- name: wikipedia
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: direct-wikipedia-through-egress-gateway
spec:
hosts:
- "*.wikipedia.org"
gateways:
- mesh
- istio-egressgateway
tls:
- match:
- gateways:
- mesh
port: 443
sniHosts:
- "*.wikipedia.org"
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
subset: wikipedia
port:
number: 443
weight: 100
- match:
- gateways:
- istio-egressgateway
port: 443
sniHosts:
- "*.wikipedia.org"
route:
- destination:
host: www.wikipedia.org
port:
number: 443
weight: 100
EOF
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: wikipedia-egress-gateway
annotations:
networking.istio.io/service-type: ClusterIP
spec:
gatewayClassName: istio
listeners:
- name: tls
hostname: "*.wikipedia.org"
port: 443
protocol: TLS
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
name: direct-wikipedia-to-egress-gateway
spec:
parentRefs:
- kind: ServiceEntry
group: networking.istio.io
name: wikipedia
rules:
- backendRefs:
- name: wikipedia-egress-gateway-istio
port: 443
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
name: forward-wikipedia-from-egress-gateway
spec:
parentRefs:
- name: wikipedia-egress-gateway
hostnames:
- "*.wikipedia.org"
rules:
- backendRefs:
- kind: Hostname
group: networking.istio.io
name: www.wikipedia.org
port: 443
---
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: wikipedia
spec:
hosts:
- "*.wikipedia.org"
ports:
- number: 443
name: https
protocol: HTTPS
EOF
为目标服务器 www.wikipedia.org 创建一个 `ServiceEntry`。
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: ServiceEntry metadata: name: www-wikipedia spec: hosts: - www.wikipedia.org ports: - number: 443 name: https protocol: HTTPS resolution: DNS EOF
向https://en.wikipedia.org和https://de.wikipedia.org发送 HTTPS 请求。
$ kubectl exec "$SOURCE_POD" -c curl -- sh -c 'curl -s https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>"; curl -s https://de.wikipedia.org/wiki/Wikipedia:Hauptseite | grep -o "<title>.*</title>"' <title>Wikipedia, the free encyclopedia</title> <title>Wikipedia – Die freie Enzyklopädie</title>
检查出站网关代理的统计信息,以查看与您对 *.wikipedia.org 的请求相对应的计数器。
$ kubectl exec "$(kubectl get pod -l istio=egressgateway -n istio-system -o jsonpath='{.items[0].metadata.name}')" -c istio-proxy -n istio-system -- pilot-agent request GET clusters | grep '^outbound|443||www.wikipedia.org.*cx_total:'
outbound|443||www.wikipedia.org::208.80.154.224:443::cx_total::2
$ kubectl exec "$(kubectl get pod -l gateway.networking.k8s.io/gateway-name=wikipedia-egress-gateway -o jsonpath='{.items[0].metadata.name}')" -c istio-proxy -- pilot-agent request GET clusters | grep '^outbound|443||www.wikipedia.org.*cx_total:'
outbound|443||www.wikipedia.org::208.80.154.224:443::cx_total::2
清理到通配符主机的出口网关流量
$ kubectl delete serviceentry www-wikipedia
$ kubectl delete gateway istio-egressgateway
$ kubectl delete virtualservice direct-wikipedia-through-egress-gateway
$ kubectl delete destinationrule egressgateway-for-wikipedia
$ kubectl delete se wikipedia
$ kubectl delete se www-wikipedia
$ kubectl delete gtw wikipedia-egress-gateway
$ kubectl delete tlsroute direct-wikipedia-to-egress-gateway
$ kubectl delete tlsroute forward-wikipedia-from-egress-gateway
任意域的通配符配置
上一节中的配置之所以有效,是因为所有 `*.wikipedia.org` 站点都可以由任何一个 `wikipedia.org` 服务器提供服务。但是,情况并非总是如此。例如,您可能希望配置出站控制以访问更通用的通配符域名,例如 `*.com` 或 `*.org`。将流量配置到任意通配符域名会给 Istio 网关带来挑战;Istio 网关只能配置为将流量路由到预定义的主机、预定义的 IP 地址或请求的原始目标 IP 地址。
在上一节中,您将虚拟服务配置为将流量定向到预定义的主机 `www.wikipedia.org`。但是,在一般情况下,您不知道可以为请求中接收到的任意主机提供服务的服务器的主机或 IP 地址,这使得请求的原始目标地址成为唯一可以用来路由请求的值。不幸的是,当使用出站网关时,请求的原始目标地址会丢失,因为原始请求会被重定向到网关,导致目标 IP 地址变成网关的 IP 地址。
虽然不像依赖于 Istio 实现细节那样简单且有点脆弱,但您可以使用Envoy 过滤器来配置网关以支持任意域名,方法是在 HTTPS 或任何 TLS 请求中使用SNI值来识别要将请求路由到的原始目标。有关此配置方法的一个示例,请参见将出站流量路由到通配符目标。
清理
关闭curl服务。
$ kubectl delete -f @samples/curl/curl.yaml@
从您的集群中卸载 Istio。
$ istioctl uninstall --purge -y