Kubernetes 出站流量服务
Kubernetes ExternalName 服务和具有 端点 的 Kubernetes 服务可以让您创建到外部服务的本地 DNS 别名。此 DNS 别名与本地服务的 DNS 条目的形式相同,即 <服务名称>.<命名空间名称>.svc.cluster.local
。DNS 别名为您的工作负载提供位置透明性:工作负载可以以相同的方式调用本地和外部服务。如果您在某个时间点决定在您的集群中部署外部服务,您只需更新其 Kubernetes 服务以引用本地版本。工作负载将继续运行而没有任何更改。
此任务说明了 Istio 仍然支持这些访问外部服务的 Kubernetes 机制。您必须执行的唯一配置步骤是使用除 Istio 的 双向 TLS 之外的 TLS 模式。外部服务不是 Istio 服务网格的一部分,因此它们无法执行 Istio 的双向 TLS。您必须根据外部服务的 TLS 要求以及工作负载访问外部服务的方式设置 TLS 模式。如果您的工作负载发出纯 HTTP 请求并且外部服务需要 TLS,您可能希望由 Istio 执行 TLS 发起。如果您的工作负载已使用 TLS,则流量已加密,您只需禁用 Istio 的双向 TLS。
虽然此任务中的示例使用 HTTP 协议,但 Kubernetes 服务用于出口流量也适用于其他协议。
在您开始之前
按照 安装指南 中的说明设置 Istio。
部署 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})
为没有 Istio 控制的源 Pod 创建命名空间
$ kubectl create namespace without-istio
在
without-istio
命名空间中启动 curl 示例。$ kubectl apply -f @samples/curl/curl.yaml@ -n without-istio
要发送请求,请创建
SOURCE_POD_WITHOUT_ISTIO
环境变量以存储源 Pod 的名称$ export SOURCE_POD_WITHOUT_ISTIO="$(kubectl get pod -n without-istio -l app=curl -o jsonpath={.items..metadata.name})"
验证 Istio Sidecar 是否未被注入,即 Pod 只有一个容器
$ kubectl get pod "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio NAME READY STATUS RESTARTS AGE curl-66c8d79ff5-8tqrl 1/1 Running 0 32s
Kubernetes ExternalName 服务以访问外部服务
为
httpbin.org
在默认命名空间中创建一个 Kubernetes ExternalName 服务$ kubectl apply -f - <<EOF kind: Service apiVersion: v1 metadata: name: my-httpbin spec: type: ExternalName externalName: httpbin.org ports: - name: http protocol: TCP port: 80 EOF
观察您的服务。请注意,它没有集群 IP。
$ kubectl get svc my-httpbin NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-httpbin ExternalName <none> httpbin.org 80/TCP 4s
从没有 Istio Sidecar 的源 Pod 通过 Kubernetes 服务的主机名访问
httpbin.org
。请注意,以下 curl 命令使用 Kubernetes 服务的 DNS 格式:<服务名称>.<命名空间>.svc.cluster.local
。$ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers { "headers": { "Accept": "*/*", "Host": "my-httpbin.default.svc.cluster.local", "User-Agent": "curl/7.55.0" } }
在此示例中,未加密的 HTTP 请求被发送到
httpbin.org
。出于示例目的,您禁用 TLS 模式并允许未加密的流量到达外部服务。在实际应用中,我们建议由 Istio 执行 出口 TLS 发起。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: my-httpbin spec: host: my-httpbin.default.svc.cluster.local trafficPolicy: tls: mode: DISABLE EOF
从具有 Istio Sidecar 的源 Pod 通过 Kubernetes 服务的主机名访问
httpbin.org
。注意 Istio Sidecar 添加的标头,例如X-Envoy-Peer-Metadata
。还要注意Host
标头等于您的服务的主机名。$ kubectl exec "$SOURCE_POD" -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers { "headers": { "Accept": "*/*", "Content-Length": "0", "Host": "my-httpbin.default.svc.cluster.local", "User-Agent": "curl/7.64.0", "X-B3-Sampled": "0", "X-B3-Spanid": "5795fab599dca0b8", "X-B3-Traceid": "5079ad3a4af418915795fab599dca0b8", "X-Envoy-Peer-Metadata": "...", "X-Envoy-Peer-Metadata-Id": "sidecar~10.28.1.74~curl-6bdb595bcb-drr45.default~default.svc.cluster.local" } }
清理 Kubernetes ExternalName 服务
$ kubectl delete destinationrule my-httpbin
$ kubectl delete service my-httpbin
使用具有端点的 Kubernetes 服务以访问外部服务
为 Wikipedia 创建一个没有选择器的 Kubernetes 服务
$ kubectl apply -f - <<EOF kind: Service apiVersion: v1 metadata: name: my-wikipedia spec: ports: - protocol: TCP port: 443 name: tls EOF
为您的服务创建端点。从 Wikipedia 范围列表 中选择几个 IP。
$ kubectl apply -f - <<EOF kind: Endpoints apiVersion: v1 metadata: name: my-wikipedia subsets: - addresses: - ip: 198.35.26.96 - ip: 208.80.153.224 ports: - port: 443 name: tls EOF
观察您的服务。请注意,它有一个集群 IP,您可以使用它访问
wikipedia.org
。$ kubectl get svc my-wikipedia NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-wikipedia ClusterIP 172.21.156.230 <none> 443/TCP 21h
从没有 Istio Sidecar 的源 Pod 通过 Kubernetes 服务的集群 IP 向
wikipedia.org
发送 HTTPS 请求。使用curl
的--resolve
选项通过集群 IP 访问wikipedia.org
$ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>" <title>Wikipedia, the free encyclopedia</title>
在这种情况下,工作负载向
wikipedia.org
发送 HTTPS 请求(打开 TLS 连接)。流量已由工作负载加密,因此您可以安全地禁用 Istio 的双向 TLS$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: my-wikipedia spec: host: my-wikipedia.default.svc.cluster.local trafficPolicy: tls: mode: DISABLE EOF
从具有 Istio Sidecar 的源 Pod 通过 Kubernetes 服务的集群 IP 访问
wikipedia.org
$ kubectl exec "$SOURCE_POD" -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>" <title>Wikipedia, the free encyclopedia</title>
检查访问是否确实通过集群 IP 执行。注意
curl -v
输出中的句子Connected to en.wikipedia.org (172.21.156.230)
,它提到了在您服务输出中打印的 IP 作为集群 IP。$ kubectl exec "$SOURCE_POD" -c curl -- curl -sS -v --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page -o /dev/null * Added en.wikipedia.org:443:172.21.156.230 to DNS cache * Hostname en.wikipedia.org was found in DNS cache * Trying 172.21.156.230... * TCP_NODELAY set * Connected to en.wikipedia.org (172.21.156.230) port 443 (#0) ...
清理具有端点的 Kubernetes 服务
$ kubectl delete destinationrule my-wikipedia
$ kubectl delete endpoints my-wikipedia
$ kubectl delete service my-wikipedia