• Istio 入门(七):出入口网关 - 负载均衡和熔断等一系列功能


    本教程已加入 Istio 系列:https://istio.whuanle.cn

    5,出入口网关

    Istio 可以管理集群的出入口流量,当客户端访问集群内的应用时, Istio 可以将经过 istio-ingressgateway 的流量实现负载均衡和熔断等一系列功能。

    可是,如果集群内的一个应用要访问 google.com ,那么我们可以给内部所有请求了 google.com 的流量设置负载均衡吗?答案是可以,Istio 提供了 istio-egressgateway 实现这种功能。因为 Pod 中的容器要访问网络时,会被 Envoy 拦截,Envoy 可以很容易地分析这些请求,然后通过一系列手段影响着请求的行为。

    在本章中,将会简单说一下 istio-ingressgateway 和 istio-egressgateway。

    istio-ingressgateway

    入口网关指的是从外部经过 istio-ingressgateway 流入集群的流量,需要创建 Gateway 绑定流量。

    关于 istio-ingressgateway 经过前面几章的学习,大家应该不陌生了。

    istio-ingressgateway 由 Pod 和 Service 组成。 istio-ingressgateway 本身就是一个网关应用,你可以把它当作 Nginx、Apisix、Kong ,你可以从各种各种网关应用中找到与 istio-ingressgateway 类似的概念。

    image-20230526194223740

    image-20230526194154234

    作为一个应用,它需要对外开放一些端口,只有当流量经过这些端口时, istio-ingressgateway 才会起作用。为了在 Kubernetes 中暴露端口, istio-ingressgateway 还有一个 Service 对象。

    image-20230526194139225

    有了 istio-ingressgateway 之后,我们可以通过 Istio Gateway 监控一些域名或IP,然后暴露集群内部的服务 。

    Gateway 的概念跟 Nginx 有很多相似之处。

    比如从配置上看, Gateway 跟 Nginx 如果要监控某个入口流量,它们的配置如下:

    Nginx:

    server {
        listen      80;
        server_name example.org www.example.org;
        #...
    }
    

    Gateway:

      servers:
      - port:
          number: 80
          name: http
          protocol: HTTP
        hosts:
        - example.org
        - www.example.org
    

    这些配置指定了 Gateway 和 Nginx 只监控哪些流量。

    紧接着,监控到指定入口的流量之后,需要将流量转发到集群内的应用中。

    Nginx 可以直接在同一个配置文件里面设置:

    server {
        listen      80;
        server_name example.org www.example.org;
        #...
    }
    
    location /some/path/ {
        proxy_pass http:/bookinfo:9080/;
    }
    

    而 Gateway 需要使用 VirtualService 指定流量转发到哪里,并且 VirtualService 还可以进一步筛选入口地址。

    spec:
      hosts:
      - "www.example.org"
      gateways:
      # 绑定 Gateway
      - mygateway
      http:
        route:
        - destination:
            host: bookinfo
            port:
              number: 9080
    

    所以总结起来,Istio 的做法是 Gateway 监控入口流量,通过 VirtualService 设置流量进入的策略,并指向 Service。而 DestinationRule 则定义了流量流向 Pod 的策略

    部署服务

    下面我们将使用 httpbin 服务作为示例,如何一步步配置在外部访问 httpbin 服务。

    首先部署一个 httpbin 服务,这个 httpbin 服务很简单,包含了 Service 和 Deployment 。

    httpbin.yaml

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: httpbin
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: httpbin
      labels:
        app: httpbin
        service: httpbin
    spec:
      ports:
      - name: http
        port: 8000
        targetPort: 80
      selector:
        app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: httpbin
          version: v1
      template:
        metadata:
          labels:
            app: httpbin
            version: v1
        spec:
          serviceAccountName: httpbin
          containers:
          - image: docker.io/kennethreitz/httpbin
            imagePullPolicy: IfNotPresent
            name: httpbin
            ports:
            - containerPort: 80
    
    kubectl -n bookinfo apply -f httpbin.yaml
    

    配置 Gateway

    然后创建一个 Gateway ,指定监听哪些入口流量。

    httpbin_gw.yaml

    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      selector:
        istio: ingressgateway # use Istio default gateway implementation
      servers:
      - port:
          number: 80
          name: http
          protocol: HTTP
        hosts:
        - "httpbin.s1.whuanle.cn"
        - "*"
    

    这一步为了大家能够通过域名更加直观地了解 Gateway,大家可以修改 httpbin.s1.whuanle.cn 替换为自己的域名。

    然后在自己的电脑中打开 C:\Windows\System32\drivers\etc\hosts 增加一条记录 ,将 IP 指向自己的服务器。

    image-20230515193213923

    kubectl -n bookinfo apply -f httpbin_gw.yaml
    

    现在,我们已经让 istio-ingressgateway 帮我们关注 httpbin.s1.whuanle.cn 这个地址,如果有人访问了 httpbin.s1.whuanle.cn,那么这个流量将会流入到 httpbin-gateway。

    image-20230515190518804

    接下来我们将要为 Gateway 配置服务地址,并配置外部允许访问的地址后缀。

    配置 VistualService:

    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      hosts:
      - "*"
      gateways:
      - httpbin-gateway
      http:
      - match: 
        - uri:
            prefix: /status
        - uri:
            prefix: /delay 
        route:
        - destination:
            port:
              number: 8000
            host: httpbin
    

    当 Gateway 和 VirtualService 端口只有一个时,不需要配置端口绑定。

    kubectl -n bookinfo apply -f httpbin_vs.yaml
    

    找到 istio-ingressgateway 对外暴露的端口。

    kubectl get svc istio-ingressgateway  -n istio-system
    

    1683287785674

    httpbin 是一个 http 测试程序,我们可以通过使用 /status/{状态码} 获取对应的 http 请求状态。

    例如:

    image-20230505200437890

    image-20230505200444999

    image-20230515193314909image-20230515193301641

    如果我们不希望这个服务被外界访问到,我们可以先把 /status 删除。

    kubectl apply -f - <
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      hosts:
      - "*"
      gateways:
      - httpbin-gateway
      http:
      - match:
        - uri:
            prefix: /delay
        route:
        - destination:
            port:
              number: 8000
            host: httpbin
    EOF
    

    此时你将无法访问 status 路径。但是我们还可以访问 /delay 路径。

    httpbin 的 /delay 路径用于测试延迟 http 请求响应使用,/delay/{秒数} 可以指定服务器在多久之后才会返回响应。

    例如 http://192.168.3.150:32309/delay/5 将在 5 秒后响应。

    httpbin 还有很多路由接口,我们可以通过 VirtualService 配置放通哪些路径。

    image-20230505201156220

    如果需要全部放通,可以使用:

    kubectl apply -f - <
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: httpbin
    spec:
      hosts:
      - "*"
      gateways:
      - httpbin-gateway
      http:
      - match:
        - uri:
            prefix: /
        route:
        - destination:
            port:
              number: 8000
            host: httpbin
            subset: v1
    EOF
    

    子版本

    第四章中进行版本路由实验时使用到,可以将流量导入到不同的版本之中。

    kubectl -n bookinfo apply -f - <
    apiVersion: networking.istio.io/v1alpha3
    kind: DestinationRule
    metadata:
      name: httpbin
    spec:
      host: httpbin
      subsets:
      - name: v1
        labels:
          version: v1
    EOF
    

    首先是使用 DestinationRule 指向一个 Service:

      host: httpbin
    

    当然,我们也可以写成

      host: httpbin.bookinfo.svc.cluster.local
    

    通过 host 可以识别到对应的 Kubernetes Service,然后从 Service 对应的 Endpoints 中获得所有 Pod 列表。

    image-20230515194105645

    1684151025350

    通过 Endpoints 获得所有 Pod 之后,查看每个 Pod 的描述信息。当有一个请求到达时,根据 DestinationRule 中的标签选择器,选择合适的 Pod 进行访问。

      - name: v1
        labels:
          version: v1
    

    1684151265603

    istio-egressgateway

    istio-egressgateway 也是 Istio 中的一种组件,需要自行安装。安装 istio-egressgateway 命令:

    helm install istio-egressgateway istio/gateway -n istio-system
    

    在集群中,如果 A 应用访问的地址属于集群中的应用,那么 Istio 可以给这些请求注入各种行为,实现负载均衡和熔断等。

    可是,如果集群内部要访问外部的一个服务时,需要配置访问地址,如 aaa.com,我们应该如何实现负载均衡和熔断这些功能呢?

    image-20230515195151940

    Istio ServiceEntry 是一种资源,允许将外部服务(即不在 Istio 服务网格中的服务)纳入Istio服务网格。通过将外部服务添加到网格,可以使用 Istio 的流量管理和策略功能来控制与这些外部服务的交互。

    以下是一个ServiceEntry示例,将外部HTTP服务 www.google.com添加到Istio服务网格:

    apiVersion: networking.istio.io/v1alpha3  
    kind: ServiceEntry  
    metadata:  
      name: google
    spec:  
      hosts:  
      - www.google.com  
      addresses:  
      - 192.168.1.1  
      ports:  
      - number: 80  
        name: http  
        protocol: HTTP  
      location: MESH_EXTERNAL  
      resolution: DNS  
      endpoints:  
      - address: "www.google.com"  
        ports:  
          http: 80  
        locality: "us-west1/zone1"  
      exportTo:  
      - "*"  
    
    

    在此示例中,我们创建了一个名为httpbin-ext的ServiceEntry资源。指定的主机为httpbin.org,端口号为80,协议为HTTP。此外,我们将resolution设置为DNS,将location设置为MESH_EXTERNAL,表示该服务位于网格之外。

    要将此ServiceEntry应用到集群,请将其保存到一个YAML文件(例如:httpbin-ext.yaml),然后运行以下命令:

    kubectl apply -f httpbin-ext.yaml  
    

    现在,Istio 服务网格中的服务访问 www.google.com 时仍受Istio策略的控制。例如,可以为此 ServiceEntry 创建 VirtualService 以应用流量管理规则,或者为其创建 DestinationRule 以配置负载均衡和连接池设置。

    spec: 包含ServiceEntry的具体配置的对象。

    • hosts: 一个包含要导入的外部服务的主机名(FQDN)的列表。例如:["httpbin.org"]
    • addresses: (可选)与外部服务关联的虚拟IP地址的列表。例如:["192.168.1.1"]
    • ports: 一个描述外部服务使用的端口的列表。每个端口都有以下属性:
      • number: 端口号,例如:80。
      • name: 端口的名称,例如:http
      • protocol: 使用的协议,例如:HTTPTCPHTTPS等。
    • location: 服务的位置。可以是MESH_EXTERNAL(表示服务在网格外部)或MESH_INTERNAL(表示服务在网格内部,但不属于任何已知服务)。
    • resolution: 用于确定服务实例地址的解析方法。可以是NONE(默认值,表示不解析地址),STATIC(表示使用addresses字段中的IP地址),DNS(表示使用DNS解析主机名)或MESH_EXTERNAL
    • endpoints: (可选)外部服务的端点列表。每个端点都有以下属性:
      • address: 端点的IP地址或主机名。
      • ports: 一个包含端口名称和端口号的映射,例如:{"http": 8080}
      • labels: (可选)应用于端点的标签。
      • locality: (可选)端点的地理位置,例如:us-west1/zone1
    • exportTo: (可选)一个包含命名空间名称的列表,指定可以访问此ServiceEntry的命名空间。可以使用星号(*)表示所有命名空间。默认值为*
    • subjectAltNames: (可选)用于验证服务器证书主题替代名(SANs)的列表。

    读者可以从官方文档中了解更多:

    https://istio.io/latest/zh/docs/tasks/traffic-management/egress/egress-control/

  • 相关阅读:
    九、Vue3基础之九
    DCM 中间件家族迎来新成员
    基于docker构建容器镜像
    Vue中事件修饰符与键盘事件
    Docker 实用操作文档
    Docker已存在的容器,怎么(添加新端口号·图文详解)
    [开源福利] FreeRedis 历时两年正式发布 v1.0 [C#.NET Redis Client]
    景联文科技带你了解数据标注之文本标注
    mysql数据库 操作常用命令
    RedisJava基础代码实现
  • 原文地址:https://www.cnblogs.com/whuanle/p/17538692.html