Skip to content

Commit

Permalink
chore: support load balancer service in multi-cluster (#7133)
Browse files Browse the repository at this point in the history
(cherry picked from commit d22abd5)
  • Loading branch information
leon-inf committed Apr 25, 2024
1 parent d59d78a commit 3384b32
Show file tree
Hide file tree
Showing 13 changed files with 567 additions and 52 deletions.
7 changes: 7 additions & 0 deletions apis/apps/v1alpha1/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,13 @@ type ServiceVars struct {
// +optional
Host *VarOption `json:"host,omitempty"`

// LoadBalancer represents the LoadBalancer ingress point of the service.
//
// If multiple ingress points are available, the first one will be used automatically, choosing between IP and Hostname.
//
// +optional
LoadBalancer *VarOption `json:"loadBalancer,omitempty"`

// Port references a port or node-port defined in the service.
//
// If the referenced service is a pod-service, there will be multiple service objects matched,
Expand Down
5 changes: 5 additions & 0 deletions apis/apps/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions config/crd/bases/apps.kubeblocks.io_componentdefinitions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15027,6 +15027,15 @@ spec:
- Required
- Optional
type: string
loadBalancer:
description: "LoadBalancer represents the LoadBalancer
ingress point of the service. \n If multiple ingress
points are available, the first one will be used automatically,
choosing between IP and Hostname."
enum:
- Required
- Optional
type: string
multipleClusterObjectOption:
description: This option defines the behavior when multiple
component objects match the specified @CompDef. If
Expand Down
14 changes: 9 additions & 5 deletions controllers/apps/systemaccount_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,18 @@ func (r *SystemAccountReconciler) Reconcile(ctx context.Context, req ctrl.Reques
}

clusterdefinition := &appsv1alpha1.ClusterDefinition{}
clusterDefNS := types.NamespacedName{Name: cluster.Spec.ClusterDefRef}
if err := r.Client.Get(reqCtx.Ctx, clusterDefNS, clusterdefinition); err != nil {
return intctrlutil.RequeueWithErrorAndRecordEvent(cluster, r.Recorder, err, reqCtx.Log)
if len(cluster.Spec.ClusterDefRef) > 0 {
clusterDefNS := types.NamespacedName{Name: cluster.Spec.ClusterDefRef}
if err := r.Client.Get(reqCtx.Ctx, clusterDefNS, clusterdefinition); err != nil {
return intctrlutil.RequeueWithErrorAndRecordEvent(cluster, r.Recorder, err, reqCtx.Log)
}
}

clusterVersion := &appsv1alpha1.ClusterVersion{}
if err := r.Client.Get(reqCtx.Ctx, types.NamespacedName{Name: cluster.Spec.ClusterVersionRef}, clusterVersion); err != nil {
return intctrlutil.RequeueWithErrorAndRecordEvent(cluster, r.Recorder, err, reqCtx.Log)
if len(cluster.Spec.ClusterVersionRef) > 0 {
if err := r.Client.Get(reqCtx.Ctx, types.NamespacedName{Name: cluster.Spec.ClusterVersionRef}, clusterVersion); err != nil {
return intctrlutil.RequeueWithErrorAndRecordEvent(cluster, r.Recorder, err, reqCtx.Log)
}
}

componentVersions := clusterVersion.Spec.GetDefNameMappingComponents()
Expand Down
3 changes: 0 additions & 3 deletions controllers/apps/transformer_cluster_placement.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ func (t *clusterPlacementTransformer) Transform(ctx graph.TransformContext, dag
cluster.Annotations[constant.KBAppMultiClusterPlacementKey] = strings.Join(p, ",")
transCtx.Context = intoContext(transCtx.Context, placement(cluster))

graphCli, _ := transCtx.Client.(model.GraphClient)
graphCli.Update(dag, transCtx.OrigCluster, cluster)

return nil
}

Expand Down
49 changes: 45 additions & 4 deletions controllers/apps/transformer_component_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@ import (
"github.com/apecloud/kubeblocks/pkg/controller/graph"
"github.com/apecloud/kubeblocks/pkg/controller/instanceset"
"github.com/apecloud/kubeblocks/pkg/controller/model"
"github.com/apecloud/kubeblocks/pkg/controller/multicluster"
)

var (
ordinalRegexpPattern = `-\d+$`
ordinalRegexp = regexp.MustCompile(ordinalRegexpPattern)

multiClusterServicePlacementInMirror = "mirror"
multiClusterServicePlacementInUnique = "unique"
)

// componentServiceTransformer handles component services.
Expand Down Expand Up @@ -71,7 +75,7 @@ func (t *componentServiceTransformer) Transform(ctx graph.TransformContext, dag
return err
}
for _, svc := range services {
if err = createOrUpdateService(ctx, dag, graphCli, svc, transCtx.ComponentOrig); err != nil {
if err = t.createOrUpdateService(ctx, dag, graphCli, &service, svc, transCtx.ComponentOrig); err != nil {
return err
}
}
Expand All @@ -86,10 +90,14 @@ func (t *componentServiceTransformer) buildCompService(comp *appsv1alpha1.Compon
return nil, nil
}

if service.PodService == nil || !*service.PodService {
return t.buildServices(comp, synthesizeComp, []*appsv1alpha1.ComponentService{service})
if t.isPodService(service) {
return t.buildPodService(comp, synthesizeComp, service)
}
return t.buildPodService(comp, synthesizeComp, service)
return t.buildServices(comp, synthesizeComp, []*appsv1alpha1.ComponentService{service})
}

func (t *componentServiceTransformer) isPodService(service *appsv1alpha1.ComponentService) bool {
return service.PodService != nil && *service.PodService
}

func (t *componentServiceTransformer) buildPodService(comp *appsv1alpha1.Component,
Expand Down Expand Up @@ -208,6 +216,39 @@ func (t *componentServiceTransformer) skipDefaultHeadlessSvc(synthesizeComp *com
return svcName == defaultHeadlessSvcName
}

func (t *componentServiceTransformer) createOrUpdateService(ctx graph.TransformContext, dag *graph.DAG,
graphCli model.GraphClient, compService *appsv1alpha1.ComponentService, service *corev1.Service, owner client.Object) error {
var (
kind string
podService = t.isPodService(compService)
)

if service.Annotations != nil {
kind = service.Annotations[constant.MultiClusterServicePlacementKey]
delete(service.Annotations, constant.MultiClusterServicePlacementKey)
}
if podService && len(kind) > 0 && kind != multiClusterServicePlacementInMirror && kind != multiClusterServicePlacementInUnique {
return fmt.Errorf("invalid multi-cluster pod-service placement kind %s for service %s", kind, service.Name)
}

if podService && kind == multiClusterServicePlacementInUnique {
return t.createOrUpdateServiceInUnique(ctx, dag, graphCli, service, owner)
}
return createOrUpdateService(ctx, dag, graphCli, service, owner)
}

func (t *componentServiceTransformer) createOrUpdateServiceInUnique(ctx graph.TransformContext, dag *graph.DAG,
graphCli model.GraphClient, service *corev1.Service, owner client.Object) error {
// hack the pod placement strategy.
ordinal := func() int {
subs := strings.Split(service.GetName(), "-")
o, _ := strconv.Atoi(subs[len(subs)-1])
return o
}
multicluster.Assign(ctx.GetContext(), service, ordinal)
return createOrUpdateService(ctx, dag, graphCli, service, owner)
}

func generatePodNames(synthesizeComp *component.SynthesizedComponent) []string {
workloadName := constant.GenerateWorkloadNamePattern(synthesizeComp.ClusterName, synthesizeComp.Name)
var templates []instanceset.InstanceTemplate
Expand Down
9 changes: 9 additions & 0 deletions deploy/helm/crds/apps.kubeblocks.io_componentdefinitions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15027,6 +15027,15 @@ spec:
- Required
- Optional
type: string
loadBalancer:
description: "LoadBalancer represents the LoadBalancer
ingress point of the service. \n If multiple ingress
points are available, the first one will be used automatically,
choosing between IP and Hostname."
enum:
- Required
- Optional
type: string
multipleClusterObjectOption:
description: This option defines the behavior when multiple
component objects match the specified @CompDef. If
Expand Down
15 changes: 15 additions & 0 deletions docs/developer_docs/api-reference/cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -19580,6 +19580,21 @@ VarOption
</tr>
<tr>
<td>
<code>loadBalancer</code><br/>
<em>
<a href="#apps.kubeblocks.io/v1alpha1.VarOption">
VarOption
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>LoadBalancer represents the LoadBalancer ingress point of the service.</p>
<p>If multiple ingress points are available, the first one will be used automatically, choosing between IP and Hostname.</p>
</td>
</tr>
<tr>
<td>
<code>port</code><br/>
<em>
<a href="#apps.kubeblocks.io/v1alpha1.NamedVar">
Expand Down
6 changes: 6 additions & 0 deletions pkg/constant/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ func GetKBReservedAnnotationKeys() []string {
const (
HorizontalScaleBackupPolicyTemplateKey = "apps.kubeblocks.io/horizontal-scale-backup-policy-template"
)

// annotations for multi-cluster
const (
KBAppMultiClusterPlacementKey = "apps.kubeblocks.io/multi-cluster-placement"
MultiClusterServicePlacementKey = "apps.kubeblocks.io/multi-cluster-service-placement"
)
4 changes: 0 additions & 4 deletions pkg/constant/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,10 +312,6 @@ const (
ConnectionPassword = "connectionPassword"
)

const (
KBAppMultiClusterPlacementKey = "apps.kubeblocks.io/multi-cluster-placement"
)

const (
KBGeneratedVirtualCompDefPrefix = "KB_GENERATED_VIRTUAL_COMP_DEF"
)
Expand Down
Loading

0 comments on commit 3384b32

Please sign in to comment.