概述

ServiceEntry 也是 Istio 中的一个重要的 API 资源对象。
它可以将外部的服务添加到网格的内部,从而可以实现管理集群内部服务调用外部服务的请求,达到扩展网格的目的。
示例图如下所示:
image.png

实战

场景描述

在本文中,我们会将 httpbin 注册为网格内的服务,并配置相关的流控策略。
通过本文的学习,我们相信你能够掌握:

  • 学会通过 ServiceEntry 扩展网格。
  • 掌握 ServiceEntry 的配置方法。

StepByStep

Step1:添加 sleep 服务作为客户端

  1. kubectl apply -f samples/sleep/sleep.yaml -n istio-demo
  2. # serviceaccount/sleep created
  3. # service/sleep created
  4. # deployment.apps/sleep created

Step2:试用外部服务 httpbin

为了模拟外部服务,我们使用了一个开放的 httpbin.org 网站。
它是一个简单的可以用于 HTTP 请求的测试的网站服务,可以使用浏览器打开。
image.png
它提供了很多常用的 api 可以用于测试 HTTP 请求。
例如:http://httpbin.org/headers
image.png
此时,我们可以用我们刚才创建的 sleep 容器作为客户端来测试一下调用 httpbin 服务的效果:

  1. export POD_NAME=$(kubectl get pods -n istio-demo -l app=sleep -o jsonpath='{.items[0].metadata.name}')
  2. kubectl exec -it $POD_NAME -n istio-demo -c sleep curl http://httpbin.org/headers

可以看到,目前是可以正常访问外部服务的。
image.png

Step3:关闭网格内服务直接访问外部权限

为了验证 ServiceEntry 的功能,下面,我们先来临时关闭网格内服务直接访问网格外部服务的权限,而仅允许访问注册了的网格外部服务。
配置方式如下:

  1. kubectl edit cm istio -n istio-system

image.png
在 mesh 的配置中将 outboundTrafficPolicy 的 mode 修改为 REGISTRY_ONLY ,然后保存即可。
稍等片刻,再次重新访问一下 http://httpbin.org/headers 服务:

  1. export POD_NAME=$(kubectl get pods -n istio-demo -l app=sleep -o jsonpath='{.items[0].metadata.name}')
  2. kubectl exec -it $POD_NAME -n istio-demo -c sleep curl http://httpbin.org/headers

你会发现此时已经看不到响应信息了,说明上述策略已经生效啦!

Step4:为外部服务(httpbin)配置ServiceEntry

下面我们来定义一个 ServiceEntry,配置文件为 serviceentry.yaml 。

  1. apiVersion: networking.istio.io/v1alpha3
  2. kind: ServiceEntry
  3. metadata:
  4. name: httpbin-ext
  5. spec:
  6. hosts:
  7. - httpbin.org
  8. ports:
  9. - number: 80
  10. name: http
  11. protocol: HTTP
  12. resolution: DNS
  13. location: MESH_EXTERNAL

我们让它生效一下:

  1. kubectl apply -f ./samples/bookinfo/networking/serviceentry.yaml -n istio-demo
  2. # serviceentry.networking.istio.io/httpbin-ext created

然后再次重新调用一下 httpbin.org 服务看看:

  1. export POD_NAME=$(kubectl get pods -n istio-demo -l app=sleep -o jsonpath='{.items[0].metadata.name}')
  2. kubectl exec -it $POD_NAME -n istio-demo -c sleep curl http://httpbin.org/headers

又正常可以访问啦,说明我们的 ServiceEntry 已经正常生效啦!

原理说明

配置分析

下面,我们来了解一下刚才的配置文件表示的含义吧:

  1. apiVersion: networking.istio.io/v1alpha3
  2. kind: ServiceEntry
  3. metadata:
  4. name: httpbin-ext
  5. spec:
  6. hosts:
  7. - httpbin.org
  8. ports:
  9. - number: 80
  10. name: http
  11. protocol: HTTP
  12. resolution: DNS
  13. location: MESH_EXTERNAL

其中:

  • hosts: 表示注册的服务名称;
  • ports: 表示注册的端口;
  • resolution: 表示解析注册服务名称的方式;
  • location:表示注册服务真实的位置。

翻译一下就是:我们需要注册一个 http://httpbin.org:80 的服务,这个服务在 MESH 网格外部,访问该服务时,可以通过 DNS 的方式来解析真实的地址。

资源配置项

上述的配置是一个非常简单的配置方式,下面,我们来了解一下服务入口的完整的配置:
image.png

  • hosts 表示定义的外部服务的名称。
  • addresses 和 hosts 比较类似,可以认为是外部服务的 IP。
  • ports 表示具体的外部服务的端口信息和协议。
  • endpoints 可以用于定义具体的节点。
  • resolution 表示服务发现的方式,支持 NONE,STATIC和DNS三种方式。
  • location 表示该服务是在 MESH 内部还是外部。

思考与实战

配置一个 https 协议的服务入口

如果我们修改一下上述的 curl 命令,将 http 协议修改为 https 协议会发生什么呢?

  1. kubectl exec -it $POD_NAME -n istio-demo -c sleep curl https://httpbin.org/headers
  2. # curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to httpbin.org:443
  3. # command terminated with exit code 35

你会看到请求失败了,但是 httpbin.org 网站本身其实是支持 https 协议的,失败的原因正是在于我们注册的 ServiceEntry 仅支持了 http 协议,没有支持 https 协议。
下面,我们修改一下 serviceentry.yaml 配置文件如下:

  1. apiVersion: networking.istio.io/v1alpha3
  2. kind: ServiceEntry
  3. metadata:
  4. name: httpbin-ext
  5. spec:
  6. hosts:
  7. - httpbin.org
  8. ports:
  9. - number: 80
  10. name: http
  11. protocol: HTTP
  12. - number: 443
  13. name: https
  14. protocol: TLS
  15. resolution: DNS
  16. location: MESH_EXTERNAL

然后更新一下配置:

  1. kubectl apply -f ./samples/bookinfo/networking/serviceentry.yaml -n istio-demo

再看访问看看:

  1. kubectl exec -it $POD_NAME -n istio-demo -c sleep curl https://httpbin.org/headers

不错,又可以啦!