Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Myasnikov Daniil
8358c04ce9
fix(mongodb): expose replica-set members per pod for external access (#2514)
A single LoadBalancer selecting all replset members round-robined writes
across primary and secondaries, so ~⅔ of writes failed with "not primary".
Drivers couldn't auto-recover either: `isMaster` returned in-cluster DNS
names that don't resolve from outside.

Switch to the Percona operator's native `replsets[].expose` so it creates
one LoadBalancer per pod and rewrites `rs.conf` with the external IPs;
the driver then discovers the primary correctly via the standard replica
set connection string. The manual `external-svc.yaml` is now scoped to
sharded mode (mongos front-end) only.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
2026-04-28 17:06:07 +05:00
4 changed files with 81 additions and 59 deletions

View file

@ -1,4 +1,12 @@
{{- if .Values.external }}
{{- /*
External access for non-sharded replica sets is handled by the Percona
MongoDB operator via `replsets[].expose` in mongodb.yaml: the operator
creates one LoadBalancer per pod and rewrites rs.conf so the driver can
discover the primary from outside the cluster (issue #2514). For sharded
mode we still expose mongos through a single LoadBalancer because mongos
is stateless and any router can route writes to the right shard primary.
*/}}
{{- if and .Values.external .Values.sharding }}
apiVersion: v1
kind: Service
metadata:
@ -15,10 +23,5 @@ spec:
selector:
app.kubernetes.io/name: percona-server-mongodb
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .Values.sharding }}
app.kubernetes.io/component: mongos
{{- else }}
app.kubernetes.io/component: mongod
app.kubernetes.io/replset: rs0
{{- end }}
{{- end }}

View file

@ -99,7 +99,13 @@ spec:
podDisruptionBudget:
maxUnavailable: 1
expose:
{{- if .Values.external }}
enabled: true
type: LoadBalancer
externalTrafficPolicy: Local
{{- else }}
enabled: false
{{- end }}
{{- end }}
{{- if .Values.users }}

View file

@ -18,12 +18,24 @@ tests:
- hasDocuments:
count: 0
- it: renders LoadBalancer service when external is true
- it: does not render in replica-set mode (operator handles per-pod LBs via replsets[].expose)
release:
name: test-mongodb
namespace: tenant-test
set:
external: true
sharding: false
asserts:
- hasDocuments:
count: 0
- it: renders single LoadBalancer in sharded mode (mongos front-end)
release:
name: test-mongodb
namespace: tenant-test
set:
external: true
sharding: true
asserts:
- hasDocuments:
count: 1
@ -40,6 +52,7 @@ tests:
namespace: tenant-test
set:
external: true
sharding: true
asserts:
- equal:
path: metadata.name
@ -51,6 +64,7 @@ tests:
namespace: tenant-test
set:
external: true
sharding: true
asserts:
- equal:
path: spec.type
@ -62,6 +76,7 @@ tests:
namespace: tenant-test
set:
external: true
sharding: true
asserts:
- equal:
path: spec.externalTrafficPolicy
@ -73,6 +88,7 @@ tests:
namespace: tenant-test
set:
external: true
sharding: true
asserts:
- equal:
path: spec.ports[0].name
@ -82,73 +98,25 @@ tests:
value: 27017
###########################
# Common selector labels #
# Sharded selector #
###########################
- it: sets app.kubernetes.io/name selector
- it: targets mongos pods only
release:
name: test-mongodb
namespace: tenant-test
set:
external: true
sharding: true
asserts:
- equal:
path: spec.selector["app.kubernetes.io/name"]
value: percona-server-mongodb
- it: sets app.kubernetes.io/instance selector
release:
name: mydb
namespace: tenant-test
set:
external: true
asserts:
- equal:
path: spec.selector["app.kubernetes.io/instance"]
value: mydb
###########################
# Replica set mode #
###########################
- it: selects mongod for replica set mode
release:
name: test-mongodb
namespace: tenant-test
set:
external: true
sharding: false
asserts:
- equal:
path: spec.selector["app.kubernetes.io/component"]
value: mongod
- equal:
path: spec.selector["app.kubernetes.io/replset"]
value: rs0
###########################
# Sharded mode #
###########################
- it: selects mongos for sharded mode
release:
name: test-mongodb
namespace: tenant-test
set:
external: true
sharding: true
asserts:
value: test-mongodb
- equal:
path: spec.selector["app.kubernetes.io/component"]
value: mongos
- it: does not set replset selector for sharded mode
release:
name: test-mongodb
namespace: tenant-test
set:
external: true
sharding: true
asserts:
- notExists:
path: spec.selector["app.kubernetes.io/replset"]

View file

@ -213,6 +213,51 @@ tests:
path: spec.replsets[0].volumeSpec.persistentVolumeClaim.storageClassName
documentIndex: 0
###########################
# Replica set expose #
###########################
- it: disables replset expose by default
release:
name: test-mongodb
namespace: tenant-test
set:
_cluster:
cluster-domain: cozy.local
sharding: false
external: false
asserts:
- equal:
path: spec.replsets[0].expose.enabled
value: false
documentIndex: 0
- notExists:
path: spec.replsets[0].expose.type
documentIndex: 0
- it: enables per-pod LoadBalancer when external is true (issue 2514)
release:
name: test-mongodb
namespace: tenant-test
set:
_cluster:
cluster-domain: cozy.local
sharding: false
external: true
asserts:
- equal:
path: spec.replsets[0].expose.enabled
value: true
documentIndex: 0
- equal:
path: spec.replsets[0].expose.type
value: LoadBalancer
documentIndex: 0
- equal:
path: spec.replsets[0].expose.externalTrafficPolicy
value: Local
documentIndex: 0
###########################
# Sharded Cluster Mode #
###########################