envoy go-control-plane 実験
envoy control-plane を調べていた。control-plane から data-plane に接続するのかと思い込んでいたがそうではなかった。
今の解釈はこんな感じ
- envoy(data-plane)は Endpoint Discovery Service(EDS) 等のxDSの利用する側。クライアント
- control-plane は xDS を提供する側。サーバー
- envoy は control-plane から配信された情報から、自分の設定を更新していく
- envoy が参照すべき xDS のエンドポイントを envoy.yaml に設定しておく
という解釈ができるようになってから envoy.yaml を眺めると前より理解しやすくなった。
今回のコードはここに置きました。 envoyprac/prac1 at master · tjtjtj/envoyprac · GitHub
実験の流れ
ここを参考(ほとんどコピーですが)にさせていただきました。 感謝感謝
- helloを起動
- envoy 起動
- このときenvoyはhelloを知らない。 EDSのエンドポイントは知っている
- curl しても失敗するはず
- control-plane 起動
- envoy が control-plane(EDS) に接続
- control-plane がエンドポイントを配信
- curl するとhelloを参照するはず
実験
helloを起動
docker run --rm -d -p 8080:80 dockercloud/hello-world
直接 curl
# curl http://localhost:8080 <h3>My hostname is 9c2075e4f35a</h3> </body>
/tmp/envoy/envoy.yaml
node: id: node0 cluster: cluster.local static_resources: listeners: - name: listener_0 address: socket_address: { address: 0.0.0.0, port_value: 80 } filter_chains: - filters: - name: envoy.http_connection_manager config: stat_prefix: ingress_http route_config: name: route virtual_hosts: - name: hello_service domains: ["hello.local"] routes: - match: { prefix: "/" } route: { cluster: hello_cluster } http_filters: - name: envoy.router clusters: - name: hello_cluster connect_timeout: 0.25s lb_policy: ROUND_ROBIN type: EDS eds_cluster_config: eds_config: api_config_source: api_type: GRPC grpc_services: envoy_grpc: cluster_name: xds_cluster - name: xds_cluster connect_timeout: 0.25s lb_policy: ROUND_ROBIN http2_protocol_options: {} load_assignment: cluster_name: xds_cluster endpoints: - lb_endpoints: - endpoint: address: socket_address: {address: 127.0.0.1, port_value: 20000 }
envoy 起動
# docker run \ --name envoy --rm --publish 80:80 \ --net=host \ -v /tmp/envoy:/etc/envoy \ envoyproxy/envoy:v1.10.0
最初の curl は失敗
# curl -H 'Host: hello.local' 127.0.0.1 no healthy upstream
prac1.go
package main import ( "flag" "fmt" "log" "net" "os" api "github.com/envoyproxy/go-control-plane/envoy/api/v2" core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint" "github.com/envoyproxy/go-control-plane/pkg/cache" xds "github.com/envoyproxy/go-control-plane/pkg/server" "google.golang.org/grpc" ) // NodeHash interfaceの実装。Envoyの識別子から文字列をかえすハッシュ関数を実装する。 type hash struct{} func (hash) ID(node *core.Node) string { if node == nil { return "unknown" } return node.Cluster + "/" + node.Id } var upstreams = map[string][]struct { Address string Port uint32 }{ // ここはコンテナのアドレス "hello_cluster": {{"127.0.0.1", 8080}}, } // スナップショットを返す。構造体の形はProtocol Bufferの定義と同じ。 func defaultSnapshot() cache.Snapshot { var resources []cache.Resource for cluster, ups := range upstreams { eps := make([]endpoint.LocalityLbEndpoints, len(ups)) for i, up := range ups { eps[i] = endpoint.LocalityLbEndpoints{ LbEndpoints: []endpoint.LbEndpoint{{ HostIdentifier: &endpoint.LbEndpoint_Endpoint { Endpoint: &endpoint.Endpoint{ Address: &core.Address{ Address: &core.Address_SocketAddress{ SocketAddress: &core.SocketAddress{ Address: up.Address, PortSpecifier: &core.SocketAddress_PortValue{PortValue: up.Port}, }, }, }, }, }, }}, } } assignment := &api.ClusterLoadAssignment{ ClusterName: cluster, Endpoints: eps, } resources = append(resources, assignment) } return cache.NewSnapshot("0.0", resources, nil, nil, nil) } func run(listen string) error { // xDSの結果をキャッシュとして設定すると、いい感じにxDS APIとして返してくれる。 snapshotCache := cache.NewSnapshotCache(false, hash{}, nil) server := xds.NewServer(snapshotCache, nil) // NodeHashで返ってくるハッシュ値とその設定のスナップショットをキャッシュとして覚える err := snapshotCache.SetSnapshot("cluster.local/node0", defaultSnapshot()) if err != nil { return err } // gRCPサーバーを起動してAPIを提供 grpcServer := grpc.NewServer() api.RegisterEndpointDiscoveryServiceServer(grpcServer, server) lsn, err := net.Listen("tcp", listen) if err != nil { return err } return grpcServer.Serve(lsn) } func main() { var listen string flag.StringVar(&listen, "listen", ":20000", "listen port") flag.Parse() log.Printf("Starting server with -listen=%s", listen) err := run(listen) if err != nil { fmt.Println(os.Stderr, err) os.Exit(1) } }
prac1.go(controle-plane) 起動後の curl は成功した。
# curl -H 'Host: hello.local' 127.0.0.1 <h3>My hostname is 9c2075e4f35a</h3> </body>
あーenvoy の stats の変化も確認するんだった。次回やる。