278 lines
7.4 KiB
YAML
278 lines
7.4 KiB
YAML
---
|
|
# PostgreSQL High Availability with Patroni + etcd
|
|
# Run on postgres group hosts
|
|
#
|
|
# Usage:
|
|
# # Initialize first node (with existing data):
|
|
# ansible-playbook -i inventory.ini playbooks/postgres-ha.yml --limit postgres-01 -e "patroni_bootstrap=true"
|
|
#
|
|
# # Join additional nodes:
|
|
# ansible-playbook -i inventory.ini playbooks/postgres-ha.yml --limit postgres-02
|
|
#
|
|
# # All nodes at once (after bootstrap):
|
|
# ansible-playbook -i inventory.ini playbooks/postgres-ha.yml --limit postgres
|
|
|
|
- name: Configure PostgreSQL HA with Patroni + etcd
|
|
hosts: postgres
|
|
become: true
|
|
vars:
|
|
patroni_superuser_password: "{{ lookup('env', 'PATRONI_SUPERUSER_PASSWORD') | default('changeme', true) }}"
|
|
patroni_replicator_password: "{{ lookup('env', 'PATRONI_REPLICATOR_PASSWORD') | default('changeme', true) }}"
|
|
patroni_bootstrap: false
|
|
etcd_version: "3.5.17"
|
|
|
|
tasks:
|
|
# ============================================
|
|
# ETCD SETUP
|
|
# ============================================
|
|
- name: Check if etcd is installed
|
|
stat:
|
|
path: /usr/local/bin/etcd
|
|
register: etcd_binary
|
|
|
|
- name: Download etcd
|
|
get_url:
|
|
url: "https://github.com/etcd-io/etcd/releases/download/v{{ etcd_version }}/etcd-v{{ etcd_version }}-linux-amd64.tar.gz"
|
|
dest: /tmp/etcd.tar.gz
|
|
mode: '0644'
|
|
when: not etcd_binary.stat.exists
|
|
|
|
- name: Extract etcd
|
|
unarchive:
|
|
src: /tmp/etcd.tar.gz
|
|
dest: /tmp
|
|
remote_src: true
|
|
when: not etcd_binary.stat.exists
|
|
|
|
- name: Install etcd binaries
|
|
copy:
|
|
src: "/tmp/etcd-v{{ etcd_version }}-linux-amd64/{{ item }}"
|
|
dest: "/usr/local/bin/{{ item }}"
|
|
mode: '0755'
|
|
remote_src: true
|
|
loop:
|
|
- etcd
|
|
- etcdctl
|
|
- etcdutl
|
|
when: not etcd_binary.stat.exists
|
|
|
|
- name: Create symlinks for etcd binaries
|
|
file:
|
|
src: "/usr/local/bin/{{ item }}"
|
|
dest: "/usr/bin/{{ item }}"
|
|
state: link
|
|
loop:
|
|
- etcd
|
|
- etcdctl
|
|
- etcdutl
|
|
|
|
- name: Create etcd user
|
|
user:
|
|
name: etcd
|
|
system: true
|
|
shell: /sbin/nologin
|
|
home: /var/lib/etcd
|
|
create_home: true
|
|
|
|
- name: Create etcd config directory
|
|
file:
|
|
path: /etc/etcd
|
|
state: directory
|
|
mode: '0755'
|
|
|
|
- name: Create etcd data directory
|
|
file:
|
|
path: /var/lib/etcd
|
|
state: directory
|
|
owner: etcd
|
|
group: etcd
|
|
mode: '0700'
|
|
|
|
- name: Deploy etcd configuration
|
|
template:
|
|
src: ../templates/etcd.conf.j2
|
|
dest: /etc/etcd/etcd.conf
|
|
mode: '0644'
|
|
notify: restart etcd
|
|
|
|
- name: Deploy etcd systemd service
|
|
template:
|
|
src: ../templates/etcd.service.j2
|
|
dest: /etc/systemd/system/etcd.service
|
|
mode: '0644'
|
|
notify:
|
|
- reload systemd
|
|
- restart etcd
|
|
|
|
- name: Enable and start etcd
|
|
systemd:
|
|
name: etcd
|
|
state: started
|
|
enabled: true
|
|
daemon_reload: true
|
|
|
|
- name: Wait for etcd to be healthy
|
|
command: etcdctl endpoint health --endpoints=http://127.0.0.1:2379
|
|
register: etcd_health
|
|
until: etcd_health.rc == 0
|
|
retries: 30
|
|
delay: 2
|
|
changed_when: false
|
|
|
|
# ============================================
|
|
# POSTGRESQL SETUP
|
|
# ============================================
|
|
- name: Install PostgreSQL
|
|
community.general.pacman:
|
|
name: postgresql
|
|
state: present
|
|
|
|
# ============================================
|
|
# PATRONI SETUP
|
|
# ============================================
|
|
- name: Install Patroni dependencies
|
|
community.general.pacman:
|
|
name:
|
|
- python
|
|
- python-pip
|
|
- python-psycopg2
|
|
- python-yaml
|
|
- python-urllib3
|
|
- python-certifi
|
|
- python-virtualenv
|
|
state: present
|
|
|
|
- name: Create Patroni virtual environment
|
|
command: python -m venv /opt/patroni
|
|
args:
|
|
creates: /opt/patroni/bin/python
|
|
|
|
- name: Install Patroni in virtual environment
|
|
pip:
|
|
name:
|
|
- patroni[etcd3]
|
|
- psycopg2-binary
|
|
state: present
|
|
virtualenv: /opt/patroni
|
|
|
|
- name: Create PostgreSQL run directory
|
|
file:
|
|
path: /run/postgresql
|
|
state: directory
|
|
owner: postgres
|
|
group: postgres
|
|
mode: '0755'
|
|
|
|
- name: Create tmpfiles config for postgresql run directory
|
|
copy:
|
|
content: "d /run/postgresql 0755 postgres postgres -"
|
|
dest: /etc/tmpfiles.d/postgresql.conf
|
|
mode: '0644'
|
|
|
|
- name: Create patroni symlink
|
|
file:
|
|
src: /opt/patroni/bin/patroni
|
|
dest: /usr/local/bin/patroni
|
|
state: link
|
|
|
|
- name: Create patroni config directory
|
|
file:
|
|
path: /etc/patroni
|
|
state: directory
|
|
mode: '0755'
|
|
|
|
- name: Stop PostgreSQL service (Patroni will manage it)
|
|
systemd:
|
|
name: postgresql
|
|
state: stopped
|
|
enabled: false
|
|
ignore_errors: true
|
|
|
|
# For bootstrap node with existing data
|
|
- name: Prepare existing data directory for Patroni takeover
|
|
block:
|
|
- name: Ensure postgres owns data directory
|
|
file:
|
|
path: /var/lib/postgres/data
|
|
owner: postgres
|
|
group: postgres
|
|
recurse: true
|
|
|
|
- name: Create replicator role
|
|
become_user: postgres
|
|
command: >
|
|
psql -c "DO $$
|
|
BEGIN
|
|
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'replicator') THEN
|
|
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD '{{ patroni_replicator_password }}';
|
|
END IF;
|
|
END $$;"
|
|
when: patroni_bootstrap | bool
|
|
ignore_errors: true
|
|
|
|
- name: Set postgres superuser password
|
|
become_user: postgres
|
|
command: psql -c "ALTER USER postgres WITH PASSWORD '{{ patroni_superuser_password }}';"
|
|
when: patroni_bootstrap | bool
|
|
ignore_errors: true
|
|
when: patroni_bootstrap | bool
|
|
|
|
- name: Deploy Patroni configuration
|
|
template:
|
|
src: ../templates/patroni.yml.j2
|
|
dest: /etc/patroni/patroni.yml
|
|
owner: postgres
|
|
group: postgres
|
|
mode: '0600'
|
|
notify: restart patroni
|
|
|
|
- name: Create .pgpass file for postgres user
|
|
copy:
|
|
content: |
|
|
*:*:*:postgres:{{ patroni_superuser_password }}
|
|
*:*:*:replicator:{{ patroni_replicator_password }}
|
|
dest: /var/lib/postgres/.pgpass
|
|
owner: postgres
|
|
group: postgres
|
|
mode: '0600'
|
|
|
|
- name: Deploy Patroni systemd service
|
|
template:
|
|
src: ../templates/patroni.service.j2
|
|
dest: /etc/systemd/system/patroni.service
|
|
mode: '0644'
|
|
notify:
|
|
- reload systemd
|
|
- restart patroni
|
|
|
|
- name: Enable and start Patroni
|
|
systemd:
|
|
name: patroni
|
|
state: started
|
|
enabled: true
|
|
daemon_reload: true
|
|
|
|
- name: Wait for Patroni to be healthy
|
|
uri:
|
|
url: "http://{{ nebula_ip }}:8008/health"
|
|
status_code: 200
|
|
register: patroni_health
|
|
until: patroni_health.status == 200
|
|
retries: 30
|
|
delay: 5
|
|
|
|
handlers:
|
|
- name: reload systemd
|
|
systemd:
|
|
daemon_reload: true
|
|
|
|
- name: restart etcd
|
|
systemd:
|
|
name: etcd
|
|
state: restarted
|
|
|
|
- name: restart patroni
|
|
systemd:
|
|
name: patroni
|
|
state: restarted
|