mirror of
https://gitea.0xace.cc/ansible-playbooks/patroni.git
synced 2024-11-24 15:56:39 +00:00
first commit
This commit is contained in:
commit
a0b2e87dd0
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.galaxy_install_info
|
||||
roles
|
38
README.md
Normal file
38
README.md
Normal file
@ -0,0 +1,38 @@
|
||||
Deploy Patroni
|
||||
|
||||
## Install ansible and requirements in virtualenv
|
||||
|
||||
mkvirtualenv ansible-7.6.0
|
||||
pip install -r requirements.txt
|
||||
deactivate
|
||||
workon ansible-7.6.0
|
||||
|
||||
## Install roles
|
||||
|
||||
ansible-playbook ansible-roles.yaml
|
||||
|
||||
## Install Patroni
|
||||
|
||||
ansible-playbook -i inventory/hosts patroni.yaml -u almalinux
|
||||
|
||||
## Patroni options example
|
||||
|
||||
patroni_postgresql_dynamic_parameters:
|
||||
postgresql:
|
||||
parameters:
|
||||
max_connections: '2000'
|
||||
|
||||
## Backup options example
|
||||
|
||||
patroni_wal_g_install: true
|
||||
wal_g_config: >-
|
||||
{{
|
||||
{
|
||||
"AWS_ACCESS_KEY_ID": "YOUR_ACCESS_KEY_ID",
|
||||
"AWS_SECRET_ACCESS_KEY": "YOUR_SECRET_ACCESS_KEY",
|
||||
"AWS_ENDPOINT": "https://s3.amazon.com",
|
||||
"WALG_S3_PREFIX": "s3://wal-g/patroni-1",
|
||||
"WALG_LIBSODIUM_KEY": "29b43e2f46adcaf9f0d635d9fe4934e3227b3cbd13e2b19c7b28c16a581cc15c"
|
||||
"AWS_S3_FORCE_PATH_STYLE": "true"
|
||||
}
|
||||
}}
|
6
ansible-roles.yaml
Normal file
6
ansible-roles.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
- hosts: localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Install roles
|
||||
local_action: ansible.builtin.command ansible-galaxy install -r requirements.yaml -p roles
|
||||
|
13
ansible.cfg
Normal file
13
ansible.cfg
Normal file
@ -0,0 +1,13 @@
|
||||
[defaults]
|
||||
timeout = 300
|
||||
jinja2_native = True
|
||||
host_key_checking = False
|
||||
pipelining = True
|
||||
callbacks_enabled = timer, profile_tasks
|
||||
forks = 50
|
||||
roles_path = roles
|
||||
interpreter_python = auto_silent
|
||||
|
||||
[ssh_connection]
|
||||
pipelining = True
|
||||
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null
|
18
inventory/group_vars/all.yaml
Normal file
18
inventory/group_vars/all.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
consul_install_official_repo: false
|
||||
patroni_wal_g_install: false
|
||||
wal_g_config: >-
|
||||
{{
|
||||
{
|
||||
"AWS_ACCESS_KEY_ID": "YOUR_ACCESS_KEY_ID",
|
||||
"AWS_SECRET_ACCESS_KEY": "YOUR_SECRET_ACCESS_KEY",
|
||||
"AWS_ENDPOINT": "https://s3.amazon.com",
|
||||
"WALG_S3_PREFIX": "s3://wal-g/patroni-1",
|
||||
"WALG_LIBSODIUM_KEY": "29b43e2f46adcaf9f0d635d9fe4934e3227b3cbd13e2b19c7b28c16a581cc15c"
|
||||
"AWS_S3_FORCE_PATH_STYLE": "true"
|
||||
}
|
||||
}}
|
||||
|
||||
patroni_postgresql_dynamic_parameters:
|
||||
postgresql:
|
||||
parameters:
|
||||
max_connections: '2000'
|
9
inventory/hosts
Normal file
9
inventory/hosts
Normal file
@ -0,0 +1,9 @@
|
||||
[patroni]
|
||||
patroni-1 ansible_host=192.168.79.37
|
||||
patroni-2 ansible_host=192.168.79.94
|
||||
patroni-3 ansible_host=192.168.79.16
|
||||
|
||||
[consul_server]
|
||||
patroni-1 ansible_host=192.168.79.37
|
||||
patroni-2 ansible_host=192.168.79.94
|
||||
patroni-3 ansible_host=192.168.79.16
|
86
patroni.yaml
Normal file
86
patroni.yaml
Normal file
@ -0,0 +1,86 @@
|
||||
- hosts: localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Print Ansible version
|
||||
debug:
|
||||
msg: "{{ ansible_version }}"
|
||||
|
||||
- hosts: all,!localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- name: Wait 300 seconds
|
||||
ansible.builtin.wait_for_connection:
|
||||
timeout: 300
|
||||
|
||||
- hosts: all,!localhost
|
||||
tasks:
|
||||
- name: Include Patroni vars
|
||||
ansible.builtin.include_vars: "{{ lookup('first_found', params) }}"
|
||||
vars:
|
||||
params:
|
||||
files:
|
||||
- "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_major_version'] }}.yaml"
|
||||
- "{{ ansible_facts['distribution'] }}-{{ ansible_facts['distribution_version'] }}.yaml"
|
||||
- "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_major_version'] }}.yaml"
|
||||
- "{{ ansible_facts['os_family'] }}-{{ ansible_facts['distribution_version'] }}.yaml"
|
||||
- '{{ ansible_distribution }}.yaml'
|
||||
- '{{ ansible_os_family }}.yaml'
|
||||
- patroni.yaml
|
||||
paths:
|
||||
- 'vars'
|
||||
|
||||
- hosts: all,!localhost
|
||||
become: true
|
||||
tasks:
|
||||
- name: Debian based repository
|
||||
when: ansible_facts['os_family'] == "Debian"
|
||||
block:
|
||||
- name: Add repository for Debian
|
||||
copy:
|
||||
dest: /etc/apt/sources.list.d/mirror.0xace.cc.list
|
||||
content: |
|
||||
deb [trusted=yes] https://mirror.0xace.cc/debian/consul/ default all
|
||||
deb [trusted=yes] https://mirror.0xace.cc/debian/custom/ default all
|
||||
|
||||
- name: RHEL based repository
|
||||
when: ansible_facts['os_family'] == "RedHat"
|
||||
block:
|
||||
- name: Add custom 0xace.cc repository for RHEL
|
||||
ansible.builtin.yum_repository:
|
||||
name: "rhel-custom"
|
||||
description: "RHEL custom 0xace.cc repository"
|
||||
file: "mirror.0xace.cc"
|
||||
baseurl: "https://mirror.0xace.cc/rhel/$releasever/custom"
|
||||
gpgcheck: false
|
||||
enabled: true
|
||||
|
||||
- hosts: all,!localhost
|
||||
gather_facts: true
|
||||
become: true
|
||||
tasks:
|
||||
- name: Set hostname
|
||||
ansible.builtin.hostname:
|
||||
name: "{{ inventory_hostname }}"
|
||||
- import_role:
|
||||
name: hosts
|
||||
|
||||
- hosts: all,!localhost
|
||||
gather_facts: true
|
||||
become: true
|
||||
tasks:
|
||||
- import_role:
|
||||
name: consul
|
||||
|
||||
- hosts: patroni
|
||||
gather_facts: true
|
||||
become: true
|
||||
tasks:
|
||||
- import_role:
|
||||
name: patroni
|
||||
- import_role:
|
||||
name: keepalived
|
||||
when: keepalived_vip is defined
|
||||
- import_role:
|
||||
name: haproxy
|
||||
- import_role:
|
||||
name: pgbouncer
|
28
requirements.txt
Normal file
28
requirements.txt
Normal file
@ -0,0 +1,28 @@
|
||||
ansible==7.6.0
|
||||
ansible-core==2.14.7
|
||||
awscli==1.28.0
|
||||
awscli-plugin-endpoint==0.4
|
||||
botocore==1.30.0
|
||||
certifi==2023.5.7
|
||||
cffi==1.15.1
|
||||
charset-normalizer==3.1.0
|
||||
colorama==0.4.4
|
||||
cryptography==41.0.1
|
||||
docutils==0.16
|
||||
hvac==1.1.1
|
||||
idna==3.4
|
||||
Jinja2==3.1.2
|
||||
jmespath==1.0.1
|
||||
MarkupSafe==2.1.3
|
||||
packaging==23.1
|
||||
pyasn1==0.5.0
|
||||
pycparser==2.21
|
||||
pyhcl==0.4.4
|
||||
python-dateutil==2.8.2
|
||||
PyYAML==5.4.1
|
||||
requests==2.31.0
|
||||
resolvelib==0.8.1
|
||||
rsa==4.7.2
|
||||
s3transfer==0.6.1
|
||||
six==1.16.0
|
||||
urllib3==1.26.16
|
49
requirements.yaml
Normal file
49
requirements.yaml
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/podman.git
|
||||
scm: git
|
||||
name: podman
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/docker.git
|
||||
scm: git
|
||||
name: docker
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/hostname.git
|
||||
scm: git
|
||||
name: hostname
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/hosts.git
|
||||
scm: git
|
||||
name: hosts
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/haproxy.git
|
||||
scm: git
|
||||
name: haproxy
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/selinux.git
|
||||
scm: git
|
||||
name: selinux
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/postgresql.git
|
||||
scm: git
|
||||
name: postgresql
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/patroni.git
|
||||
scm: git
|
||||
name: patroni
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/wal-g.git
|
||||
scm: git
|
||||
name: wal-g
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/pgbouncer.git
|
||||
scm: git
|
||||
name: pgbouncer
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/consul.git
|
||||
scm: git
|
||||
name: consul
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/keepalived.git
|
||||
scm: git
|
||||
name: keepalived
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/bird.git
|
||||
scm: git
|
||||
name: bird
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/cacert.git
|
||||
scm: git
|
||||
name: cacert
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/node-exporter.git
|
||||
scm: git
|
||||
name: node-exporter
|
||||
- src: https://gitea.geekhome.org/ansible-galaxy/postgres-exporter.git
|
||||
scm: git
|
||||
name: postgres-exporter
|
149
vars/patroni.yaml
Normal file
149
vars/patroni.yaml
Normal file
@ -0,0 +1,149 @@
|
||||
# pgbouncer configuration
|
||||
pgbouncer_client_tls_key_file: "/etc/patroni/ssl/cert.key"
|
||||
pgbouncer_client_tls_cert_file: "/etc/patroni/ssl/cert.crt"
|
||||
pgbouncer_systemd_user: "postgres"
|
||||
pgbouncer_systemd_group: "postgres"
|
||||
pgbouncer_postgresql_major_version: "{{ patroni_postgresql_major_version }}"
|
||||
pgbouncer_postgresql_superuser_username: "{{ patroni_superuser_username }}"
|
||||
pgbouncer_postgresql_superuser_password: "{{ patroni_superuser_password }}"
|
||||
pgbouncer_auth_hba_file: "{{ patroni_postgresql_data_dir }}/pg_hba.conf"
|
||||
|
||||
# HAProxy configuration
|
||||
haproxy_listen_port:
|
||||
master: 5000
|
||||
replicas: 5001
|
||||
replicas_sync: 5002
|
||||
replicas_async: 5003
|
||||
stats: 9000
|
||||
haproxy_maxconn:
|
||||
global: 100000
|
||||
master: 10000
|
||||
replica: 10000
|
||||
haproxy_timeout:
|
||||
client: "60m"
|
||||
server: "60m"
|
||||
|
||||
haproxy_config_override: |
|
||||
global
|
||||
maxconn {{ haproxy_maxconn.global }}
|
||||
log /dev/log local0
|
||||
log /dev/log local1 notice
|
||||
chroot /var/lib/haproxy
|
||||
stats socket /var/lib/haproxy/stats mode 660 level admin expose-fd listeners
|
||||
stats timeout 30s
|
||||
user haproxy
|
||||
group haproxy
|
||||
daemon
|
||||
|
||||
defaults
|
||||
mode tcp
|
||||
log global
|
||||
retries 2
|
||||
timeout queue 5s
|
||||
timeout connect 5s
|
||||
timeout client {{ haproxy_timeout.client }}
|
||||
timeout server {{ haproxy_timeout.server }}
|
||||
timeout check 15s
|
||||
|
||||
listen stats
|
||||
mode http
|
||||
bind *:{{ haproxy_listen_port.stats }}
|
||||
stats enable
|
||||
stats uri /
|
||||
|
||||
listen master
|
||||
bind *:{{ haproxy_listen_port.master }}
|
||||
maxconn {{ haproxy_maxconn.master }}
|
||||
option tcplog
|
||||
option httpchk OPTIONS /master
|
||||
http-check expect status 200
|
||||
default-server inter 3s fastinter 1s fall 3 rise 4 on-marked-down shutdown-sessions
|
||||
{% for server in groups.patroni %}
|
||||
server {{ server }} {{ server }}:{{ pgbouncer_listen_port }} check port {{ patroni_restapi_listen_port }} check-ssl verify none
|
||||
{% endfor %}
|
||||
|
||||
listen replicas
|
||||
bind *:{{ haproxy_listen_port.replicas }}
|
||||
maxconn {{ haproxy_maxconn.replica }}
|
||||
option tcplog
|
||||
option httpchk OPTIONS /replica
|
||||
balance roundrobin
|
||||
http-check expect status 200
|
||||
default-server inter 3s fastinter 1s fall 3 rise 2 on-marked-down shutdown-sessions
|
||||
{% for server in groups.patroni %}
|
||||
server {{ server }} {{ server }}:{{ pgbouncer_listen_port }} check port {{ patroni_restapi_listen_port }} check-ssl verify none
|
||||
{% endfor %}
|
||||
|
||||
listen replicas_sync
|
||||
bind *:{{ haproxy_listen_port.replicas_sync }}
|
||||
maxconn {{ haproxy_maxconn.replica }}
|
||||
option tcplog
|
||||
option httpchk OPTIONS /sync
|
||||
balance roundrobin
|
||||
http-check expect status 200
|
||||
default-server inter 3s fastinter 1s fall 3 rise 2 on-marked-down shutdown-sessions
|
||||
{% for server in groups.patroni %}
|
||||
server {{ server }} {{ server }}:{{ pgbouncer_listen_port }} check port {{ patroni_restapi_listen_port }} check-ssl verify none
|
||||
{% endfor %}
|
||||
|
||||
listen replicas_async
|
||||
bind *:{{ haproxy_listen_port.replicas_async }}
|
||||
maxconn {{ haproxy_maxconn.replica }}
|
||||
option tcplog
|
||||
option httpchk OPTIONS /async
|
||||
balance roundrobin
|
||||
http-check expect status 200
|
||||
default-server inter 3s fastinter 1s fall 3 rise 2 on-marked-down shutdown-sessions
|
||||
{% for server in groups.patroni %}
|
||||
server {{ server }} {{ server }}:{{ pgbouncer_listen_port }} check port {{ patroni_restapi_listen_port }} check-ssl verify none
|
||||
{% endfor %}
|
||||
|
||||
keepalived_config_override: |
|
||||
global_defs {
|
||||
router_id {{ patroni_cluster_name }}
|
||||
}
|
||||
vrrp_track_process haproxy {
|
||||
process haproxy
|
||||
quorum 1
|
||||
delay 2
|
||||
}
|
||||
vrrp_instance VRRP_1 {
|
||||
state MASTER
|
||||
virtual_router_id {{ keepalived_vip.split('.')[-1][-3:] }}
|
||||
priority {{ ansible_default_ipv4.address.split('.')[-1][-3:] }}
|
||||
interface {{ ansible_default_ipv4.interface }}
|
||||
unicast_src_ip {{ ansible_default_ipv4.address }}
|
||||
unicast_peer {
|
||||
{% for peer in groups.patroni %}
|
||||
{{ peer if peer != ansible_default_ipv4.address }}
|
||||
{% endfor %}
|
||||
}
|
||||
virtual_ipaddress {
|
||||
{{ keepalived_vip }}/32 dev {{ ansible_default_ipv4.interface }}
|
||||
}
|
||||
track_process {
|
||||
haproxy
|
||||
}
|
||||
}
|
||||
|
||||
# Backup and restore options
|
||||
patroni_postgresql_archive_command: "{{ 'http_proxy=' ~ wal_g_http_proxy ~ ' ' if wal_g_http_proxy is defined else '' }}{{ 'https_proxy=' ~ wal_g_https_proxy ~ ' ' if wal_g_https_proxy is defined else 'https_proxy=' ~ wal_g_http_proxy ~ ' ' if wal_g_http_proxy is defined else '' }}{{ wal_g_pg_binary_name ~ ' --config ' ~ wal_g_pg_home_dir ~ '/' ~ wal_g_config_name ~ ' wal-push %p' if patroni_wal_g_install else '' }}"
|
||||
patroni_postgresql_restore_command: "{{ 'http_proxy=' ~ wal_g_http_proxy ~ ' ' if wal_g_http_proxy is defined else '' }}{{ 'https_proxy=' ~ wal_g_https_proxy ~ ' ' if wal_g_https_proxy is defined else 'https_proxy=' ~ wal_g_http_proxy ~ ' ' if wal_g_http_proxy is defined else '' }}{{ wal_g_pg_binary_name ~ ' --config ' ~ wal_g_pg_home_dir ~ '/' ~ wal_g_config_name ~ ' wal-fetch %f %p' if patroni_wal_g_install else '' }}"
|
||||
patroni_cluster_bootstrap_command: "{{ 'http_proxy=' ~ wal_g_http_proxy ~ ' ' if wal_g_http_proxy is defined else '' }}{{ 'https_proxy=' ~ wal_g_https_proxy ~ ' ' if wal_g_https_proxy is defined else 'https_proxy=' ~ wal_g_http_proxy ~ ' ' if wal_g_http_proxy is defined else '' }}{{ wal_g_pg_binary_name ~ ' --config ' ~ wal_g_pg_home_dir ~ '/' ~ wal_g_restore_config_name ~ ' backup-fetch ' ~ patroni_postgresql_data_dir ~ ' ' ~ patroni_wal_g_restore_backup_name }}"
|
||||
# "restore_command" written to recovery.conf when configuring follower (create replica)
|
||||
patroni_cluster_restore_command: "{{ 'http_proxy=' ~ wal_g_http_proxy ~ ' ' if wal_g_http_proxy is defined else '' }}{{ 'https_proxy=' ~ wal_g_https_proxy ~ ' ' if wal_g_https_proxy is defined else 'https_proxy=' ~ wal_g_http_proxy ~ ' ' if wal_g_http_proxy is defined else '' }}{{ wal_g_pg_binary_name ~ ' --config ' ~ wal_g_pg_home_dir ~ '/' ~ wal_g_restore_config_name ~ ' wal-fetch %f %p' if patroni_wal_g_restore_from_backup else '' }}"
|
||||
patroni_wal_g_create_replica_methods:
|
||||
- {option: "command", value: "{{ patroni_cluster_bootstrap_command }}"}
|
||||
- {option: "no_params", value: "True"}
|
||||
patroni_basebackup_create_replica_methods:
|
||||
- {option: "max-rate", value: "1000M"}
|
||||
- {option: "checkpoint", value: "fast"}
|
||||
|
||||
# WAL-G options
|
||||
wal_g_pg: "{{ patroni_wal_g_install }}"
|
||||
wal_g_pg_binary_name: "wal-g-pg"
|
||||
wal_g_config_name: ".walg.json"
|
||||
wal_g_restore_config_name: ".walg-restore.json"
|
||||
wal_g_pg_home_dir: "{{ patroni_postgresql_home_dir }}"
|
||||
wal_g_pg_data_dir: "{{ patroni_postgresql_home_dir }}/{{ patroni_postgresql_major_version }}/{{ patroni_postgresql_cluster_name }}"
|
||||
wal_g_pg_major_version: "{{ patroni_postgresql_major_version }}"
|
Loading…
Reference in New Issue
Block a user