savagebidoof de4ae7dd09 Documented 06_Envoy examples:
- 01-Envoy-add-response-headers
- 02-envoy-logging

Added section README.md to:
- 05-Sidecar
- 06-Envoy
2023-10-14 10:19:01 +02:00
..
2023-10-14 10:19:01 +02:00
2023-10-14 10:19:01 +02:00
2023-10-14 10:19:01 +02:00
2023-10-14 10:19:01 +02:00
2023-10-14 10:19:01 +02:00

Table of Contents

Description

This example deploys the same infrastructure as the previous example, but instead of adding a header to the response, we will be raising a custom log entry.

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.

On this deployment, we have set an annotation to configure a log level for the Istio sidecar/envoy-proxy attached to the deployment, that will allow the Lua scripts for a "debug" log level.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloworld-nginx
  labels:
    app: helloworld
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helloworld
  template:
    metadata:
      labels:
        app: helloworld
      annotations:
        sidecar.istio.io/componentLogLevel: lua:debug
    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 fairly simple, as it will generate multiple logs in various tier levels, going from Critical to Trace:

response_handle:logCritical("Critical: This is my Critical log")
response_handle:logErr("Error: This is my Error log")
response_handle:logWarn("Warning: This is my Warning log")
response_handle:logInfo("Info: This is my Info log")
response_handle:logDebug("Debug: This is my Debug log")
response_handle:logTrace("Trace: This is my Trace log")
response_handle:logInfo(">>>> Executed `envoy-raise-logs` <<<<")
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: envoy-raise-logs
  namespace: default
spec:
  priority:  40
  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:logCritical("Critical: This is my Critical log")
                response_handle:logErr("Error: This is my Error log")
                response_handle:logWarn("Warning: This is my Warning log")
                response_handle:logInfo("Info: This is my Info log")
                response_handle:logDebug("Debug: This is my Debug log")
                response_handle:logTrace("Trace: This is my Trace log")
                response_handle:logInfo(">>>> Executed `envoy-raise-logs` <<<<")
              end

Walkthrough

Deploy resources

Deploy the resources.

kubectl apply -f ./
deployment.apps/helloworld-nginx created
envoyfilter.networking.istio.io/envoy-raise-logs 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           7s

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

Monitor the logs

In a new shell we will use the following command to monitor the logs from the istio-proxy container located in the deployment created.

kubectl logs -l app=helloworld -c istio-proxy -f

Initiate a traffic request

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 -s | grep "<h1>.*</h1>"
<h1>Welcome to nginx!</h1>

Logs generated

2023-10-14T07:59:36.213492Z	critical	envoy lua external/envoy/source/extensions/filters/http/lua/lua_filter.cc:933	script log: Critical: This is my Critical log	thread=28
2023-10-14T07:59:36.213714Z	error	envoy lua external/envoy/source/extensions/filters/http/lua/lua_filter.cc:930	script log: Error: This is my Error log	thread=28
2023-10-14T07:59:36.213846Z	warning	envoy lua external/envoy/source/extensions/filters/http/lua/lua_filter.cc:927	script log: Warning: This is my Warning log	thread=28
2023-10-14T07:59:36.213972Z	info	envoy lua external/envoy/source/extensions/filters/http/lua/lua_filter.cc:924	script log: Info: This is my Info log	thread=28
2023-10-14T07:59:36.214096Z	debug	envoy lua external/envoy/source/extensions/filters/http/lua/lua_filter.cc:921	script log: Debug: This is my Debug log	thread=28
2023-10-14T07:59:36.214296Z	info	envoy lua external/envoy/source/extensions/filters/http/lua/lua_filter.cc:924	script log: >>>> Executed `envoy-raise-logs` <<<<	thread=28
2023-10-14T07:59:36.214425Z	debug	envoy lua external/envoy/source/extensions/filters/common/lua/lua.cc:39	coroutine finished	thread=28
[2023-10-14T07:59:36.210Z] "GET /helloworld HTTP/1.1" 200 - via_upstream - "-" 0 615 11 1 "192.168.1.44" "curl/8.4.0" "47093b83-6658-4ec6-8d21-7da5e70d6423" "192.168.1.50" "172.16.106.50:80" inbound|80|| 127.0.0.6:44723 172.16.106.50:80 192.168.1.44:0 outbound_.80_._.helloworld.default.svc.cluster.local default

Reviewing the logs generated, we can observe that the entries range from critical to debug, yet we cannot locate the trace level log entry that we configured in the Lua script.

This is caused due to the annotation configured in the Deployment, where we selected a log level for the Lua script to be debug, out-ranging the trace level.

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, even tho the log entry with trace level was not recorded.

How to check the log level settings from a pod?

Through the command istioctl proxy-config log <POD>.

istioctl proxy-config log "$(kubectl get pod -l app=helloworld | grep helloworld-nginx | awk '{print $1}')"
helloworld-nginx-d8bc84b86-h6c68.default:
active loggers:
...
  health_checker: warning
  http: warning
  http2: warning
  hystrix: warning
  init: warning
  io: warning
  jwt: warning
  kafka: warning
  key_value_store: warning
  lua: debug
  main: warning
...

As well, we can confirm that by default the settings are set to only retain "warning" level logs.

Cleanup

Finally, a cleanup from the resources deployed.

kubectl delete -f ./
deployment.apps "helloworld-nginx" deleted
envoyfilter.networking.istio.io "envoy-raise-logs" deleted
gateway.networking.istio.io "helloworld-gateway" deleted
service "helloworld" deleted
virtualservice.networking.istio.io "helloworld-vs" deleted