first commit

This commit is contained in:
ace 2023-08-11 13:51:51 +03:00
commit a0b2e87dd0
Signed by: ace
GPG Key ID: 2C08973DD37A76FD
10 changed files with 398 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.galaxy_install_info
roles

38
README.md Normal file
View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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 }}"