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
4 changes: 2 additions & 2 deletions automation/roles/upgrade/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ The upgrade is supported starting from PostgreSQL 9.3 for in-place upgrade metho

Specify the current (old) version of PostgreSQL in the `pg_old_version` variable and target version of PostgreSQL for the upgrade in the `pg_new_version` variable.

For the blue-green method, deploy the target cluster in standby cluster mode. Ensure that the target cluster has the same number of PostgreSQL servers as the source cluster. This is important during switchover when configuring PgBouncer to redirect traffic to the target cluster (if PgBouncer is installed).
For the blue-green method, deploy the target cluster in standby cluster mode. See `patroni_standby_cluster` variable.

## Recommendations

Expand Down Expand Up @@ -549,7 +549,7 @@ Note: for blue-green upgrade method (`pg_logical_switchover` playbook)
- Prepare PgBouncer configuration to redirect primary traffic
- Note: replace the 'host=' option value with the target primary host address
- Prepare PgBouncer configuration to redirect replica traffic
- Note: replace the 'host=' option value with the target secondary hosts addresses
- Note: replace the 'host=' option value with target hosts addresses using deterministic mapping by replica index; if target has no replicas, use target primary
- Temporarily disable TLS from PgBouncer to Postgres during redirect
- Note: if self-signed certificates are used (tls_cert_generate = true), target cluster uses a different CA, so PgBouncer on source may fail to verify TLS when connecting to Postgres on target
- **Increase all sequence values**
Expand Down
23 changes: 14 additions & 9 deletions automation/roles/upgrade/tasks/pgbouncer_redirect.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
---
# Prepare PgBouncer config to redirect traffic to the target cluster (blue-green deployment method)

- name: "Pre-Check error. Fail if replica counts mismatch between source and target clusters"
ansible.builtin.fail:
- name: "Pre-check notice. Source and target replica counts differ"
ansible.builtin.debug:
msg: >-
Replica count mismatch:
source secondary={{ (groups.get('source_secondary', []) | length) }},
target secondary={{ (groups.get('secondary', []) | length) }}
when:
- inventory_hostname in groups.get('source_primary', [])
- (groups.get('secondary', []) | length) != (groups.get('source_secondary', []) | length)
Replica count mismatch detected:
source secondary={{ groups.get('source_secondary', []) | length }},
target secondary={{ groups.get('secondary', []) | length }}.
PgBouncer redirection will use deterministic modulo mapping across target replicas,
and fallback to target primary when target replicas are absent.
when: (groups.get('secondary', []) | length) != (groups.get('source_secondary', []) | length)
run_once: true

- name: Prepare PgBouncer configuration to redirect primary traffic
ansible.builtin.replace:
Expand All @@ -30,6 +31,9 @@
}}
when: inventory_hostname in groups.get('source_primary', [])

# PgBouncer traffic redirection supports different numbers of source and target replicas:
# source replicas are mapped to target replicas deterministically by index (modulo target replica count).
# If the target cluster has no replicas, replica traffic is redirected to the target primary.
- name: Prepare PgBouncer configuration to redirect replica traffic
ansible.builtin.replace:
path: "{{ pgbouncer_conf_dir }}/pgbouncer{{ '-%d' % (idx + 1) if idx > 0 else '' }}.ini"
Expand All @@ -42,8 +46,9 @@
vars:
source_secondaries: "{{ groups.get('source_secondary', []) | sort }}"
target_secondaries: "{{ groups.get('secondary', []) | sort }}"
target_hosts_for_replicas: "{{ target_secondaries if (target_secondaries | length) > 0 else groups.get('primary', []) }}"
source_idx: "{{ source_secondaries.index(inventory_hostname) }}"
target_secondary_host: "{{ target_secondaries[source_idx] }}"
target_secondary_host: "{{ target_hosts_for_replicas[(source_idx | int) % (target_hosts_for_replicas | length)] }}"
target_secondary_host_addr: >-
{{
hostvars[target_secondary_host].patroni_bind_address
Expand Down
Loading