美文网首页
ServiceEntry

ServiceEntry

作者: 程序员札记 | 来源:发表于2022-12-30 16:45 被阅读0次

使用服务入口(Service Entry) 来添加一个服务入口到 Istio 内部维护的服务注册中心。添加了服务入口后,Envoy 代理可以向服务发送流量,就好像它是网格内部的服务一样,可参考 https://istio.io/latest/zh/docs/concepts/traffic-management/#service-entries

ServiceEntry介绍

ServiceEntry用于将未能自动添加至网格中的服务,以手动形式添加至网格中,以使得网格内的自动发现机制能够访问或路由到这些服务

  • 未能自动添加至网格中的服务
  • 网格外部的服务
  • 位于网格内部但自身并未注册于平台注册表的服务手动添加至Istio的内部的服务注册表中

ServiceEntry本身用于描述要引入的外部服务的属性,包括服务的DNS名称、IP地址、端口、协议和相关的端点;

提示:类似于Gateway引入的流量需要由VirtualService进行路由,发往由ServiceEntry引入的服务的流量,还需要由DestinationRule定义其分发机制

image

ServiceEntry

image

ServiceEntry配置示例

示例一

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-https
spec:
  hosts:
  - api.dropboxapi.com
  - www.googleapis.com
  - api.facebook.com
  location: MESH_EXTERNAL
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: DNS

示例二

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-mongocluster
spec:
  hosts:
  - mymongodb.somedomain # not used
  addresses:
  - 192.192.192.192/24 # VIPs
  ports:
  - number: 27018
    name: mongodb
    protocol: MONGO
  location: MESH_INTERNAL
  resolution: STATIC
  endpoints:
  - address: 2.2.2.2
  - address: 3.3.3.3
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: mtls-mongocluster
spec:
  host: mymongodb.somedomain
  trafficPolicy:
    tls:
      mode: MUTUAL
      clientCertificate: /etc/certs/myclientcert.pem
      privateKey: /etc/certs/client_private_key.pem
      caCertificates: /etc/certs/rootcacerts.pem

示例三

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-redirect
spec:
  hosts:
  - wikipedia.org
  - "*.wikipedia.org"
  location: MESH_EXTERNAL
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: NONE
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: tls-routing
spec:
  hosts:
  - wikipedia.org
  - "*.wikipedia.org"
  tls:
  - match:
    - sniHosts:
      - wikipedia.org
      - "*.wikipedia.org"
    route:
    - destination:
        host: internal-egress-firewall.ns1.svc.cluster.local

示例四

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-httpbin
  namespace : egress
spec:
  hosts:
  - example.com
  exportTo:
  - "."
  location: MESH_EXTERNAL
  ports:
  - number: 80
    name: http
    protocol: HTTP
  resolution: DNS
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
 name: istio-egressgateway
 namespace: istio-system
spec:
 selector:
   istio: egressgateway
 servers:
 - port:
     number: 80
     name: http
     protocol: HTTP
   hosts:
   - "*"
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: gateway-routing
  namespace: egress
spec:
  hosts:
  - example.com
  exportTo:
  - "*"
  gateways:
  - mesh
  - istio-egressgateway
  http:
  - match:
    - port: 80
      gateways:
      - mesh
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
  - match:
    - port: 80
      gateways:
      - istio-egressgateway
    route:
    - destination:
        host: example.com

简单的理解就是允许内网向外网服务发送流量请求,但你可能会说正常情况下在pod里也是可以访问外网的,这两者有什么区别呢?

确实默认情况下,Istio 配置 Envoy 代理可以将请求传递给外部服务。但是无法使用 Istio 的特性来控制没有在网格中注册的目标流量。这也正是 ServiceEntry 真正发挥的作用,通过配置服务入口允许您管理运行在网格外的服务的流量。

此外,可以配置虚拟服务和目标规则,以更精细的方式控制到服务条目的流量,就像为网格中的其他任何服务配置流量一样。

为了更好的理解这一块的内容,我们先看一下普通POD发送请求的流程图

image.png

创建 ServiceEntry 资源

举例来说:

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: svc-entry
spec:
  hosts:
  - "www.baidu.com"
  ports:
  - number: 80
    name: http
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS
  location: MESH_EXTERNAL
  resolution: DNS

该 ServiceEntry 资源定义了一个外部网站 www.baidu.com 服务,并将它纳入到 Istio 内部维护的服务注册表(服务网格)中。

创建资源

$ kubectl apply -f svc-entry.yaml`
serviceentry.networking.istio.io/svc-entry created

现在我们已经创建了一个 ServiceEntry, 默认在 default 命名空间。

root@vm:/home/sxf/service-entry# kubectl get se
NAMESPACE   NAME        HOSTS               LOCATION        RESOLUTION   AGE
default     svc-entry   ["www.baidu.com"]   MESH_EXTERNAL   DNS          13s

为了测试这个效果,我们再创建一个pod,然后在pod里访问上面创建的 ServiceEntry。

创建请求客户端资源

为了测试这里创建一个 deployment,并指定了pod数量1个,将其添加到服务网格中

apiVersion: apps/v1
kind: Deployment
metadata:
  name: svc-entry-client
spec:
  replicas: 1
  selector:
    matchLabels:
      app: svc-entry-client-app
  template:
    metadata:
      labels:
        app: svc-entry-client-app
    spec:
      containers:
      - name: busybox
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ["/bin/sh", "-c", "sleep 3600"]

创建资源:

root@vm:/home/sxf/service-entry# kubectl apply -f svc-entry-client.yaml

deployment.apps/svc-entry-client created

默认使用的 default 命名空间,且已默认启用了自动注入功能,否则需要手动注入,执行命令为

$ istioctl kube-inject -f svc-entry-client.yaml | kubectl apply -f -

查看注入结果

root@vm:/home/sxf/service-entry# kubectl get pods -n default
NAME                                READY   STATUS    RESTARTS   AGE
svc-entry-client-67dd4c7794-qkcxg   2/2     Running   0          4m49s

READY 字段的值为2/2,表示当前pod中有两个容器, 说明代理容器已经通过 sidecar 模式注入成功。

我们这里确认一下,可以从下面的 Containers 字段中看到有一个busybox容器,还有一个刚刚注入的 istio-proxy 代理容器。

root@vm:/home/sxf/service-entry# kubectl describe pod/svc-entry-client-67dd4c7794-qkcxg
...
Init Containers:
  istio-init:
    Container ID:  docker://9c9025d0461461c4cebf27ae8aa81570979682eac5f38899016b383fb88d259d
...
Containers:
  busybox:
    Container ID:  docker://7bd46baf68bb00b1c43e128adc4a051f46d5fa9b7aab0207885195e8c596727b
  istio-proxy:
    Container ID:  docker://6d21efecc66bad9a7ea0a76b83d893db6bd60adb663f7fc812964cbf0aa6ce3b 
...   

此时的 client 已经处于服务网络之中。对于上面的 istio-init 这个容器是什么什么的,有兴趣的话,可以参考相关文档。

测试效果

我们在pod 里测试一下效果。

root@vm:/home/sxf/service-entry# kubectl exec -it svc-entry-client-67dd4c7794-qkcxg -- wget -q -O - http://www.baidu.com
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Com...</div> </body> </html

访问成功。

为了通过对比了解它的作用,我们对 svc-entry.yaml 文件做一些修改。将 Service discovery mode 字段resolution 值由 DNS 修改为 STATIC, 同时再添加一个 endpoint 字段。

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: svc-entry
spec:
  hosts:
  - "www.baidu.com"
  ports:
  - number: 80
    name: http
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS
  location: MESH_EXTERNAL
  resolution: STATIC
  endpoints:
  - address: 192.168.0.100

重新应用svc-enry.yaml

root@vm:/home/sxf/service-entry# kubectl apply -f svc-entry.yaml 
serviceentry.networking.istio.io/svc-entry configured

root@vm:/home/sxf/service-entry# kubectl exec -it svc-entry-client-67dd4c7794-qkcxg -- wget -q -O - http://www.baidu.com
wget: server returned error: HTTP/1.1 503 Service Unavailable
command terminated with exit code 1

再次测试,发现已经无法访问。这里503错误是由代理返回的。

出现此现象的主要原因就是 ServiceEntry 在发挥使用。当域名通过istio-proxy(envoy)的时候,会将流量自动定位到endpoints的IP列表上,所以就出现了无法访问的现象。

可以看到我们已经实现到对服务的流量管理。

将外部服务通过 ServiceEntry 加入服务网格后大概是这个样子

image.png

此实验主要是面向网格外部的服务,即 location: MESH_EXTERNAL 的情况。如果是网格内部的服务的话,则为 MESH_INTERNAL

我们先看下关键字段resolution的定义, 它用来定义服务发现的模式,它有三种值,分别为 DNS、STATIC 和 NONE。

对于 DNS 模式来说,当 pod 里的应用发送 www.baidu.com 请求的时候,会使用dns来查找域名指定的服务器,在这种情况下,就和我们平时打开一个网站逻辑完全一样,所以肯定是可以正常访问的。

而对于 STATIC 模式来说,当 pod 里的应用发送 www.baidu.com 请求的时候,会向请求转到 endpoints 字段指定的IP 服务器,我们这里指向的是一个内网IP地址,所以无法正常响应。对于endpoints字段可以多个,并允许对其根据 LB 权重设置, 有兴趣的可以了解下 https://istio.io/latest/zh/docs/reference/config/networking/service-entry/#ServiceEntry-Endpoint

对于 NONE 模式来说,要小心使用,在这种模式下,如果未指定任何IP地址的话,则默认将允许发送到任意IP上。

清理

$ kubectl delete -f svc-entry-client.yaml

$ kubectl delete -f svc-entry.yaml

总结

ServiceEntry 主要用来将一些从内部流向外部的流量进行拦截,并根据情况进行流量转发。如果想要以更细粒度的方式控制到服务入口的流量,可能通过配置虚拟服务和目标规则来实现。

参考

相关文章

  • ServiceEntry

    使用服务入口(Service Entry) 来添加一个服务入口到 Istio 内部维护的服务注册中心。添加了服务入...

网友评论

      本文标题:ServiceEntry

      本文链接:https://www.haomeiwen.com/subject/wunxcdtx.html