Istio Ingress Gateway 介绍、演示

2021-05-07  本文已影响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-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
[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
[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

[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 路由的问题。

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 提供的几个分析、诊断命令:

[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
[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 规则。

[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

~ 终 ~

上一篇下一篇

猜你喜欢

热点阅读