In this example, we show how a Lua filter can be used with the Envoy
proxy. The Envoy proxy configuration includes a lua
filter that contains two functions namely
envoy_on_request(request_handle)
and
envoy_on_response(response_handle)
as documented
here.
docker-compose pull
docker-compose up --build
curl -v localhost:8000
Curl output should include our headers:
# <b> curl -v localhost:8000</b>
* Rebuilt URL to: localhost:8000/
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< x-powered-by: Express
< content-type: application/json; charset=utf-8
< content-length: 544
< etag: W/"220-PQ/ZOdrX2lwANTIy144XG4sc/sw"
< date: Thu, 31 May 2018 15:29:56 GMT
< x-envoy-upstream-service-time: 2
< response-body-size: 544 <-- This is added to the response header by our Lua script. --<
< server: envoy
<
{
"path": "/",
"headers": {
"host": "localhost:8000",
"user-agent": "curl/7.47.0",
"accept": "*/*",
"x-forwarded-proto": "http",
"x-request-id": "0adbf0d3-8dfd-452f-a80a-1d6aa2ab06e2",
"foo": "bar", <-- This is added to the request header by our Lua script. --<
"x-envoy-expected-rq-timeout-ms": "15000",
"content-length": "0"
},
"method": "GET",
"body": "",
"fresh": false,
"hostname": "localhost",
"ip": "::ffff:172.18.0.2",
"ips": [],
"protocol": "http",
"query": {},
"subdomains": [],
"xhr": false,
"os": {
"hostname": "5ad758105577"
}
* Connection #0 to host localhost left intact
}
To run the examples change directory and run normal docker-compose up/down assuming you already pull and build
Run the example 1:
cd example-1-query
docker-compose up
Parse a query parameter and add the value as a header into the request
Send the request curl "localhost:8000/api?locale=us"
The value us
is included in the request header locale
going out from the proxy to the web service
{
"path": "/api",
"headers": {
"host": "localhost:8000",
"user-agent": "curl/7.54.0",
"locale": "us",
},
"method": "GET",
"body": "",
"protocol": "http",
"query": {
"locale": "us"
},
}
Loads the library ./example-2-lib/uuid.lua
Adds a header with a random uuid if the header is not already present in the request
Send the request
curl "localhost:8000/api/v1"
The random uuid is included in the request header correlationid
going out from the proxy to the web service
{
"path": "/api",
"headers": {
"host": "localhost:8000",
"user-agent": "curl/7.54.0",
"correlationid": "GEN-cbb297c0-14a9-46bc-c691-1d0ef9b42df9"
},
"method": "GET",
"body": "",
"protocol": "http"
}
Loads the library ./example-3-json/JSON.lua
Adds a header using the value from the body if the header is not already present in the request.
Send the request POST with an application/json
body:
curl -d '{"correlationid":"GEN-00000000-1111-2222-3333-444444444444"}' \
-H "Content-Type:application/json" \
http://localhost:8000
The value from the body field correlationid
is included in the request header correlationid
going out from the proxy to the web service
{
"path": "/",
"headers": {
"host": "localhost:8000",
"user-agent": "curl/7.54.0",
"accept": "*/*",
"content-type": "application/json",
"content-length": "60",
"correlationid": "GEN-00000000-1111-2222-3333-444444444444"
},
"method": "POST",
"body": "{\"correlationid\":\"GEN-00000000-1111-2222-3333-444444444444\"}",
"protocol": "http",
}
Full complex example parsing headers, query, body, and generating uuid
Loads the libraries:
Detects if any of the headers (locale
,brand
,systemid
,correlationid
) are missing, tries to add the header with the value from query parameter or body json.
If correlationid is not present at all then a new value is generated using a random uuid.
Send the request POST with an application/json
body:
curl -d '{"systemid":"FFEE"}' \
-H "Content-Type:application/json" \
"http://localhost:8000/api/v1?brand=acme&locale=en-us"
The request will include all the missing headers going from the proxy to the web service.
{
"locale": "en-us",
"brand": "acme",
"systemid": "FFEE",
"correlationid": "GEN-cbb297c0-14a9-46bc-c691-1d0ef9b42df9"
}
Full request echo back from web service:
{
"path": "/api/v1",
"headers": {
"host": "localhost:8000",
"user-agent": "curl/7.54.0",
"accept": "*/*",
"content-type": "application/json",
"content-length": "19",
"locale": "en-us",
"brand": "acme",
"systemid": "FFEE",
"correlationid": "GEN-cbb297c0-14a9-46bc-c691-1d0ef9b42df9",
},
"method": "POST",
"body": "{\"systemid\":\"FFEE\"}",
"protocol": "http",
"query": {
"brand": "acme",
"locale": "en-us"
},
}
This example shows how to store the lua files in a ConfigMap, then mounting in envoy container
Deploy config-map, deployment, and services
cd example-5-kubernetes/
kubectl apply -k .
Open a port forward to reach the envoy provice service
kubectl port-forward service/envoy-service 8000:80
Now send a request similar as example 4:
curl -d '{"systemid":"FFEE"}' \
-H "Content-Type:application/json" \
"http://localhost:8000/api/v1?brand=acme&locale=en-us"
This example shows how to store the lua files in a ConfigMap, then mounting in envoy container
Deploy config-map, deployment, and services
cd example-6-istio/
kubectl apply -f .
Update the deployment istio-ingressgateway
to add the lua files
kubectl edit deployment istio-ingressgateway -n istio-system
Add the volumenMounts in the corresponding section in the container proxy
volumeMounts:
- mountPath: /var/lib/lua
name: config-volume-lua
Add the volume in the corresponding section in the container proxy
volumes:
- name: config-volume-lua
configMap:
name: lua-libs
items:
- key: JSON.lua
path: JSON.lua
- key: uuid.lua
path: uuid.lua
Open a port forward to reach the istio-ingressgateway
kubectl port-forward service/istio-ingressgateway 8000:80 -n istio-system
Now send a request similar as example 4:
curl -v -d '{"systemid":"FFEE"}' \
-H "Content-Type:application/json" \
"http://localhost:8000/api/v1?brand=acme&locale=en-us"