Istio 小入门 —— ServiceEntry 的对外通信
上一篇讲了一些入口流量的事情,在实际项目运行中,还有另外一类边界流量,就是出口流量,也常被称为 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/null
real 0m 2.51s
user 0m 0.00s
sys 0m 0.00s
/ # time curl -sSL http://httpbin.org/delay/5
upstream 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 intact
fault 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