github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/docs/proposals/edgemesh-design.md (about)

     1  ---
     2  title: EdgeMesh Design
     3  status: implementable
     4  authors:
     5      - "@qizha"
     6      - "@sids-b"
     7  approvers:
     8    - "@kevin-wangzefeng"
     9    - "@CindyXing"
    10  creation-date: 2019-03-20
    11  last-updated: 2019-03-27
    12  ---
    13  
    14  # Edge Mesh on edge
    15  
    16  ## Abstract
    17  To support service mesh capabilities on edge to support microservice communication cross cloud and edge.
    18  The service discovery, communication should be considered in this feature.
    19  Developers can define services on top of the deployments deployed on the cloud or edges in a unified manner without caring about their location. The service name is the only thing they need to know to do the communication. For example, the following address can be used for a REST request:
    20  `http://{service_name}/resources`
    21  
    22  ## Motivation
    23  The cloud native and microservice architecture is becoming more and more popular and the edge node is becoming more and more powerful. The user want to decompose their application into multiple microservices. Some of those microservices need to be deployed in edge node to get close to the data generated by devices. By simplify the development, the user need to use the same mechanism to do the service discovery and communication with what they are doing on cloud.
    24  
    25  ## Constraints and Assumptions
    26  1. No DNS services available for edge.
    27  2. The identification and authentication should be handled by microservices.
    28  3. When service communication between edge to edge, they may work offline. With the purpose to deliver a "expected result" to the user system, the service definition should be push down to the edge right after the definition operation. That is to say, the istio model may not be suitable for edge, in istio model, the service definition is pull from K8S master when the service is invoked.
    29  4. Only support HTTP communication in the first step
    30  5. All edge nodes are in the same sub-network and they have the network reachability.
    31  
    32  ## Use cases
    33  <img src="../images/proposals/service-design.png">
    34  
    35  ### Register the service located on cloud
    36  * CS0.1: User create service(type ClusterIP) in K8S API Server
    37  * CS0.2: ServiceController get the service definition and create router rules with the edge ServiceBus as source and service clusterIP as target.
    38  * CS0.3: Send the service definition to edge
    39  
    40  ### Register the service located on edge
    41  * CS1: User create service(headless service without ClusterIP) in K8S API Server
    42  * CS2, CS3: ServiceController get the service definition and update the service ClusterIP to itself. Then create router rule with the EC(Router) address as the source and edge ServiceBus as target.
    43  * CS4: Send the service definition to edge
    44  
    45  ### Service discovery on cloud
    46  * Application access service with the same mechanism no matter it located on cloud or edge
    47  
    48  ### Service discovery on edge
    49  * Use iptables to redirect inbound and outbound traffic to the EdgeHub/ServiceBus. Then do service discovery in EdgeHub/ServiceBus by pick up the right POD from the service definition. The idea is similar with what istio is doing in the init_container: https://github.com/istio/istio/blob/master/tools/packaging/common/istio-iptables.sh
    50  
    51  ### Service communication from cloud to edge
    52  * ESD1: Application on cloud visit service with clusterIP and request goes to EC(refer to step CS2, CS3)
    53  * ESD2: Router find out the PODs in this service and pick one with some kind of load balance mechanism. Then send the request to the choosen edge with the router rule set in CS3.
    54  * ESD3: EdgeHub/ServiceBus get the request and redirect to the POD
    55  
    56  ### Service communication between edges
    57  * ESR1: Application send the request to ServiceBus(refer to the "Service discovery on edge")
    58  * ESR2: ServiceBus pick one POD in this service with some kind of load balance mechanism. If the target is in the same node, just forward the request. If not, edgehub wrapper the request and send to the target.
    59  * ESR3: EdgeHub open the wrapped package and forward to the POD
    60  
    61  ### Service communication from edge to cloud
    62  * ESU1: Application send the request to ServiceBus(refer to the "Service discovery on edge")
    63  * ESU2: ServiceBus pick one POD in this service with some kind of load balance mechanism. The target is on cloud, EdgeHub send the request to cloud.
    64  * ESU3: Router send the request to the corresponding POD on cloud following the rule created in CS0.2
    65  
    66  ## Proposal Changes
    67  ### Add servicebus on Edge to handle request proxy
    68  ServiceBus is in the same process with EdgeHub as a module
    69  
    70  ### Router
    71  Add two endpoints definition:
    72  
    73  |Endpoint|Type|Capability|
    74  |---|---|---|
    75  |ClusterIP|Target|Request Forward|
    76  |ServiceBus|Source|Request Forward, Service Discovery, Load Balance|
    77  |ServiceBus|Target|Request Forward|
    78  |Router|Source|Request Forward, Service Discovery, Load Balance|
    79  
    80  <img src="../images/proposals/router-design.png">
    81  
    82  * R1: ServiceController(SC) watches on k8s apiserver for Services/Endpoints.
    83  * R2: SC get the service definition and create router rule definition and save in DB(ETCD).
    84  * R3: Router gets the rule definition from DB and initializes the listeners/handlers for source and target.
    85  * R4: Users/Applications create a request.
    86  * R5: Router receives the request and forwards it to the target based on rule.
    87  
    88  Since Router fetches rules from DB, in later versions it can be started as a different process than edge-controller. Also it enables router to retrieve all the rules after process restarts.
    89  ### Router Low-level Design
    90  
    91  ### Providers
    92  Providers are plugins to reach a service running on edge or on cloud. For example (ServiceBus, EventBus running in edgecore) 
    93  Providers can be classified into two types
    94  1) Source
    95  2) Target
    96  
    97  In Alpha only ServiceBus, REST and EventBus providers will be supported.
    98  
    99  Providers in router work in following way.
   100  
   101  <img src="../images/proposals/router-flow.png">
   102  
   103  1) Router rule is added by SC say REST as source and ServiceBus at edge as target.
   104  2) Router receives the rule and registers a listener in the source which is REST in this case.
   105  3) REST provider starts listening on the path mentioned in the SourceResource of the rule.
   106  for eg: http://${rest_endpoint}:${rest_endpoint_port}/${node_id}${path of rule.source_resource}
   107  4) 4.1 User/App make a request to the endpoint in 3.
   108  
   109     4.2 REST provider forwards the request to ServiceBus provider.
   110  5) 5.1 ServiceBus provider then creates a beehive message and sends it to CloudHub.
   111  
   112     5.2 CloudHub then forwards the message to edgeHub.
   113  
   114     5.3 EdgeHub send the message to ServiceBus module.
   115  6) 6.1 ServiceBus at edge receives the message, makes the http request to applications running at edge.
   116  
   117     6.2  Receives the response back from the application.
   118  7) 7.1 ServiceBus at Edge sends the response in beehive message back to EdgeHub.
   119  
   120     7.2 EdgeHub forwards the message to CloudHub.
   121  
   122     7.3 CloudHub sends the message back to router.
   123  
   124     7.4 The message is then converted to http response and sent to the user/application which made the request in step 4.1
   125  
   126  ### Source Interfaces
   127  
   128  Each provider that wants to register as a Source should implement following interfaces.
   129  
   130  ```go
   131  type Source interface {
   132  	// Name Returns name of the provider
   133  	Name() string
   134  	// RegisterListener is used to register listener for a rule with this source type
   135  	RegisterListener(rule model.Rule, res model.Map, handler func(interface{})) error
   136  	// UnregisterListener is used to unregister a listener when rule is deleted
   137  	UnregisterListener(rule model.Rule, res map[string]interface{})
   138  	// Callback is function for sending response/ACK if required for a request 
   139  	Callback(map[string]interface{})
   140  }
   141  ```
   142  
   143  ```go
   144  type SourceFactory interface {
   145  	// Type returns type of the source
   146  	Type() string
   147  	// GetSource returns Source implementation
   148  	GetSource(ep *model.Endpoint) Source
   149  }
   150  ```
   151  
   152  ### Target Interfaces
   153  
   154  Each provider that wants to register as a Target should implement following interfaces.
   155  
   156  ```go
   157  type Target interface {
   158  	// Name returns name of the provider
   159  	Name() string
   160  	// Forward is used to forward the request to target 
   161  	Forward(map[string]interface{}, interface{}, func(map[string]interface{})) error
   162  }
   163  ```
   164  
   165  ```go
   166  type TargetFactory interface {
   167  	// Type returns type of the target
   168  	Type() string
   169  	// GetTarget returns Target implementation
   170  	GetTarget(ep *model.Endpoint) Target
   171  }
   172  ```
   173  
   174  ### Rule Definition
   175  
   176  ```go
   177  // Rule define message translate from Endpoint to Endpoint
   178  type Rule struct {
   179  	// ID is unique id of rule
   180  	ID              string    `orm:"column(id); size(36); pk" json:"id" yaml:"id"`
   181  	// Name is the name of the Rule
   182  	Name            string    `orm:"column(name); size(64)" json:"name" yaml:"name"`
   183  	// ProjectID can be used to differentiate rules across projects
   184  	ProjectID       string    `orm:"column(project_id); size(36); index" json:"project_id" yaml:"project_id"`
   185  	// DomainID is the domain from where the source is accessed
   186  	DomainID        string    `orm:"column(domain_id); size(36); index" json:"domain_id" yaml:"domain_id"`
   187  	// Source is the source Endpoint
   188  	Source          *Endpoint `orm:"column(source); rel(fk)" json:"source" yaml:"source"`
   189  	// SourceResource is a map used to store resources required for source
   190  	SourceResource  Map       `orm:"column(source_resource); size(1024)" json:"source_resource" yaml:"source_resource"`
   191  	// Target is target endpoint
   192  	Target          *Endpoint `orm:"column(target); rel(fk)" json:"target" yaml:"target"`
   193  	// TargetResource is a map used to store resources required for target
   194  	TargetResource  Map       `orm:"column(target_resource); size(1024)" json:"target_resource" yaml:"target_resource"`
   195  	// InUse is flag to check if rule is in use
   196  	InUse           bool      `orm:"column(in_use); default(true)" json:"in_use" yaml:"in_use"`
   197  	// IsDeleted is flag to check if rule is deleted
   198  	IsDeleted       bool      `orm:"column(is_deleted); default(false)" json:"is_deleted" `
   199  	// CreatedAt is rule creation timestamp
   200  	CreatedAt       time.Time `orm:"column(created_at); auto_now_add; type(datetime)" json:"created_at" `
   201  	// UpdatedAt is last rule updation timestamp
   202  	UpdatedAt       time.Time `orm:"column(updated_at); auto_now; type(datetime)" json:"updated_at" `
   203  	// SuccessMessages is the number of success messages for this rule
   204  	SuccessMessages uint64    `orm:"column(success_messages); default(0)" json:"success_messages" `
   205  	// FailMessages in the number of fail messages for this rule
   206  	FailMessages    uint64    `orm:"column(fail_messages); default(0)" json:"fail_messages" `
   207  	// Error is reverse maping of error messages for this rule
   208  	Error           []*Error  `orm:"reverse(many)" json:"-"`
   209  }
   210  ```
   211  
   212  
   213  ### Endpoint Definition
   214  
   215  ```go
   216  // Endpoint define how to access external service
   217  type Endpoint struct {
   218  	// ID is the ID of the endpoint
   219  	ID         string    `orm:"column(id); size(36); pk" json:"id" yaml:"id"`
   220  	// Type is type of the endpoint
   221  	Type       string    `orm:"column(type); size(64)" json:"type" yaml:"type"`
   222  	// Name is name of the endpoint
   223  	Name       string    `orm:"column(name); size(64)" json:"name" yaml:"name"`
   224  	// ProjectID can be used to differentiate endpoints across projects
   225  	ProjectID  string    `orm:"column(project_id); size(36); index; null" json:"project_id" yaml:"project_id"`
   226  	// IsShared is flag to check if endpoint is shared
   227  	IsShared   bool      `orm:"column(is_shared); default(false)" json:"is_shared" `
   228  	// URI is unique resource identifier of the endpoint
   229  	URI        string    `orm:"column(uri); size(256)" json:"uri" yaml:"uri"`
   230  	// Properties is map used to store properties of an Endpoint
   231  	Properties Map       `orm:"column(properties); size(10240)" json:"properties" yaml:"properties"`
   232  	// CreatedAt is endpoint creation timestamp
   233  	CreatedAt  time.Time `orm:"column(created_at); auto_now_add; type(datetime)" json:"created_at" `
   234  	// UpdatedAt is last endpoint updation timestamp
   235  	UpdatedAt  time.Time `orm:"column(updated_at); auto_now; type(datetime)" json:"updated_at" `
   236  	// Rule is reverse mapping of Rules of this endpoint
   237  	Rule       []*Rule   `orm:"reverse(many)" json:"-"`
   238  }
   239  ```
   240  ### EdgeHub
   241  * Listen to the edge communication
   242  * Package the message and send to the target
   243  
   244  ### EdgeController
   245  * Listen the service definition and create routing rule
   246  * Listen the service definition to PODs deployed on edge and update the ClusterIP