上一篇讲了一些入口流量的事情,在实际项目运行中,还有另外一类边界流量,就是出口流量,也常被称为 egress 流量。这一篇结合一点实际需求,设计一些常用场景,讲讲服务网格中对外部服务的调用过程。
这里我们需要几个服务定义,首先是用于模拟客户端服务的工作负载,这里继续使用 dustise/sleep
镜像。外部我们使用两个网站作为我们的外部服务演示,分别代表 http
和 https
两种:http://httpbin.org
和 https://api.jd.com/
。
开始之前
根据安装文档的说明完成 Istio 的部署,这里建议使用 Helm 方式。
使用的 dustise/sleep
镜像生成两个负载,使用 version
标签将负载拆分为 v1
和 v2
两个版本。源码见文末。
$ istioctl kube-inject -f sleep.dual.yaml | kubectl apply -f - service/sleep created deployment.extensions/sleep-v1 created deployment.extensions/sleep-v2 created
然后使用环境变量保存新建 Pod 名称:
export SLEEP_V1=$(kubectl get pod -l app=sleep,version=v1 -o jsonpath={.items..metadata.name})export SLEEP_V2=$(kubectl get pod -l app=sleep,version=v2 -o jsonpath={.items..metadata.name})
创建 ServiceEntry
首先创建一个 ServiceEntry
,指向 httpbin.org:
apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: httpbin-ext spec: hosts: - httpbin.org ports: - number: 80 name: http protocol: HTTP resolution: DNS
然后给 api.jd.com 创建一个 ServiceEntry:
apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: jd-api spec: hosts: - api.jd.com ports: - number: 443 name: https protocol: HTTPS resolution: DNS
发起外部访问
$ kubectl exec -it $SLEEP_V1 -c sleep sh / # curl http://httpbin.org/ip{ "origin": "168.63.251.242"} / # curl https://api.jd.com<html> ... </html> / # curl -v http://api.jd.com... < HTTP/1.1 404 Not Found ... * Connection #0 to host api.jd.com left intact
可以看到,已经注册了的主机,可以通过对应的协议来进行访问了,但是如果协议不匹配,也会返回 404 代码。后面的内容,会选择几个常见场景进行演示。
服务质量监控
Istio 提供了很多的指标数据,对于外部服务来说,其服务端并不受控,但是还是可以从客户端获取一定的指标,来判断服务的状态。例如用下面的命令生成负载之后:
kubectl exec -it $SLEEP_V2 -c sleep -- wrk -d 10m http://httpbin.org/
可以在 Grafana 中看到如下的图形:
设置超时限制
外部应用的服务质量通常是不受调用方管理的,为了防止意外超时拖累整体应用,我们可以给外部服务设置一个超时限制,超过这一规则的调用直接中断。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: httpbin-service spec: hosts: - httpbin.org http: - timeout: 3s route: - destination: host: httpbin.org
应用之后,再次进入 Pod 执行指令访问 http://httpbin.org
:
$ kubectl apply -f httpbin-timeout.yaml virtualservice.networking.istio.io/httpbin-service created $ kubectl exec -it $SLEEP_V1 -c sleep sh / # time curl -sSL http://httpbin.org/delay/2 >> /dev/nullreal 0m 2.51s user 0m 0.00s sys 0m 0.00s / # time curl -sSL http://httpbin.org/delay/5upstream request timeout real 0m 3.01s user 0m 0.00s sys 0m 0.00s
上面的测试可以看出,第二次的延迟五秒调用已经返回了超时的结果,并且是在我们的三秒限制之内完成了调用。
使用 kubectl delete -f httpbin-timeout.yaml
删除这一定义,进行下一步。
仅允许指定源头访问
设想我们的网格中,仅有部分应用可以访问一些外部服务,这里我们借用 Istio 的故障注入功能,定义一个 abort 的注入,只允许 sleep:v2
访问 http://httpbin.org
,其他服务的访问尝试会失败。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: httpbin-service spec: hosts: - httpbin.org http: - match: - sourceLabels: app: sleep version: v2 route: - destination: host: httpbin.org - route: - destination: host: httpbin.org fault: abort: percent: 100 httpStatus: 403
上面的定义中,我们首先让 sleep:v2
的筛选条件的请求,转发给 httpbin.org
;而其余流量,则会被注入一个 403 错误。
我们分别从 sleep:v1
和 sleep:v2
服务发起对 httpbin.org
的访问:
$ kubectl exec $SLEEP_V2 -c sleep -- curl -s http://httpbin.org/ip { "origin": "168.63.251.242"} $ kubectl exec $SLEEP_V1 -c sleep -- curl -s -v http://httpbin.org/ip * Trying 52.72.80.190... ... < HTTP/1.1 403 Forbidden < content-length: 18< content-type: text/plain < date: Wed, 22 Aug 2018 06:20:04 GMT < server: envoy < { [18 bytes data] * Connection #0 to host httpbin.org left intactfault filter abort%
可以看到,结果和我们的预测是一致的。
To be continued
上面所述,只是针对 ServiceEntry
的一些粗浅应用,Istio 还提供了 Egress Gateway 这样的高级组件。可以提供更多管理能力,敬请期待。
相关链接
安装文档:
https://istio.io/zh/docs/setup/kubernetes/
RBAC:
https://istio.io/zh/docs/tasks/security/role-based-access-control/
基于 Mixer Adaptor 的访问控制:
https://istio.io/zh/docs/tasks/policy-enforcement/denial-and-list/
部分源码
sleep.yaml
apiVersion: v1 kind: Service metadata: name: sleep labels: app: sleep spec: selector: app: sleep ports: - name: ssh port: 80 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: sleep-v1 spec: replicas: 1 template: metadata: labels: app: sleep version: v1 spec: containers: - name: sleep image: dustise/sleep:v0.5 imagePullPolicy: IfNotPresent --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: sleep-v2 spec: replicas: 1 template: metadata: labels: app: sleep version: v2 spec: containers: - name: sleep image: dustise/sleep:v0.5 imagePullPolicy: IfNotPresent