当前位置:   article > 正文

Envoy 【1】入门_envoy教程

envoy教程

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

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
  • 2
  • 3
  • 4

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

过滤器使用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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

1.5 Admin

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

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }
  • 1
  • 2
  • 3
  • 4

这个结构定义了 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 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

您可以通过本地浏览器查看此 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 }
  • 1
  • 2
  • 3
  • 4

启动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
  • 1
  • 2
  • 3
  • 4
  • 5

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

5. 路由到 Docker 应用容器

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

5.1 配置

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

cat examples/front-proxy/docker-compose.yml
  • 1
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: {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

5.2 应用程序

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

cat examples/front-proxy/service.py
  • 1
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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

5.3 Envoy Frontend Proxy

Envoy 代理配置定义在:

cat examples/front-proxy/front-envoy.yaml
  • 1
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

如第一步所述,配置从定义一组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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

应用路由

$ 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
  • 2
  • 3
  • 4
本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号