内容简介:Service Mesh是微服务设置中的通信层。来自每个服务的所有请求都将通过服务网格。每个服务都有自己的代理服务,所有这些代理服务一起形成“服务网格”。因此,如果服务想要调用另一个服务,它不会直接调用目标服务,它会先将请求路由到本地代理,然后代理将其路由到目标服务。从本质上讲,您的服务实例对外部世界一无所知,只了解本地代理。当您谈到“Service Mesh”时,您肯定会听到“Sidecar”边车这个词,“Sidecar”是一个代理,可用于您的每个服务实例,每个“Sidecar”负责一个服务的一个实例。
Service Mesh是微服务设置中的通信层。来自每个服务的所有请求都将通过服务网格。每个服务都有自己的代理服务,所有这些代理服务一起形成“服务网格”。因此,如果服务想要调用另一个服务,它不会直接调用目标服务,它会先将请求路由到本地代理,然后代理将其路由到目标服务。从本质上讲,您的服务实例对外部世界一无所知,只了解本地代理。
当您谈到“Service Mesh”时,您肯定会听到“Sidecar”边车这个词,“Sidecar”是一个代理,可用于您的每个服务实例,每个“Sidecar”负责一个服务的一个实例。
服务网格提供什么?
- 服务发现
- 可观察性(指标)
- 限速
- 断路器
- 交通流量
- 负载均衡
- 身份验证和授权
- 分布式跟踪
Envoy
Envoy是一个用C ++编写的高性能代理。使用Envoy构建您的“Service Mesh”并不是强制性的,您可以使用其他代理,如Nginx,Traefik等......但是对于这篇文章,我们将继续使用Envoy。
好的,让我们用3个服务构建一个“Service Mesh”设置。
Front Envoy
“Front Envoy”是我们设置中的边缘代理,您通常会在其中执行TLS终止,身份验证,生成请求标头等...
以下是Front Envoy配置:
--- admin: access_log_path: "/tmp/admin_access.log" address: socket_address: address: "127.0.0.1" port_value: 9901 static_resources: listeners: - name: "http_listener" address: socket_address: address: "0.0.0.0" port_value: 80 filter_chains: filters: - name: "envoy.http_connection_manager" config: stat_prefix: "ingress" route_config: name: "local_route" virtual_hosts: - name: "http-route" domains: - "*" routes: - match: prefix: "/" route: cluster: "service_a" http_filters: - name: "envoy.router" clusters: - name: "service_a" connect_timeout: "0.25s" type: "strict_dns" lb_policy: "ROUND_ROBIN" hosts: - socket_address: address: "service_a_envoy" port_value: 8786
Envoy配置主要包括
- Listeners监听器
- Route路由
- 集群
- 端点
Listeners监听器:
可以在一个Envoy实例中运行一个或多个侦听器。第9-36行listeners是配置当前监听器的地址和端口,每个监听器也可以有一个或多个网络过滤器。使用这些过滤器可以实现路由,终止,流量转移等大部分内容......“envoy.http_connection_manager”是我们在这里使用的内置过滤器之一,除了这个特使还有其他几个 过滤器 。
Route路由:
第22-34行filter_chains开始配置我们的过滤器的路由规范,您应该接受请求的域和与每个请求匹配的路由匹配器,并将请求发送到适当的集群。
集群:
集群是Envoy将流量路由到的上游服务的规范。
第41-50行clusters定义了“service_a”,这是“Front Envoy”将与之交谈的唯一上游。“connect_timeout”是在返回503之前获得与上游服务的连接的时间限制。通常会有多个“service_a”实例,而envoy支持 多种负载均衡算法 来路由流量。这里我们使用简单的循环法。
端点:
“hosts”指定我们要将流量路由到的service_a的实例,在我们的例子中,我们只有一个。
第48行,port_value: 8786,正如我们所讨论的那样,我们不直接与“service_a”对话,我们会与服务A的Envoy代理实例进行通信,然后将其路由到本地服务A实例。
我们在这里做客户端负载平衡。Envoy缓存“service_a”的所有主机,并且每5秒钟它将继续刷新主机列表。Envoy支持主动和被动健康检查。如果要使其处于活动状态,请在群集配置中配置运行状况检查。
其他:
第2-7行,配置管理服务器,可用于查看配置,更改日志级别,查看统计信息等...
第8行,“static_resources”,意味着我们手动加载所有配置,我们也可以动态地完成它,我们将在后面的文章中看看它是如何做到的。
配置比我们看到的要多得多,我们的目标是不经历所有可能的配置,而是要有最小的配置才能开始。
service_a
这是“服务A”的Envoy配置:
admin: access_log_path: "/tmp/admin_access.log" address: socket_address: address: "127.0.0.1" port_value: 9901 static_resources: listeners: - name: "service-a-svc-http-listener" address: socket_address: address: "0.0.0.0" port_value: 8786 filter_chains: - filters: - name: "envoy.http_connection_manager" config: stat_prefix: "ingress" codec_type: "AUTO" route_config: name: "service-a-svc-http-route" virtual_hosts: - name: "service-a-svc-http-route" domains: - "*" routes: - match: prefix: "/" route: cluster: "service_a" http_filters: - name: "envoy.router" - name: "service-b-svc-http-listener" address: socket_address: address: "0.0.0.0" port_value: 8788 filter_chains: - filters: - name: "envoy.http_connection_manager" config: stat_prefix: "egress" codec_type: "AUTO" route_config: name: "service-b-svc-http-route" virtual_hosts: - name: "service-b-svc-http-route" domains: - "*" routes: - match: prefix: "/" route: cluster: "service_b" http_filters: - name: "envoy.router" - name: "service-c-svc-http-listener" address: socket_address: address: "0.0.0.0" port_value: 8791 filter_chains: - filters: - name: "envoy.http_connection_manager" config: stat_prefix: "egress" codec_type: "AUTO" route_config: name: "service-b-svc-http-route" virtual_hosts: - name: "service-b-svc-http-route" domains: - "*" routes: - match: prefix: "/" route: cluster: "service_c" http_filters: - name: "envoy.router" clusters: - name: "service_a" connect_timeout: "0.25s" type: "strict_dns" lb_policy: "ROUND_ROBIN" hosts: - socket_address: address: "service_a" port_value: 8081 - name: "service_b" connect_timeout: "0.25s" type: "strict_dns" lb_policy: "ROUND_ROBIN" hosts: - socket_address: address: "service_b_envoy" port_value: 8789 - name: "service_c" connect_timeout: "0.25s" type: "strict_dns" lb_policy: "ROUND_ROBIN" hosts: - socket_address: address: "service_c_envoy" port_value: 8790
第11-39行定义了一个用于将流量路由到实际“Service A”实例的侦听器,您可以在103-111上找到service_a实例的相应群集定义。
“服务A”需要与“服务B”和“服务C”对话,因此我们分别有两个监听器和集群。在这里,我们为每个上游(localhost,Service B和Service C)分别设置了监听器,另一种方法是根据url或header向任何上游提供单个监听器和路由。
服务B和服务C.
服务B和服务C处于叶级别,除了本地主机服务实例之外,不与任何其他上游通信。所以配置会很简单:
admin: access_log_path: "/tmp/admin_access.log" address: socket_address: address: "127.0.0.1" port_value: 9901 static_resources: listeners: - name: "service-b-svc-http-listener" address: socket_address: address: "0.0.0.0" port_value: 8789 filter_chains: - filters: - name: "envoy.http_connection_manager" config: stat_prefix: "ingress" codec_type: "AUTO" route_config: name: "service-b-svc-http-route" virtual_hosts: - name: "service-b-svc-http-route" domains: - "*" routes: - match: prefix: "/" route: cluster: "service_b" http_filters: - name: "envoy.router" clusters: - name: "service_b" connect_timeout: "0.25s" type: "strict_dns" lb_policy: "ROUND_ROBIN" hosts: - socket_address: address: "service_b" port_value: 8082
这里没什么特别的,只有一个监听器和一个集群。
我们完成了所有配置,我们可以将此设置部署到kubernetes或使用docker-compose进行测试。运行docker-compose build and docker-compose up并点击localhost:8080 ,您应该看到请求成功通过所有服务和Envoy代理。您可以使用日志进行验证。
Envoy xDS
我们通过为每辆边车提供配置来实现所有这些,并且根据服务配置在服务之间变化。最初使用2或3个服务手动管理这些边车配置似乎没有问题,但是当服务数量增加时,变得困难。此外,当边车配置更改时,您必须重新启动Envoy实例才能使更改生效。
如前所述,我们可以完全避免手动配置并使用api服务器加载所有组件,集群(CDS),端点(EDS),监听器(LDS)和路由(RDS)。因此,每个边车将与api服务器通信以获取配置,并且当在api服务器中更新新配置时,它会自动反映在Envoy实例中,从而避免重启。
有关动态配置, 在这里 ,并 在这里 是你可以用一个例子XDS服务器
Kubernetes
如果我们要在Kubernetes中实现这个设置,它会是什么样子?
需要改变:
- Pod
- Service
Pod:
通常Pod规范只在其中定义了一个容器。但是根据定义,Pod可以容纳一个或多个容器。由于我们想要为每个服务实例运行一个边车代理,我们将Envoy容器添加到每个pod。因此,为了与外界通信,服务容器将通过localhost与Envoy容器通信。这就是部署文件的样子
apiVersion: apps/v1beta1 kind: Deployment metadata: name: servicea spec: replicas: 2 template: metadata: labels: app: servicea spec: containers: - name: servicea image: dnivra26/servicea:0.6 ports: - containerPort: 8081 name: svc-port protocol: TCP - name: envoy image: envoyproxy/envoy:latest ports: - containerPort: 9901 protocol: TCP name: envoy-admin - containerPort: 8786 protocol: TCP name: envoy-web volumeMounts: - name: envoy-config-volume mountPath: /etc/envoy-config/ command: ["/usr/local/bin/envoy"] args: ["-c", "/etc/envoy-config/config.yaml", "--v2-config-only", "-l", "info","--service-cluster","servicea","--service-node","servicea", "--log-format", "[METADATA][%Y-%m-%d %T.%e][%t][%l][%n] %v"] volumes: - name: envoy-config-volume configMap: name: sidecar-config items: - key: envoy-config path: config.yaml
我们在那里添加了我们的Envoy侧车。我们将在第33-39行的configmap中安装我们的Envoy配置文件。
服务Service
Kubernetes服务负责维护可以路由流量的Pod端点列表。通常kube-proxy在这些pod端点之间进行负载平衡。但在我们的情况下,如果你还记得,我们自己进行的客户端负载平衡,所以我们不希望使用kube-proxy负载均衡,我们希望得到Pod端点列表并自己实现负载均衡。为此,我们可以使用“无头服务”,它将返回端点列表。这是它的样子:
kind: Service apiVersion: v1 metadata: name: servicea spec: clusterIP: None ports: - name: envoy-web port: 8786 targetPort: 8786 selector: app: servicea
第6行使服务无头。此外,您应该注意我们没有将kubernetes服务端口映射到应用程序的服务端口,但我们正在将它映射到Envoy侦听器端口。流量首先流向Envoy。
在此处 找到所有配置和代码
以上所述就是小编给大家介绍的《使用Envoy实现Service Mesh》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 使用Akka实现并发
- 使用GOLANG实现猴子排序
- 使用 WebSocket 实现 JsBridge
- 使用 RabbitMQ 实现 RPC
- 使用Kafka实现事件溯源
- 使用 Swift 实现 Promise
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。