Envoy 【1】入门

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
云解析 DNS,旗舰版 1个月
简介: Envoy 【1】入门

文章目录

1. 简介

2. 配置

1.1 **Resources**

1.2 **Listeners**

1.3 Filter Chains and Filters

1.4 **Clusters**

1.5 **Admin**

3. 部署代理

4. 部署界面访问

5. 路由到 Docker 应用容器

5.1 配置

5.2 应用程序

5.3 Envoy Frontend Proxy

5.4 部署

5.5 admin访问

1. 简介

Envoy是一个开源的边缘和服务代理,专为云原生应用程序而设计。


以下场景演示了如何将 Envoy 配置为代理,允许您将流量转发到不同的目的地。


你将学到如何:


配置 Envoy 代理以将流量转发到外部网站。

配置 Envoy 代理以将流量转发到 Docker 容器。

执行基于路径的路由以控制流量目的地。

一旦 Envoy 代理就位,它可以扩展以支持负载平衡、健康检查和指标。这些将在更高级的场景中讨论。

2. 配置

Envoy 使用 YAML 定义文件/etc/envoy/envoy.yaml进行配置,以控制代理的行为。在这一步中,我们将使用静态配置 API 构建配置。这意味着所有设置都是在配置中预先定义的。

Envoy 还支持动态配置。这允许通过外部源发现设置。

1.1 Resources

Envoy 配置的第一行定义了正在使用的 API 配置。在这种情况下,我们正在配置静态 API,所以第一行应该是static_resources。将代码片段复制到编辑器。

static_resources:

1.2 Listeners

配置的开头定义了Listeners。侦听器是 Envoy 侦听请求的网络配置,例如 IP 地址和端口。Envoy 在 Docker 容器内部运行,因此它需要侦听 IP 地址0.0.0.0。在这种情况下,Envoy 将侦听端口10000。


以下是定义此设置的配置。将代码片段复制到编辑器

  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }

1.3 Filter Chains and Filters

随着 Envoy 侦听传入流量,下一阶段是定义如何处理请求。每个 Listener 都有一组过滤器,不同的 Listener 可以有一组不同的过滤器。


在此示例中,我们将所有流量代理到 Google.com(感谢 Google!)。结果:我们应该能够请求 Envoy 端点并看到 Google 主页出现,而不需要更改 URL。


过滤是使用filter_chains定义的。每个过滤器的目的是找到传入请求的匹配项,将其匹配到目标目的地。将代码片段复制到编辑器。

filter_chains:
 - filters:
 - name: envoy.http_connection_manager
    config:
      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.router

过滤器使用envoy.http_connection_manager,一个专为 HTTP 连接设计的内置过滤器。详细情况如下:


stat_prefix:为连接管理器发出统计信息时使用的人类可读前缀。

route_config:路由的配置。如果虚拟主机匹配,则检查路由。在这个例子中, route_config匹配所有传入的 HTTP

请求,不管请求的主机域。

routes:如果 URL 前缀匹配,则一组路由规则定义接下来应该发生什么。在这种情况下,“/”表示匹配请求的根

host_rewrite:更改 HTTP 请求的入站主机标头。

cluster:将处理请求的集群的名称。实现定义如下。

http_filters:过滤器允许 Envoy 在处理请求时调整和修改请求。

1.4 Clusters

当请求与过滤器匹配时,请求被传递到集群上。下面显示的集群定义了主机是通过 HTTPS 运行的 google.com。如果定义了多个主机,那么 Envoy 将执行循环策略。

复制集群实现完成配置:

  clusters:
  - name: service_google
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    hosts: [{ socket_address: { address: google.com, port_value: 443 }}]
    tls_context: { sni: www.google.com }

1.5 Admin

最后,需要一个管理部分。在以下步骤中更详细地解释了管理部分。

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

这个结构定义了 Envoy 静态配置的样板。监听器定义了 Envoy 的端口和 IP 地址。侦听器有一组过滤器来匹配传入的请求。一旦请求匹配,它将被转发到集群。

你可以在Github上查看完整的配置。

/etc/envoy/envoy.yaml

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 127.0.0.1, port_value: 9901 }
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 10000 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          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.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
    hosts: [{ socket_address: { address: google.com, port_value: 443 }}]
    tls_context: { sni: www.google.com }

3. 部署代理

配置到位后,可以启动容器并将其提供给 Envoy。使用 Docker,这是通过将 Volume Mount 挂载到/etc/envoy/envoy.yaml 来完成的。

启动代理,绑定到端口 80:

docker run --name=proxy -d \
  -p 80:10000 \
  -v $(pwd)/envoy/envoy.yaml:/etc/envoy/envoy.yaml \
  envoyproxy/envoy:latest
#启动后,您应该能够将 HTTP 请求发送到 80 端口
curl localhost

您可以通过本地浏览器查看此 URL正如您将看到的,请求被代理到 Google.com,您应该看到没有 URL 的 Google 主页改变。

4. 部署界面访问

Envoy 提供了一个管理视图,允许您查看配置、统计信息、日志和其他 Envoy 内部数据。

可以通过添加额外的资源定义来定义 admin,其中定义了 admin 视图的端口。该端口不应与其他侦听器配置冲突。

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

启动admin

这个 Docker 容器还向外界公开了管理端口。上面的资源配置将使管理视图对公众可用,仅用于演示目的,请参阅有关如何保护管理门户的文档。

要公开管理门户,请运行以下命令:

docker run --name=proxy-with-admin -d \
    -p 9901:9901 \
    -p 10000:10000 \
    -v $(pwd)/envoy/envoy.yaml:/etc/envoy/envoy.yaml \
    envoyproxy/envoy:latest

通过端口http://ip:9901访问界面

“当前形式的管理界面既允许执行破坏性操作(例如,关闭服务器),也可能暴露私人信息(例如,统计信息、集群名称、证书信息等)。访问权限至关重要仅允许通过安全网络访问管理界面” Envoy 文档

5. 路由到 Docker 应用容器

最后一个示例使用 Envoy 根据请求的 URL 路径将流量代理到不同的 Python 服务。

5.1 配置

应用程序的配置被定义为一个 Docker Compose 文件。我们使用 Docker Compose 文件是因为我们想同时运行多个容器——一个用于代理,一个用于每个单独的服务。

cat examples/front-proxy/docker-compose.yml
version: '2'
services:
  front-envoy:
    build:
      context: .
      dockerfile: Dockerfile-frontenvoy
    volumes:
      - ./front-envoy.yaml:/etc/front-envoy.yaml
    networks:
      - envoymesh
    expose:
      - "80"
      - "8001"
    ports:
      - "8000:80"
      - "8001:8001"
  service1:
    build:
      context: .
      dockerfile: Dockerfile-service
    volumes:
      - ./service-envoy.yaml:/etc/service-envoy.yaml
    networks:
      envoymesh:
        aliases:
          - service1
    environment:
      - SERVICE_NAME=1
    expose:
      - "80"
  service2:
    build:
      context: .
      dockerfile: Dockerfile-service
    volumes:
      - ./service-envoy.yaml:/etc/service-envoy.yaml
    networks:
      envoymesh:
        aliases:
          - service2
    environment:
      - SERVICE_NAME=2
    expose:
      - "80"
networks:
  envoymesh: {}

5.2 应用程序

该服务是一个 Python Web 应用程序,它还使用容器内的 Envoy 将流量转发到 Python 应用程序。没有必要在应用程序前面放置 Envoy。

cat examples/front-proxy/service.py
from flask import Flask
from flask import request
import socket
import os
import sys
import requests
app = Flask(__name__)
TRACE_HEADERS_TO_PROPAGATE = [
    'X-Ot-Span-Context',
    'X-Request-Id',
    # Zipkin headers
    'X-B3-TraceId',
    'X-B3-SpanId',
    'X-B3-ParentSpanId',
    'X-B3-Sampled',
    'X-B3-Flags',
    # Jaeger header (for native client)
    "uber-trace-id"
]
@app.route('/service/<service_number>')
def hello(service_number):
    return ('Hello from behind Envoy (service {})! hostname: {} resolved'
            'hostname: {}\n'.format(os.environ['SERVICE_NAME'], 
                                    socket.gethostname(),
                                    socket.gethostbyname(socket.gethostname())))
@app.route('/trace/<service_number>')
def trace(service_number):
    headers = {}
    # call service 2 from service 1
    if int(os.environ['SERVICE_NAME']) == 1 :
        for header in TRACE_HEADERS_TO_PROPAGATE:
            if header in request.headers:
                headers[header] = request.headers[header]
        ret = requests.get("http://localhost:9000/trace/2", headers=headers)
    return ('Hello from behind Envoy (service {})! hostname: {} resolved'
            'hostname: {}\n'.format(os.environ['SERVICE_NAME'], 
                                    socket.gethostname(),
                                    socket.gethostbyname(socket.gethostname())))
if __name__ == "__main__":
    app.run(host='127.0.0.1', port=8080, debug=True)

5.3 Envoy Frontend Proxy

Envoy 代理配置定义在:

cat examples/front-proxy/front-envoy.yaml
static_resources:
  listeners:
  - address:
      socket_address:
        address: 0.0.0.0
        port_value: 80
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/service/1"
                route:
                  cluster: service1
              - match:
                  prefix: "/service/2"
                route:
                  cluster: service2
          http_filters:
          - name: envoy.router
            config: {}
  clusters:
  - name: service1
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    http2_protocol_options: {}
    hosts:
    - socket_address:
        address: service1
        port_value: 80
  - name: service2
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    http2_protocol_options: {}
    hosts:
    - socket_address:
        address: service2
        port_value: 80
admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8001

如第一步所述,配置从定义一组static_resources 开始。路由根据请求的 URL 进行匹配。

5.4 部署

使用下面的 Docker Compose 命令启动示例:

$ $ ls envoy/examples/front-proxy/
deprecated_v1/         Dockerfile-frontenvoy  front-envoy.yaml       service-envoy.yaml     start_service.sh
docker-compose.yml     Dockerfile-service     README.md              service.py        
$ docker-compose -f ~/envoy/examples/front-proxy/docker-compose.yml up -d
Creating network "frontproxy_envoymesh" with the default driver
Creating frontproxy_service1_1 ... 
Creating frontproxy_front-envoy_1 ... 
Creating frontproxy_service2_1 ... 
Creating frontproxy_front-envoy_1
Creating frontproxy_service1_1
Creating frontproxy_front-envoy_1 ... done

5.5 admin访问

访问界面

$ curl http://localhost:8001
<head>
  <title>Envoy Admin</title>
  <link rel='shortcut icon' type='image/png' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAH9SURBVEhL7ZRdTttAFIUrUFaAX5w9gIhgUfzshFRK+gIbaVbAzwaqCly1dSpKk5A485/YCdXpHTB4BsdgVe0bD0cZ3Xsm38yZ8byTUuJ/6g3wqqoBrBhPTzmmLfptMbAzttJTpTKAF2MWC7ADCdNIwXZpvMMwayiIwwS874CcOc9VuQPR1dBBChPMITpFXXU45hukIIH6kHhzVqkEYB8F5HYGvZ5B7EvwmHt9K/59CrU3QbY2RNYaQPYmJc+jPIBICNCcg20ZsAsCPfbcrFlRF+cJZpvXSJt9yMTxO/IAzJrCOfhJXiOgFEX/SbZmezTWxyNk4Q9anHMmjnzAhEyhAW8LCE6wl26J7ZFHH1FMYQxh567weQBOO1AW8D7P/UXAQySq/QvL8Fu9HfCEw4SKALm5BkC3bwjwhSKrA5hYAMXTJnPNiMyRBVzVjcgCyHiSm+8P+WGlnmwtP2RzbCMiQJ0d2KtmmmPorRHEhfMROVfTG5/fYrF5iWXzE80tfy9WPsCqx5Buj7FYH0LvDyHiqd+3otpsr4/fa5+xbEVQPfrYnntylQG5VGeMLBhgEfyE7o6e6qYzwHIjwl0QwXSvvTmrVAY4D5ddvT64wV0jRrr7FekO/XEjwuwwhuw7Ef7NY+dlfXpLb06EtHUJdVbsxvNUqBrwj/QGeEUSfwBAkmWHn5Bb/gAAAABJRU5ErkJggg=='/>
  <style>
    .home-table {
      font-family: sans-serif;
      font-size: medium;
      border-collapse: collapse;
    }
    .home-row:nth-child(even) {
      background-color: #dddddd;
    }
    .home-data {
      border: 1px solid #dddddd;
      text-align: left;
      padding: 8px;
    }
    .home-form {
      margin-bottom: 0;
    }
  </style>
</head>
<body>
  <table class='home-table'>
    <thead>
      <th class='home-data'>Command</th>
      <th class='home-data'>Description</th>
     </thead>
     <tbody>
<tr class='home-row'><td class='home-data'><a href='certs'>certs</a></td><td class='home-data'>print certs on machine</td></tr>
<tr class='home-row'><td class='home-data'><a href='clusters'>clusters</a></td><td class='home-data'>upstream cluster status</td></tr>
<tr class='home-row'><td class='home-data'><a href='config_dump'>config_dump</a></td><td class='home-data'>dump current Envoy configs (experimental)</td></tr>
<tr class='home-row'><td class='home-data'><form action='cpuprofiler' method='post' class='home-form'><button>cpuprofiler</button></form></td><td class='home-data'>enable/disable the CPU profiler</td></tr>
<tr class='home-row'><td class='home-data'><form action='healthcheck/fail' method='post' class='home-form'><button>healthcheck/fail</button></form></td><td class='home-data'>cause the server to fail health checks</td></tr>
<tr class='home-row'><td class='home-data'><form action='healthcheck/ok' method='post' class='home-form'><button>healthcheck/ok</button></form></td><td class='home-data'>cause the server to pass health checks</td></tr>
<tr class='home-row'><td class='home-data'><a href='help'>help</a></td><td class='home-data'>print out list of admin commands</td></tr>
<tr class='home-row'><td class='home-data'><a href='hot_restart_version'>hot_restart_version</a></td><td class='home-data'>print the hot restart compatibility version</td></tr>
<tr class='home-row'><td class='home-data'><a href='listeners'>listeners</a></td><td class='home-data'>print listener addresses</td></tr>
<tr class='home-row'><td class='home-data'><form action='logging' method='post' class='home-form'><button>logging</button></form></td><td class='home-data'>query/change logging levels</td></tr>
<tr class='home-row'><td class='home-data'><a href='memory'>memory</a></td><td class='home-data'>print current allocation/heap usage</td></tr>
<tr class='home-row'><td class='home-data'><form action='quitquitquit' method='post' class='home-form'><button>quitquitquit</button></form></td><td class='home-data'>exit the server</td></tr>
<tr class='home-row'><td class='home-data'><form action='reset_counters' method='post' class='home-form'><button>reset_counters</button></form></td><td class='home-data'>reset all counters to zero</td></tr>
<tr class='home-row'><td class='home-data'><a href='runtime'>runtime</a></td><td class='home-data'>print runtime values</td></tr>
<tr class='home-row'><td class='home-data'><form action='runtime_modify' method='post' class='home-form'><button>runtime_modify</button></form></td><td class='home-data'>modify runtime values</td></tr>
<tr class='home-row'><td class='home-data'><a href='server_info'>server_info</a></td><td class='home-data'>print server version/status information</td></tr>
<tr class='home-row'><td class='home-data'><a href='stats'>stats</a></td><td class='home-data'>print server stats</td></tr>
<tr class='home-row'><td class='home-data'><a href='stats/prometheus'>stats/prometheus</a></td><td class='home-data'>print server stats in prometheus format</td></tr>
    </tbody>
  </table>
</body>

应用路由

$ curl localhost:8000/service/1
Hello from behind Envoy (service 1)! hostname: 270af01a022e resolvedhostname: 172.19.0.2
$ curl localhost:8000/service/2
Hello from behind Envoy (service 2)! hostname: b39f03aae28d resolvedhostname: 172.19.0.3
相关文章
|
1月前
|
Kubernetes 安全 应用服务中间件
Istio的流量管理(实操二)
Istio的流量管理(实操二)
46 2
|
1月前
|
Kubernetes 网络协议 应用服务中间件
Istio的流量管理(实操三)
Istio的流量管理(实操三)
43 1
|
JSON Rust 安全
Istio Ambient Mesh Ztunnel实现剖析(1)配置解析
前言在Istio Ambient Mesh中,社区引入了名为ztunnel的新组件,ztunnel的名字来源于Zero-Trust Tunnel,即零信任管道,Ztunnel 旨在专注于Ambient Mesh中工作负载4层安全能力,例如 mTLS、身份验证、L4 授权,而无需进行七层流量解析。ztunnel 确保流量高效、安全地传输到负责七层处理的Waypoint Proxy或在对端无waypo
336 0
|
1月前
|
Kubernetes 网络协议 微服务
Istio的流量管理(实操一)
Istio的流量管理(实操一)
39 3
|
容器 微服务 Kubernetes
带你读《Istio入门与实战》之一:服务网格与Istio
本书系统化介绍Istio技术要点与应用技巧,可帮助读者快速搭建微服务架构并进行管理。主要内容包括:service mesh基本概念与使用,Istio架构设计与主要功能,快速搭建一个微服务实验,介绍如何让服务流量控制更简单,让服务更具弹性,让服务故障测试更容易,让服务通信更安全可控,让服务更易观测与监控,以及istio维护方案。本书内容丰富、案例讲解,实用性强,非常适合入门级读者快速掌握Istio技术。
|
4月前
|
缓存 监控 安全
Istio架构及工作原理
【2月更文挑战第17天】从 Istio 的设计和实现原理可以看出,它是采用模块化设计,并且各个模块之间高度解耦,Proxy 专注于负责服务之间的通信,Pilot 专注于流量控制,Mixer 专注于策略控制以及监控日志功能,而 Citadel 专注于安全。
|
JSON Kubernetes 数据可视化
Istio入门二——手把手教你使用Istio
Istio入门二——手把手教你使用Istio
345 1
|
SpringCloudAlibaba Kubernetes Java
Istio初体验:使用Spring Boot+gRPC构建微服务并部署
Istio初体验:使用Spring Boot+gRPC构建微服务并部署
554 0
|
负载均衡 Kubernetes Java
Envoy和类似的系统比较
Envoy和类似的系统比较
|
存储 负载均衡 网络协议
Envoy架构概览(3):服务发现
Envoy架构概览(3):服务发现