Envoy implements the dynamic configuration of gateway based on control plane in. NET architecture

What is a control panel

In this article, let's see how to configure Envoy through the Control Panel.

The control plane is a separate service that provides envoy configuration information. Envoy can load the configuration by calling the api of this service.

Configure control panel

The official provides us with two control panels that have been implemented.

Go control panel: https://github.com/envoyproxy/go-control-plane

Java control panel: https://github.com/envoyproxy/java-control-plane

Let's download the official go language control panel and take a look at the sample structure provided in the go control panel.

There are three core files, main.go,server.go, and resource.go

1.main.go: start the entry of go control panel

2.server.go: defines the grpc service of the go control panel

3.resource.go: defines resource configurations related to envy, including cluster, listener, endpoint, etc

Among them, resource.go constitutes a structured configuration information and is provided to envoy through grpc in server.go, while main.go starts grpc. Therefore, what we need to modify is the resource configuration in resource.go. We need to set the cluster, listener and endpoint in it as our own service information. Now let's change the configuration information in resource.go to our own test project configuration.

First, modify the upstream information and specify the ip of our upstream service and the ports of the two upstream services

const (
    ClusterName   = "example_proxy_cluster"
    RouteName     = "local_route"
    ListenerName  = "listener_0"
    ListenerPort  = 10000
    UpstreamHost  = "192.168.43.94"
    UpstreamPort  = 5000
    UpstreamPort2 = 5001
)

Then we modify the dns type to static dns resolution

func makeCluster(clusterName string) *cluster.Cluster {
    return &cluster.Cluster{
        Name:                 clusterName,
        ConnectTimeout:       ptypes.DurationProto(5 * time.Second),
        ClusterDiscoveryType: &cluster.Cluster_Type{Type: cluster.Cluster_STATIC},
        LbPolicy:             cluster.Cluster_ROUND_ROBIN,
        LoadAssignment:       makeEndpoint(clusterName),
        DnsLookupFamily:      cluster.Cluster_V4_ONLY,
    }
}

Modify the makeEndpoint method and specify two test servers. The addresses of server1 and server2 are Endpoint

func makeEndpoint(clusterName string) *endpoint.ClusterLoadAssignment {
    return &endpoint.ClusterLoadAssignment{
        ClusterName: clusterName,
        Endpoints: []*endpoint.LocalityLbEndpoints{{
            LbEndpoints: []*endpoint.LbEndpoint{{
                HostIdentifier: &endpoint.LbEndpoint_Endpoint{
                    Endpoint: &endpoint.Endpoint{
                        Address: &core.Address{
                            Address: &core.Address_SocketAddress{
                                SocketAddress: &core.SocketAddress{
                                    Protocol: core.SocketAddress_TCP,
                                    Address:  UpstreamHost,
                                    PortSpecifier: &core.SocketAddress_PortValue{
                                        PortValue: UpstreamPort,
                                    },
                                },
                            },
                        },
                    },
                },
            },
                {
                    HostIdentifier: &endpoint.LbEndpoint_Endpoint{
                        Endpoint: &endpoint.Endpoint{
                            Address: &core.Address{
                                Address: &core.Address_SocketAddress{
                                    SocketAddress: &core.SocketAddress{
                                        Protocol: core.SocketAddress_TCP,
                                        Address:  UpstreamHost,
                                        PortSpecifier: &core.SocketAddress_PortValue{
                                            PortValue: UpstreamPort2,
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            },
        }},
    }
}

Start control plane

 

  The control plane monitors at port 18000

Configure Envoy

We need to configure Envoy.yaml so that Envoy can obtain detailed configuration information from the control plane. We can refer to Official website Recommended configuration for.

1. Need to be in dynamic_ Configuring ads in resources_ Config and let cds_config and lds_config read from

2. In addition, we need to configure xds cluster to let Envoy know the address of the control plane.

The specific configuration information is as follows:

admin:
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9902
      
node:
  cluster: test-cluster
  id: test-id

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

static_resources:
  clusters:
  - type: STRICT_DNS
    typed_extension_protocol_options:
      envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
        "@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
        explicit_http_config:
          http2_protocol_options: {}
    name: xds_cluster
    load_assignment:
      cluster_name: xds_cluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 192.168.43.94
                port_value: 18000

Run Envoy

We run Envoy through docker

docker run --rm -it -p 9902:9902 -p 10000:10000 -v D:/gateway/envoy/config/dynamic-plane/:/etc/envoy/ -v D:/gateway/envoy/logs:/logs envoyproxy/envoy-dev  -c /etc/envoy/envoy.yaml

Then start server1 and server2 in our previous section

test

  We pass http://localhost:10000/Name To determine whether our configuration is successful

You can see that one call returns server1 and the other call returns server2. The control panel verification is successful!

Secondary development

The configuration provided in the current sample code is hard coded, and the configuration is written in the code. If we want to use this method to configure envoy in the production environment, we can conduct secondary development based on the current code. The development steps are as follows:

1. Add a database table structure to organize resources in Envoy, such as Listener table, Cluster table, Endpoint table and Route table

2. Add an interface to add, delete, modify and query Listener, Cluster, Endpoint, Route and other resources

3. Add UI to call the add, delete, modify and query interface to manage resources

4. Refresh Snapshot information regularly

  In this way, we can implement a visual interface to dynamically configure our Envoy.

Tags: gateway

Posted on Sat, 30 Oct 2021 03:36:57 -0400 by plasko