From f4216e4fada0e39cdcd8ca3d31e8c11fdb83db51 Mon Sep 17 00:00:00 2001 From: Melissa Lee Date: Tue, 20 May 2025 21:01:24 -0700 Subject: [PATCH] Add Knative Traffic management and autoscaling support --- api/v1/runtimecomponent_types.go | 33 ++++++++++ api/v1/zz_generated.deepcopy.go | 35 +++++++++++ .../rc.app.stacks_runtimecomponents.yaml | 61 +++++++++++++++++++ ...ntime-component.clusterserviceversion.yaml | 8 +++ common/types.go | 8 +++ .../rc.app.stacks_runtimecomponents.yaml | 61 +++++++++++++++++++ ...ntime-component.clusterserviceversion.yaml | 8 +++ .../deploy/kubectl/runtime-component-crd.yaml | 61 +++++++++++++++++++ .../daily/base/runtime-component-crd.yaml | 61 +++++++++++++++++++ utils/utils.go | 4 +- 10 files changed, 339 insertions(+), 1 deletion(-) diff --git a/api/v1/runtimecomponent_types.go b/api/v1/runtimecomponent_types.go index c5cb5986..27c76130 100644 --- a/api/v1/runtimecomponent_types.go +++ b/api/v1/runtimecomponent_types.go @@ -27,6 +27,7 @@ import ( networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + servingv1 "knative.dev/serving/pkg/apis/serving/v1" ) // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. @@ -106,6 +107,9 @@ type RuntimeComponentSpec struct { // +operator-sdk:csv:customresourcedefinitions:order=17,type=spec,displayName="Monitoring" Monitoring *RuntimeComponentMonitoring `json:"monitoring,omitempty"` + // +operator-sdk:csv:customresourcedefinitions:order=17,type=spec,displayName="Knative Service" + KnativeService *RuntimeComponentKnativeService `json:"knative,omitempty"` + // An array of environment variables for the application container. // +listType=map // +listMapKey=name @@ -381,6 +385,17 @@ type RuntimeComponentMonitoring struct { Endpoints []prometheusv1.Endpoint `json:"endpoints,omitempty"` } +// Specifies parameters for Knative Service. +type RuntimeComponentKnativeService struct { + // List of traffic targets. + // +operator-sdk:csv:customresourcedefinitions:order=22,type=spec,displayName="Traffic Targets" + TrafficTarget []servingv1.TrafficTarget `json:"traffic,omitempty"` + + // Annotations for Autoscaling. + // +operator-sdk:csv:customresourcedefinitions:order=22,type=spec,displayName="Autoscaling Annotations" + AutoscalingAnnotations map[string]string `json:"autoscaling,omitempty"` +} + // Configures the ingress resource. // +k8s:openapi-gen=true type RuntimeComponentRoute struct { @@ -688,6 +703,14 @@ func (cr *RuntimeComponent) GetMonitoring() common.BaseComponentMonitoring { return cr.Spec.Monitoring } +// GetMonitoring returns monitoring settings +func (cr *RuntimeComponent) GetKnativeService() common.BaseComponentKnativeService { + if cr.Spec.KnativeService == nil { + return nil + } + return cr.Spec.KnativeService +} + // GetStatus returns RuntimeComponent status func (cr *RuntimeComponent) GetStatus() common.BaseComponentStatus { return &cr.Status @@ -904,6 +927,16 @@ func (m *RuntimeComponentMonitoring) GetEndpoints() []prometheusv1.Endpoint { return m.Endpoints } +// GetTrafficTarget returns traffic targets for Knative +func (k *RuntimeComponentKnativeService) GetTrafficTarget() []servingv1.TrafficTarget { + return k.TrafficTarget +} + +// GetTrafficTarget returns traffic targets for Knative +func (k *RuntimeComponentKnativeService) GetAutoscalingAnnotations() map[string]string { + return k.AutoscalingAnnotations +} + // GetAnnotations returns route annotations func (r *RuntimeComponentRoute) GetAnnotations() map[string]string { return r.Annotations diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 24340889..9d2a608e 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -27,6 +27,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" + servingv1 "knative.dev/serving/pkg/apis/serving/v1" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. @@ -217,6 +218,35 @@ func (in *RuntimeComponentDeployment) DeepCopy() *RuntimeComponentDeployment { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RuntimeComponentKnativeService) DeepCopyInto(out *RuntimeComponentKnativeService) { + *out = *in + if in.TrafficTarget != nil { + in, out := &in.TrafficTarget, &out.TrafficTarget + *out = make([]servingv1.TrafficTarget, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.AutoscalingAnnotations != nil { + in, out := &in.AutoscalingAnnotations, &out.AutoscalingAnnotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RuntimeComponentKnativeService. +func (in *RuntimeComponentKnativeService) DeepCopy() *RuntimeComponentKnativeService { + if in == nil { + return nil + } + out := new(RuntimeComponentKnativeService) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RuntimeComponentList) DeepCopyInto(out *RuntimeComponentList) { *out = *in @@ -559,6 +589,11 @@ func (in *RuntimeComponentSpec) DeepCopyInto(out *RuntimeComponentSpec) { *out = new(RuntimeComponentMonitoring) (*in).DeepCopyInto(*out) } + if in.KnativeService != nil { + in, out := &in.KnativeService, &out.KnativeService + *out = new(RuntimeComponentKnativeService) + (*in).DeepCopyInto(*out) + } if in.Env != nil { in, out := &in.Env, &out.Env *out = make([]corev1.EnvVar, len(*in)) diff --git a/bundle/manifests/rc.app.stacks_runtimecomponents.yaml b/bundle/manifests/rc.app.stacks_runtimecomponents.yaml index 24a23a92..0b25370a 100644 --- a/bundle/manifests/rc.app.stacks_runtimecomponents.yaml +++ b/bundle/manifests/rc.app.stacks_runtimecomponents.yaml @@ -2658,6 +2658,67 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + knative: + description: Specifies parameters for Knative Service. + properties: + autoscaling: + additionalProperties: + type: string + description: Annotations for Autoscaling. + type: object + traffic: + description: List of traffic targets. + items: + description: TrafficTarget holds a single entry of the routing + table for a Route. + properties: + configurationName: + description: |- + ConfigurationName of a configuration to whose latest revision we will send + this portion of traffic. When the "status.latestReadyRevisionName" of the + referenced configuration changes, we will automatically migrate traffic + from the prior "latest ready" revision to the new one. This field is never + set in Route's status, only its spec. This is mutually exclusive with + RevisionName. + type: string + latestRevision: + description: |- + LatestRevision may be optionally provided to indicate that the latest + ready Revision of the Configuration should be used for this traffic + target. When provided LatestRevision must be true if RevisionName is + empty; it must be false when RevisionName is non-empty. + type: boolean + percent: + description: |- + Percent indicates that percentage based routing should be used and + the value indicates the percent of traffic that is be routed to this + Revision or Configuration. `0` (zero) mean no traffic, `100` means all + traffic. + When percentage based routing is being used the follow rules apply: + - the sum of all percent values must equal 100 + - when not specified, the implied value for `percent` is zero for + that particular Revision or Configuration + format: int64 + type: integer + revisionName: + description: |- + RevisionName of a specific revision to which to send this portion of + traffic. This is mutually exclusive with ConfigurationName. + type: string + tag: + description: |- + Tag is optionally used to expose a dedicated url for referencing + this target exclusively. + type: string + url: + description: |- + URL displays the URL for accessing named traffic targets. URL is displayed in + status, and is disallowed on spec. URL must contain a scheme (e.g. http://) and + a hostname, but may not contain anything else (e.g. basic auth, url path, etc.) + type: string + type: object + type: array + type: object manageTLS: description: Enable management of TLS certificates. Defaults to true. type: boolean diff --git a/bundle/manifests/runtime-component.clusterserviceversion.yaml b/bundle/manifests/runtime-component.clusterserviceversion.yaml index b5230f20..ebbdb94c 100644 --- a/bundle/manifests/runtime-component.clusterserviceversion.yaml +++ b/bundle/manifests/runtime-component.clusterserviceversion.yaml @@ -307,6 +307,8 @@ spec: - description: Configure service certificate. displayName: Service Certificate path: service.certificate + - displayName: Knative Service + path: knative - displayName: Monitoring path: monitoring - description: An array consisting of service ports. @@ -340,6 +342,12 @@ spec: - description: List of containers to run before other containers in a pod. displayName: Init Containers path: initContainers + - description: Annotations for Autoscaling. + displayName: Autoscaling Annotations + path: knative.autoscaling + - description: List of traffic targets. + displayName: Traffic Targets + path: knative.traffic - description: List of sidecar containers. These are additional containers to be added to the pods. displayName: Sidecar Containers diff --git a/common/types.go b/common/types.go index 63a03db2..4c1bd610 100644 --- a/common/types.go +++ b/common/types.go @@ -7,6 +7,7 @@ import ( corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + servingv1 "knative.dev/serving/pkg/apis/serving/v1" ) // StatusConditionType ... @@ -150,6 +151,12 @@ type BaseComponentMonitoring interface { GetEndpoints() []prometheusv1.Endpoint } +// BaseComponentKnativeService represents basic Knative service configuration +type BaseComponentKnativeService interface { + GetTrafficTarget() []servingv1.TrafficTarget + GetAutoscalingAnnotations() map[string]string +} + // BaseComponentRoute represents route configuration type BaseComponentRoute interface { GetTermination() *routev1.TLSTerminationType @@ -233,6 +240,7 @@ type BaseComponent interface { GetApplicationVersion() string GetApplicationName() string GetMonitoring() BaseComponentMonitoring + GetKnativeService() BaseComponentKnativeService GetLabels() map[string]string GetAnnotations() map[string]string GetStatus() BaseComponentStatus diff --git a/config/crd/bases/rc.app.stacks_runtimecomponents.yaml b/config/crd/bases/rc.app.stacks_runtimecomponents.yaml index f4f9011a..4db43fc6 100644 --- a/config/crd/bases/rc.app.stacks_runtimecomponents.yaml +++ b/config/crd/bases/rc.app.stacks_runtimecomponents.yaml @@ -2654,6 +2654,67 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + knative: + description: Specifies parameters for Knative Service. + properties: + autoscaling: + additionalProperties: + type: string + description: Annotations for Autoscaling. + type: object + traffic: + description: List of traffic targets. + items: + description: TrafficTarget holds a single entry of the routing + table for a Route. + properties: + configurationName: + description: |- + ConfigurationName of a configuration to whose latest revision we will send + this portion of traffic. When the "status.latestReadyRevisionName" of the + referenced configuration changes, we will automatically migrate traffic + from the prior "latest ready" revision to the new one. This field is never + set in Route's status, only its spec. This is mutually exclusive with + RevisionName. + type: string + latestRevision: + description: |- + LatestRevision may be optionally provided to indicate that the latest + ready Revision of the Configuration should be used for this traffic + target. When provided LatestRevision must be true if RevisionName is + empty; it must be false when RevisionName is non-empty. + type: boolean + percent: + description: |- + Percent indicates that percentage based routing should be used and + the value indicates the percent of traffic that is be routed to this + Revision or Configuration. `0` (zero) mean no traffic, `100` means all + traffic. + When percentage based routing is being used the follow rules apply: + - the sum of all percent values must equal 100 + - when not specified, the implied value for `percent` is zero for + that particular Revision or Configuration + format: int64 + type: integer + revisionName: + description: |- + RevisionName of a specific revision to which to send this portion of + traffic. This is mutually exclusive with ConfigurationName. + type: string + tag: + description: |- + Tag is optionally used to expose a dedicated url for referencing + this target exclusively. + type: string + url: + description: |- + URL displays the URL for accessing named traffic targets. URL is displayed in + status, and is disallowed on spec. URL must contain a scheme (e.g. http://) and + a hostname, but may not contain anything else (e.g. basic auth, url path, etc.) + type: string + type: object + type: array + type: object manageTLS: description: Enable management of TLS certificates. Defaults to true. type: boolean diff --git a/config/manifests/bases/runtime-component.clusterserviceversion.yaml b/config/manifests/bases/runtime-component.clusterserviceversion.yaml index 37516e87..2d67ede8 100644 --- a/config/manifests/bases/runtime-component.clusterserviceversion.yaml +++ b/config/manifests/bases/runtime-component.clusterserviceversion.yaml @@ -241,6 +241,8 @@ spec: - description: Configure service certificate. displayName: Service Certificate path: service.certificate + - displayName: Knative Service + path: knative - displayName: Monitoring path: monitoring - description: An array consisting of service ports. @@ -274,6 +276,12 @@ spec: - description: List of containers to run before other containers in a pod. displayName: Init Containers path: initContainers + - description: Annotations for Autoscaling. + displayName: Autoscaling Annotations + path: knative.autoscaling + - description: List of traffic targets. + displayName: Traffic Targets + path: knative.traffic - description: List of sidecar containers. These are additional containers to be added to the pods. displayName: Sidecar Containers diff --git a/internal/deploy/kubectl/runtime-component-crd.yaml b/internal/deploy/kubectl/runtime-component-crd.yaml index b5034f7b..48e68e8f 100644 --- a/internal/deploy/kubectl/runtime-component-crd.yaml +++ b/internal/deploy/kubectl/runtime-component-crd.yaml @@ -2657,6 +2657,67 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + knative: + description: Specifies parameters for Knative Service. + properties: + autoscaling: + additionalProperties: + type: string + description: Annotations for Autoscaling. + type: object + traffic: + description: List of traffic targets. + items: + description: TrafficTarget holds a single entry of the routing + table for a Route. + properties: + configurationName: + description: |- + ConfigurationName of a configuration to whose latest revision we will send + this portion of traffic. When the "status.latestReadyRevisionName" of the + referenced configuration changes, we will automatically migrate traffic + from the prior "latest ready" revision to the new one. This field is never + set in Route's status, only its spec. This is mutually exclusive with + RevisionName. + type: string + latestRevision: + description: |- + LatestRevision may be optionally provided to indicate that the latest + ready Revision of the Configuration should be used for this traffic + target. When provided LatestRevision must be true if RevisionName is + empty; it must be false when RevisionName is non-empty. + type: boolean + percent: + description: |- + Percent indicates that percentage based routing should be used and + the value indicates the percent of traffic that is be routed to this + Revision or Configuration. `0` (zero) mean no traffic, `100` means all + traffic. + When percentage based routing is being used the follow rules apply: + - the sum of all percent values must equal 100 + - when not specified, the implied value for `percent` is zero for + that particular Revision or Configuration + format: int64 + type: integer + revisionName: + description: |- + RevisionName of a specific revision to which to send this portion of + traffic. This is mutually exclusive with ConfigurationName. + type: string + tag: + description: |- + Tag is optionally used to expose a dedicated url for referencing + this target exclusively. + type: string + url: + description: |- + URL displays the URL for accessing named traffic targets. URL is displayed in + status, and is disallowed on spec. URL must contain a scheme (e.g. http://) and + a hostname, but may not contain anything else (e.g. basic auth, url path, etc.) + type: string + type: object + type: array + type: object manageTLS: description: Enable management of TLS certificates. Defaults to true. type: boolean diff --git a/internal/deploy/kustomize/daily/base/runtime-component-crd.yaml b/internal/deploy/kustomize/daily/base/runtime-component-crd.yaml index b5034f7b..48e68e8f 100644 --- a/internal/deploy/kustomize/daily/base/runtime-component-crd.yaml +++ b/internal/deploy/kustomize/daily/base/runtime-component-crd.yaml @@ -2657,6 +2657,67 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + knative: + description: Specifies parameters for Knative Service. + properties: + autoscaling: + additionalProperties: + type: string + description: Annotations for Autoscaling. + type: object + traffic: + description: List of traffic targets. + items: + description: TrafficTarget holds a single entry of the routing + table for a Route. + properties: + configurationName: + description: |- + ConfigurationName of a configuration to whose latest revision we will send + this portion of traffic. When the "status.latestReadyRevisionName" of the + referenced configuration changes, we will automatically migrate traffic + from the prior "latest ready" revision to the new one. This field is never + set in Route's status, only its spec. This is mutually exclusive with + RevisionName. + type: string + latestRevision: + description: |- + LatestRevision may be optionally provided to indicate that the latest + ready Revision of the Configuration should be used for this traffic + target. When provided LatestRevision must be true if RevisionName is + empty; it must be false when RevisionName is non-empty. + type: boolean + percent: + description: |- + Percent indicates that percentage based routing should be used and + the value indicates the percent of traffic that is be routed to this + Revision or Configuration. `0` (zero) mean no traffic, `100` means all + traffic. + When percentage based routing is being used the follow rules apply: + - the sum of all percent values must equal 100 + - when not specified, the implied value for `percent` is zero for + that particular Revision or Configuration + format: int64 + type: integer + revisionName: + description: |- + RevisionName of a specific revision to which to send this portion of + traffic. This is mutually exclusive with ConfigurationName. + type: string + tag: + description: |- + Tag is optionally used to expose a dedicated url for referencing + this target exclusively. + type: string + url: + description: |- + URL displays the URL for accessing named traffic targets. URL is displayed in + status, and is disallowed on spec. URL must contain a scheme (e.g. http://) and + a hostname, but may not contain anything else (e.g. basic auth, url path, etc.) + type: string + type: object + type: array + type: object manageTLS: description: Enable management of TLS certificates. Defaults to true. type: boolean diff --git a/utils/utils.go b/utils/utils.go index a4d905fd..33005dad 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -942,7 +942,7 @@ func CustomizeKnativeService(ksvc *servingv1.Service, ba common.BaseComponent) { ksvc.Spec.Template.Spec.Containers[0].Ports = append(ksvc.Spec.Template.Spec.Containers[0].Ports, corev1.ContainerPort{}) } ksvc.Spec.Template.ObjectMeta.Labels = ba.GetLabels() - ksvc.Spec.Template.ObjectMeta.Annotations = MergeMaps(ksvc.Spec.Template.ObjectMeta.Annotations, ba.GetAnnotations()) + ksvc.Spec.Template.ObjectMeta.Annotations = MergeMaps(ksvc.Spec.Template.ObjectMeta.Annotations, ba.GetAnnotations(), ba.GetKnativeService().GetAutoscalingAnnotations()) if ba.GetService().GetTargetPort() != nil { ksvc.Spec.Template.Spec.Containers[0].Ports[0].ContainerPort = *ba.GetService().GetTargetPort() @@ -1002,6 +1002,8 @@ func CustomizeKnativeService(ksvc *servingv1.Service, ba common.BaseComponent) { } } + ksvc.Spec.Traffic = ba.GetKnativeService().GetTrafficTarget() + basa := ba.GetServiceAccount() if basa != nil && basa.GetMountToken() != nil && !*basa.GetMountToken() { // not nil and set to false