美文网首页
Istio Ingress Gateway 介绍、演示

Istio Ingress Gateway 介绍、演示

作者: 读书学习看报 | 来源:发表于2021-05-07 22:31 被阅读0次

    前面演示了 Ingress 在 Kubernetes 中的应用,这章介绍下 Istio Gateway 入站网关。

    下载 Istio

    curl -L https://istio.io/downloadIstio | sh -
    cd istio-1.9.0
    
    cat >> /etc/profile <<EOF
    export PATH=/opt/istio/istio-1.9.0/bin:$PATH
    EOF
    source /etc/profile
    

    安装 Istio

    # istioctl install -f /opt/cloud/istio-operator.yml -y
    istioctl install --set profile=demo -y
    kubectl label namespace cloud istio-injection=enabled
    

    输出信息:

    ✔ Istio core installed                                                                                                                                                                       
    ✔ Istiod installed                                                                                                                                                                           
    ✔ Egress gateways installed                                                                                                                                                                  
    ✔ Ingress gateways installed                                                                                                                                                                 
    ✔ Installation complete
    

    Istio 控制器运行起来后,可以通过编辑 IstioOperator 对象来改变 Istio 的配置。控制器会检测到改变,继而用相应配置更新 Istio 的安装内容。istio-operator.yml 这个文件我也放在了项目的根目录下。

    apiVersion: install.istio.io/v1alpha1
    kind: IstioOperator
    metadata:
      name: cloud-istio-operator
      namespace: istio-system
    spec:
      profile: demo
      meshConfig:
        accessLogFile: /dev/stdout
        accessLogEncoding: TEXT
    

    安装完成后,即可在 Dashboard 界面看到 istio-system 命名空间下的 Workloads、Discovery and Load Balancing 信息。

    在 istio-1.9.0/samples/addons 下有一些监控、追踪的插件 Prometheus、 Grafana、Jaeger,安装很容易,下面一条命令即可,你可以去部署了解一下。

    # 在 istio-1.9.0 文件夹下
    kubectl apply -f samples/addons
    

    下图是 Istio 可视化工具 Kiali 的界面:

    上面在安装 Istio 的时候,执行了这一句:kubectl label namespace cloud istio-injection=enabled 它会给我们微服务所在的 cloud 命名空间添加 istio-injection=enabled 标签,这样在部署应用的时候,Istio 会自动的将 sidecar 容器注入到 Pod 中 ,查看命名空间标签信息:

    [root@k8s002 ~]# kubectl get namespaces --show-labels
    NAME                   STATUS   AGE    LABELS
    cloud                  Active   4d     istio-injection=enabled
    default                Active   4d     istio-injection=enabled
    ingress-nginx          Active   3d1h   app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    istio-system           Active   34h    istio-injection=disabled
    

    Istio 的流量管理模型源于和服务一起部署的 Envoy 代理,网格内服务发送和接收的所有流量都经由 Envoy 代理,这让控制网格内的流量变得非常简单,而且不需要对服务做任何的更改,它是一种与语言彻底解偶的服务治理方案。

    上一节,我们已经将几个微服务部署到了 Kubernetes 平台,现在为了给我们的服务添加 Istio 支持,通过下面的命令将 cloud 命名空间下的所有 Pod 都删除,然后 Deployment、ReplicaSet 控制器模式会重建所有 Pod,这时 Istio 会自动为我们的服务注入 sidecar 容器。

    kubectl delete --all pods --namespace=cloud
    

    这时候再去看下新的 Pod 信息,已经被自动注入了下面两个容器:istio-proxy、istio-init。(或者通过命令 kubectl describe pod {name} -n cloud 查看 Pod 信息)

    sidecar 注入其实就是在 Pod 的 YML 模板中添加额外的容器配置,这个模板在名称为 istio-sidecar-injector 的 Config Maps 对象中。

    • istio-init

      它的作用是配置 iptables 规则,将入站、出站流量交由 istio-proxy 代理,init 容器会在应用容器启动之前运行,并且执行完成后就退出了,通常用来完成一些初始化任务。

    • istio-proxy

      真正的 sidecar 代理,基于 Envoy 实现。

    istio-proxy 是如何获取应用容器的入站和出站流量?答案就在 istio-init 这个容器中。

    initContainers:
        - name: istio-init
          image: docker.io/istio/proxyv2:1.9.0
          args:
            - istio-iptables
            - '-p'
            - '15001'
            - '-z'
            - '15006'
            - '-u'
            - '1337'
            - '-m'
            - REDIRECT
            - '-i'
            - '*'
            - '-x'
            - ''
            - '-b'
            - '*'
            - '-d'
            - 15090,15021,15020
    
    • -p 15001 表示出站流量被 iptable 重定向到 Envoy 的 15001 端口
    • -z 15006 表示入站流量被 iptable 重定向到 Envoy 的 15006 端口
    • -u 1337 用于排除用户 ID 为 1337 即 istio-proxy 自身的流量
    [root@k8s002 ~]# docker ps -a | grep istio-init
    a06bf54904f9   istio/proxyv2  "/usr/local/bin/pilo…"   5 hours ago    Exited (0) 5 hours ago  k8s_istio-init_user-server-9b9656cbb-7vsx2_cloud_2809324e-6fc6-4f32-8fec-c7dfa95f0497_0
    ab76b4bfb6f1   istio/proxyv2  "/usr/local/bin/pilo…"   5 hours ago    Exited (0) 5 hours ago  k8s_istio-init_order-server-d5f799765-9w7vn_cloud_98772936-423f-4796-b6d4-fdf170b8bb2a_0
    35149e8f46b1   istio/proxyv2  "/usr/local/bin/pilo…"   5 hours ago    Exited (0) 5 hours ago  k8s_istio-init_actuator-admin-7c595b74d9-kn6wk_cloud_3ce9994b-0b52-4b81-b93d-978134bbbeb7_0
    

    通过 docker logs a06bf54904f9 查看一个 istio-init 容器的日志,会输出 istio-init 所配置的 iptables 规则。

    *nat
    ......
    -A PREROUTING -p tcp -j ISTIO_INBOUND
    -A OUTPUT -p tcp -j ISTIO_OUTPUT
    ......
    -A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
    -A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
    ......
    -A ISTIO_OUTPUT -j ISTIO_REDIRECT
    -A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
    COMMIT
    
    • PREROUTING 所有到达 Pod 的入站流量被重定向到端口 15006
    • OUTPUT 所有出站流量被重定向到端口 15001,这些都是 istio-proxy 正在监听的端口。
    [root@k8s002 ~]# docker exec -it b5e4c3488480  netstat -tnlp
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name  
    tcp        0      0 0.0.0.0:15006           0.0.0.0:*               LISTEN      13/envoy  
    tcp        0      0 0.0.0.0:9097            0.0.0.0:*               LISTEN      -   
    tcp        0      0 0.0.0.0:15021           0.0.0.0:*               LISTEN      13/envoy  
    tcp        0      0 0.0.0.0:15090           0.0.0.0:*               LISTEN      13/envoy  
    tcp        0      0 127.0.0.1:15000         0.0.0.0:*               LISTEN      13/envoy  
    tcp        0      0 0.0.0.0:15001           0.0.0.0:*               LISTEN      13/envoy  
    tcp6       0      0 :::15020                :::*                    LISTEN      1/pilot-agent
    

    在 Kubernetes 中,代理被注入到 Pod 中,通过配置 iptables 规则来捕获流量,一旦 sidecar 代理被注入,Istio 就可以通过 sidecar 代理来协调所有的流量。

    下面是 order-server 中 sidecar 代理的部分日志,会看到所有 inbound 和 outbound 的请求信息,下面一个是 actuator-admin 服务探测客户端是否在线的请求,另一个是 eureka 客户端的续约请求。查看 istio-proxy 日志命令:kubectl logs -f -l app=order-server -c istio-proxy -n cloud

    • -l 指定标签信息
    • -c 指定容器名称
    • -n 指定命名空间
    [2021-02-24] "GET /actuator/health HTTP/1.1" 200 - via_upstream - "-" 0 15 2 1 "-" "ReactorNetty/0.8.15.RELEASE" "8bcd13fa-2e95-90c6-8fa3-a579c36facf2" "10.244.1.70:9099" "127.0.0.1:9099" inbound|9099|| 127.0.0.1:38332 10.244.1.70:9099 10.244.1.69:34062 - default
    [2021-02-24] "PUT /eureka/apps/ORDER-SERVER/10.244.1.70:9099?status=UP&lastDirtyTimestamp=1614156772911 HTTP/1.1" 200 - via_upstream - "-" 0 0 1 1 "-" "Java-EurekaClient/v1.9.8" "6b711a7c-1d72-9f0b-a825-1fafdb9da462" "eureka-server:18761" "10.244.0.16:18761" outbound|18761||eureka-server.cloud.svc.cluster.local 10.244.1.70:53380 10.97.40.48:18761 10.244.1.70:45068 - default
    [2021-02-24] "GET /eureka/apps/delta HTTP/1.1" 200 - via_upstream - "-" 0 87 1 1 "-" "Java-EurekaClient/v1.9.8" "179d11d3-5591-92c7-871b-05bfd71e98fd" "eureka-server:18761" "10.244.0.16:18761" outbound|18761||eureka-server.cloud.svc.cluster.local 10.244.1.70:53380 10.97.40.48:18761 10.244.1.70:45068 - default
    

    下面演示如何通过 Istio Ingress Gateway 来转发外部请求

    在 Kubernetes 环境中,使用 Ingress 对象来指定需要暴露到集群外的服务,但是 Ingress 本身是不支持 TCP 协议的,只能用于 HTTP 流量。在 Istio 服务网格中,使用了一种新的配置模型 Istio Gateway 将服务暴露至服务网格之外,它通过将 L4 配置与 L7 配置分离的方式克服了 Ingress 不支持 TCP 路由的问题。

    • Gateway
    • VirtualService

    Istio Gateway 是运行在网格边界的独立 Envoy 代理,而不是工作负载的 sidecar 代理,Istio 为我们提供了一些预先配置好的网关代理部署 istio-ingressgateway 和 istio-egressgateway,下面要创建的 cloud-gateway 就是基于 istio-ingressgateway 实现的 selector:istio:ingressgateway

    cloud-gateway 网关配置让 HTTP 流量从 47.103.80.230 通过 80 端口流入网格,这里没有为请求指定任何的路由规则,要为网关指定路由,需要把网关绑定到虚拟服务 VirtualService 上。

    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
      name: cloud-gateway
    spec:
      selector:
        istio: ingressgateway # use Istio default gateway implementation
      servers:
        - port:
            number: 80
            name: http
            protocol: HTTP
          hosts:
            - 47.103.80.230
    

    VirtualService

    在 VirtualService 中使用路由规则,告诉 istio-ingressgateway 将请求路由到哪个服务,路由目标地址可以是同一服务的不同版本,也可以是完全不同的服务(DestinationRule),未匹配任何路由规则的请求均会被拒绝并返回 404 响应。

    VirtualService 中的路由规则要比 Ingress 强大很多,它可以配置请求超时时间、失败重试次数、熔断器,可以进行故障注入测试,而且它提供的匹配规则非常丰富,可以在端口、header 字段、URI 、queryParams 查询参数等内容上设置匹配条件,还可以对请求进行重定向 HTTPRedirect、重写 HTTPRewrite,这些功能在项目中均提供了示例。

    spec:hosts 虚拟服务主机名可以是 IP 地址,或者是完全限定域名 FQDN,也可以使用通配符 "*" 前缀,匹配所有服务的路由规则。

    destination:host 必须是存在于 Istio 服务注册中心的实际目标地址,否则 Envoy 代理不知道将请求发送到哪里。

    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: user
    spec:
      hosts:
      - "*"
      gateways:
      - cloud-gateway
      http:
      - match:
        - uri:
            prefix: /user
        route:
        - destination:
            port:
              number: 9097
            host: user-server.cloud.svc.cluster.local
        timeout: 10s
        retries:
          attempts: 3
          perTryTimeout: 2s
    ...... 完整配置,请 clone 项目后查看
    

    我们 cloud 微服务演示项目提供的 Istio 网关路由配置文件在项目的根目录下,名称为 istio-gateway.yml。

    部署命令 kubectl apply -f /opt/cloud/istio-gateway.yml,部署成功后即可进行下面的测试。

    Ingress Gateway 使用了 Loadbalancer 的方式暴露,通过 kubectl get svc -n istio-system 命令查看到 istio-ingressgateway 暴露到了 31963 端口,下面通过几个微服务的接口来测试下(注意暴露端口需要添加 ECS 安全组规则)。

    [root@k8s001 ~]# kubectl get svc -n istio-system
    NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                                                                      AGE
    istio-egressgateway    ClusterIP      10.109.231.239   <none>        80/TCP,443/TCP,15443/TCP                                                     165m
    istio-ingressgateway   LoadBalancer   10.99.186.2      <pending>     15021:31872/TCP,80:31963/TCP,443:31474/TCP,31400:30316/TCP,15443:32160/TCP   165m
    istiod                 ClusterIP      10.109.254.235   <none>        15010/TCP,15012/TCP,443/TCP,15014/TCP                                        165m
    

    下面是每个微服务中提供的一些接口,可以访问测试下连通性:

    接口地址 调用服务
    http://IP:31963/order/init order-server
    http://IP:31963/auth/init auth-server
    http://IP:31963/order/user/list order-server -> user-server -> auth-server
    http://IP:31963/user/init user-server

    访问后,可以查看 istio-ingressgateway 的日志,会输出一次请求的具体信息。

    查看日志命令为:kubectl logs -f -l istio=ingressgateway -c istio-proxy -n istio-system

    [2021-02-24T06:30:07.775Z] "GET /order/init HTTP/1.1" 200 - via_upstream - "-" 0 86 9 8 "10.244.1.1" "PostmanRuntime/7.26.10" "e304f605-0047-93b8-b201-10da3ce764fe" "47.103.80.230:31963" "10.244.1.66:9099" outbound|9099||order-server.cloud.svc.cluster.local 10.244.1.57:58992 10.244.1.57:8080 10.244.1.1:24551 - -
    [2021-02-24T06:30:12.370Z] "GET /auth/init HTTP/1.1" 200 - via_upstream - "-" 0 85 6 6 "10.244.1.1" "PostmanRuntime/7.26.10" "d1afb272-413c-987b-92c4-d6dc5514823b" "47.103.80.230:31963" "10.244.1.63:9096" outbound|9096||auth-server.cloud.svc.cluster.local 10.244.1.57:60132 10.244.1.57:8080 10.244.1.1:24551 - -
    [2021-02-24T06:30:21.660Z] "GET /order/user/list HTTP/1.1" 200 - via_upstream - "-" 0 204 22 22 "10.244.1.1" "PostmanRuntime/7.26.10" "b7ba1167-4507-9f9a-8ef9-2a2b5dc09c51" "47.103.80.230:31963" "10.244.1.66:9099" outbound|9099||order-server.cloud.svc.cluster.local 10.244.1.57:58992 10.244.1.57:8080 10.244.1.1:24551 - -
    [2021-02-24T06:31:24.201Z] "GET /user/init HTTP/1.1" 200 - via_upstream - "-" 0 85 3 2 "10.244.1.1" "PostmanRuntime/7.26.10" "d880d400-ff95-9958-b004-e39eca0cafc8" "47.103.80.230:31963" "10.244.1.67:9097" outbound|9097||user-server.cloud.svc.cluster.local 10.244.1.57:44756 10.244.1.57:8080 10.244.1.1:24551 - -
    

    为了在网格中导流,Istio 需要知道所有的 endpoint 在哪并且属于哪个服务,Istio 自身并不提供服务发现功能,它会连接到一个服务发现系统,我们这里是在 Kubernetes 平台中部署 Istio,它会自动检测该集群中的服务和 endpoint。

    Istiod

    在 Istio 1.5 之后,控制平面进行了简化,将 Pilot、Galley、Citadel 和 sidecar 注入器执行的功能都合并成了单一的 istiod 服务,只需启动单个 Pod,就可以启用一个包含了所有功能的 Istio 控制平面。

    istio-proxy@istiod-6f984b7878-8zxjc:/$ ps aux
    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    istio-p+     1  0.2  1.0 784732 79848 ?        Ssl  09:15   0:33 /usr/local/bin/pilot-discovery discovery --monitoringAddr=:15014 --log_output_level=default:info --domain cluster.local --keepalive
    istio-p+    53  0.0  0.0  18504  2072 pts/0    Ss   12:52   0:00 bash
    
    istio-proxy@istiod-6f984b7878-8zxjc:/$ netstat -tnlp
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address           Foreign Address    State       PID/Program name  
    tcp        0      0 127.0.0.1:9876          0.0.0.0:*          LISTEN      1/pilot-discovery   
    tcp6       0      0 :::15010                :::*               LISTEN      1/pilot-discovery   
    tcp6       0      0 :::15012                :::*               LISTEN      1/pilot-discovery   
    tcp6       0      0 :::15014                :::*               LISTEN      1/pilot-discovery   
    tcp6       0      0 :::15017                :::*               LISTEN      1/pilot-discovery   
    tcp6       0      0 :::8080                 :::*               LISTEN      1/pilot-discovery   
    

    Istio 提供的几个分析、诊断命令:

    • istioctl analyze 可以检测 Istio 配置的潜在问题
    [root@k8s002 istio-1.9.0]#  istioctl analyze -n cloud
    Info [IST0118] (Service actuator-admin.cloud) Port name  (port: 5000, targetPort: 5000) doesn't follow the naming convention of Istio port.
    Info [IST0118] (Service api-gateway.cloud) Port name  (port: 4000, targetPort: 4000) doesn't follow the naming convention of Istio port.
    ......
    

    上面诊断我们微服务示例命名空间 cloud,提示 Service 对象没有遵循 Istio 的端口命名规则。参看官方说明

    # 正确写法如下
    spec:
      ports:
      - name: tcp
        port: 5000
        protocol: TCP
        targetPort: 5000
        nodePort: 32700
    
    • istioctl describe 验证 Pod 网络
    [root@k8s002 istio-1.9.0]# istioctl experimental describe pod user-server-9b9656cbb-t8dx6 -n cloud
    Pod: user-server-9b9656cbb-t8dx6
       Pod Ports: 9097 (user-server), 15090 (istio-proxy)
    Suggestion: add 'app' label to pod for Istio telemetry.
    Suggestion: add 'version' label to pod for Istio telemetry.
    --------------------
    Service: user-server
       Port:  9097/auto-detect targets pod port 9097
    
    Exposed on Ingress Gateway http://172.24.251.203
    VirtualService: user.default
       /user*
       2 additional destination(s) that will not reach this pod
    

    Pod 内的服务容器的端口 9097,Pod 内的 istio-proxy 容器的端口 15090,通过 Ingress Gateway 暴露的 virtual service 规则。

    • istioctl proxy-config endpoints 查看当前可用的 endpoint
    [root@k8s002 ~]# istioctl proxy-config endpoints order-server-5676b7dcd6-85xrn.cloud | grep cloud
    10.244.0.39:4000     HEALTHY     OK     outbound|4000||api-gateway.cloud.svc.cluster.local
    10.244.0.40:9099     HEALTHY     OK     outbound|9099||order-server.cloud.svc.cluster.local
    10.244.0.41:9097     HEALTHY     OK     outbound|9097||user-server.cloud.svc.cluster.local
    10.244.1.134:5000    HEALTHY     OK     outbound|5000||actuator-admin.cloud.svc.cluster.local
    10.244.1.135:18761   HEALTHY     OK     outbound|18761||eureka-server.cloud.svc.cluster.local
    10.244.1.136:9096    HEALTHY     OK     outbound|9096||auth-server.cloud.svc.cluster.local
    

    卸载 Istio 命令:

    istioctl x uninstall --purge
    kubectl delete namespace istio-system
    

    ~ 终 ~

    相关文章

      网友评论

          本文标题:Istio Ingress Gateway 介绍、演示

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