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
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
$ 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)。
--service-cluster
和--service-node
,也可以在envoy.yaml配置文件中指定node.cluster
和node.id。
参考连接:
https://blog.csdn.net/huwei0518/article/details/97626386
https://zhuanlan.zhihu.com/p/35830194
https://www.jianshu.com/p/90f9ee98ce70