技术

《Redis核心技术与实现》笔记 《Prometheus监控实战》笔记 Prometheus 告警学习 calico源码分析 对容器云平台的理解 Prometheus 源码分析 并发的成本 基础设施优化 hashicorp raft源码学习 docker 架构 mosn细节 与微服务框架整合 Java动态代理 编程范式 并发通信模型 《网络是怎样连接的》笔记 go细节 codereview mat使用 jvm 线程实现 go打包机制 go interface及反射 如何学习Kubernetes 《编译原理之美》笔记——后端部分 《编译原理之美》笔记——前端部分 Pilot MCP协议分析 go gc 内存管理玩法汇总 软件机制 istio流量管理 Pilot源码分析 golang io 学习Spring mosn源码浅析 MOSN简介 《datacenter as a computer》笔记 学习JVM Tomcat源码分析 Linux可观测性 MVCC 学习存储 学计算 Gotty源码分析 kubernetes operator kaggle泰坦尼克问题实践 kubernetes自动扩容缩容 神经网络模型优化 直觉上理解机器学习 knative入门 如何学习机器学习 神经网络系列笔记 TIDB源码分析 《阿里巴巴云原生实践15讲》笔记 Alibaba Java诊断工具Arthas TIDB存储——TIKV 《Apache Kafka源码分析》——简介 netty中的线程池 guava cache 源码分析 Springboot 启动过程分析 Spring 创建Bean的年代变迁 Linux内存管理 自定义CNI IPAM 副本一致性 spring redis 源码分析 kafka实践 spring kafka 源码分析 Linux进程调度 让kafka支持优先级队列 Codis源码分析 Redis源码分析 C语言学习 《趣谈Linux操作系统》笔记 docker和k8s安全机制 jvm crash分析 Kubernetes监控 Kubernetes 控制器模型 Prometheus 学习 容器日志采集 容器狂占cpu怎么办? Kubernetes资源调度——scheduler 时序性数据库介绍及对比 influxdb入门 maven的基本概念 《Apache Kafka源码分析》——server Kubernetes objects之编排对象 源码分析体会 《数据结构与算法之美》——算法新解 Kubernetes源码分析——controller mananger Kubernetes源码分析——apiserver Kubernetes源码分析——kubelet Kubernetes介绍 ansible学习 Kubernetes源码分析——从kubectl开始 jib源码分析之Step实现 kubernetes实践 jib源码分析之细节 线程排队 跨主机容器通信 jib源码分析及应用 为容器选择一个合适的entrypoint kubernetes yaml配置 《持续交付36讲》笔记 mybatis学习 程序猿应该知道的 无锁数据结构和算法 CNI——容器网络是如何打通的 为什么很多业务程序猿觉得数据结构和算法没用? 串一串一致性协议 当我在说PaaS时,我在说什么 《数据结构与算法之美》——数据结构笔记 PouchContainer技术分享体会 harbor学习 用groovy 来动态化你的代码 《深入剖析kubernetes》笔记 精简代码的利器——lombok 学习 编程语言的动态性 rxjava3——背压 rxjava2——线程切换 spring cloud 初识 《深入拆解java 虚拟机》笔记 《how tomcat works》笔记 hystrix 学习 rxjava1——概念 Redis 学习 TIDB 学习 分布式计算系统的那些套路 Storm 学习 AQS1——论文学习 Unsafe Spark Stream 学习 linux vfs轮廓 mysql 批量操作优化 《自己动手写docker》笔记 java8 实践 中本聪比特币白皮书 细读 区块链泛谈 比特币 大杂烩 总纲——如何学习分布式系统 hbase 泛谈 forkjoin 泛谈 看不见摸不着的cdn是啥 《jdk8 in action》笔记 程序猿视角看网络 bgp初识 calico学习 AQS2——粗略的代码分析 我们能用反射做什么 web 跨域问题 《clean code》笔记 硬件对软件设计的影响 《Elasticsearch权威指南》笔记 mockito简介及源码分析 2017软件开发小结—— 从做功能到做系统 《Apache Kafka源码分析》——clients dns隐藏的一个坑 《mysql技术内幕》笔记2 《mysql技术内幕》笔记1 log4j学习 为什么netty比较难懂? 回溯法 apollo client源码分析及看待面向对象设计 学习并发 docker运行java项目的常见问题 Scala的一些梗 OpenTSDB 入门 spring事务小结 事务一致性 javascript应用在哪里 《netty in action》读书笔记 netty对http2协议的解析 ssl证书是什么东西 http那些事 苹果APNs推送框架pushy apple 推送那些事儿 编写java框架的几大利器 java内存模型 java exception Linux IO学习 network channel network byte buffer 测试环境docker化实践 netty(七)netty在框架中的使用套路 Nginx简单使用 《Linux内核设计的艺术》小结 Go并发机制及语言层工具 Macvlan Linux网络源代码学习——数据包的发送与接收 《docker源码分析》小结 docker中涉及到的一些linux知识 hystrix学习 Linux网络源代码学习——整体介绍 zookeeper三重奏 数据库的一些知识 Spark 泛谈 链式处理的那些套路 netty(六)netty回顾 Thrift基本原理与实践(二) Thrift基本原理与实践(一) 回调 异步执行抽象——Executor与Future Docker0.1.0源码分析 java gc Jedis源码分析 Redis概述 机器学习泛谈 Linux网络命令操作 JTA与TCC 换个角度看待设计模式 Scala初识 向Hadoop学习NIO的使用 以新的角度看数据结构 并发控制相关的硬件与内核支持 systemd 简介 异构数据库表在线同步 quartz 源码分析 基于docker搭建测试环境(二) spring aop 实现原理简述 自己动手写spring(八) 支持AOP 自己动手写spring(七) 类结构设计调整 分析log日志 自己动手写spring(六) 支持FactoryBean 自己动手写spring(九) 总结 自己动手写spring(五) bean的生命周期管理 自己动手写spring(四) 整合xml与注解方式 自己动手写spring(三) 支持注解方式 自己动手写spring(二) 创建一个bean工厂 自己动手写spring(一) 使用digester varnish 简单使用 关于docker image的那点事儿 基于docker搭建测试环境 分布式配置系统 JVM内存与执行 git spring rmi和thrift maven/ant/gradle使用 再看tcp 缓存系统 java nio的多线程扩展 《Concurrency Models》笔记 回头看Spring IOC IntelliJ IDEA使用 Java泛型 vagrant 使用 Go常用的一些库 Python初学 Goroutine 调度模型 虚拟网络 《程序员的自我修养》小结 VPN(Virtual Private Network) Kubernetes存储 Kubernetes 其它特性 访问Kubernetes上的Service Kubernetes副本管理 Kubernetes pod 组件 使用etcd + confd + nginx做动态负载均衡 如何通过fleet unit files 来构建灵活的服务 CoreOS 安装 CoreOS 使用 Go学习 JVM类加载 硬币和扑克牌问题 LRU实现 virtualbox 使用 ThreadLocal小结 docker快速入门

架构

openkruise 学习 kubernetes crd 及kubebuilder学习 pv与pvc实现 csi学习 client-go学习 kubelet 组件分析 调度实践 Pod是如何被创建出来的? 《软件设计之美》笔记 mecha 架构学习 Kubernetes events学习及应用 CRI 《推荐系统36式》笔记 资源调度泛谈 系统设计原则 grpc学习 元编程 以应用为中心 istio学习 下一代微服务Service Mesh 《实现领域驱动设计》笔记 serverless 泛谈 《架构整洁之道》笔记 处理复杂性 那些年追过的并发 服务器端编程 网络通信协议 《聊聊架构》 书评的笔记 如何学习架构 《反应式设计模式》笔记 项目的演化特点 反应式架构摸索 函数式编程的设计模式 服务化 ddd反模式——CRUD的败笔 研发效能平台 重新看面向对象设计 业务系统设计的一些体会 函数式编程 《左耳听风》笔记 业务程序猿眼中的微服务管理 DDD实践——CQRS 项目隔离——案例研究 《编程的本质》笔记 系统故障排查汇总及教训 平台支持类系统的几个点 代码腾挪的艺术 abtest 系统设计汇总 《从0开始学架构》笔记 初级权限系统设计 领域驱动理念入门 现有上传协议分析 移动网络下的文件上传要注意的几个问题 推送系统的几个基本问题 用户登陆 做配置中心要想好的几个基本问题 不同层面的异步 分层那些事儿 性能问题分析 当我在说模板引擎的时候,我在说什么 用户认证问题 资源的分配与回收——池 消息/任务队列

标签


istio流量管理

2020年01月14日

前言

envoy 好在哪里?

应用交付老兵眼中的Envoy, 云原生时代下的思考

动态性:Envoy 的配置高度依赖接口自动化产生各种配置,这些配置是可以进行 Runtime 修改而无需 reload 文件,在现代应用架构中,一个服务端点的生命周期都变得更短,其运行的不确定性或弹性都变得更大,所以能够对配置进行 runtime 修改而无需重新 reload 配置文件这个能力在现代应用架构中显得尤其珍贵,这正是 Istio 选择 Envoy 作为数据平面的一个重要考虑。Envoy 同时还具备热重启能力,这使得在升级或必须进行重启的时候变得更加优雅,已有连接能够得到更多的保护。

扩展性:Envoy 的配置中可以看到大量的 filter,这些都是其扩展性的表现,Envoy 学习了 F5 以及 NGINX 的架构,大量使用插件式,使得开发者可以更加容易的开发。从 listener 开始就支持使用 filter,支持开发者开发 L3,L4,L7 的插件从而实现对协议扩展与更多控制。

可观测性:可观测的三大组件:logs,metrics,tracing 默认都被 Envoy 所支持。Envoy 容许用户以灵活的方式在灵活的位置定义灵活的日志格式,这些变化可以通过动态配置下发从而实现立即生效,并容许定义对日志的采样等。在 Metrics 则提供了能够与 Prometheus 进行集成的诸多指标,值得一提的是 Envoy 容许 filter 本身来扩充这些指标,例如在限流或者验证等 filter 中容许插件本身定义属于自己的指标从而帮助用户更好的使用和量化插件的运行状态。在 Tracing 方面 Envoy 支持向 zipkin,jaeger,datadog,lightStep 等第三方集成,Envoy 能够生产统一的请求 ID 并在整个网络结构中保持传播,同时也支持外部的 x-client-trace-id,从而实现对微服务之间关系拓扑的描述。

流量管理配置

功能划分

Envoy 官方文档中文版

Envoy的工作模式如图所示,横向是管理平面/管理流,纵向是数据流。Envoy会暴露admin的API,可以通过API查看Envoy中的路由或者集群的配置。

Envoy按照使用 场景可以分三种:

  1. sidecar,和应用一起部署在容器中,对进出应用服务的容量进行拦截
  2. router,作为独立的代理服务,对应用的L4/L7层流量进行代理
  3. ingress,作为集群入口的Ingress代理,对集群的入口流量进行拦截和代理

router 和ingress 均属于和应用服务不在一起的纯代理场景,可以归为一类,成为Gateway模式。对于sidecar 模式来说, envoy 负责服务出入方向流量的透明拦截,并且出入方向的流量在监听管理、路由管理等方面有很大的区别,因此sidecar 的xds配置是按照出入方向分别进行组织和管理。因此从xds 配置的视角上 配置可以划分为

  1. sidecar inbound,inbound 将发往本节点的流量转发到 对应的服务节点,因此inbound 方向的集群和路由信息都比较确定:单一的集群,单一的VirtualHost,并且集群固定只有一个节点信息。对于Http来说,会拼装HTTP 对应的路由信息,对于TCP来说,直接通过Tcp Proxy方式进行路由,只做全局统计和管控,无法进行协议相关的链路治理。
  2. sidecar outbound,从当前节点发往节点外的流量。根据协议的不同有所不同,待进一步认识
  3. gateway

envoy sidecar 配置 与 xds

Envoy是一个高性能的C++写的proxy转发器,那Envoy如何转发请求呢?需要定一些规则,然后按照这些规则进行转发。规则可以是静态的,放在配置文件中的,启动的时候加载,要想重新加载,一般需要重新启动。当然最好的方式是规则设置为动态的,放在统一的地方维护,这个统一的地方在Envoy眼中看来称为Discovery Service,Envoy过一段时间去这里拿一下配置,就修改了转发策略。无论是静态的,还是动态的,在配置里面往往会配置四个东西。

  xds 备注
Listener LDS 既然是proxy,就得监听一个端口
Endpoints EDS 目标的ip地址和端口,这个是proxy最终将请求转发到的地方
Routes RDS 一个cluster是具有完全相同行为的多个endpoint
它们组成一个Cluster,从cluster到endpoint的过程称为负载均衡
Cluters CDS 有时候多个cluster具有类似的功能,但是是不同的版本号,
可以通过route规则,选择将请求路由到某一个版本号

  envoy nginx
监听入口 listener listener 以及部分 Server 段落配置
路由控制逻辑 route 各种 Locations 匹配等
  clusters upstream
  endpoints upstream 里的 server

envoy ingress 配置 与xds

istio 的流控支持那么多功能,由用户直接 决定 给某个pod 的envoy 发送 xds 数据是不现实的。Traffic ManagementYou can do all this and more by adding your own traffic configuration to Istio using Istio’s traffic management API.

流量管理 traffic management API
traffic routing VirtualService + DestinationRule
Timeouts VirtualService.spec.http.timeout
Retries VirtualService.spec.http.retries
Circuit breakers DestinationRule.spec.trafficPolicy
Fault injection VirtualService.spec.http.fault
  1. With a virtual service, you can specify traffic behavior for one or more hostnames. You use routing rules in the virtual service that tell Envoy how to send the virtual service’s traffic to appropriate destinations.
  2. You can think of virtual services as how you route your traffic to a given destination, and then you use destination rules to configure what happens to traffic for that destination.
  3. Gateway configurations are applied to standalone Envoy proxies that are running at the edge of the mesh, rather than sidecar Envoy proxies running alongside your service workloads. Istio’s Gateway resource just lets you configure layer 4-6 load balancing properties such as ports to expose, TLS settings, and so on. Then instead of adding application-layer traffic routing (L7) to the same API resource, you bind a regular Istio virtual service to the gateway. This lets you basically manage gateway traffic like any other data plane traffic in an Istio mesh. Gateway 负责4~6层,与其绑定的VirtualService 负责七层,管理gateway就像管理普通的数据面代理一样。

流量管理

一个istio 自带的Bookinfo 为例,对应istio-1.4.2-linux.tar.gz 解压后istio-1.4.2/samples/bookinfo

kubectl label namespace default istio-injection=enabled
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
# 安装 bookinfo 的 ingress gateway:
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

全流程都是 http 协议

下文 大部分时候 以bookinfo 为例

Pod内流量 管理

流量拦截

深入解读Service Mesh背后的技术细节istio 对流量采取了透明拦截的方式

  1. 在PREROUTING规则中,使用这个转发链,从而进入容器的所有流量,都被先转发到envoy的15000端口。
  2. envoy作为一个代理,已经被配置好了,将请求转发给productpage程序。
  3. productpage程序接受到请求,会转向调用外部的reviews或者ratings,当productpage往后端进行调用的时候,就碰到了output链,这个链会使用转发链,将所有出容器的请求都转发到envoy的15000端口。这样无论是入口的流量,还是出口的流量,全部用envoy做成了汉堡包
  4. envoy根据服务发现的配置,知道reviews或者ratings如何访问,于是做最终的对外调用。iptables规则会对从envoy出去的流量做一个特殊处理,允许他发出去,不再使用上面的output规则。

目标端口被改写后, 可以通过SO_ORIGINAL_DST TCP 套件获取原始的ipport

envoy 内部流转

envoy 是一个proxy 组件,一个proxy 具体的说是listener、filter、route、cluster、endpoint 的协同工作

为了实现正确的流量路由与转发,envoy 的监听器分为两类

  1. 虚拟监听器,需要绑定相应的端口号,iptables 拦截的流量会转发到这个端口上
  2. 真实监听器,用于处理iptables 拦截前的”真实目的地址“,虚拟机监听器接收到监听请求时,按照一定的匹配规则找到对应的真实监听器进行处理。真实监听器因为不需要和网络交互,因此不需要配置和绑定端口号。

理解 Istio Service Mesh 中 Envoy Sidecar 代理的路由转发 未读

网格内流量管理

istioctl proxy-config listener $podname 可以查看Pod 中的具有哪些 Listener,也可以使用istioctl proxy-config listener $podname -o json 查看更详细的配置

Istio流量管理实现机制深度解析Productpage服务调用Reviews服务的请求流程

将details 服务扩容到2个实例,可以通过Pilot的调试接口获取该Cluster的endpointhttp://pilot_service_ip:15014/debug/edsz ,可以看到 details 对应的cluster的endpoints 变成了两个。查看 productpage pod中 envoy 的endpoint 配置发现也对应有了2个endpoint

$ istioctl pc endpoint productpage-v1-596598f447-nn64q
ENDPOINT                STATUS      OUTLIER CHECK     CLUSTER
10.20.0.10:9080         HEALTHY     OK                outbound|9080||details.default.svc.cluster.local
10.20.0.2:9080          HEALTHY     OK                outbound|9080||details.default.svc.cluster.local

进出网格的流量管理

istio网络转发分析

Exploring Istio - The VirtualService resource 整体来说,istio Virtual Service 更像k8s Ingress

  k8s Service k8s Ingress istio Virtual Service
流量导给谁 Pod Service Service
Pod
路由规则 权重 host and path
path匹配语法的丰富程度取决于Ingress Controller 的选用
HTTP host, path (with full regular expression support), method, headers, ports, query parameters, and more.
实现原理 kube-proxy+iptables nginx-ingress+kube-proxy+iptables  
其它特性     retried, injecting faults or delays for testing, and rewriting or redirecting requests.

以下 是一个通过ingress 访问 pod 的示例

apiVersion: v1
kind: Pod
metadata:
 name: nginx-pod
 labels:
   app: web
spec:
 containers:
   - name: nginx-container
     image: nginx
     ports:
       - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
  selector:
    app: web

---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: website-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: nginx-virtual-service
spec:
  hosts:
  - "*"
  gateways:
  - website-gateway
  http:
  - route:
    - destination:
        host: nginx-service
        subset: subset1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: nginx-destination-rule
spec:
  host: nginx-service
  subsets:
  - name: subset1
    labels:
      app: web

  1. istio 只是指定了 流量入口,具体的 路由工作由 绑定的VirtualService 负责
  2. VirtualService 负责配置路由规则 match,demo 中为简单起见没有配置,表示所有流量都路由到 http.route 指定的destination(也就是一个service)

相关组件

与istio ingress 功能对应的 是istio-ingressgateway Pod 以及附属的 istio-ingressgateway Service

root@ubuntu-01:~# kubectl describe pod istio-ingressgateway-74cb7595bd-gqhl7 -n istio-system
Name:         istio-ingressgateway-74cb7595bd-gqhl7
Namespace:    istio-system
Priority:     0
Node:         ubuntu-02/192.168.56.102
Start Time:   Wed, 27 May 2020 18:01:36 +0800
Labels:       app=istio-ingressgateway
              chart=gateways
              heritage=Tiller
              istio=ingressgateway
              pod-template-hash=74cb7595bd
              release=istio
              service.istio.io/canonical-name=istio-ingressgateway
              service.istio.io/canonical-revision=latest
Annotations:  sidecar.istio.io/inject: false

root@ubuntu-01:~# kubectl describe svc istio-ingressgateway -n istio-system
Name:                     istio-ingressgateway
Namespace:                istio-system
Labels:                   app=istio-ingressgateway
                          install.operator.istio.io/owning-resource=installed-state
                          istio=ingressgateway
                          operator.istio.io/component=IngressGateways
                          operator.istio.io/managed=Reconcile
                          operator.istio.io/version=1.6.0
                          release=istio
Annotations:              Selector:  app=istio-ingressgateway,istio=ingressgateway
Type:                     LoadBalancer
  1. istio-ingressgateway Pod 运行了一个envoy ,从istio 中接收 xds 数据
  2. istio-ingressgateway 是一个 LoadBalancer 类型的 Service,通过NodePort 转发数据。包含一个Label istio: ingressgateway 与 istio Gateway 的selector 相对应
root@ubuntu-01:~# kubectl exec -it  istio-ingressgateway-74cb7595bd-gqhl7 -n istio-system bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
root@istio-ingressgateway-74cb7595bd-gqhl7:/# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 02:02 ?        00:00:10 /usr/local/bin/pilot-agent proxy router --domain istio-system.svc.cluster.local --proxyLogLevel=warning --proxyCom
root        13     1  0 02:02 ?        00:01:13 /usr/local/bin/envoy -c etc/istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45 --parent-shutdown-time
root        27     0  0 05:48 pts/0    00:00:00 bash

请求包流转

istio网络转发分析

  1. curl http://node-ip:istio-ingressgateway-service-node-port 请求发往 istio-ingressgateway Service
  2. 通过iptables,流量被转发到 istio-ingressgateway Pod
  3. 进入pod 查看envoy实时配置 curl http://127.0.0.1:15000/config_dump
  4. / path 下的流量被转发到 outbound_.80_._.nginx-service.default.svc.cluster.local 对应的 k8s service outbound|80||nginx-service.default.svc.cluster.local
  5. 深入解读Service Mesh背后的技术细节pilot使用Kubernetes的Service,仅仅使用它的服务发现功能,而不使用它的转发功能,pilot通过在kubernetes里面注册一个controller来监听事件,从而获取Service和Kubernetes的Endpoint以及Pod的关系,但是在转发层面,就不会再使用kube-proxy根据service下发的iptables规则进行转发了,而是将这些映射关系转换成为pilot自己的转发模型,下发到envoy进行转发,这样就把控制面和数据面彻底分离开来,服务之间的相互关系是管理面的事情,不要和真正的转发绑定在一起。
{
    "configs":[
        {
            "static_clusters": [],
            "dynamic_active_clusters":[]
        }
        {
            "static_route_configs": [],
            "dynamic_route_configs": [
                {
                    "route_config":{
                        "virtual_hosts":[
                            {
                                "routes":[]
                            }
                        ]
                    }
                }
            ]
        }
    ]
}
// dynamic_active_clusters 中跟demo 相关的部分
{
    "version_info": "2020-05-30T06:02:33Z/24",
    "cluster": {
        "@type": "type.googleapis.com/envoy.api.v2.Cluster",
        "name": "outbound|80||nginx-service.default.svc.cluster.local",
        "type": "EDS",
        "eds_cluster_config": {
            "eds_config": {
                "ads": {}
            },
            "service_name": "outbound|80||nginx-service.default.svc.cluster.local"
        },
        "connect_timeout": "10s",
        "circuit_breakers": {},
        "metadata": {},
        "filters": [],
        "transport_socket_matches": []
    },
    "last_updated": "2020-05-30T06:02:34.248Z"
},
// routes   demo 相关的部分
{
    "match": {
        "prefix": "/"
    },
    "route": {
        "cluster": "outbound|80|subset1|nginx-service.default.svc.cluster.local",
        "timeout": "0s",
        "retry_policy": {},
        "max_grpc_timeout": "0s"
    },
    "metadata": {
        "filter_metadata": {
            "istio": {
                "config": "/apis/networking.istio.io/v1alpha3/namespaces/default/virtual-service/nginx-virtual-service"
            }
        }
    },
    "decorator": {
        "operation": "nginx-service.default.svc.cluster.local:80/*"
    }
}