简述
默认情况下,Istio服务Mesh中的Pod,由于其 iptables 将所有外发流量都透明的转发给了 Sidecar,所以这些集群内的服务无法访问集群之外的 URL,而只能处理集群内部的目标。本文主要介绍如何让Istio 集群中的服务访问外部的服务,即如何通过定义 ServiceEntry 来调用外部服务简单的对 Istio 进行配置,或要求其直接放行对特定 IP 范围的访问。
前提
- 正确安装Istio
- 安装实例程序sleep
- 手动或自动注入sidecar
kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml)
YAML具体内容如下:
apiVersion: v1
kind: ServiceAccount
metadata:
name: sleep
---
apiVersion: v1
kind: Service
metadata:
name: sleep
labels:
app: sleep
spec:
ports:
- port: 80
name: http
selector:
app: sleep
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: sleep
spec:
replicas: 1
template:
metadata:
labels:
app: sleep
spec:
serviceAccountName: sleep
containers:
- name: sleep
image: pstauffer/curl
command: ["/bin/sleep", "3650d"]
imagePullPolicy: IfNotPresent
- 将 SOURCE_POD 环境变量设置为已部署的 sleep pod:
export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})
在 Istio 中配置外部服务
通过配置 Istio ServiceEntry,可以从 Istio 集群中访问任何可公开外部的服务。 这里我们会使用 httpbin.org 以及 www.google.com 进行试验。
- 配置外部服务
1.创建一个 ServiceEntry 对象,放行对一个外部 HTTP 服务的访问:
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
ports:
- number: 80
name: http
protocol: HTTP
resolution: DNS
location: MESH_EXTERNAL
EOF
2.进入具体的服务Pod:
kubectl exec -it $SOURCE_POD -c sleep sh
3.向外部 HTTP 服务发出请求。
curl http://httpbin.org/headers
- 配置外部 HTTPS 服务
1.创建一个 ServiceEntry 以允许访问外部 HTTPS 服务。
对于 TLS 协议(包括 HTTPS),除了 ServiceEntry 之外,还需要 VirtualService。 没有 VirtualService, ServiceEntry 所暴露的服务将不被定义。VirtualService 必须在 match 子句中包含 tls 规则和 sni_hosts 以启用 SNI 路由。
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: google
spec:
hosts:
- www.google.com
ports:
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: google
spec:
hosts:
- www.google.com
tls:
- match:
- port: 443
sni_hosts:
- www.google.com
route:
- destination:
host: www.google.com
port:
number: 443
weight: 100
EOF
2.执行 sleep service 源 pod:
kubectl exec -it $SOURCE_POD -c sleep sh
3.向外部 HTTPS 服务发出请求:
curl https://www.google.com
- 为外部服务设置路由规则
通过 ServiceEntry 访问外部服务的流量,和网格内流量类似,都可以进行 Istio 路由规则 的配置。下面我们使用 istioctl 为 httpbin.org 服务设置一个超时规则。在测试 Pod 内部,使用 curl 调用 httpbin.org 这一外部服务的 /delay 端点:
kubectl exec -it $SOURCE_POD -c sleep sh
time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
200
real 0m5.024s
user 0m0.003s
sys 0m0.003s
这个请求会在大概五秒钟左右返回一个内容为 200 (OK) 的响应。退出测试 Pod,使用 kubectl 为 httpbin.org 外部服务的访问设置一个 3 秒钟的超时:
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
http:
- timeout: 3s
route:
- destination:
host: httpbin.org
weight: 100
EOF
等待几秒钟之后,再次发起 curl 请求:
kubectl exec -it $SOURCE_POD -c sleep sh
time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
504
real 0m3.149s
user 0m0.004s
sys 0m0.004s
这一次会在 3 秒钟之后收到一个内容为 504 (Gateway Timeout) 的响应。虽然 httpbin.org 还在等待他的 5 秒钟,Istio 却在 3 秒钟的时候切断了请求。
直接调用外部服务
如果想要跳过 Istio直接访问某个 IP 范围内的外部服务,就需要对 Envoy sidecar 进行配置,阻止 Envoy 对外部请求的劫持。不推荐此方式,详细了解请自行查阅文档。
总结
控制Egress流量,可以使用两种方式从 Istio 服务Mesh内部来完成对外部服务的调用:
- 使用 ServiceEntry (推荐方式)
- 配置 Istio sidecar,从它的重定向 IP 表中排除外部服务的 IP 范围
第一种方式(ServiceEntry)中,Mesh内部的服务不论是访问内部还是外部的服务,都可以使用同样的 Istio 服务Mesh的特性。我们通过为外部服务访问设置超时规则的例子,来证实了这一优势。第二种方式越过了 Istio sidecar proxy,让服务直接访问到对应的外部地址。然而要进行这种配置,需要了解云供应商特定的知识和配置。