Skip to content

Commit

Permalink
Header Modifier and Splitting use cases
Browse files Browse the repository at this point in the history
Signed-off-by: Nico Vibert <[email protected]>
  • Loading branch information
nvibert authored and squeed committed May 26, 2023
1 parent 023fad5 commit bb50725
Show file tree
Hide file tree
Showing 7 changed files with 455 additions and 0 deletions.
21 changes: 21 additions & 0 deletions Documentation/network/servicemesh/echo-app.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Deploy the Echo App
===================

We will use a deployment made of echo servers.

The application will reply to the client and, in the body of the reply, will include information about the pod and node receiving the original request.
We will use this information to illustrate how the traffic is manipulated by the Gateway.

.. parsed-literal::
$ kubectl apply -f \ |SCM_WEB|\/examples/kubernetes/gateway/echo.yaml
Verify the pods are running as expected.

.. code-block:: shell-session
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
echo-1-7d88f779b-m6r46 1/1 Running 0 21s
echo-2-5bfb6668b4-n7llh 1/1 Running 0 21s
2 changes: 2 additions & 0 deletions Documentation/network/servicemesh/gateway-api/gateway-api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,7 @@ Cilium's Gateway API features:

http
https
splitting
header

More examples can be found `upstream repository <https://github.com/kubernetes-sigs/gateway-api/tree/v0.6.1/examples/standard>`_.
109 changes: 109 additions & 0 deletions Documentation/network/servicemesh/gateway-api/header.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
.. only:: not (epub or latex or html)

WARNING: You are looking at unreleased Cilium documentation.
Please use the official rendered version released here:
https://docs.cilium.io

.. _gs_gateway_header:

************
HTTP Header Modifier Examples
************

The Gateway can modify the headers of HTTP requests from clients.

.. include:: ../echo-app.rst

Deploy the Cilium Gateway
=========================

HTTP header modification is the process of adding, removing, or modifying HTTP headers in incoming requests.
To configure HTTP header modification, define a Gateway object with one or more HTTP filters. Each filter specifies a specific modification to make to incoming requests, such as adding a custom header or modifying an existing header.

To add a header to a HTTP request, use a filter of the type ``RequestHeaderModifier`` with the ``add`` action and the name and value of the header.

You'll find the example Gateway and HTTPRoute definition in ``request-header.yaml``.

.. literalinclude:: ../../../../examples/kubernetes/gateway/request-header.yaml

In this example, we will add a header named ``my-header-name`` with the ``my-header-value`` value.

Deploy the Gateway and the HTTPRoute:

.. parsed-literal::
$ kubectl apply -f \ |SCM_WEB|\/examples/kubernetes/gateway/request-header.yaml
The above example creates a Gateway named ``cilium-gw`` that listens on port 80.

.. code-block:: shell-session
$ kubectl get gateway cilium-gw
NAME CLASS ADDRESS PROGRAMMED AGE
cilium-gw cilium 172.18.255.200 8s
.. Note::

Some providers e.g. EKS use a fully-qualified domain name rather than an IP address.

Modify incoming HTTP Requests
==================

Now that the Gateway is ready, you can make HTTP requests.

.. code-block:: shell-session
$ curl -s http://$GATEWAY/add-a-request-header | grep -A 6 "Request Headers"
Request Headers:
accept=*/*
host=172.18.255.200
my-header-name=my-header-value
user-agent=curl/7.81.0
x-forwarded-proto=http
x-request-id=61a72702-3dfa-4bc3-a21c-7544ef36af7b
A curl is successful and in the body of the response sent back from the echo server, you can see the HTTP Header from the incoming request.
Note how the header had been added by the Gateway.

Headers can also be removed, by using the ``remove`` keyword and a list of header names.

.. code-block:: shell-session
filters
- type: RequestHeaderModifier
requestHeaderModifier:
remove: ["x-request-id"]
Note how the ``x-request-id`` header has been removed (using this filter with the ``remove-a-request-header`` prefix match):

.. code-block:: shell-session
$ curl --fail -s http://$GATEWAY/remove-a-request-header | grep -A 6 "Request Headers"
Request Headers:
accept=*/*
host=172.18.255.200
user-agent=curl/7.81.0
x-forwarded-proto=http
To edit an existing header, use the ``set`` action and specify the value of the header to be modified and the new header value to be set.

.. code-block:: shell-session
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: x-request-id
value: set-cilium-header-value
Note how the ``x-request-id`` header value has been modified (using this filter with the ``edit-a-request-header`` prefix match).

.. code-block:: shell-session
$ curl -s http://$GATEWAY/edit-a-request-header | grep -A 6 "Request Headers"
Request Headers:
accept=*/*
host=172.18.255.200
user-agent=curl/7.81.0
x-forwarded-proto=http
x-request-id=set-cilium-header-value
143 changes: 143 additions & 0 deletions Documentation/network/servicemesh/gateway-api/splitting.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
.. only:: not (epub or latex or html)

WARNING: You are looking at unreleased Cilium documentation.
Please use the official rendered version released here:
https://docs.cilium.io

.. _gs_gateway_splitting:

************
Traffic Splitting Example
************

HTTP traffic splitting is the process of sending incoming traffic to multiple backend services, based on predefined weights or other criteria.
The Cilium Gateway API includes built-in support for traffic splitting, allowing users to easily distribute incoming traffic across multiple backend services.
This is very useful for canary testing or A/B scenarios.

For this particular use case, we're going to use Gateway API to load-balance incoming traffic to different backends, starting with the same weights before testing with a 99/1 weight distribution.

.. include:: ../echo-app.rst

Deploy the Cilium Gateway
=========================

You'll find the example Gateway and HTTPRoute definition in ``splitting.yaml``.

.. literalinclude:: ../../../../examples/kubernetes/gateway/splitting.yaml

Note the even 50/50 split between the two Services. Deploy the Gateway and the HTTPRoute:

.. parsed-literal::
$ kubectl apply -f \ |SCM_WEB|\/examples/kubernetes/gateway/splitting.yaml
The above example creates a Gateway named ``cilium-gw`` that listens on port 80.
A single route is defined and includes two different ``backendRefs`` (``echo-1`` and ``echo-2``) and weights associated with them.

.. code-block:: shell-session
$ kubectl get gateway cilium-gw
NAME CLASS ADDRESS PROGRAMMED AGE
cilium-gw cilium 172.18.255.200 8s
.. Note::

Some providers e.g. EKS use a fully-qualified domain name rather than an IP address.

Even traffic split
==================

Now that the Gateway is ready, you can make HTTP requests to the services.

.. code-block:: shell-session
$ GATEWAY=$(kubectl get gateway cilium-gw -o jsonpath='{.status.addresses[0].value}')
$ curl --fail -s http://$GATEWAY/echo
Hostname: echo-1-7d88f779b-m6r46
Pod Information:
node name: kind-worker2
pod name: echo-1-7d88f779b-m6r46
pod namespace: default
pod IP: 10.0.2.15
Server values:
server_version=nginx: 1.12.2 - lua: 10010
Request Information:
client_address=10.0.2.252
method=GET
real path=/echo
query=
request_version=1.1
request_scheme=http
request_uri=http://172.18.255.200:8080/echo
Request Headers:
accept=*/*
host=172.18.255.200
user-agent=curl/7.81.0
x-forwarded-proto=http
x-request-id=ee152a07-2be2-4539-b74d-ebcebf912907
Request Body:
-no body in request-
Notice that, in the reply, you get the name of the pod that received the query. For example:

.. code-block:: shell-session
Hostname: echo-2-5bfb6668b4-2rl4t
Repeat the command several times.
You should see the reply being balanced evenly across both pods/nodes.
Let's double check that traffic is evenly split across multiple Pods by running a loop and counting the requests:

.. code-block:: shell-session
while true; do curl -s -k "http://$GATEWAY/echo" >> curlresponses.txt ;done
Stop with ``Ctrl+C``.
Verify that the responses have been (more or less) evenly spread.

.. code-block:: shell-session
$ cat curlresponses.txt| grep -c "Hostname: echo-1"
1221
$ cat curlresponses.txt| grep -c "Hostname: echo-2"
1162
Uneven (99/1) traffic split
==================

Update the HTTPRoute weights (either by using ``kubectl edit httproute`` or by updating the value in the original manifest before reapplying it) to, for example, ``99`` for echo-1 and ``1`` for echo-2:

.. code-block:: shell-session
backendRefs:
- kind: Service
name: echo-1
port: 8080
weight: 99
- kind: Service
name: echo-2
port: 8090
weight: 1
Let's double check that traffic has been unevenly split across multiple Pods by running a loop and counting the requests:

.. code-block:: shell-session
while true; do curl -s -k "http://$GATEWAY/echo" >> curlresponses991.txt ;done
Stop with ``Ctrl+C``.
Verify that the responses have been (more or less) evenly spread.

.. code-block:: shell-session
$ cat curlresponses991.txt| grep -c "Hostname: echo-1"
24739
$ cat curlresponses991.txt| grep -c "Hostname: echo-2"
239
108 changes: 108 additions & 0 deletions examples/kubernetes/gateway/echo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
apiVersion: v1
kind: Service
metadata:
labels:
app: echo-1
name: echo-1
spec:
ports:
- port: 8080
name: high
protocol: TCP
targetPort: 8080
selector:
app: echo-1
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: echo-1
name: echo-1
spec:
replicas: 1
selector:
matchLabels:
app: echo-1
template:
metadata:
labels:
app: echo-1
spec:
containers:
- image: gcr.io/kubernetes-e2e-test-images/echoserver:2.2
name: echo-1
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
---
apiVersion: v1
kind: Service
metadata:
labels:
app: echo-2
name: echo-2
spec:
ports:
- port: 8090
name: high
protocol: TCP
targetPort: 8080
selector:
app: echo-2
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: echo-2
name: echo-2
spec:
replicas: 1
selector:
matchLabels:
app: echo-2
template:
metadata:
labels:
app: echo-2
spec:
containers:
- image: gcr.io/kubernetes-e2e-test-images/echoserver:2.2
name: echo-2
ports:
- containerPort: 8080
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
Loading

0 comments on commit bb50725

Please sign in to comment.