
- 01-Envoy-add-response-headers - 02-envoy-logging Added section README.md to: - 05-Sidecar - 06-Envoy
Table of Contents
Description
This example deploys the same infrastructure as the previous example, this time we will be configuring Envoy
to add a custom header to the request response when our deployed service replies back.
This example configures:
Generic Kubernetes resources:
- 1 Service
- 1 Deployment
Istio resources:
- 1 Gateway
- 1 Virtual Service
- 1 EnvoyFilter
Based on
Configuration
Service
Creates a service named helloworld
.
This service listens for the port 80
expecting HTTP
traffic and will forward the incoming traffic towards the port 80
from the destination pod.
apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
app: helloworld
service: helloworld
spec:
ports:
- port: 80
name: http
selector:
app: helloworld
Deployment
helloworld
Deploys a Nginx server that listens for the port 80
.
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloworld-nginx
labels:
app: helloworld
spec:
replicas: 1
selector:
matchLabels:
app: helloworld
template:
metadata:
labels:
app: helloworld
spec:
containers:
- name: helloworld
image: nginx
resources:
requests:
cpu: "100m"
imagePullPolicy: IfNotPresent #Always
ports:
- containerPort: 80
Gateway
Deploys an Istio gateway that's listening to the port 80
for HTTP
traffic.
It doesn't filter for any specific host.
The selector
field is used to "choose" which Istio Load Balancers will have this gateway assigned to.
The Istio default
profile creates a Load Balancer in the namespace istio-system
that has the label istio: ingressgateway
set, allowing us to target that specific Load Balancer and assign this gateway resource to it.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: helloworld-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
VirtualService
The Virtual Service resources are used to route and filter the received traffic from the gateway resources, and route it towards the desired destination.
On this example we select the gateway helloworld-gateway
, which is the gateway that 's described in the Gateway
section.
On this resource, we are also not limiting the incoming traffic to any specific host, allowing for all the incoming traffic to go through the rules set.
Here we created a rule that will be applied on HTTP
related traffic (including HTTPS
and HTTP2
) when the destination path is exactly /helloworld
.
This traffic will be forwarded to the port 80
of the destination service helloworld
(the full path URL equivalent would be helloworld.$NAMESPACE.svc.cluster.local
).
Additionally, there will be an internal URL rewrite set, as if the URL is not modified, it would attempt to reach to the /helloworld
path from the Nginx deployment, which currently has no content and would result in an error code 404
(Not found).
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld-vs
spec:
hosts:
- "*"
gateways:
- helloworld-gateway
http:
- match:
- uri:
exact: /helloworld
route:
- destination:
host: helloworld
port:
number: 80
rewrite:
uri: "/"
EnvoyFilter
EnvoyFilter
allows to customize the Envoy configuration generated by Istio Pilot.
On this scenario we will be targeting the pods deployed in the namespace default
with the label app
set to helloworld
.
The rule created will apply to the filter HTTP_FILTER
to attach the Lua script to the http connection manager.
This script will be triggered with the incoming traffic goes through the port 80.
The code inside the lua script is very straightforward:
response_handle:headers():add("numbers", "lots of numbers")
Adds a header on the response request, which on this scenario is adding the header numbers
, and giving it a value of lots of numbers
.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: envoy-add-response-header
namespace: default
spec:
priority: 30
workloadSelector:
labels:
app: helloworld
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
portNumber: 80
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_response(response_handle)
response_handle:headers():add("numbers", "lots of numbers")
end
Walkthrough
Deploy resources
Deploy the resources.
kubectl apply -f ./
deployment.apps/helloworld-nginx created
envoyfilter.networking.istio.io/envoy-add-response-header created
gateway.networking.istio.io/helloworld-gateway created
service/helloworld created
virtualservice.networking.istio.io/helloworld-vs created
Wait for the pods to be ready
Wait for the Nginx deployment to be ready.
kubectl get deployment helloworld-nginx -w
NAME READY UP-TO-DATE AVAILABLE AGE
helloworld-nginx 1/1 1 1 49s
Test the service
Get LB IP
To perform the desired tests, we will need to obtain the IP Istio Load Balancer that we selected in the Gateway section.
On my environment, the IP is the 192.168.1.50
.
kubectl get svc -l istio=ingressgateway -A
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-system istio-ingressgateway LoadBalancer 10.97.47.216 192.168.1.50 15021:31316/TCP,80:32012/TCP,443:32486/TCP 72d
Confirm the deployment works correctly.
curl 192.168.1.50/helloworld -s | grep "<h1>.*</h1>"
<h1>Welcome to nginx!</h1>
Confirm the Lua Script is working correctly
After confirming that the request is able to succeed and confirming the backend that it's handling such request, the next step is to verify if the Lua script we deployed on through the EnvoyFilter is adding a new header.
curl 192.168.1.50/helloworld --head
HTTP/1.1 200 OK
server: istio-envoy
date: Sat, 14 Oct 2023 07:21:03 GMT
content-type: text/html
content-length: 615
last-modified: Tue, 15 Aug 2023 17:03:04 GMT
etag: "64dbafc8-267"
accept-ranges: bytes
x-envoy-upstream-service-time: 3
numbers: lots of numbers
Reviewing the response
If we take a closer look at the fields returned, at the bottom of the textblock, we can appreciate the following line:
numbers: lots of numbers
Therefore, we were able to confirm that the EnvoyFilter configuration we set with a Lua script, did work as intended and added the desired Header to the response from the backend.
Cleanup
Finally, a cleanup from the resources deployed.
kubectl delete -f ./
deployment.apps "helloworld-nginx" deleted
envoyfilter.networking.istio.io "envoy-add-response-header" deleted
gateway.networking.istio.io "helloworld-gateway" deleted
service "helloworld" deleted
virtualservice.networking.istio.io "helloworld-vs" deleted
Links of interest
- https://istio.io/latest/docs/reference/config/networking/envoy-filter/
- https://istio.io/latest/docs/reference/config/networking/envoy-filter/#EnvoyFilter-ApplyTo
- https://github.com/istio/istio/wiki/EnvoyFilter-Samples
- https://istio.io/latest/docs/reference/config/networking/envoy-filter/#EnvoyFilter-Patch-Operation