Skip to content

Commit 97a5a5d

Browse files
authored
Add KServe destination rule for Inference Services in the ServiceMesh (#315)
* Add DestinationRule creation for KServe serverless * Add permissions for destination rules * Add role for destination rules * Add missing role for creating destination rules * Fix spacing in DestinationRule template
1 parent c072d51 commit 97a5a5d

File tree

6 files changed

+108
-3
lines changed

6 files changed

+108
-3
lines changed

config/overlays/odh/params.env

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
trustyaiServiceImage=quay.io/trustyai/trustyai-service:v0.19.0
2-
trustyaiOperatorImage=quay.io/trustyai/trustyai-service-operator:v1.25.0
1+
trustyaiServiceImage=quay.io/trustyai/trustyai-service:latest
2+
trustyaiOperatorImage=quay.io/trustyai/trustyai-service-operator:latest
33
oauthProxyImage=quay.io/openshift/origin-oauth-proxy:4.14.0
44
kServeServerless=enabled

config/rbac/role.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,18 @@ rules:
134134
- create
135135
- list
136136
- watch
137+
- apiGroups:
138+
- networking.istio.io
139+
resources:
140+
- destinationrules
141+
verbs:
142+
- create
143+
- delete
144+
- get
145+
- list
146+
- patch
147+
- update
148+
- watch
137149
- apiGroups:
138150
- rbac.authorization.k8s.io
139151
resources:

controllers/destination_rule.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package controllers
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"reflect"
7+
8+
trustyaiopendatahubiov1alpha1 "github.com/trustyai-explainability/trustyai-service-operator/api/v1alpha1"
9+
templateParser "github.com/trustyai-explainability/trustyai-service-operator/controllers/templates"
10+
"k8s.io/apimachinery/pkg/api/errors"
11+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
12+
"k8s.io/apimachinery/pkg/types"
13+
ctrl "sigs.k8s.io/controller-runtime"
14+
"sigs.k8s.io/controller-runtime/pkg/log"
15+
)
16+
17+
const (
18+
destinationRuleTemplatePath = "service/destination-rule.tmpl.yaml"
19+
)
20+
21+
// DestinationRuleConfig has the variables for the DestinationRule template
22+
type DestinationRuleConfig struct {
23+
Name string
24+
Namespace string
25+
DestinationRuleName string
26+
}
27+
28+
func (r *TrustyAIServiceReconciler) ensureDestinationRule(ctx context.Context, instance *trustyaiopendatahubiov1alpha1.TrustyAIService) error {
29+
destinationRuleName := instance.Name + "-internal"
30+
31+
existingDestinationRule := &unstructured.Unstructured{}
32+
existingDestinationRule.SetKind("DestinationRule")
33+
existingDestinationRule.SetAPIVersion("networking.istio.io/v1beta1")
34+
35+
// Check if the DestinationRule already exists
36+
err := r.Get(ctx, types.NamespacedName{Name: destinationRuleName, Namespace: instance.Namespace}, existingDestinationRule)
37+
if err == nil {
38+
// DestinationRule exists
39+
return nil
40+
}
41+
42+
if !errors.IsNotFound(err) {
43+
return fmt.Errorf("failed to check for existing DestinationRule: %v", err)
44+
}
45+
46+
destinationRuleConfig := DestinationRuleConfig{
47+
Name: instance.Name,
48+
Namespace: instance.Namespace,
49+
DestinationRuleName: destinationRuleName,
50+
}
51+
52+
var destinationRule *unstructured.Unstructured
53+
destinationRule, err = templateParser.ParseResource[unstructured.Unstructured](destinationRuleTemplatePath, destinationRuleConfig, reflect.TypeOf(&unstructured.Unstructured{}))
54+
if err != nil {
55+
log.FromContext(ctx).Error(err, "could not parse the DestinationRule template")
56+
return err
57+
}
58+
59+
if err := ctrl.SetControllerReference(instance, destinationRule, r.Scheme); err != nil {
60+
return err
61+
}
62+
63+
err = r.Create(ctx, destinationRule)
64+
if err != nil {
65+
return fmt.Errorf("failed to create DestinationRule: %v", err)
66+
}
67+
68+
return nil
69+
}

controllers/inference_services.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ package controllers
33
import (
44
"context"
55
"fmt"
6+
"strings"
7+
68
kservev1beta1 "github.com/kserve/kserve/pkg/apis/serving/v1beta1"
79
trustyaiopendatahubiov1alpha1 "github.com/trustyai-explainability/trustyai-service-operator/api/v1alpha1"
810
appsv1 "k8s.io/api/apps/v1"
911
corev1 "k8s.io/api/core/v1"
1012
"sigs.k8s.io/controller-runtime/pkg/client"
1113
"sigs.k8s.io/controller-runtime/pkg/log"
12-
"strings"
1314
)
1415

1516
const (
@@ -271,6 +272,15 @@ func (r *TrustyAIServiceReconciler) patchKServe(ctx context.Context, instance *t
271272
infService.Spec.Predictor.Logger = &logger
272273
}
273274

275+
// Only if the Istio sidecar annotation is set
276+
annotations := infService.GetAnnotations()
277+
if inject, exists := annotations["sidecar.istio.io/inject"]; exists && inject == "true" {
278+
err := r.ensureDestinationRule(ctx, instance)
279+
if err != nil {
280+
return fmt.Errorf("failed to ensure DestinationRule: %v", err)
281+
}
282+
}
283+
274284
// Update the InferenceService
275285
err := r.Update(ctx, &infService)
276286
if err == nil {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: networking.istio.io/v1beta1
2+
kind: DestinationRule
3+
metadata:
4+
name: {{ .DestinationRuleName }}
5+
namespace: {{ .Namespace }}
6+
spec:
7+
host: {{ .Name }}.{{ .Namespace }}.svc.cluster.local
8+
trafficPolicy:
9+
portLevelSettings:
10+
- port:
11+
number: 443
12+
tls:
13+
mode: SIMPLE

controllers/trustyaiservice_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ type TrustyAIServiceReconciler struct {
6969
//+kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch;create;update;delete
7070
//+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=clusterrolebindings,verbs=get;list;watch;create;update;delete
7171
//+kubebuilder:rbac:groups=coordination.k8s.io,resources=leases,verbs=get;create;update
72+
//+kubebuilder:rbac:groups=networking.istio.io,resources=destinationrules,verbs=create;list;watch;get;update;patch;delete
7273

7374
// Reconcile is part of the main kubernetes reconciliation loop which aims to
7475
// move the current state of the cluster closer to the desired state.

0 commit comments

Comments
 (0)