EnvoyのGetting Startedをやってみた

# TL;DR
- 仕事でEnvoyを導入する機会があったので、初めに公式のサンプル(https://www.envoyproxy.io/docs/envoy/latest/start/start) をやってみた。
- 日本語での情報と導入事例はまだ少ない多分CookpadさんのService Meshの事例(https://techlife.cookpad.com/entry/2018/05/08/080000) ぐらい

## 公式サンプル
- URL
    - https://www.envoyproxy.io/docs/envoy/latest/start/start
- 内容
    - dockerでlocalにenvoyを立てて、googleに飛ばす。シンプル。

- コマンド

```sh
docker pull envoyproxy/envoy:latest
docker run --rm -d -p 10000:10000 envoyproxy/envoy:latest
curl -v localhost:10000
```

- curl
    - localhost:10000にcurlするとenvoy経由でgoogleに飛ばされることが確認出来る。

```shell
curl -I localhost:10000
HTTP/1.1 200 OK
date: Fri, 19 Oct 2018 10:27:05 GMT
expires: -1
cache-control: private, max-age=0
content-type: text/html; charset=ISO-8859-1
p3p: CP="This is not a P3P policy! See g.co/p3phelp for more info."
server: envoy
x-xss-protection: 1; mode=block
x-frame-options: SAMEORIGIN
set-cookie: 1P_JAR=2018-10-19-10; expires=Sun, 18-Nov-2018 10:27:05 GMT; path=/; domain=.google.com
set-cookie: NID=141=xxxxxxxxxxxxxxxxxxxx; expires=Sat, 20-Apr-2019 10:27:05 GMT; path=/; domain=.google.com; HttpOnly
alt-svc: quic=":443"; ma=2592000; v="44,43,39,35"
accept-ranges: none
vary: Accept-Encoding
x-envoy-upstream-service-time: 111
transfer-encoding: chunked
```
### 以上
- でおわるとあまりに何も無いので設定ファイルの内容を読み込んでみた.

## 設定ファイル
- Getting startedの設定ファイルは公式のrepoのhttps://github.com/envoyproxy/envoy/blob/master/configs/google_com_proxy.v2.yaml に置いてある。
- Envoyの設定ファイルはJsonとYamlを利用出来、v1とv2がある。
 	- 1.8.0削除予定(短くても12月ぐらい)みたいなのでv2使ったほうが良さそう。ネットで情報調べるときはそこらへん気にしたほうが良さげ。
 		- https://groups.google.com/forum/#!topic/envoy-announce/Lb1QZcSclGQ

```yml
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.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 }
```


- admin部分の解説

```yaml

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

- Envoyにはproxyと同時にadmin機能が提供されている。
- adminにはweb guiとenvoyの状態を取得するapiがある。

#### Web GUI

![image.png](https://qiita-image-store.s3.amazonaws.com/0/149835/58610481-771f-2af1-0980-f9b93bb75b4f.png)

- admin機能にはcluster(Envoyからproxy出来る対象)の状況を見たり、Envoyを止めるなどの機能が提供されている。
  権限が強いのでアクセス制限された設定をするのが通常らしい。
- access_log_path
 - adminにアクセスしたaccess_logを出力する箇所
 - 出力しない場合は `/dev/null` を入れれば良い
- address
 - admin機能をlistenerするaddressを記載する

- Getting Startedの場合はlocalからの9901しか許可されていないため、 container入ってからcurlするとadminサーバーの存在が動いていることが確認出来る。

```shell-session
root@9debcc6e7549:/# curl -I localhost:9901
HTTP/1.1 200 OK
content-type: text/html; charset=UTF-8
cache-control: no-cache, max-age=0
x-content-type-options: nosniff
date: Tue, 14 Aug 2018 02:01:08 GMT
server: envoy
transfer-encoding: chunked
 
root@9debcc6e7549:/# cat /tmp/admin_access.log
[2018-08-14T02:00:40.709Z] "GET / HTTP/1.1" 200 - 0 4389 0 - "172.17.0.2" "curl/7.47.0" "-" "localhost:9901" "-"
[2018-08-14T02:00:42.322Z] "GET / HTTP/1.1" 200 - 0 4389 0 - "172.17.0.2" "curl/7.47.0" "-" "localhost:9901" "-"
[2018-08-14T02:01:08.336Z] "HEAD / HTTP/1.1" 200 - 0 4389 0 - "172.17.0.2" "curl/7.47.0" "-" "localhost:9901" "-"
```

- 設定のreference
       - https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/bootstrap/v2/bootstrap.proto#envoy-api-msg-config-bootstrap-v2-admin

- static_resourcesの部分の解説
 	- 静的な設定はこちらに書く

```yaml
 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 }
```

- Listener
  - Envoyがlistenするaddress及びport、更にfilterする内容などを書く
    - name
    	- 	Listener instanceの名前、他で設定を利用するときなどに使える、性質上一意な名前が必要
    - address 
		- admin機能をlistenするaddressを記載する
    - 	socket_address
        - address
        	- 0.0.0.0 は全てを表す
        - port
        	- 10000ポート
      		- この場合は全てのaddressからの10000 portへの処理を待ち受けしている
    - filter_chains
    - 	送られてくるrequestのfilter方法
      - doc
      		- https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/listener/listener.proto#envoy-api-msg-listener-filter
      - filters
      		- filiter部分の大分類、filter自体は複数書ける
      - name 
        - Instanceの名前。Build-in filterがいつかある
          - 今回は`envoy.http_connection_manager` 利用している
        - config 
        	- filterの設定
          - この設定では `envoy.http_connection_manager` を利用しているため、ここに設定するのは `envoy.http_connection_manager` の設定になる。
          - doc
	    		- https://www.envoyproxy.io/docs/envoy/latest/api-v2/config/filter/network/http_connection_manager/v2/http_connection_manager.proto#envoy-api-msg-config-filter-network-http-connection-manager-v2-httpconnectionmanager
          - stat_prefix
          	- The human readable prefix to use when emitting statistics for the connection manager.
              - 各種statにここで書いたprefixがつく
          - route_config
          - The route table for the connection manager is static
              - この下に静的なroutingの設定を書く
              - 今回の場合は `RouteConfiguration` が提供するもので利用する形になる
              - doc
              - 	https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/rds.proto#envoy-api-msg-routeconfiguration
                - name
                		- route_configの名前
                - virtual_hosts
                		- route tableに登録するvirtual hostの設定、配列で複数渡せる。
                  - name
                  		- 	virtural hostの名前
                  - domain
                  		- 	virtual hostにmatchさせるdomainのlist、*をサポートしている・
                  - routes
                  		- 	requestに対応するroute、配列で複数渡せる、最初に評価されたものにroutingされる。
                    - match
                    	- 送られてきたrequestに対してのpatternにmatchするかを評価する項目、例ではprefixが利用されているが、path, regex, header,case_sensitive(大文字、小文字の判別)など色々用意されている
                      - docs
                      		- https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route.proto#envoy-api-msg-route-routematch
                  - route
                    	- 	合致したrequestのrouting先の設定
                      	- 	route先にはcluster(後述)を設定することが出来る、docs見る限りretryとかもここで設定出来るっぽい。
                        - host_rewrite
                          - Indicates that during forwarding, the host header will be swapped with this value.\
                          - ここに入れた値をhost_headerに入れることが出来る。この例でだと `www.google.com` を入れてる
                          - cluster側で設定したDNSから入れる `auto_host_rewrite` というのもあるみたい
                        - cluster
                        	- 	遷移させる cluster名を指定する
                      - 	docs
                       	 - 	https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/route/route.proto#envoy-api-msg-route-routeaction
        - clusters
       	 - 	Envoyが遷移させる先を記述する部分、配列で複数指定をする
         	 - name
         		 - 	clusterの名前、routeなどのclusterの遷移先名を指定するときに利用する
          - connect_timeout
         		 - 	connectionのtime out値の設定
          - type
         		 - 	指定するaddressのtypeを指定する
         		   - Sampleの場合はLOGICAL_DNSが指定されている
            		- 	各種別の説明はhttps://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/service_discovery#arch-overview-service-discovery-types-strict-dns に記載されている。
              - Service Discoveryっていうのがどういう挙動をするものなのかわかりきってないから、説明もよくわからん。。。勉強しないと。
          - 	docs
            		- 	https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/cds.proto#envoy-api-enum-cluster-discoverytype
          - lb_policy
          		- 	ロードバランスのポリシー
            - docs
            		- 	https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/load_balancing#arch-overview-load-balancing-types
          - hosts
          		- 	到達させるhostの記載箇所、配列で複数記載可能
            		- docs 
            		- 	https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/core/address.proto#envoy-api-msg-core-address
        			- docs
          - 	https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/cds.proto
          	- tls_context
          		- 	tlsを使うconnection場合は設定する設定しない場合は接続出来ない。
- docs
     - https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/listener/listener.proto#envoy-api-file-envoy-api-v2-listener-listener-proto

### 設定ファイル
- 環境変数は使えないっぽい。
- Lyftはjinja (http://jinja.pocoo.org/) というtemplate使ってるみたい。