knative/eventing

Question: Is it possible to broadcast events to all replicas of a target?

oEscal opened this issue · 5 comments

For instance, imagine I have a Trigger whose subscriber is a Knative Service. It seems that the expected behavior is that when there is a new event, it is sent to one of the replicas of that Service. However, would it be possible to send that event to all replicas of that Service?

the way I would do it is to have an init container in your subscriber service creating a pod-specific trigger with subscriber uri: <pod_ip>, for example:

apiVersion: eventing.knative.dev/v1
kind: Trigger
metadata:
  name: <pod_name>
  namespace: <pod_namespace>
  ownerReferences: # This configures garbage collection, when the pod is deleted the trigger will be deleted
  - apiVersion: v1
    kind: Pod
    name: <pod_name>
    uid: <pod_uid>
    controller: true
    blockOwnerDeletion: false
spec:
  broker: my-broker
  subscriber:
    uri: http://<pod_ip>:<your_subscriber_pod_port>

you can inject the various variables <pod_ip>, <pod_name> into the init container environment variables using the k8s downward API: https://kubernetes.io/docs/concepts/workloads/pods/downward-api/#downwardapi-fieldRef

For example: (I didn't check the syntax but it should give you an idea)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: subscriber-deployment
spec:
  selector:
    matchLabels:
      app: subscriber
  template:
    metadata:
      labels:
        app: subscriber
    spec:
      serviceAccountName: <service_account> # Ensure this service account has permissions to create Knative triggers
      initContainers:
      - name: init-trigger
        image: bitnami/kubectl:latest
        command:
          - sh
          - -c
          - |
            cat <<EOF | kubectl apply -f -
            apiVersion: eventing.knative.dev/v1
            kind: Trigger
            metadata:
              name: $(POD_NAME)
              namespace: $(POD_NAMESPACE)
              ownerReferences:
              - apiVersion: v1
                kind: Pod
                name: $(POD_NAME)
                uid: $(POD_UID)
                controller: true
                blockOwnerDeletion: false
            spec:
              broker: my-broker
              subscriber:
                uri: http://$(POD_IP):80
            EOF
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: POD_UID
          valueFrom:
            fieldRef:
              fieldPath: metadata.uid
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
      containers:
      - name: subscriber
        image: nginx
        ports:
        - containerPort: 80

This way each pod (instance) will get all events from the broker my-broker

in addition, I'd wait for the created trigger to become ready in the init container

kubectl wait triggers.eventing.knative.dev --for=condition=Ready=true -n $(POD_NAMESPACE)  $(POD_NAME) --timeout=20m

With a Knative Service that scales from 0 might not be possible though, as the real receiver when scaling from 0 to 1 needs to be the activator https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md

Closing this issue for now, re-open in case the above doesn't work for you