xdev.asia
目標___HTMLTAG_66__HTMLTAG_67___完成本課程後,您將:____HTMLTAG_68__HTMLTAG_69__HTMLTAG_70___使用 Ansible 自動執行 Patroni 叢集部署____HTMLTAG_71__HTMLTAG_7221212112112112121121212121212121213233 級分錄管理配置____HTMLTAG_73__HTMLTAG_74___實作自動化測試____HTMLTAG_75__HTMLTAG_76___將資料庫變更整合到 CI/CD 中____HTMLTAG_77__HTMLTAG_78___使用基礎架構即程式碼原則____HTMLTAG_79__11G_79__1 PostgreSQL 的 Ansible 基礎知識___HTMLTAG_82__HTMLTAG_83___1.1。安裝 Ansible___HTMLTAG_84__CODEBLOCK_0__HTMLTAG_85___1.2。庫存檔案____HTMLTAG_86__CODEBLOCK_1__HTMLTAG_87___1.3。 Ansible 設定___HTMLTAG_88__CODEBLOCK_2__HTMLTAG_89___2。完整的 Patroni 部署手冊___HTMLTAG_90__HTMLTAG_91___2.1。主要劇本___HTMLTAG_92__CODEBLOCK_3__HTMLTAG_93___2.2。變數___HTMLTAG_94__CODEBLOCK_4__HTMLTAG_95___2.3。常見角色___HTMLTAG_96__CODEBLOCK_5__HTMLTAG_97___2.4。 etcd 角色___HTMLTAG_98__CODEBLOCK_6__CODEBLOCK_7__HTMLTAG_99___2.5。 PostgreSQL 角色___HTMLTAG_100__CODEBLOCK_8__HTMLTAG_101___2.6。守護者角色
# roles/patroni/tasks/main.yml
-
name: Install Python dependencies pip: name: - patroni[etcd] - psycopg2-binary - python-etcd state: present executable: pip3
-
name: Create Patroni configuration directory file: path: /etc/patroni state: directory owner: postgres group: postgres mode: '0755'
-
name: Template Patroni configuration template: src: patroni.yml.j2 dest: /etc/patroni/patroni.yml owner: postgres group: postgres mode: '0600' notify: restart patroni
-
name: Template Patroni systemd service template: src: patroni.service.j2 dest: /etc/systemd/system/patroni.service notify: restart patroni
-
name: Start and enable Patroni systemd: name: patroni state: started enabled: yes daemon_reload: yes
name: Wait for Patroni to be ready wait_for: port: 8008 timeout: 60
{# roles/patroni/templates/patroni.yml.j2 #} scope: {{ patroni_scope }} name: {{ ansible_hostname }}restapi: listen: {{ ansible_default_ipv4.address }}:8008 connect_address: {{ ansible_default_ipv4.address }}:8008
etcd: hosts: {% for node in cluster_nodes %}{{ node.ip }}:2379{% if not loop.last %},{% endif %}{% endfor %}
bootstrap: dcs: ttl: 30 loop_wait: 10 retry_timeout: 10 maximum_lag_on_failover: 1048576 postgresql: use_pg_rewind: true use_slots: true parameters: max_connections: 100 shared_buffers: 256MB effective_cache_size: 1GB maintenance_work_mem: 64MB checkpoint_completion_target: 0.9 wal_buffers: 16MB default_statistics_target: 100 random_page_cost: 1.1 effective_io_concurrency: 200 work_mem: 2621kB min_wal_size: 1GB max_wal_size: 4GB max_worker_processes: 4 max_parallel_workers_per_gather: 2 max_parallel_workers: 4 max_parallel_maintenance_workers: 2 wal_level: replica max_wal_senders: 10 max_replication_slots: 10 hot_standby: on archive_mode: on archive_command: 'test ! -f /var/lib/postgresql/wal_archive/%f && cp %p /var/lib/postgresql/wal_archive/%f'
initdb: - encoding: UTF8 - data-checksums
pg_hba: - host replication replicator 0.0.0.0/0 scram-sha-256 - host all all 0.0.0.0/0 scram-sha-256
postgresql: listen: 0.0.0.0:5432 connect_address: {{ ansible_default_ipv4.address }}:5432 data_dir: {{ postgresql_data_dir }} bin_dir: {{ postgresql_bin_dir }} authentication: replication: username: replicator password: {{ replicator_password }} superuser: username: postgres password: {{ postgres_password }}
tags: nofailover: false noloadbalance: false clonefrom: false nosync: false
3。部署___HTMLTAG_104__HTMLTAG_105___3.1。運行劇本___HTMLTAG_106__CODEBLOCK_11__HTMLTAG_107___3.2。驗證部署
# verify.yml
name: Verify Patroni cluster hosts: postgres_cluster tasks:-
name: Check Patroni service systemd: name: patroni state: started register: patroni_status
-
name: Get cluster status command: patronictl -c /etc/patroni/patroni.yml list register: cluster_status changed_when: false
-
name: Display cluster status debug: var: cluster_status.stdout_lines
name: Check PostgreSQL connectivity postgresql_ping: db: postgres login_host: localhost login_user: postgres login_password: "{{ postgres_password }}" become_user: postgres
-
ansible-playbook verify.yml
4。設定管理___HTMLTAG_110__HTMLTAG_111___4.1。動態設定更新___HTMLTAG_112__CODEBLOCK_14__HTMLTAG_113___4.2。備份自動化___HTMLTAG_114__CODEBLOCK_15__HTMLTAG_115___5。測試自動化___HTMLTAG_116__HTMLTAG_117___5.1。用於測試的分子_
# Install Molecule pip3 install molecule molecule-plugins[docker]Initialize Molecule scenario
cd roles/patroni molecule init scenario --driver-name docker
# roles/patroni/molecule/default/molecule.yml
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: pg-node1 image: ubuntu:22.04 pre_build_image: true
- name: pg-node2 image: ubuntu:22.04 pre_build_image: true
name: pg-node3 image: ubuntu:22.04 pre_build_image: true provisioner: name: ansible verifier: name: ansible
# roles/patroni/molecule/default/verify.yml
name: Verify hosts: all tasks:-
name: Check Patroni is running systemd: name: patroni state: started register: result failed_when: result.status.ActiveState != 'active'
name: Check cluster has leader shell: patronictl -c /etc/patroni/patroni.yml list | grep Leader register: leader_check failed_when: leader_check.rc != 0
-
# Run tests
molecule test
5.2。用於驗證的測試基礎設施
pip3 install testinfra
# tests/test_patroni.py import testinfradef test_patroni_service(host): """Test Patroni service is running""" service = host.service("patroni") assert service.is_running assert service.is_enabled
def test_postgresql_port(host): """Test PostgreSQL port is listening""" assert host.socket("tcp://0.0.0.0:5432").is_listening
def test_patroni_rest_api(host): """Test Patroni REST API""" assert host.socket("tcp://0.0.0.0:8008").is_listening
def test_etcd_connectivity(host): """Test etcd cluster health""" cmd = host.run("etcdctl endpoint health") assert cmd.rc == 0 assert "healthy" in cmd.stdout
def test_cluster_has_leader(host): """Test cluster has exactly one leader""" cmd = host.run("patronictl -c /etc/patroni/patroni.yml list") assert cmd.rc == 0 assert cmd.stdout.count("Leader") == 1
def test_replication_lag(host): """Test replication lag is low""" cmd = host.run("sudo -u postgres psql -Atc "SELECT pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) FROM pg_stat_replication;"") if cmd.rc == 0 and cmd.stdout: lag = int(cmd.stdout.strip()) assert lag < 1048576 # < 1MB lag
# Run tests
pytest tests/test_patroni.py -v