Envoy入门实战部署

一、Envoy介绍

  官方文档解释:

  Envoy是专为大型现SOA(面向服务架构)设置的L7代理和通信总线。该项目源于以下理念:网络对应用程序来说应该是透明的。当网络和应用程序出现问题时,应该很容易确定问题的根源。

  为了做到上述目标,Envoy提供了以下高级功能:

  • 进程外架构:Envoy是一个独立进程,伴随每个应用程序服务运行。所有的Envoy形成一个透明的通信网格,每个应用程发送消息到本地主机或从本地主机接受消息,但不知道网络拓扑。Envoy可以使用任何应用程序语言,并且易升级部署。
  • 现代C++11代码库:性能优异。
  • L3/L4过滤器架构、HTTP L7过滤器架构、推荐使用HTTP/2。
  • gRPC支持:方便支持gRPC,特别是在负载和代理上。
  • 服务发现、健康检查、高级的负载均衡方案、Tracing、统计与监控
  • 动态配置:通过动态配置API实现配置的动态调整,而无需重启Envoy服务。

  Envoy的一些术语:

 

 

 

二、Envoy实践

1. Service Mesh

  Service Mesh用于处理服务间通信的基础设施层,用于在云原生应用复杂的服务拓扑中实现可靠的请求传递。

 

  在实践中,Service Mesh基本来说是一组轻量级的服务代理和应用逻辑的服务在一起,同生共死,并且对于应用服务是透明的。通过sidecar,Service Mesh会抽离为服务中的通用功能,比如服务注册发现,负载均衡,熔断降级,限流扩容,监控等功能,把这些功能放到sidecar中,通过代理proxy的方式于业务服务进行通信。

 

 

  目前Service Mesh已经进入了以Istio为代表的第二代,由Data Panel(Proxy)、Control Panel两部分组成。Istio是对Service Mesh的产品化实践,帮助微服务实现了分层解耦,架构图如下:

 

  逻辑上Istio分为数据平面(data panel)和控制平面(control panel),数据平面由一些智能代理组成,微服务之间的网络通信,控制平面负责对智能代理进行管理和配置。Istio自己没有实现Data Panel,而是在现有的Data Panel实现上做了Control Panel来达成目标。而今天的主角Envoy作为一个主打的Service Mesh方案的proxy,其设计处处考虑Service Mesh。

2. 快速开始运行简单示例

  Envoy目前不提供单独的预先编译好的二进制文件,但提供了Docker镜像。如果希望在Docker容器外使用Envoy,则需要构建它。Envoy提供了两个版本的API,v1和v2,现阶段通常使用v2。v2的API提供了两种方式的访问,一种是HTTP REST方式,一种是GRPC方式。Envoy的启动配置文件分为两种:静态配置和动态配置。静态配置是将所有信息都放在配置文件中,启动的时候直接加载。动态配置需要提供一个Envoy的服务端,用于动态生成Envoy需要的服务发现接口(XDS),通过发现服务来动态的调整配置信息。

  让我们通过静态配置方式运行一个简单实例并进行分析。

  我们拉取Envoy镜像后,Envoy被安装到/usr/local/bin目录下。envoy进程启动的时候需要指定一些参数,最重要的是--config-yaml参数,用于指定envoy进程启动的时候需要读取的配置文件地址。Docker配置文件默认放在/etc/envoy中,名字为envoy.yaml。所以启动容器的时候需要将自定义的envoy.yaml配置文件挂载到指定目录下替换掉默认的配置文件。

  让我们运行一个envoy实例,通过查看默认配置文件来看看默认功能是什么。

$ docker pull envoyproxy/envoy
$ docker run --rm -d -p 10000:10000 --name envoy envoy proxy/envoy
$ docker exec -it envoy /bin/bash #进入envoy容器
$ cat /etc/envoy/envoy.yaml #查看默认配置文件

   默认配置文件内容如下:

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
      protocol: TCP
      address: 127.0.0.1
      port_value: 9901
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  host_rewrite: www.google.com
                  cluster: service_google
          http_filters:
          - name: envoy.filters.http.router
  clusters:
  - name: service_google
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service_google
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.google.com
                port_value: 443
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext
        sni: www.google.com
View Code

    admin是administration服务必须的配置,address指定监听地址。

  static_resources包含了Envoy启动时静态配置的所有内容,而不是Envoy在运行时动态配置的资源。

  这个配置表明,实例监听127.0.0.1:10000,支持http协议访问,http访问域名为domains所描述内容时,将流量路由到cluster: service_google服务,即www.google.com:443。

  了解配置文件后,我们自己重写一下配置文件:

#为了避免出现Cannot find field错误,建议使用docker cp命令把默认配置文件拷贝到宿主机下,然后进行修改。
$ docker cp envoy:/etc/envoy/envoy.yaml . 
$ vim envoy.yaml #按照下面去修改

 

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
      protocol: TCP
      address: 127.0.0.1
      port_value: 9901
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                #  host_rewrite: www.google.com
                  cluster: some_service
          http_filters:
          - name: envoy.filters.http.router
  clusters:
  - name: some_service
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    # Comment out the following line to test on v6 networks
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: some_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 80
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext
        sni: 127.0.0.1
View Code

 

$ docker run -d -p 10000:10000 -v `pwd`/envoy.yaml:/etc/envoy/envoy.yaml --name envoy envoyproxy/envoy #运行实例,把配置文件挂载到相应目录
$ docker run -d --network=container:envoy --name nginx nginx #在运行一个nginx容器,共享envoy容器网络,以此模拟sidecar

   根据配置文件规则,envoy监听10000端口,同时在宿主机端口10000暴漏出来。当有请求到达监听后,envoy会对所有请求路由到some_service这个cluster上,而该cluster的upstream指向本地80端口,也就是nginx服务上。

  中途一直报这个错误,然后我把端口换成10001,并注释掉clusters后面的一些内容后,成功访问到nginx服务。(至于为什么,我也不太清楚,还处于摸索状态)。

3. 动态配置实践

  我们发现上面envoy.yaml文件中我们的endpoint里的adres是固定的,但实际应用中,比如在k8s集群中,pod的IP不是固定的,我们不可能每次都去修改yaml文件,这个时候就需要用到动态配置了。动态配置可以实现全动态,即实现LDS(Listener Discovery Service)、CDS(Cluster Discovery Service)、RDS(Route Discovery Service)、EDS(Endpoint Discovery Service),以及ADS(Aggregated Discovery Service)。

  

  动态配置和静态配置最大的区别在于,启动的时候一定要指定cluster和id,这两个参数表示该Envoy进程属于哪个cluster,id要求在相同的cluster下唯一,以表示不同的指向发现服务的连接信息。这两个参数可以在envoy的启动命令中添加--service-cluster--service-node,也可以在envoy.yaml配置文件中指定node.clusternode.id。

  

 

 

 

 

 

 

参考连接:

https://blog.csdn.net/huwei0518/article/details/97626386

https://zhuanlan.zhihu.com/p/35830194

https://www.jianshu.com/p/90f9ee98ce70

 

posted @ 2020-12-05 18:49  尹瑞星  阅读(3147)  评论(0编辑  收藏  举报