Skip to content

Commit d8d681e

Browse files
committed
pr feedback
1 parent d70b7f6 commit d8d681e

File tree

2 files changed

+50
-26
lines changed

2 files changed

+50
-26
lines changed

DEV.md

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
Architecture:
2-
3-
KGateway is a control plane for envoy based on the gateway-api. This means that we translate K8s objects like Gateways, HttpRoutes, Service, EndpointSlices and User policy into envoy configuration.
1+
# Architecture
2+
Kgateway is a control plane for envoy based on the gateway-api. This means that we translate K8s objects like Gateways, HttpRoutes, Service, EndpointSlices and User policy into envoy configuration.
43

54
Our goals with the architecture of the project are to make it scalable and extendable.
65

7-
To make the project scalable, its importnat to keep the computation minimal when changes occur. For example, when a pod changes, or a policy is updated, we don't do the minimum amount of computation to update the envoy configuration.
6+
To make the project scalable, it's important to keep the computation minimal when changes occur. For example, when a pod changes, or a policy is updated, we do the minimum amount of computation to update the envoy configuration.
87

9-
With extendability, we KGateway to be the basis on-top of which users can easily add their own custom logic. to that end we have a plugin system that allows users to add their own custom logic to the control plane in a way that's opaque to the core code.
8+
With extendability, Kgateway is the basis on-top of which users can easily add their own custom logic. to that end we have a plugin system that allows users to add their own custom logic to the control plane in a way that's opaque to the core code.
109

1110

12-
Going down further, to enable these goals we use KRT based system. KRT gives us a few advantages:
13-
- The ability to complement controllers of custom Intermediate representation (henceforth IR).
11+
Going down further, to enable these goals we use [KRT](https://github.com/istio/istio/tree/master/pkg/kube/krt#krt-kubernetes-declarative-controller-runtime) based system. KRT gives us a few advantages:
12+
- The ability to complement controllers of custom Intermediate Representation (henceforth IR).
1413
- Automatically track object dependencies and changes and only invoke logic that depends on the object that changed.
1514

1615
# CRD Journey
@@ -22,13 +21,20 @@ Let's focus on the first one - Routes and Listeners, as this is where the majori
2221

2322
Envoy Routes & Listeners translate from Gateways, HttpRoutes, and user policies (i.e. RoutePolicy, ListenerPolicy, etc).
2423

25-
## Policies
24+
## Policies (Contributed by Plugins)
25+
26+
To add a policy to Kgateway we need to 'contribute' it as a plugin. You can think of a plugin as an
27+
independent k8s controller that translates a CRD to an krt-collection of policies in IR form Kgateway can understand (it's called `ir.PolicyWrapper`).
28+
A plugin lifecycle is the length of the program - it doesn't reset on each translation (we will explain later where we hold translation state).
29+
30+
2631
The first step is to convert each user policy into an IR form. This is done by creating a collection of these objects from k8s, and transforming the collection to an IR representation.
2732

28-
For policies, this is pluggable. Plugins can Contribute a policy to kgateway. Contributing a policy means that we add a policy collection to kgateway. It's the users plugin responsibility to convert the policy CRD to the IR form. Ideally, the IR should look as close as possible to the envoy configuration, so this translation only happens when the policy CRD changes.
33+
When a plugin can contribute a policy to Kgateway, Kgateway uses policy collection to perform policy attachment - this is the process of assigning policies to the object they impact (like HttpRoutes) based on their targetRefs.
34+
It's the plugin responsibility to convert the policy CRD to the IR form. Ideally, the IR should look as close as possible to the envoy configuration, so this translation only happens when the policy CRD changes.
2935

3036
You can see in the Plugin interface a field called `ContributesPolicies` which is a map of GK -> `PolicyPlugin`.
31-
The policy plugin contains a bunch of fields, but for out discussion we'll focus on these two:
37+
The policy plugin contains a bunch of fields, but for our discussion we'll focus on these two:
3238

3339
```go
3440
type PolicyPlugin struct {
@@ -38,43 +44,57 @@ type PolicyPlugin struct {
3844
}
3945
```
4046
Policies is a the collection of policies that the plugin contributes. The plugin is responsible to create
41-
this collection, usually by started with a CRD collection, and then translating to a `ir.PolicyWrapper` struct.
47+
this collection, usually by starting with a CRD collection, and then translating to a `ir.PolicyWrapper` struct.
4248

4349
Lets look at the important fields in the PolicyWrapper:
4450

4551
```go
4652
type PolicyWrapper struct {
4753
// The Group, Kind Name, Namespace to the original policy object
4854
ObjectSource `json:",inline"`
49-
// The IR of the policy objects. ideally with structural errors removed.
55+
// The IR of the policy objects. Ideally with structural errors either removed so it can be applied to envoy, or retained and returned in the translation pass (this depends on the defined fallback behavior).
5056
// Opaque to us other than metadata.
5157
PolicyIR PolicyIR
5258
// Where to attach the policy. This usually comes from the policy CRD.
5359
TargetRefs []PolicyTargetRef
5460
}
5561
```
5662

57-
The system will make use of the traget refs to attach the policy IR to Listners and HttpRoutes. You will then
63+
The system will make use of the targetRefs to attach the policy IR to Listners and HttpRoutes. You will then
5864
get access to the IR during translation (more on that later).
5965

66+
When translating a Policy to a PolicyIR, you'll want to take the translation as far as you can. For example, if your policy will result in an envoy
67+
PerFilterConfig on a route, the PolicyIR should contain the proto.Any that will be applied there. Doing most of the policy translation at this phase as advantages:
68+
- Policy will only re-translate when the policy CRD changes
69+
- We can expose errors in translation on the policy CRD status as soon as the policy is written (no need to depend on later translation phases).
70+
6071
The second field, `NewGatewayTranslationPass` allocates a new translation state for the
6172
gateway/route translation. This function will be invoked during the Translation to xDS phase, so will expand on it later.
6273

6374
## HttpRotues and Gateways
6475

65-
HttpRoutes and Gateways are handled by KGateway. Kgateway builds an IR for HttpRoutes and Gateways, that looks very similar to
76+
HttpRoutes and Gateways are handled by Kgateway. Kgateway builds an IR for HttpRoutes and Gateways, that looks very similar to
6677
the original object, but in additional has an `AttachedPolicies` struct that contains all the policies that are attached to the object.
6778

68-
KGateway uses the `TargetRefs` field in the PolicyWrapper to opaquely attach the policy to the HttpRoute or Gateway.
79+
Kgateway uses the `TargetRefs` field in the PolicyWrapper (and extensionRefs in the Route objects) to opaquely attach the policy to the HttpRoute or Gateway.
6980

7081
## Translation to xDS
7182

72-
When we reach this phase, we already ahve the Policy -> IR translation done; and we have all the HttpRoutes and Gateways in IR form with the policies attached to them.
83+
When we reach this phase, we already have the Policy -> IR translation done; and we have all the HttpRoutes and Gateways in IR form with the policies attached to them.
84+
85+
The translation to xDS has 2 phases.
86+
- The first phase, aggregating all the httproutes for a single gateway into a single gateway IR object with all the policies and routes inside it. This resolves delegation, and merges http routes based on the Gateway Api spec. The phases uses KRT to track the dependencies of the routes and gateways (like for example, ssl certs). recall that by the time we get here, policy attachment was already performed (i.e. policies will already be in the AttachedPolicies struct).
87+
- The second phase, translates the gateway IR to envoy configuration. It does not use KRT, as all the dependencies are resolved in the first phase, and everything needed for translation is in the gateway IR. At this phase the **policy plugins** are invoked.
88+
89+
Having these 2 phases has these advantages:
90+
- The second phase is simple and fast, as all the dependencies are resolved in the previous phases.
91+
- We can create alternative translators for the gateway IR, for example, to translate a waypoint.
92+
7393

74-
In the begining of the transaltion to xDS, we take all the contributed policies and allocate a `NewGatewayTranslationPass` for each of them. This will hold the state for the length of the translation.
94+
In the begining of the transaltion of the gateway IR to xDS, we take all the contributed policies and allocate a `NewGatewayTranslationPass` for each of them. This will hold the state for the duration of the translation.
7595

7696
This allows us for example translate a route, and in response to that hold state that tells us to add an http filter.
7797

78-
KGateway handles merging of httproutes per gw-api spec. When it translates GW-api route rules to
79-
envoy routes, it reads the `AttachedPolicies` and calls the appropriate function in the `ProxyTranslationPass` and passes in
80-
the attached policy IR. This let's the policy plugin code the modify the route or listener as needed, based on the policy IR.
98+
When it translates GW-api route rules to envoy routes, it reads the `AttachedPolicies` and calls the appropriate function in the `ProxyTranslationPass` and passes in
99+
the attached policy IR. This let's the policy plugin code the modify the route or listener as needed, based on the policy IR (add filters, add filter route config, etc..).
100+
Then policy plugins are invoked with the attached policy IR, and can modify the envoy protbufs as needed

internal/kgateway/ir/iface.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ type HcmContext struct {
5757
Policy PolicyIR
5858
}
5959

60+
// ProxyTranslationPass represents a single translation pass for a gateway. It can hold state
61+
// for the duration of the translation.
62+
// Each of the functions here will be called in the order they appear in the interface.
6063
type ProxyTranslationPass interface {
6164
// Name() string
6265
// called 1 time for each listener
@@ -90,12 +93,6 @@ type ProxyTranslationPass interface {
9093
pCtx *RouteContext,
9194
out *envoy_config_route_v3.Route) error
9295

93-
// Appliesa policy attached to a specific Backend (via extensionRef on the BackendRef).
94-
ApplyForRouteBackend(
95-
ctx context.Context,
96-
policy PolicyIR,
97-
pCtx *RouteBackendContext,
98-
) error
9996
// no policy applied - this is called for every backend in a route.
10097
// For this to work the backend needs to register itself as a policy. TODO: rethink this.
10198
ApplyForBackend(
@@ -105,6 +102,13 @@ type ProxyTranslationPass interface {
105102
out *envoy_config_route_v3.Route,
106103
) error
107104

105+
// Applies a policy attached to a specific Backend (via extensionRef on the BackendRef).
106+
ApplyForRouteBackend(
107+
ctx context.Context,
108+
policy PolicyIR,
109+
pCtx *RouteBackendContext,
110+
) error
111+
108112
// called 1 time per filter-chain.
109113
// If a plugin emits new filters, they must be with a plugin unique name.
110114
// filters added to impact specific routes should be disabled on the listener level, so they don't impact other routes.

0 commit comments

Comments
 (0)