From e2594a7790a348267ab44b961a2f0e9467d668b0 Mon Sep 17 00:00:00 2001 From: Leo Li Date: Mon, 22 Jul 2024 12:17:38 -0400 Subject: [PATCH 1/2] feat: add the documentation for the default broker class feature --- .../configuration/broker-configuration.md | 370 ++++-------------- .../images/default-hierarchy-flowchart.png | Bin 0 -> 49815 bytes 2 files changed, 73 insertions(+), 297 deletions(-) create mode 100644 docs/eventing/configuration/images/default-hierarchy-flowchart.png diff --git a/docs/eventing/configuration/broker-configuration.md b/docs/eventing/configuration/broker-configuration.md index 5b3b6bcb32..eba5efc09d 100644 --- a/docs/eventing/configuration/broker-configuration.md +++ b/docs/eventing/configuration/broker-configuration.md @@ -1,52 +1,12 @@ -# Configure Broker defaults +# Configuring Broker Defaults -If you have cluster administrator permissions for your Knative installation, you can modify ConfigMaps to change the global default configuration options for Brokers on the cluster. +## Overview -Knative Eventing provides a `config-br-defaults` ConfigMap that contains the configuration settings that govern default Broker creation. +Knative Eventing allows you to configure default Broker classes at both the cluster and namespace levels. This feature provides flexibility in managing Broker configurations across your Knative installation. This document explains how to set up and use default Broker classes using the `config-br-defaults` ConfigMap. -The default `config-br-defaults` ConfigMap is as follows: +## The `config-br-defaults` ConfigMap -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: config-br-defaults - namespace: knative-eventing -data: - # Configures the default for any Broker that does not specify a spec.config or Broker class. - default-br-config: | - clusterDefault: - brokerClass: MTChannelBasedBroker - apiVersion: v1 - kind: ConfigMap - name: config-br-default-channel - namespace: knative-eventing -``` - -In this case, each new Broker created in the cluster would use by default the `MTChannelBasedBroker` Broker class and the `config-br-default-channel` ConfigMap from the `knative-eventing` namespace for its configuration if not other specified in the Brokers `eventing.knative.dev/broker.class` annotation and/or `.spec.config` (see [Developer configuration options](../brokers/broker-developer-config-options.md)). - -However, if you would like like for example a Kafka Channel to be used as the default Channel implementation for any Broker that is created, you can change the `config-br-defaults` ConfigMap to look as follows: - -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: config-br-defaults - namespace: knative-eventing -data: - # Configures the default for any Broker that does not specify a spec.config or Broker class. - default-br-config: | - clusterDefault: - brokerClass: MTChannelBasedBroker - apiVersion: v1 - kind: ConfigMap - name: kafka-channel - namespace: knative-eventing -``` - -Now every Broker created in the cluster that does not have a `spec.config` will be configured to use the `kafka-channel` ConfigMap. For more information about creating a `kafka-channel` ConfigMap to use with your Broker, see the [Kafka Channel ConfigMap](./kafka-channel-configuration.md#create-a-kafka-channel-configmap) documentation. - -You can also modify the default Broker configuration for one or more dedicated namespaces, by defining it in the `namespaceDefaults` section. For example, if you want to use the `config-br-default-channel` ConfigMap for all Brokers by default, but want to use `kafka-channel` ConfigMap for `namespace-1` and `namespace-2`, you would use the following ConfigMap: +The `config-br-defaults` ConfigMap in the `knative-eventing` namespace contains the configuration settings that govern default Broker creation. Here's an example of its structure: ```yaml apiVersion: v1 @@ -62,291 +22,107 @@ data: kind: ConfigMap name: config-br-default-channel namespace: knative-eventing + brokerClasses: + MTChannelBasedBroker: + # Configuration for MTChannelBasedBroker + KafkaBroker: + # Configuration for KafkaBroker namespaceDefaults: namespace-1: - apiVersion: v1 - kind: ConfigMap - name: kafka-channel - namespace: knative-eventing + brokerClass: KafkaBroker + brokerClasses: + KafkaBroker: + # Configuration for KafkaBroker in namespace-1 namespace-2: - apiVersion: v1 - kind: ConfigMap - name: kafka-channel - namespace: knative-eventing + brokerClass: MTChannelBasedBroker + brokerClasses: + MTChannelBasedBroker: + # Configuration for MTChannelBasedBroker in namespace-2 ``` -## Configuring the Broker class -Besides configuring the Broker class for each broker [individually](../brokers/create-broker.md#broker-class-options), it is possible to define the default Broker class cluster wide or on a per namespace basis: +## Configuration Decision Flow -### Configuring the default Broker class for the cluster +The following flow chart illustrates the decision-making process for determining the broker class and configuration: -You can configure the `clusterDefault` Broker class so that any Broker created in the cluster that does not have a `eventing.knative.dev/broker.class` annotation uses this default Broker class: +![Configuration Decision Flow](images/default-hierarchy-flowchart.png) -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: config-br-defaults - namespace: knative-eventing -data: - # Configures the default for any Broker that does not specify a spec.config or Broker class. - default-br-config: | - clusterDefault: - brokerClass: MTChannelBasedBroker -``` +This flow chart demonstrates the priority and fallback mechanisms in place when determining the broker class and configuration. It visually represents the process described in the Configuration Hierarchy section. -### Configuring the default Broker class for namespaces -You can modify the default Broker class for one or more namespaces. +## Configuration Hierarchy -For example, if you want to use a `KafkaBroker` Broker class for all other Brokers created on the cluster, but you want to use the `MTChannelBasedBroker` Broker class for Brokers created in `namespace-1` and `namespace-2`, you would use the following ConfigMap settings: +The system uses the following priority order to determine the Broker class and configuration: -```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: config-br-defaults - namespace: knative-eventing -data: - # Configures the default for any Broker that does not specify a spec.config or Broker class. - default-br-config: | - clusterDefault: - brokerClass: KafkaBroker - namespaceDefaults: - namespace1: - brokerClass: MTChannelBasedBroker - namespace2: - brokerClass: MTChannelBasedBroker -``` +If a specific Broker class **is provided** for a Broker: + + 1. Check namespace-specific configuration for the given Broker class + 2. If not found, check cluster-wide configuration for the given Broker class + 3. If still not found, use the cluster-wide default configuration -!!! note - Be aware that different Broker classes usually require different configuration ConfigMaps. See the configuration options of the different [Broker implementations](../brokers/broker-types/README.md) on how their referenced ConfigMaps have to look like (e.g. for [MTChannelBasedBroker](../brokers/broker-types/channel-based-broker/README.md#configuration-configmap) or [Knative Broker for Apache Kafka](../brokers/broker-types/kafka-broker/README.md#configure-a-kafka-broker)). +--- +If **no specific Broker class** is provided: -## Configuring delivery spec defaults + 1. Check namespace-specific default Broker class + 2. If found, use its configuration + 3. If not found, use cluster-wide default Broker class and configuration -You can configure default event delivery parameters for Brokers that are applied in cases where an event fails to be delivered: +## Configuring Cluster-wide Defaults + +To set a cluster-wide default Broker class and its configuration: ```yaml -apiVersion: v1 -kind: ConfigMap -metadata: - name: config-br-defaults - namespace: knative-eventing -data: - # Configures the default for any Broker that does not specify a spec.config or Broker class. - default-br-config: | - clusterDefault: - brokerClass: MTChannelBasedBroker +clusterDefault: + brokerClass: MTChannelBasedBroker + brokerClasses: + MTChannelBasedBroker: apiVersion: v1 kind: ConfigMap - name: kafka-channel + name: config-br-default-channel namespace: knative-eventing - delivery: - retry: 10 - backoffDelay: PT0.2S - backoffPolicy: exponential - namespaceDefaults: - namespace-1: - apiVersion: v1 - kind: ConfigMap - name: config-br-default-channel - namespace: knative-eventing - delivery: - deadLetterSink: - ref: - kind: Service - namespace: example-namespace - name: example-service - apiVersion: v1 - uri: example-uri - retry: 10 - backoffPolicy: exponential - backoffDelay: "PT0.2S" ``` -### Dead letter sink - -You can configure the `deadLetterSink` delivery parameter so that if an event fails to be delivered it is sent to the specified event sink. - -### Retries - -You can set a minimum number of times that the delivery must be retried before the event is sent to the dead letter sink, by configuring the `retry` delivery parameter with an integer value. +This configuration sets `MTChannelBasedBroker` as the default Broker class for the entire cluster and specifies its configuration. -### Back off delay +## Configuring Namespace-specific Defaults -You can set the `backoffDelay` delivery parameter to specify the time delay before an event delivery retry is attempted after a failure. The duration of the `backoffDelay` parameter is specified using the ISO 8601 format. +To set default Broker classes and configurations for specific namespaces: -### Back off policy - -The `backoffPolicy` delivery parameter can be used to specify the retry back off policy. The policy can be specified as either linear or exponential. When using the linear back off policy, the back off delay is the time interval specified between retries. When using the exponential backoff policy, the back off delay is equal to `backoffDelay*2^`. - -## Integrating Istio with Knative Brokers - -### Protect a Knative Broker by using JSON Web Token (JWT) and Istio - -#### Prerequisites - -- You have installed Knative Eventing. -- You have installed Istio. - -#### Procedure - -1. Label the `knative-eventing` namespace, so that Istio can handle JWT-based user authentication, by running the command: - - ```bash - kubectl label namespace knative-eventing istio-injection=enabled - ``` - -1. Restart the broker ingress pod, so that the `istio-proxy` container can be injected as a sidecar, by running the command: - - ```bash - kubectl delete pod -n knative-eventing - ``` - - Where `` is the name of your Broker ingress pod. - - The pod now has two containers: - - ```{ .bash .no-copy } - knative-eventing 2/2 Running 1 175m - ``` - -1. Create a broker, then use get the URL of your Broker by running the command: - - ```bash - kubectl get broker - ``` - - Where `` is the name of your Broker. - - Example output: - - ```{ .bash .no-copy } - NAMESPACE NAME URL AGE READY REASON - default my-broker http://broker-ingress.knative-eventing.svc.cluster.local/default/my-broker 6s True - ``` - -1. Start a `curl` pod by running the following command: +```yaml +namespaceDefaults: + namespace-1: + brokerClass: KafkaBroker + brokerClasses: + KafkaBroker: + apiVersion: v1 + kind: ConfigMap + name: kafka-broker-config + namespace: knative-eventing + namespace-2: + brokerClass: MTChannelBasedBroker + brokerClasses: + MTChannelBasedBroker: + apiVersion: v1 + kind: ConfigMap + name: mt-channel-broker-config + namespace: knative-eventing +``` - ```bash - kubectl -n default run curl --image=radial/busyboxplus:curl -i --tty - ``` +This configuration sets different default Broker classes and configurations for `namespace-1` and `namespace-2`. -1. Send a CloudEvent with an HTTP POST against the Broker URL by running the following command: +## Best Practices and Considerations - ```bash - curl -X POST -v \ - -H "content-type: application/json" \ - -H "ce-specversion: 1.0" \ - -H "ce-source: my/curl/command" \ - -H "ce-type: my.demo.event" \ - -H "ce-id: 0815" \ - -d '{"value":"Hello Knative"}' \ - - ``` +1. **Consistency**: Ensure that the `brokerClass` specified matches a key in the `brokerClasses` map to maintain consistency. - Where `` is the URL of your Broker. For example: +2. **Namespace Isolation**: Use namespace-specific defaults to isolate Broker configurations between different namespaces. - ```{ .bash .no-copy } - curl -X POST -v \ - -H "content-type: application/json" \ - -H "ce-specversion: 1.0" \ - -H "ce-source: my/curl/command" \ - -H "ce-type: my.demo.event" \ - -H "ce-id: 0815" \ - -d '{"value":"Hello Knative"}' \ - http://broker-ingress.knative-eventing.svc.cluster.local/default/my-broker - ``` +3. **Fallback Mechanism**: The system will fall back to cluster-wide defaults if namespace-specific configurations are not found. -1. You will receive a `202` HTTP response code, that the broker did accept the request: +4. **Configuration Updates**: When updating the ConfigMap, be aware that changes may affect newly created Brokers but will not automatically update existing ones. - ```{ .bash .no-copy } - ... - * Mark bundle as not supporting multiuse - < HTTP/1.1 202 Accepted - < allow: POST, OPTIONS - < date: Tue, 15 Mar 2022 13:37:57 GMT - < content-length: 0 - < x-envoy-upstream-service-time: 79 - < server: istio-envoy - < x-envoy-decorator-operation: broker-ingress.knative-eventing.svc.cluster.local:80/* - ``` +5. **Validation**: Always validate your ConfigMap changes before applying them to avoid potential misconfigurations. -1. Apply a `AuthorizationPolicy` object in the `knative-eventing` namespace to describe that the path to the Broker is restricted to a given user: +## Conclusion - ```yaml - apiVersion: security.istio.io/v1beta1 - kind: AuthorizationPolicy - metadata: - name: require-jwt - namespace: knative-eventing - spec: - action: ALLOW - rules: - - from: - - source: - requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"] - to: - - operation: - methods: ["POST"] - paths: ["/default/my-broker"] - ``` - -1. Create a `RequestAuthentication` object for the user `requestPrincipal` in the `istio-system` namespace: - - ```yaml - apiVersion: security.istio.io/v1beta1 - kind: RequestAuthentication - metadata: - name: "jwt-example" - namespace: istio-system - spec: - jwtRules: - - issuer: "testing@secure.istio.io" - jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.13/security/tools/jwt/samples/jwks.json" - ``` - -1. Now retrying the `curl` command results in a `403 - Forbidden` response code from the server: - - ```{ .bash .no-copy } - ... - * Mark bundle as not supporting multiuse - < HTTP/1.1 403 Forbidden - < content-length: 19 - < content-type: text/plain - < date: Tue, 15 Mar 2022 13:47:53 GMT - < server: istio-envoy - < connection: close - < x-envoy-decorator-operation: broker-ingress.knative-eventing.svc.cluster.local:80/* - ``` - -1. To access the Broker, add the Bearer JSON Web Token as part of the request: - - ```bash - TOKEN=$(curl https://raw.githubusercontent.com/istio/istio/release-1.13/security/tools/jwt/samples/demo.jwt -s) - - curl -X POST -v \ - -H "content-type: application/json" \ - -H "Authorization: Bearer ${TOKEN}" \ - -H "ce-specversion: 1.0" \ - -H "ce-source: my/curl/command" \ - -H "ce-type: my.demo.event" \ - -H "ce-id: 0815" \ - -d '{"value":"Hello Knative"}' \ - - ``` - - The server now responds with a `202` response code, indicating that it has accepted the HTTP request: - - ```{ .bash .no-copy } - * Mark bundle as not supporting multiuse - < HTTP/1.1 202 Accepted - < allow: POST, OPTIONS - < date: Tue, 15 Mar 2022 14:05:09 GMT - < content-length: 0 - < x-envoy-upstream-service-time: 40 - < server: istio-envoy - < x-envoy-decorator-operation: broker-ingress.knative-eventing.svc.cluster.local:80/* - ``` +The default Broker classes feature in Knative Eventing offers a flexible way to manage Broker configurations across your cluster and individual namespaces. By properly configuring the `config-br-defaults` ConfigMap, you can ensure that your Brokers are created with the desired settings, promoting consistency and reducing manual configuration efforts. \ No newline at end of file diff --git a/docs/eventing/configuration/images/default-hierarchy-flowchart.png b/docs/eventing/configuration/images/default-hierarchy-flowchart.png new file mode 100644 index 0000000000000000000000000000000000000000..6a72ff73c4cdf21f060c0a18d659937635b1e957 GIT binary patch literal 49815 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 Date: Mon, 22 Jul 2024 13:52:22 -0400 Subject: [PATCH 2/2] feat: add the necessary portion of the doc from the old doc --- .../configuration/broker-configuration.md | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/docs/eventing/configuration/broker-configuration.md b/docs/eventing/configuration/broker-configuration.md index eba5efc09d..c80bf9a1cd 100644 --- a/docs/eventing/configuration/broker-configuration.md +++ b/docs/eventing/configuration/broker-configuration.md @@ -85,6 +85,9 @@ clusterDefault: This configuration sets `MTChannelBasedBroker` as the default Broker class for the entire cluster and specifies its configuration. +!!! note + Be aware that different Broker classes usually require different configuration ConfigMaps. See the configuration options of the different [Broker implementations](../brokers/broker-types/README.md) on how their referenced ConfigMaps have to look like (e.g. for [MTChannelBasedBroker](../brokers/broker-types/channel-based-broker/README.md#configuration-configmap) or [Knative Broker for Apache Kafka](../brokers/broker-types/kafka-broker/README.md#configure-a-kafka-broker)). + ## Configuring Namespace-specific Defaults To set default Broker classes and configurations for specific namespaces: @@ -111,6 +114,240 @@ namespaceDefaults: This configuration sets different default Broker classes and configurations for `namespace-1` and `namespace-2`. + +## Configuring delivery spec defaults + +You can configure default event delivery parameters for Brokers that are applied in cases where an event fails to be delivered: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: config-br-defaults + namespace: knative-eventing +data: + # Configures the default for any Broker that does not specify a spec.config or Broker class. + default-br-config: | + clusterDefault: + brokerClass: MTChannelBasedBroker + brokerClasses: + MTChannelBasedBroker: + apiVersion: v1 + kind: ConfigMap + name: kafka-channel + namespace: knative-eventing + delivery: + retry: 10 + backoffDelay: PT0.2S + backoffPolicy: exponential + namespaceDefaults: + namespace-1: + brokerClass: MTChannelBasedBroker + brokerClasses: + MTChannelBasedBroker: + apiVersion: v1 + kind: ConfigMap + name: config-br-default-channel + namespace: knative-eventing + delivery: + deadLetterSink: + ref: + kind: Service + namespace: example-namespace + name: example-service + apiVersion: v1 + uri: example-uri + retry: 10 + backoffPolicy: exponential + backoffDelay: "PT0.2S" +``` + +### Dead letter sink + +You can configure the `deadLetterSink` delivery parameter so that if an event fails to be delivered it is sent to the specified event sink. + +### Retries + +You can set a minimum number of times that the delivery must be retried before the event is sent to the dead letter sink, by configuring the `retry` delivery parameter with an integer value. + +### Back off delay + +You can set the `backoffDelay` delivery parameter to specify the time delay before an event delivery retry is attempted after a failure. The duration of the `backoffDelay` parameter is specified using the ISO 8601 format. + +### Back off policy + +The `backoffPolicy` delivery parameter can be used to specify the retry back off policy. The policy can be specified as either linear or exponential. When using the linear back off policy, the back off delay is the time interval specified between retries. When using the exponential backoff policy, the back off delay is equal to `backoffDelay*2^`. + +## Integrating Istio with Knative Brokers + +### Protect a Knative Broker by using JSON Web Token (JWT) and Istio + +#### Prerequisites + +- You have installed Knative Eventing. +- You have installed Istio. + +#### Procedure + +1. Label the `knative-eventing` namespace, so that Istio can handle JWT-based user authentication, by running the command: + + ```bash + kubectl label namespace knative-eventing istio-injection=enabled + ``` + +1. Restart the broker ingress pod, so that the `istio-proxy` container can be injected as a sidecar, by running the command: + + ```bash + kubectl delete pod -n knative-eventing + ``` + + Where `` is the name of your Broker ingress pod. + + The pod now has two containers: + + ```{ .bash .no-copy } + knative-eventing 2/2 Running 1 175m + ``` + +1. Create a broker, then use get the URL of your Broker by running the command: + + ```bash + kubectl get broker + ``` + + Where `` is the name of your Broker. + + Example output: + + ```{ .bash .no-copy } + NAMESPACE NAME URL AGE READY REASON + default my-broker http://broker-ingress.knative-eventing.svc.cluster.local/default/my-broker 6s True + ``` + +1. Start a `curl` pod by running the following command: + + ```bash + kubectl -n default run curl --image=radial/busyboxplus:curl -i --tty + ``` + +1. Send a CloudEvent with an HTTP POST against the Broker URL by running the following command: + + ```bash + curl -X POST -v \ + -H "content-type: application/json" \ + -H "ce-specversion: 1.0" \ + -H "ce-source: my/curl/command" \ + -H "ce-type: my.demo.event" \ + -H "ce-id: 0815" \ + -d '{"value":"Hello Knative"}' \ + + ``` + + Where `` is the URL of your Broker. For example: + + ```{ .bash .no-copy } + curl -X POST -v \ + -H "content-type: application/json" \ + -H "ce-specversion: 1.0" \ + -H "ce-source: my/curl/command" \ + -H "ce-type: my.demo.event" \ + -H "ce-id: 0815" \ + -d '{"value":"Hello Knative"}' \ + http://broker-ingress.knative-eventing.svc.cluster.local/default/my-broker + ``` + +1. You will receive a `202` HTTP response code, that the broker did accept the request: + + ```{ .bash .no-copy } + ... + * Mark bundle as not supporting multiuse + < HTTP/1.1 202 Accepted + < allow: POST, OPTIONS + < date: Tue, 15 Mar 2022 13:37:57 GMT + < content-length: 0 + < x-envoy-upstream-service-time: 79 + < server: istio-envoy + < x-envoy-decorator-operation: broker-ingress.knative-eventing.svc.cluster.local:80/* + ``` + +1. Apply a `AuthorizationPolicy` object in the `knative-eventing` namespace to describe that the path to the Broker is restricted to a given user: + + ```yaml + apiVersion: security.istio.io/v1beta1 + kind: AuthorizationPolicy + metadata: + name: require-jwt + namespace: knative-eventing + spec: + action: ALLOW + rules: + - from: + - source: + requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"] + to: + - operation: + methods: ["POST"] + paths: ["/default/my-broker"] + ``` + +1. Create a `RequestAuthentication` object for the user `requestPrincipal` in the `istio-system` namespace: + + ```yaml + apiVersion: security.istio.io/v1beta1 + kind: RequestAuthentication + metadata: + name: "jwt-example" + namespace: istio-system + spec: + jwtRules: + - issuer: "testing@secure.istio.io" + jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.13/security/tools/jwt/samples/jwks.json" + ``` + +1. Now retrying the `curl` command results in a `403 - Forbidden` response code from the server: + + ```{ .bash .no-copy } + ... + * Mark bundle as not supporting multiuse + < HTTP/1.1 403 Forbidden + < content-length: 19 + < content-type: text/plain + < date: Tue, 15 Mar 2022 13:47:53 GMT + < server: istio-envoy + < connection: close + < x-envoy-decorator-operation: broker-ingress.knative-eventing.svc.cluster.local:80/* + ``` + +1. To access the Broker, add the Bearer JSON Web Token as part of the request: + + ```bash + TOKEN=$(curl https://raw.githubusercontent.com/istio/istio/release-1.13/security/tools/jwt/samples/demo.jwt -s) + + curl -X POST -v \ + -H "content-type: application/json" \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "ce-specversion: 1.0" \ + -H "ce-source: my/curl/command" \ + -H "ce-type: my.demo.event" \ + -H "ce-id: 0815" \ + -d '{"value":"Hello Knative"}' \ + + ``` + + The server now responds with a `202` response code, indicating that it has accepted the HTTP request: + + ```{ .bash .no-copy } + * Mark bundle as not supporting multiuse + < HTTP/1.1 202 Accepted + < allow: POST, OPTIONS + < date: Tue, 15 Mar 2022 14:05:09 GMT + < content-length: 0 + < x-envoy-upstream-service-time: 40 + < server: istio-envoy + < x-envoy-decorator-operation: broker-ingress.knative-eventing.svc.cluster.local:80/* + ``` + + ## Best Practices and Considerations 1. **Consistency**: Ensure that the `brokerClass` specified matches a key in the `brokerClasses` map to maintain consistency.