Upstream
  • 21 Mar 2024
  • 2 Minutes to read
  • Contributors
  • Dark
    Light
  • PDF

Upstream

  • Dark
    Light
  • PDF

Article summary

An upstream represents a destination requests get sent to. They contain configuration related to routing to the destination as well as features of the request like TLS options, health checking, and circuit breaking. They form the last link in the application networking hierarchy.

Service discovery

Upstreams require some networking information. There are two methods of populating this:

  • statically defined

  • discovered

Statically defined endpoints refer to an domain name or IP, and a port. Discovered endpoints are a way to dynamically update the networking information for a service given the service name and namespace. Greymatter will ensure that any change to a service’s network location will get propagated to all upstreams that depend on it.

Service discovery relies on the name and namespace of the service you want to discover. To configre an upstream to use service discovery, set the upstream name to the name of the destination service (found in the GSL file for that service). Then, inside the upstream definition, set the namespace field to the namespace that service runs in (this should be the project name).

Example

{
  gsl.#Upstream
  name: "destinationService"
  namespace: "inThisNamespace"
}

For Upstreams that are defined within a map, the name of the upstream gets set from the key of the upstream.

// inside an HTTP route
upstreams: {
  "destinationService: {
    gsl.#Upstream
    // name is not necessary here
    namespace: "inThisNamespace"
  }
}

Built-in Mix-ins

#TLSUpstream

Sets the upstream to use TLS.

#MTLSUpstream

Sets the upstream to use mTLS.

#SpireUpstream

Sets the upstream to use mTLS with Spire-minted certificates.

#HTTP2Upstream

Configures HTTP/2 support on the upstream.

Schema

// TLS options. Should not be set directly, rather use the #TLSUpstream definition.
#UpstreamTLSSchema
// SPIRE options. Should not be set directly, rather use the #SpireUpstream definition.
#UpstreamSecretSchema


// Name of the upstream. Must match the destination service name
// if the instances are resolved through service discovery
name:     string

// Name of the upstream's namespace. Required only if performing service discovery.
// Cannot be set with instances.
namespace?: string

// List of service IP addresses and ports. Cannot be set along with namespace.
instances?: [...#Instance]

// Determines the load balancing policy. One of:
// round_robin, least_request, ring_hash, random, maglev.
// Defaults to round_robin.
lb_policy?:               string

// Configuration for ring hash lb policy.
ring_hash_lb_config?:     #RingHashLbConfig

// configuration for original destination lb.
original_dst_lb_config?:  #OriginalDstLbConfig

// configuraiton for least request lb policy.
least_request_lb_config?: #LeastRequestLbConfig

// configuration common to load balancing.
common_lb_config?:        #CommonLbConfig

// Determines how the proxy resolves host names in the instances array.
// See: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/cluster.proto#enum-config-cluster-v3-cluster-discoverytype
dns_type?:                string

// Active health checking configuration.
health_checks?: [...#HealthCheck]

// Passive health checking configuration.
outlier_detection?:      #OutlierDetection

// Circuit breaker configuration. Circuit breaking is a type of rate
// limiting that occurs when there is a service failure to prevent unnecessary
// and perhaps harmful retries.
circuit_breakers?:       #CircuitBreakersThresholds

// HTTP protocol specific options. Has no effect on UDP upstreams.
http_protocol_options?:  #HTTPProtocolOptions

// HTTP/2 protocol specific options. MUST BE SET TO TURN THE UPSTREAM
// INTO AN HTTP/2 CONNECTION. Has no effect on UDP upstreams.
http2_protocol_options?: #HTTP2ProtocolOptions

protocol_selection?:     string

// Determines any traffic shaping. Should not be set directly.
traffic_options: {
	behavior: "shadow" | *"split"
	weight:   *1 | int
}

// List of failover upstreams to use in the case that the current upstream is
// unhealthy. 
failover_instances?: [...#FailoverSchema]


Was this article helpful?