Exposing an Application using Tetrate Enterprise Gateway for Envoy (TEG)
With Tetrate Enterprise Gateway for Envoy (TEG) installed, we can now expose an application to the outside world. This means that requests to our application should be sent to Tetrate Enterprise Gateway for Envoy (TEG), which will forward them to our application. Our application is not directly exposed to the outside world, and all requests to it will be subject to processing by TEG, e.g. enforcing authentication or a ratelimit.
Deploy Test Application
If you don't have an application in your cluster ready to use with Tetrate Enterprise Gateway for Envoy (TEG), you can deploy a demo application, httpbin, instead:
kubectl create namespace httpbin
kubectl apply -n httpbin -f https://raw.githubusercontent.com/istio/istio/master/samples/httpbin/httpbin.yamlnoteWe need somewhere for TEG to send traffic. In addition to Pods, the above file also deployed a Service called
httpbin
which listens on port 8000. If you're using your own app, be sure it has a Kubernetes Service deployed in thedefault
namespace, and that you know that Service's name and port.Deploy Envoy Proxies
Requests destined for our application will be handled by a set of Envoy proxies at the edge of our cluster's network. They listen for incoming requests from the outside world and forward them on to our app; sitting between it and its clients. They perform the same job that you might be familiar with nginx, haproxy, or other ingress controllers doing.
However when you install TEG, you only deploy a piece of software that manages Envoy proxies, not any proxies themselves. Our first job is to arrange for a set of proxies to be deployed to handle our traffic.
infoThe deployment style we're using here is dedicated gateways. For more information, read about the difference between dedicated gateways and shared gateways.
This is done with the Gateway resource as follows:
dedicated-gateway.yamlapiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: dedicated-gateway
namespace: httpbin
spec:
gatewayClassName: teg
listeners:
- name: http
protocol: HTTP
port: 80With the above Gateway configuration applied, you'll see the dedicated Envoy Gateway will be deployed in the
envoy-gateway-system
namespace. There'll likely only be one for now as load is low; they'll autoscale up if more are needed.kubectl get pods -n envoy-gateway-system -l gateway.envoyproxy.io/owning-gateway-namespace=httpbin
NAME READY STATUS RESTARTS AGE
envoy-httpbin-dedicated-gateway-c4239473-687774796c-w4ckf 1/1 Running 0 95sThe gateway is listening for traffic coming from outside the cluster, on port 80.
kubectl get gateway -n httpbin
NAME CLASS ADDRESS PROGRAMMED AGE
dedicated-gateway teg 104.196.111.251 True 2m42skubectl get svc -n envoy-gateway-system -l gateway.envoyproxy.io/owning-gateway-namespace=httpbin
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
envoy-httpbin-dedicated-gateway-c4239473 LoadBalancer 10.103.247.77 104.196.111.251 80:31942/TCP 2m24sRouting Traffic to our App
The proxies are running and listening on port 80; they receive traffic bound for services in our cluster. Next we need to tell TEG which apps (ie Pods, microservices) to send which requests to.
infoWe can match different requests based on any HTTP attribute they possess, but the most common to use are the HTTP
host
and the path. You're probably familiar with routing traffic on path, and on thehost
header, aka vHosting. To avoid things getting too complicated with DNS, we'll differentiate our traffic on its path, mounting our httpbin example app under/httpbin/
.For this we use an HTTPRoute resource. There are different types of Route resource for different protocols, allowing us to route on protocol-specific attributes, e.g. HTTPRoute can talk about paths, which are not present in TCP.
Apply the following resource. Since it's a little longer, we'll examine it section-by-section afterwards.
noteIf you're using your own app, rather than the example httpbin, change the details in the
backendRefs
section.httpbin-httproute.yamlapiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: httpbin
namespace: httpbin
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: dedicated-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /httpbin/
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- group: ""
kind: Service
name: httpbin
port: 8000The notable sections of this config are:
parentRefs
: the HTTPRoute attaches to the Gateway from earlier; this means its rules apply to traffic that hits the physical proxies deployed by that Gatewaymatches
: this section identifies which requests we want this resource to process. In this case, we're matching requests on their path, specifically any path that starts with/httpbin/
filters
: filters let us perform basic processing on the request before sending it on. In our case, the user will request httpbin endpoints as e.g./httpbin/get
, but httpbin doesn't know about the TEG layer in front of it, so is just expecting requests for/get
. Thus we remove the prefix that we matched before passing the request on.backendRefs
: the place to forward matching requests to. We're forwarding to a Kubernetes Service, in the same namespace as our HTTPRoute resource, calledhttpbin
, and we know it listens on port 8000.
Make a Request to httpbin
Now we can make a test request to our app, via TEG. Without making assumptions about your cluster and environment, the only way to address the apps gateway we deployed is by its IP address. The IP we want is the external one, ie the one available outside the cluster. We can find that and store it in a shell variable thus:
export DEDICATED_GATEWAY_IP=$(kubectl get service -n envoy-gateway-system -l gateway.envoyproxy.io/owning-gateway-namespace=httpbin -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}')
noteIf you're using a cluster in AWS, you'll need to use the Gateway's name instead:
.status.loadBalancer.ingress[0].hostname
.We can then make a request:
curl -i http://${DEDICATED_GATEWAY_IP}/httpbin/get
You should see output like:
HTTP/1.1 200 OK
server: envoy
date: Mon, 04 Sep 2023 15:15:32 GMT
content-type: application/json
content-length: 339
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 3
{
"args": {},
"headers": {
"Accept": "*/*",
"Host": "104.196.111.251",
"User-Agent": "curl/8.1.2",
"X-Envoy-Expected-Rq-Timeout-Ms": "15000",
"X-Envoy-External-Address": "99.254.151.222",
"X-Envoy-Original-Path": "/httpbin/get"
},
"origin": "99.254.151.222",
"url": "http://104.196.111.251/get"
}Congratulations on the successful deployment of your first Tetrate Enterprise Gateway for Envoy (TEG) instance!
Next Steps
- Point DNS at the Tetrate Enterprise Gateway for Envoy (TEG) External IP (technically: the IP of the cloud LoadBalancer made for the Gateway Service). Tetrate Enterprise Gateway for Envoy (TEG) is then available by name rather than IP, and you can filter/route on hostname using the
listener.hostname
fields in Gateway and thehostnames
field in HTTPRoute. - configure & test rate limiting for your app
- configure & test authentication for your app
- Enable TLS
- If you're on AWS, use an NLB rather than CLB to front TEG's Envoys. Watch the Tetrate site for a how-to blog on this soon!