Envoy を Front Proxy Sandbox で動作確認

Envoy

Envoy Proxy が気になっていて、docker-compose で手軽に試せる Sandbox というものがあったので試してみます

Docs » Getting Started » Sandboxes » Front Proxy

https://github.com/envoyproxy/envoy/tree/master/examples/front-proxy を使います

次のような構成を docker-compose で作ります


(https://www.envoyproxy.io/docs/envoy/latest/_images/docker_compose_v0.1.svg)

$ git clone https://github.com/envoyproxy/envoy.git
$ cd examples/front-proxy
$ docker-compose up --build -d
$ docker-compose ps
          Name                        Command               State                            Ports  
---------------------------------------------------------------------------------------------------------------------------
frontproxy_front-envoy_1   /usr/bin/dumb-init -- /bin ...   Up      10000/tcp, 0.0.0.0:8000->80/tcp, 0.0.0.0:8001->8001/tcp
frontproxy_service1_1      /bin/sh -c /usr/local/bin/ ...   Up      10000/tcp, 80/tcp               
frontproxy_service2_1      /bin/sh -c /usr/local/bin/ ...   Up      10000/tcp, 80/tcp

curl で /service/1 にアクセスすると service1 コンテナに proxy されます。また、/service/2 は service2 に proxy されます。

$ curl -sv $(docker-machine ip default):8000/service/1
Hello from behind Envoy (service 1)! hostname: e145f697d053 resolvedhostname: 172.18.0.3
*   Trying 192.168.99.100...
* TCP_NODELAY set
* Connected to 192.168.99.100 (192.168.99.100) port 8000 (#0)
> GET /service/1 HTTP/1.1
> Host: 192.168.99.100:8000
> User-Agent: curl/7.57.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: text/html; charset=utf-8
< content-length: 89
< server: envoy
< date: Tue, 10 Apr 2018 12:58:39 GMT
< x-envoy-upstream-service-time: 8
<
{ [89 bytes data]
* Connection #0 to host 192.168.99.100 left intact

コンテナ内を確認してみます
front-proxy コンテナのプロセスは次のようになっています

$ winpty docker-compose exec front-envoy bash
root@ad056b51de9b:/# ps auxwwf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root        13  0.1  0.3  18236  3400 pts/0    Ss   13:03   0:00 bash
root        26  0.0  0.2  34420  2936 pts/0    R+   13:04   0:00  \_ ps auxwwf
root         1  0.0  0.0    208     4 ?        Ss   12:46   0:00 /usr/bin/dumb-init -- /bin/sh -c /u
sr/local/bin/envoy -c /etc/front-envoy.yaml --service-cluster front-proxy
root         5  0.0  0.0   4500   744 ?        Ss   12:46   0:00 /bin/sh -c /usr/local/bin/envoy -c
/etc/front-envoy.yaml --service-cluster front-proxy
root         6  0.6  2.1  90740 22164 ?        Sl   12:46   0:07  \_ /usr/local/bin/envoy -c /etc/fr
ont-envoy.yaml --service-cluster front-proxy
root@ad056b51de9b:/#

サービス側は次のようになっています

$ winpty docker-compose exec service1 bash
bash-4.4# ps auxwwf
PID   USER     TIME   COMMAND
    1 root       0:00 /bin/sh -c /usr/local/bin/start_service.sh
    5 root       0:00 bash /usr/local/bin/start_service.sh
    6 root       0:00 python3 /code/service.py
    7 root       0:07 envoy -c /etc/service-envoy.yaml --service-cluster servic
   16 root       0:36 /usr/bin/python3 /code/service.py
   21 root       0:00 bash
   25 root       0:00 ps auxwwf
bash-4.4#

Proxy Server の /etc/front-envoy.yaml の内容は次のようになっています

static_resources:
  listeners:
  - address: # 0.0.0.0:80 を listen
      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: # Host ヘッダー条件
              - "*"
              routes:
              - match: # /service/1 は下の clusters で定義されてる service1 に proxy
                  prefix: "/service/1"
                route:
                  cluster: service1
              - match: # /service/2 は下の clusters で定義されてる service2 に proxy
                  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: # proxy 先サーバーリスト
    - socket_address:
        address: service1
        port_value: 80
  - name: service2
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin # 振り分けアルゴリズム
    http2_protocol_options: {}
    hosts: # proxy 先サーバーリスト
    - socket_address:
        address: service2
        port_value: 80
admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8001

:8001 で Admin UI にアクセスできます

/help にアクセスすると各 path の説明が返ってきます。prometheus 用の stats endpoint もあるし、オンラインで logging やランタイム設定を変更できるようです。

admin commands are:
  /: Admin home page
  /certs: print certs on machine
  /clusters: upstream cluster status
  /config_dump: dump current Envoy configs
  /cpuprofiler: enable/disable the CPU profiler
  /healthcheck/fail: cause the server to fail health checks
  /healthcheck/ok: cause the server to pass health checks
  /help: print out list of admin commands
  /hot_restart_version: print the hot restart compatability version
  /listeners: print listener addresses
  /logging: query/change logging levels
  /quitquitquit: exit the server
  /reset_counters: reset all counters to zero
  /runtime: print runtime values
  /runtime_modify: modify runtime values
  /server_info: print server version/status information
  /stats: print server stats
  /stats/prometheus: print server stats in prometheus format

Service Server 側の /etc/service-envoy.yaml の内容は次のようになっています。Kubernetes だと side car で動かすやつですね。
内容は front-proxy とほぼ同じでした。

static_resources:
  listeners:
  - address: # 0.0.0.0:80 を listen
      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: service
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/service"
                route:
                  cluster: local_service
          http_filters:
          - name: envoy.router
            config: {}
  clusters:
  - name: local_service
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    hosts:
    - socket_address:
        address: 127.0.0.1
        port_value: 8080
admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8081

次に service1 のコンテナを3つに増やしてみます

$ docker-compose scale service1=3
The scale command is deprecated. Use the up command with the --scale flag instead.
Starting frontproxy_service1_1 ... done
Creating frontproxy_service1_2 ... done
Creating frontproxy_service1_3 ... done

curl -sv $(docker-machine ip default):8000/service/1 を実行すると service1 の3つのコンテナに順にアクセスが振り分けられました。front-envoy.yaml が書き換わる感じはしなかったけどと、front-envoy.yaml を確認しましたがやはり変わっていません。単に DNS RoundRobin でした。

clustertypestrict_dns となってるために DNS で複数のIPアドレスが返ってくるとそれぞれのアドレスを別々のホストとして lb_policy にしたがって振り分けてくれるようです。

# dig +short @127.0.0.11 service1
172.18.0.6
172.18.0.5
172.18.0.3

service discovery や healthcheck まわりをもうちょっと調べてみよう