envoy ads配置

基于envoy ads的动态配置服务发现,直接上代码。

package main

import (
    "context"
    "flag"
    "fmt"
    "log"
    "net"
    "os"
    "os/signal"
    "time"

    "github.com/envoyproxy/go-control-plane/envoy/api/v2"
    envoyapi "github.com/envoyproxy/go-control-plane/envoy/api/v2"
    envoycore "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
    envoyendpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
    envoylistener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
    envoyroute "github.com/envoyproxy/go-control-plane/envoy/api/v2/route"
    envoyhcm "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2"
    discovery "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v2"
    envoycache "github.com/envoyproxy/go-control-plane/pkg/cache"
    envoyserver "github.com/envoyproxy/go-control-plane/pkg/server"
    envoyutil "github.com/envoyproxy/go-control-plane/pkg/util"
    grpc "google.golang.org/grpc"
)

type hash struct{}

func (hash) ID(node *envoycore.Node) string {
    if node == nil {
        return "unknown"
    }
    return node.Cluster + "/" + node.Id
}

func createListener() *envoyapi.Listener {
    manager := &envoyhcm.HttpConnectionManager{
        StatPrefix: "http",
        RouteSpecifier: &envoyhcm.HttpConnectionManager_Rds{
            Rds: &envoyhcm.Rds{
                RouteConfigName: "hello_route",
                ConfigSource: envoycore.ConfigSource{
                    ConfigSourceSpecifier: &envoycore.ConfigSource_ApiConfigSource{
                        ApiConfigSource: &envoycore.ApiConfigSource{
                            ApiType: envoycore.ApiConfigSource_GRPC,
                            GrpcServices: []*envoycore.GrpcService{{
                                TargetSpecifier: &envoycore.GrpcService_EnvoyGrpc_{
                                    EnvoyGrpc: &envoycore.GrpcService_EnvoyGrpc{
                                        ClusterName: "xds_cluster",
                                    },
                                },
                            }},
                        },
                    },
                },
            },
        },
        HttpFilters: []*envoyhcm.HttpFilter{{
            Name: "envoy.router",
        }},
    }
    filterConfig, err := envoyutil.MessageToStruct(manager)
    if err != nil {
        panic(err.Error())
    }
    listener := &envoyapi.Listener{
        Name: "listener_0",
        Address: envoycore.Address{
            Address: &envoycore.Address_SocketAddress{
                SocketAddress: &envoycore.SocketAddress{
                    Address:       "0.0.0.0",
                    PortSpecifier: &envoycore.SocketAddress_PortValue{PortValue: 80},
                },
            },
        },
        FilterChains: []envoylistener.FilterChain{{
            Filters: []envoylistener.Filter{{
                Name: "envoy.http_connection_manager",
                ConfigType: &envoylistener.Filter_Config{
                    Config: filterConfig,
                },
            }},
        }},
    }
    return listener
}

func createRouteConfig() *envoyapi.RouteConfiguration {
    routeconfig := &envoyapi.RouteConfiguration{
        Name: "hello_route",
        VirtualHosts: []envoyroute.VirtualHost{{
            Name: "hello_service",
            //Domains: []string{"hello.local"},
            Domains: []string{"*"},
            Routes: []envoyroute.Route{{
                Match: envoyroute.RouteMatch{
                    PathSpecifier: &envoyroute.RouteMatch_Prefix{
                        Prefix: "/",
                    },
                },
                Action: &envoyroute.Route_Route{
                    Route: &envoyroute.RouteAction{
                        ClusterSpecifier: &envoyroute.RouteAction_Cluster{
                            Cluster: "hello_cluster",
                        },
                    },
                },
            }},
        }},
    }
    return routeconfig
}

func createCluster() *envoyapi.Cluster {
    connectionTimeout := time.Duration(60*1000) * time.Millisecond

    cluster := &envoyapi.Cluster{
        Name:           "hello_cluster",
        ConnectTimeout: connectionTimeout,
        LbPolicy:       envoyapi.Cluster_ROUND_ROBIN,
        ClusterDiscoveryType: &envoyapi.Cluster_Type{
            Type: envoyapi.Cluster_EDS,
        },
        EdsClusterConfig: &envoyapi.Cluster_EdsClusterConfig{
            EdsConfig: &envoycore.ConfigSource{
                ConfigSourceSpecifier: &envoycore.ConfigSource_ApiConfigSource{
                    ApiConfigSource: &envoycore.ApiConfigSource{
                        ApiType: envoycore.ApiConfigSource_GRPC,
                        GrpcServices: []*envoycore.GrpcService{{
                            TargetSpecifier: &envoycore.GrpcService_EnvoyGrpc_{
                                EnvoyGrpc: &envoycore.GrpcService_EnvoyGrpc{
                                    ClusterName: "xds_cluster",
                                },
                            },
                        }},
                    },
                },
            },
        },
    }
    return cluster
}

func createEndpoint(endp MyEndpoint) *envoyapi.ClusterLoadAssignment {
    clusterLoadAssignment := &envoyapi.ClusterLoadAssignment{
        ClusterName: endp.name,
        Endpoints: []envoyendpoint.LocalityLbEndpoints{{
            LbEndpoints: []envoyendpoint.LbEndpoint{{
                HostIdentifier: &envoyendpoint.LbEndpoint_Endpoint{
                    Endpoint: &envoyendpoint.Endpoint{
                        Address: &envoycore.Address{
                            Address: &envoycore.Address_SocketAddress{
                                SocketAddress: &envoycore.SocketAddress{
                                    Address:       endp.address,
                                    PortSpecifier: &envoycore.SocketAddress_PortValue{PortValue: endp.port},
                                },
                            },
                        },
                    },
                },
            }},
        }},
    }
    return clusterLoadAssignment
}

func createSnapshot(endp MyEndpoint) envoycache.Snapshot {

    var endpoints []envoycache.Resource
    endpoints = append(endpoints, createEndpoint(endp))
    var clusters []envoycache.Resource
    clusters = append(clusters, createCluster())
    var routes []envoycache.Resource
    routes = append(routes, createRouteConfig())
    var listeners []envoycache.Resource
    listeners = append(listeners, createListener())

    return envoycache.NewSnapshot(endp.version, endpoints, clusters, routes, listeners)
}

func run(listen string, endp MyEndpoint) error {
    snapshotCache := envoycache.NewSnapshotCache(false, hash{}, nil)
    server := envoyserver.NewServer(snapshotCache, Callback{})

    err := snapshotCache.SetSnapshot("cluster.local/node0", createSnapshot(endp))
    if err != nil {
        return err
    }

    grpcServer := grpc.NewServer()
    discovery.RegisterAggregatedDiscoveryServiceServer(grpcServer, server)
    envoyapi.RegisterEndpointDiscoveryServiceServer(grpcServer, server)
    envoyapi.RegisterClusterDiscoveryServiceServer(grpcServer, server)
    envoyapi.RegisterRouteDiscoveryServiceServer(grpcServer, server)
    envoyapi.RegisterListenerDiscoveryServiceServer(grpcServer, server)

    lsn, err := net.Listen("tcp", listen)
    if err != nil {
        return err
    }
    go func() {
        log.Printf("start grpc server version:%s", endp.version)
        grpcServer.Serve(lsn)
    }()

    quit := make(chan os.Signal)
    signal.Notify(quit, os.Interrupt)
    <-quit
    log.Println("stopping grpc server...")

    grpcServer.Stop()
    //grpcServer.GracefulStop()

    return nil
}

func main() {
    var listen string
    flag.StringVar(&listen, "listen", ":20000", "listen port")
    flag.Parse()

    log.Printf("Starting server with -listen=%s", listen)

    end0 := MyEndpoint{
        version: "0",
        name:    "hello_cluster",
        address: "127.0.0.1",
        port:    8080,
    }
    err := run(listen, end0)
    if err != nil {
        fmt.Println(os.Stderr, err)
        os.Exit(1)
    }

    end1 := MyEndpoint{
        version: "1",
        name:    "hello_cluster",
        address: "127.0.0.1",
        port:    8081,
    }
    err = run(listen, end1)
    if err != nil {
        fmt.Println(os.Stderr, err)
        os.Exit(1)
    }
}

type MyEndpoint struct {
    version string
    name    string
    address string
    port    uint32
}
type Callback struct{}

func (cb Callback) OnStreamOpen(context.Context, int64, string) error { return nil }
func (cb Callback) OnStreamClosed(int64)                              {}
func (cb Callback) OnStreamRequest(int64, *v2.DiscoveryRequest) error {
    return nil
}
func (cb Callback) OnStreamResponse(int64, *v2.DiscoveryRequest, *v2.DiscoveryResponse) {}
func (cb Callback) OnFetchRequest(context.Context, *v2.DiscoveryRequest) error          { return nil }
func (cb Callback) OnFetchResponse(*v2.DiscoveryRequest, *v2.DiscoveryResponse)         {}

go.mod文件

module envoyprac

go 1.12

require (
    github.com/envoyproxy/go-control-plane v0.8.1
    github.com/gogo/protobuf v1.2.1
    google.golang.org/grpc v1.21.1
)

envoy yaml配置文件:

node:
  id: node0
  cluster: cluster.local

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
      protocol: TCP
      address: 127.0.0.1
      port_value: 9901

static_resources:
  clusters:
  - 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 }

dynamic_resources:
  ads_config:
    api_type: GRPC
    grpc_services:
    - envoy_grpc:
        cluster_name: xds_cluster
  cds_config:
    ads: {}
  lds_config:
    ads: {}

参考https://github.com/tjtjtj/envoyprac

你可能感兴趣的:(envoy ads配置)