Add a primary (write) Service routing to pod-0
Secondaries reject RFC2136/nsupdate writes, but the read Service round- robins across all pods. Add an optional per-cluster write endpoint that targets only the primary pod (ordinal 0) via the StatefulSet pod-name label. Reads keep using the all-pods Service. - api: BindCluster.spec.primaryService (*ClusterServiceSpec) — ClusterIP for in-cluster writers (external-dns) or LoadBalancer for external - reconcilePrimaryService creates <cluster>-primary selecting pod-0 when set, deletes it when unset - regenerate CRDs + install.yaml
This commit is contained in:
@@ -277,7 +277,52 @@ func (r *BindClusterReconciler) reconcileServices(ctx context.Context, c *bindv1
|
||||
if svcType == corev1.ServiceTypeLoadBalancer || svcType == corev1.ServiceTypeNodePort {
|
||||
client.Spec.ExternalTrafficPolicy = c.Spec.Service.ExternalTrafficPolicy
|
||||
}
|
||||
return r.upsertService(ctx, c, client)
|
||||
if err := r.upsertService(ctx, c, client); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Primary (write) Service: routes only to pod-0. Created when configured,
|
||||
// deleted when removed.
|
||||
return r.reconcilePrimaryService(ctx, c, dnsPorts)
|
||||
}
|
||||
|
||||
func (r *BindClusterReconciler) reconcilePrimaryService(ctx context.Context, c *bindv1alpha1.BindCluster, dnsPorts []corev1.ServicePort) error {
|
||||
name := primaryServiceName(c.Name)
|
||||
if c.Spec.PrimaryService == nil {
|
||||
var existing corev1.Service
|
||||
err := r.Get(ctx, types.NamespacedName{Namespace: c.Namespace, Name: name}, &existing)
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return client.IgnoreNotFound(r.Delete(ctx, &existing))
|
||||
}
|
||||
|
||||
ps := c.Spec.PrimaryService
|
||||
psType := ps.Type
|
||||
if psType == "" {
|
||||
psType = corev1.ServiceTypeClusterIP
|
||||
}
|
||||
svc := &corev1.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: c.Namespace,
|
||||
Labels: commonLabels(c.Name),
|
||||
Annotations: ps.Annotations,
|
||||
},
|
||||
Spec: corev1.ServiceSpec{
|
||||
Type: psType,
|
||||
Selector: primaryPodSelector(c.Name),
|
||||
Ports: dnsPorts,
|
||||
LoadBalancerIP: ps.LoadBalancerIP,
|
||||
},
|
||||
}
|
||||
if psType == corev1.ServiceTypeLoadBalancer || psType == corev1.ServiceTypeNodePort {
|
||||
svc.Spec.ExternalTrafficPolicy = ps.ExternalTrafficPolicy
|
||||
}
|
||||
return r.upsertService(ctx, c, svc)
|
||||
}
|
||||
|
||||
func (r *BindClusterReconciler) reconcileStatefulSet(ctx context.Context, c *bindv1alpha1.BindCluster) (*appsv1.StatefulSet, error) {
|
||||
|
||||
@@ -29,11 +29,20 @@ const (
|
||||
)
|
||||
|
||||
func headlessServiceName(cluster string) string { return cluster + "-headless" }
|
||||
func clientServiceName(cluster string) string { return cluster }
|
||||
func primaryPodName(cluster string) string { return cluster + "-0" }
|
||||
func configMapName(cluster string) string { return cluster + "-config" }
|
||||
func keysSecretName(cluster string) string { return cluster + "-keys" }
|
||||
func rndcSecretName(cluster string) string { return cluster + "-rndc" }
|
||||
func primaryServiceName(cluster string) string { return cluster + "-primary" }
|
||||
|
||||
// primaryPodSelector selects only the primary pod (ordinal 0) via the stable
|
||||
// StatefulSet pod-name label, for the write Service.
|
||||
func primaryPodSelector(cluster string) map[string]string {
|
||||
s := commonLabels(cluster)
|
||||
s["statefulset.kubernetes.io/pod-name"] = primaryPodName(cluster)
|
||||
return s
|
||||
}
|
||||
func clientServiceName(cluster string) string { return cluster }
|
||||
func primaryPodName(cluster string) string { return cluster + "-0" }
|
||||
func configMapName(cluster string) string { return cluster + "-config" }
|
||||
func keysSecretName(cluster string) string { return cluster + "-keys" }
|
||||
func rndcSecretName(cluster string) string { return cluster + "-rndc" }
|
||||
|
||||
// primaryAddress is the in-cluster DNS name of the primary pod (ordinal 0).
|
||||
func primaryAddress(cluster, namespace string) string {
|
||||
|
||||
Reference in New Issue
Block a user