Introduction
Upstreams exist at the very bottom of the application networking object hierarchy. They represent a networked set of hosts that requests get proxied to.
This guide will walk you through adding an upstream to both a TCP and an HTTP listener. This guide will also showcase the two types of upstream host resolution: static and discovered. By the end, you will have a service with a new upstream, either by itself, or in a collection of upstreams in the case of traffic shaping.
Prerequisites
- A GSL service file
Add an Upstream
Upstreams have two possible attachment points: HTTP and TCP Listeners. For HTTP listeners, they attach to routes and for TCP listeners they attach directly to the listener object.
HTTP Listener
Inside the routes template for the listener, locate the route path that needs an upstream and add the upstream field if it does not already exist:
...
routes: {
"<route path>": {
...
upstreams: {
}
}
}
Just like the ingress/egress and routes field, and upstream is a template struct. Each key-value pair defines a new upstream on that route. Routes with multiple upstreams allow for advanced traffic shaping patterns like Blue-Green deployments.
Define a new upstream by adding its name as a key to the template( leave the name empty for now):
upstreams: {
"": {
gsl.Upstream
}
...
}
TCP Listener
Since TCP listeners can only reference one upstream, make sure to create a new one. Inside the listener object, add the upstream
field (leave the name
empty for now):
"<tcp listener name>": {
...
upstream: {
name: ""
}
}
Configure the Upstream Host
Greymatter exposes two different types of host resolution: Service Discovery and Static. Static resolution refers to using a known and unchanging IP address (or DNS record). Discovered resolution uses service discovery to find new instances of a particular service. Upstreams can enable one or the other.
Service Discovery
To discover the host, you need to set two values:
- the upstream
name
to the name of the application found in the Kubernetes manifest. - the upstream
namespace
field to the namespace of the application.
For an HTTP listener:
upstreams: {
"<Name of the application>": {
gsl.#Upstream
namespace: "<namespace of the application>"
...
}
}
For a TCP listener:
upstream: {
gsl.#Upstream
name: '<name of the application>'
namespace: '<namespace of the application>'
...
}
Static
Static host addresses get placed in the instances
list.
For HTTP:
upstreams: {
"<any name>": {
gsl.#Upstream
instances: [{ host: "<host address>", port: "<host port>" }]
}
}
And for TCP:
upstream: {
gsl.#Upstream
name: '<any name>'
instances: [{host: '<host address>', port: '<host port>'}]
}
When defining static host addresses, the name of the upstream does not matter. It only matters in the case of service discovery.
Conclusion
You now have a basic configured upstream on either an HTTP or TCP listener pointing to some hosts through service discovery or static addresses. At this point, you can continue configuring the upstream with security policies, changing load balancing policies, or use traffic shaping with multiple upstreams.