Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions build/configs/patroni.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ kubernetes:
app: ${PATRONI_CLUSTER_NAME}
role_label: pgtype
scope_label: app
pod_ip: ${LISTEN_ADDR}
pod_ip: ${POD_DNS_NAME}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh, I'm not sure about this change

I've checked all patroni-related projects (spilo, postgres-operator from Zalando), and they are using pod status.podIP everywhere:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my kubernetes environment, "pod ip" is like fd07:b51a:cc66:a::17f 192.168.194.10

How do you think it would work?

For instance, connect_address: ${LISTEN_ADDR}:8008 becomes connect_address: fd07:b51a:cc66:a::17f 192.168.194.10:8008 which is definitely not workable.


Both ChatGPT and Claude suggest stable pod dns names should be used for Patroni on Kubernetes.
E.g. https://chatgpt.com/share/68ecb326-44e4-800f-a125-a7a8cae96bd0

Copy link
Member

@mrMigles mrMigles Oct 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vlsi
first of all, could you please provide environment/confirmation when you have migrated previous version of podIp based version to headless dns name? Have you performed integrations tests there?

Then, what I'm worried about and need to double check: you've modified kubernetes.pod_ip that with use_endpoints: true is used for preparing subsets.addresses.ip on endpoints that must be IP I suppose.
https://github.com/patroni/patroni/blob/v4.1.0/patroni/dcs/kubernetes.py#L1122
That's my HL analysis and I'm sure that should work with dns names and has IP resolving, but that's why I cannot apply it w/o confirmation of correct upgrade case.
Please correct me If I'm wrong

postgresql:
authentication:
replication:
Expand All @@ -67,17 +67,17 @@ postgresql:
on_role_change: /setup_endpoint_callback.py
on_start: /setup_endpoint_callback.py
on_stop: /setup_endpoint_callback.py
connect_address: ${LISTEN_ADDR}:5432
connect_address: ${POD_DNS_NAME}:5432
data_dir: /var/lib/pgsql/data/postgresql_${NODE_NAME}
listen: '0.0.0.0, ::0:5432'
listen: '*:5432'
parameters:
unix_socket_directories: /var/run/postgresql, /tmp
pgpass: /tmp/pgpass0
restapi:
connect_address: ${LISTEN_ADDR}:8008
listen: ${LISTEN_ADDR}:8008
connect_address: ${POD_DNS_NAME}:8008
listen: '*:8008'
tags:
clonefrom: false
nofailover: ${DR_MODE}
noloadbalance: false
nosync: false
nosync: false
2 changes: 1 addition & 1 deletion charts/patroni-services/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ connectionPooler:
'*': "host=pg-patroni-direct port=5432"
pgbouncer:
listen_port: '6432'
listen_addr: '0.0.0.0'
listen_addr: '*'
auth_type: 'md5'
auth_file: '/etc/pgbouncer/userlist.txt'
auth_user: 'pgbouncer'
Expand Down
2 changes: 1 addition & 1 deletion docs/public/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@ For more information on how to do the Major Upgrade of PostgreSQL, please, follo
```yaml
pgbouncer:
listen_port: '6432'
listen_addr: '0.0.0.0'
listen_addr: '*'
auth_type: 'md5'
auth_file: '/etc/pgbouncer/userlist.txt'
auth_user: 'pgbouncer'
Expand Down
19 changes: 18 additions & 1 deletion pkg/deployment/patroni.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,23 @@ func NewPatroniStatefulset(cr *patroniv1.PatroniCore, deploymentIdx int, cluster
},
},
},
{
Name: "POD_NAME",
ValueFrom: &corev1.EnvVarSource{
FieldRef: &corev1.ObjectFieldSelector{
APIVersion: "v1",
FieldPath: "metadata.name",
},
},
},
{
Name: "HEADLESS_SERVICE",
Value: "patroni-headless",
},
{
Name: "POD_DNS_NAME",
Value: "$(POD_NAME).$(HEADLESS_SERVICE).$(POD_NAMESPACE).svc.cluster.local",
},
{
Name: "PG_RESOURCES_LIMIT_MEM",
ValueFrom: &corev1.EnvVarSource{
Expand Down Expand Up @@ -309,7 +326,7 @@ func NewPatroniStatefulset(cr *patroniv1.PatroniCore, deploymentIdx int, cluster
DNSPolicy: corev1.DNSClusterFirst,
},
},
ServiceName: "backrest-headless",
ServiceName: "patroni-headless",
PodManagementPolicy: appsv1.OrderedReadyPodManagement,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{Type: appsv1.RollingUpdateStatefulSetStrategyType},
RevisionHistoryLimit: ptr.To[int32](10),
Expand Down
24 changes: 24 additions & 0 deletions pkg/deployment/pgbackrest.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,30 @@ func GetBackrestHeadless() *corev1.Service {
}
}

func GetPatroniHeadless(clusterName string) *corev1.Service {
labels := map[string]string{"app": clusterName}
ports := []corev1.ServicePort{
{Name: "postgresql", Port: 5432},
{Name: "patroni-api", Port: 8008},
}
return &corev1.Service{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Service",
},
ObjectMeta: metav1.ObjectMeta{
Name: "patroni-headless",
Namespace: util.GetNameSpace(),
},

Spec: corev1.ServiceSpec{
Selector: labels,
Ports: ports,
ClusterIP: "None",
},
}
}

func getPgBackRestSettings(pgBackrestSpec *v1.PgBackRest, isStandby bool) string {
var listSettings []string
listSettings = append(listSettings, "[global]")
Expand Down
8 changes: 8 additions & 0 deletions pkg/reconciler/patroni.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,14 @@ func (r *PatroniReconciler) processPatroniServices(cr *v1.PatroniCore, patroniSp
}
}
}

// Create patroni headless service for DNS-based pod discovery
patroniHeadless := deployment.GetPatroniHeadless(r.cluster.ClusterName)
if err := r.helper.ResourceManager.CreateOrUpdateService(patroniHeadless); err != nil {
logger.Error(fmt.Sprintf("Cannot create service %s", patroniHeadless.Name), zap.Error(err))
return err
}

return nil
}

Expand Down