Немного предисловия. Захотелось попробовать крайние версии PostgreSQL для работы 1С. Были испробованы решения на Consul, pgautofailover и etcd. Из всех найденных решений, успешно заработало только конфигурация с etcd. Важный момент, который не освещается ни где — это использование как минимум трех нод в реализации конфигурации. В данной статья описано простое решение, без тюнига и дополнительных плюшек, так как далее все это будет упаковано в docker контейнеры. Стек следующий — Oracle Linux 9, postgres-pro-1c-17, etcd, haproxy, keepalived. В статье я максимально упросил составление конфигураций и немного скудно добавил описание, так как важно собрать кластер, а уже потом тюнить и выяснять, что это за параметры использовались (имхо) Назовем его rc0.1 Дорастем и до релиза, после проверки материала )
Поехали!
Подготовка системы
Так как я использую в своей лаборатории исключительно образы minimal, приходиться готовить систему перед началом работ. Небольшие модификации и установка необходимого ПО.
Установка необходимого ПО и переменных окружения
Необходимые утилиты и репозитории для установки patroni, подтюним ВМ и пропишем соответствие IP адресов и имен хостов, так как на ДНС надежды нет ) В моем примере ноды имеют следующее сопоставление — node01 — 10.10.88.10, node02 — 10.10.88.20, node03 — 10.10.88.30. Выполняется на всех хостах кластера
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
yum update -y yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-`rpm -E %{rhel}`-x86_64/pgdg-redhat-repo-latest.noarch.rpm sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm yum install tar wget yum-utils -y yum-config-manager --disable pgdg1{2,3,4,5,6} timedatectl set-timezone Europe/Moscow echo 'PATRONICTL_CONFIG_FILE=/etc/patroni/patroni.yml' >> /etc/environment echo 'export PATH=/var/lib/pgpro/1c-17/data/:$PATH' >> /etc/profile.d/patroni.sh cat <<EOF >> /etc/sysctl.conf vm.overcommit_memory=2 vm.overcommit_ratio = 70 vm.nr_hugepages=2048 EOF sysctl -w vm.nr_hugepages=2048 sysctl -p cat <<EOF >> /etc/security/limits.conf @postgres soft nofile 4096 @postgres hard nofile 65536 @postgres soft nproc 16384 @postgres soft stack 10240 EOF NODE01=10.10.88.10 NODE02=10.10.88.20 NODE03=10.10.88.30 cat <<EOF | sudo tee /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 #::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 10.10.88.10 node01 10.10.88.20 node02 10.10.88.30 node03 EOF hostnamectl set-hostname node01 |
Отключение SELinix и Firewalld
Для тестового стенда это приемлемо, для своего прода порты можно найти необходимые порты для сетевого взаимодействия
1 2 3 4 5 6 |
chkconfig firewalld off setenforce 0 sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config reboot |
Установка PostgresSQL Pro 17
1 2 3 4 5 6 |
wget https://repo.postgrespro.ru/1c/1c-17/keys/pgpro-repo-add.sh sh pgpro-repo-add.sh yum -y --disablerepo="pgdg17" --enablerepo=postgresql-1c-17 install postgrespro-1c-17 sudo systemctl disable --now postgrespro-1c-17.service |
Установка ETCD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
ETCD_RELEASE=$(curl -s https://api.github.com/repos/etcd-io/etcd/releases/latest | grep tag_name | cut -d '"' -f 4) echo $ETCD_RELEASE wget https://github.com/etcd-io/etcd/releases/download/${ETCD_RELEASE}/etcd-${ETCD_RELEASE}-linux-amd64.tar.gz sudo groupadd --system etcd sudo useradd -s /sbin/nologin --system -g etcd etcd sudo mkdir -p /var/lib/etcd/ sudo mkdir /etc/etcd sudo chown -R etcd:etcd /var/lib/etcd/ sudo chmod -R 700 /var/lib/etcd/ tar xvf etcd-${ETCD_RELEASE}-linux-amd64.tar.gz cd etcd-${ETCD_RELEASE}-linux-amd64/ sudo mv etcd* /usr/local/bin |
Создание конфигурации etcd для node01
Зададим переменные ETCD_NAME, INT_NAME, ETCD_HOST_IP. Данная процедура описана в официальной документации. Обратить внимание на имя ноды (для каждой свое) и сетевой интерфейс с системе
1 2 3 4 5 6 |
ETCD_NAME=node01 INT_NAME="eth0" ETCD_HOST_IP=$(ip addr show $INT_NAME | grep "inet\b" | awk '{print $2}' | cut -d/ -f1) NODE_IP=$(ip addr show $INT_NAME | grep "inet\b" | awk '{print $2}' | cut -d/ -f1) |
Настроем скрипт запуска для systemd для node01
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
cat <<EOF | sudo tee /etc/systemd/system/etcd.service [Unit] Description=etcd service Documentation=https://github.com/etcd-io/etcd [Service] Type=notify User=etcd Restart=always RestartSec=20s ExecStart=/usr/local/bin/etcd \\ --name ${ETCD_NAME} \\ --data-dir=/var/lib/etcd \\ --initial-advertise-peer-urls http://${ETCD_HOST_IP}:2380 \\ --listen-peer-urls http://${ETCD_HOST_IP}:2380 \\ --listen-client-urls http://${ETCD_HOST_IP}:2379,http://127.0.0.1:2379 \\ --advertise-client-urls http://${ETCD_HOST_IP}:2379 \\ --initial-cluster-token etcd-cluster-0 \\ --initial-cluster node01=http://node01:2380,node02=http://node02:2380,node03=http://node03:2380 \\ --enable-v2=true \\ --initial-cluster-state new \ [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable etcd sudo systemctl start etcd |
Далее необходимо проинсталлировать etcd на все ноды кластера и выполним проверку. Важно для каждой ноды задавать верную переменную ETCD_NAME
1 2 3 4 5 6 |
etcdctl member list 169f4bd9b60f5251, started, node03, http://node03:2380, http://10.10.88.30:2379, false 74a4806a9146683a, started, node02, http://node02:2380, http://10.10.88.20:2379, false f3cf9c5471a8d8fd, started, node01, http://node01:2380, http://10.10.88.10:2379, false |
1 2 3 4 5 6 7 8 9 10 11 |
ETCDCTL_API=3 etcdctl endpoint status --cluster -w table +-------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | +-------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | http://10.10.88.30:2379 | 169f4bd9b60f5251 | 3.5.17 | 20 kB | false | false | 3 | 11 | 11 | | | http://10.10.88.20:2379 | 74a4806a9146683a | 3.5.17 | 20 kB | true | false | 3 | 11 | 11 | | | http://10.10.88.10:2379 | f3cf9c5471a8d8fd | 3.5.17 | 20 kB | false | false | 3 | 11 | 11 | | +-------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ |
Все ноды успешно подключены и выбран лидер в кластере.
Установка Partoni
1 2 3 4 5 6 7 8 9 10 11 12 13 |
sudo yum -y install patroni python3 python3-devel python3-pip gcc sudo mkdir /etc/patroni sudo chown -R postgres:postgres /etc/patroni/ sudo touch /etc/patroni/patroni.yml sudo ln -s /usr/bin/python3 /usr/bin/python sudo ln -s /usr/bin/pip3 /usr/bin/pip sudo -H pip install --upgrade testresources sudo -H pip install --upgrade setuptools pip install psycopg2 pip install python-etcd |
Создание файла конфигурации patroni node01
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
cat <<EOF | sudo tee /etc/patroni/patroni.yml scope: PGCL01 # must be the SAME on all cluster nodes namespace: /cluster/ # must be the SAME on all cluster nodes name: postgres_node01 # CHANGE must be the UNIQUE on all cluster nodes restapi: listen: ${ETCD_HOST_IP}:8008 # node IP address connect_address: ${ETCD_HOST_IP}:8008 # node IP address etcd: hosts: node01:2379,node02:2379,node03:2379 # Address all node cluster # this section (bootstrap) will be written into Etcd:/<namespace>/<scope>/config after initializing new cluster # and all other cluster members will use it as a global configuration bootstrap: dcs: ttl: 100 loop_wait: 10 retry_timeout: 10 maximum_lag_on_failover: 1048576 postgresql: use_pg_rewind: true use_slots: true parameters: wal_level: replica hot_standby: "on" wal_keep_segments: 128 max_wal_senders: 5 max_replication_slots: 5 checkpoint_timeout: 30 initdb: - encoding: UTF8 - data-checksums - locale: ru_RU.UTF-8 - tune: 1c # CHANGE init pg_hba.conf must contain all IP addresses in the cluster pg_hba: - host replication postgres ::1/128 md5 - host replication postgres 127.0.0.1/8 md5 - host replication postgres 10.10.88.10/32 md5 - host replication postgres 10.10.88.20/32 md5 - host replication postgres 10.10.88.30/32 md5 - host all all 0.0.0.0/0 md5 users: admin: password: admin options: - createrole - createdb postgresql: listen: 0.0.0.0:5432 # CHANGE current node address connect_address: ${ETCD_HOST_IP}:5432 # CHANGE current node address data_dir: /var/lib/pgpro/1c-17/data bin_dir: /opt/pgpro/1c-17/bin pgpass: /tmp/pgpass authentication: replication: username: postgres password: postgres superuser: username: postgres password: postgres create_replica_methods: basebackup: checkpoint: 'fast' parameters: unix_socket_directories: '.' tags: nofailover: false noloadbalance: false clonefrom: false nosync: false EOF |
Настроим скрипт запуска для systemd для node01
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
cat <<EOF | sudo tee /etc/systemd/system/patroni.service [Unit] Description=Runners to orchestrate a high-availability PostgreSQL After=syslog.target network.target [Service] Type=simple User=postgres Group=postgres ExecStart=/usr/bin/patroni /etc/patroni/patroni.yml KillMode=process TimeoutSec=30 Restart=no [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable patroni systemctl start patroni |
Проверка состояния кластера
1 2 3 4 5 6 7 8 9 10 |
patronictl -c /etc/patroni/patroni.yml list + Cluster: PGCL (7463098892943664400) -------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +--------+-------------+---------+-----------+----+-----------+ | node01 | 10.10.88.10 | Replica | streaming | 4 | 0 | | node02 | 10.10.88.20 | Replica | streaming | 4 | 0 | | node03 | 10.10.88.30 | Leader | running | 4 | | +--------+-------------+---------+-----------+----+-----------+ |
Установка и настройка HAProxy
1 2 3 |
yum -y install haproxy |
Настройка фала журналирования для HAProxy
Разрешим следующие параметры в файле /etc/rsyslog.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# for parameters see http://www.rsyslog.com/doc/imudp.html module(load="imudp") # needs to be done just once input(type="imudp" port="514") # Provides TCP syslog reception # for parameters see http://www.rsyslog.com/doc/imtcp.html module(load="imtcp") # needs to be done just once input(type="imtcp" port="514") # Log HAproxy local2.notice /var/log/haproxy.log |
1 2 3 |
service rsyslog restart |
Конфигурационный файл HAProxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
cat <<EOF | sudo tee /etc/haproxy/haproxy.cfg global log 127.0.0.1 local2 maxconn 100 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid user haproxy group haproxy daemon stats socket /var/lib/haproxy/stats defaults log global option dontlognull option dontlog-normal mode tcp retries 2 timeout client 30m timeout connect 4s timeout server 30m timeout check 5s listen stats mode http bind *:7000 stats enable stats uri / listen primary bind *:5000 option httpchk /primary http-check expect status 200 default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions server node01 node01:5432 maxconn 100 check port 8008 server node02 node02:5432 maxconn 100 check port 8008 server node03 node03:5432 maxconn 100 check port 8008 listen standbys balance roundrobin bind *:5001 option httpchk /replica http-check expect status 200 default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions server node01 node01:5432 maxconn 100 check port 8008 server node02 node02:5432 maxconn 100 check port 8008 server node03 node03:5432 maxconn 100 check port 8008 EOF |
Установка keepalived
1 2 3 |
yum -y install keepalived |
Поддержка виртуального IP адреса
1 2 3 4 |
echo net.ipv4.ip_nonlocal_bind=1 >> /etc/sysctl.conf sysctl -p |
Скрипт проверки доступности haproxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
cat <<EOF | sudo tee /usr/local/sbin/pgstatus.sh #!/bin/bash PARTONI_API_PORT='8008' PATRONI_API_HOST='localhost' killall -0 haproxy HAPROXY_STATUS=$? PATRONI_HTTP_RETURN_CODE=$(curl --connect-timeout 5 --max-time 5 --write-out '%{http_code}' --silent --output /dev/null localhost:8008) if [ $HAPROXY_STATUS != 0 ] || [ $PATRONI_HTTP_RETURN_CODE != '200' ]; then exit 1 fi EOF |
1 2 3 |
chmod 755 /usr/local/sbin/pgstatus.sh |
Файл конфигурации keepalived.conf для node01
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
cat <<EOF | sudo tee /etc/keepalived/keepalived.conf global_defs { router_id node01 } vrrp_script chk_haproxy { script "/usr/local/sbin/pgstatus.sh" # timeout set to 7s to match inscript curl timeout timeout 7 interval 1 weight -20 fall 2 rise 2 } vrrp_instance node01 { interface eth0 state BACKUP virtual_router_id 150 priority 100 authentication { auth_type PASS auth_pass 6cfe7eef } track_script { chk_haproxy weight 20 } virtual_ipaddress { 10.10.88.100/24 dev eth0 } } EOF |
Настройка фала журналирования для keepalived
1 2 3 4 5 |
cat <<EOF | sudo tee /etc/rsyslog.d/keepalived.conf :programname, startswith, "Keepalived" -/var/log/keepalived.log EOF |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
cat <<EOF | sudo tee /etc/logrotate.d/keepalived "/var/log/keepalived.log" { compress compresscmd /usr/bin/bzip2 compressext .bz2 daily dateext delaycompress missingok nocopytruncate notifempty sharedscripts rotate 14 } EOF |
1 2 3 |
service rsyslog restart |
Запуск и добавление в автозагрузку
1 2 3 4 |
systemctl enable keepalived service keepalived start |
Добавление БД в кластер 1С Предприятие
Немного полезных команд
Состояние кластера etcd
1 2 3 4 |
etcdctl member list ETCDCTL_API=3 etcdctl endpoint status --cluster -w table |
Состояние кластера patroni
1 2 3 |
patronictl -c /etc/patroni/patroni.yml list |
Реинициализация ноды
1 2 3 |
patronictl -c /etc/patroni/patroni.yml reinit PGCL node02 |
Переключение активной ноды
1 2 3 |
patronictl switchover |
Рестарт ноды
1 2 3 4 |
patronictl restart patronictl -c /etc/patroni/patroni.yml restart PGCL node01 |
Редактирование конфигурации
1 2 3 4 |
patronictl edit-config patronictl -c /etc/patroni/patroni.yml edit-config |
Применение конфигурации
1 2 3 |
patronictl -c /etc/patroni/patroni.yml reload PGCL |