Istio Ingress Gateway 介绍、演示

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

下载 Istio

curl -L https://istio.io/downloadIstio | sh -
cd istio-1.9.0

cat >> /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           80/TCP,443/TCP,15443/TCP                                                     165m
istio-ingressgateway   LoadBalancer   10.99.186.2           15021:31872/TCP,80:31963/TCP,443:31474/TCP,31400:30316/TCP,15443:32160/TCP   165m
istiod                 ClusterIP      10.109.254.235           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 介绍、演示)