ื‘ื ื™ื™ืช ืืฉื›ื•ืœ PostgreSQL ื–ืžื™ืŸ ื‘ืžื™ื•ื—ื“ ื‘ืืžืฆืขื•ืช Patroni, ื•ื›ื•', HAProxy

ืงืจื” ืฉื‘ื–ืžืŸ ืฉื”ื‘ืขื™ื” ื”ื•ืฆื’ื”, ืœื ื”ื™ื” ืœื™ ืžืกืคื™ืง ื ื™ืกื™ื•ืŸ ืœืคืชื— ื•ืœื”ืฉื™ืง ืืช ื”ืคืชืจื•ืŸ ื”ื–ื” ืœื‘ื“. ื•ืื– ื”ืชื—ืœืชื™ ื‘ื’ื•ื’ืœ.

ืื ื™ ืœื ื™ื•ื“ืข ืžื” ื”ืงืืฅ', ืื‘ืœ ื‘ืคืขื ื”ืžื™ ื™ื•ื“ืข ื›ืžื” ืื ื™ ืžืชืžื•ื“ื“ ืขื ื”ืขื•ื‘ื“ื” ืฉื’ื ืื ืื ื™ ืขื•ืฉื” ื”ื›ืœ ืฉืœื‘ ืื—ืจ ืฉืœื‘ ื›ืžื• ื‘ื”ื“ืจื›ื”, ืžื›ื™ืŸ ืืช ืื•ืชื” ืกื‘ื™ื‘ื” ื›ืžื• ื”ืžื—ื‘ืจ, ืื– ืฉื•ื ื“ื‘ืจ ืืฃ ืคืขื ืœื ืขื•ื‘ื“. ืื™ืŸ ืœื™ ืžื•ืฉื’ ืžื” ื”ืขื ื™ื™ืŸ, ืื‘ืœ ื›ืฉื ืชืงืœืชื™ ื‘ื–ื” ืฉื•ื‘, ื”ื—ืœื˜ืชื™ ืฉืื ื™ ืื›ืชื•ื‘ ืžื“ืจื™ืš ืžืฉืœื™ ื›ืฉื”ื›ืœ ื™ืกืชื“ืจ. ื›ื–ื” ืฉื‘ื”ื—ืœื˜ ื™ืขื‘ื•ื“.

ืžื“ืจื™ื›ื™ื ื‘ืื™ื ื˜ืจื ื˜

ื‘ืžืงืจื” ืฉื”ืื™ื ื˜ืจื ื˜ ืœื ืกื•ื‘ืœ ืžืžื—ืกื•ืจ ื‘ืžื“ืจื™ื›ื™ื ืฉื•ื ื™ื, ื”ื“ืจื›ื•ืช, ืฆืขื“ ืื—ืจ ืฆืขื“ ื•ื›ื“ื•ืžื”. ื‘ืžืงืจื” ื”ื•ื˜ืœ ืขืœื™ื™ ืœืคืชื— ืคืชืจื•ืŸ ืœืืจื’ื•ืŸ ื•ื‘ื ื™ื™ื” ื ื•ื—ื” ืฉืœ ืืฉื›ื•ืœ PostgreSQL, ืฉื”ื“ืจื™ืฉื•ืช ื”ืขื™ืงืจื™ื•ืช ืขื‘ื•ืจื• ื”ื™ื• ื”ื–ืจืžืช ืฉื›ืคื•ืœ ืžืฉืจืช ื”ืžืืกื˜ืจ ืœื›ืœ ื”ื”ืขืชืงื™ื ื•ื”ืงืฆืื” ืื•ื˜ื•ืžื˜ื™ืช ืฉืœ ืจื–ืจื‘ื” ื‘ืžืงืจื” ืฉืœ ืฉืจืช ืžืืกื˜ืจ. ื›ื™ืฉืœื•ืŸ.

ื‘ืฉืœื‘ ื–ื” ื ืงื‘ืขื” ืขืจื™ืžืช ื”ื˜ื›ื ื•ืœื•ื’ื™ื•ืช ืฉื‘ื”ืŸ ื ืขืฉื” ืฉื™ืžื•ืฉ:

  • PostgreSQL ื›-DBMS
  • ืคื˜ืจื•ื ื™ ื›ืคืชืจื•ืŸ ืžืงื‘ืฅ
  • ื•ื›ื•' ื›ืื—ืกื•ืŸ ืžื‘ื•ื–ืจ ืขื‘ื•ืจ Patroni
  • HAproxy ืœืืจื’ื•ืŸ ื ืงื•ื“ืช ื›ื ื™ืกื” ืื—ืช ืœื™ื™ืฉื•ืžื™ื ื”ืžืฉืชืžืฉื™ื ื‘ืžืกื“ ื”ื ืชื•ื ื™ื

ื”ืชืงื ื”

ืœืชืฉื•ืžืช ืœื‘ืš - ื‘ื ื™ื™ืช ืืฉื›ื•ืœ PostgreSQL ื–ืžื™ืŸ ื‘ืžื™ื•ื—ื“ ื‘ืืžืฆืขื•ืช Patroni, etcd, HAProxy.

ื›ืœ ื”ืคืขื•ืœื•ืช ื‘ื•ืฆืขื• ื‘ืžื›ื•ื ื•ืช ื•ื™ืจื˜ื•ืืœื™ื•ืช ืขื ืžืขืจื›ืช ื”ื”ืคืขืœื” Debian 10 ืžื•ืชืงื ืช.

ื•ื›ื• '

ืื ื™ ืœื ืžืžืœื™ืฅ ืœื”ืชืงื™ืŸ ืืช etcd ื‘ืื•ืชืŸ ืžื›ื•ื ื•ืช ื‘ื”ืŸ ื™ืžื•ืงืžื• patroni ื•-postgresql, ืžื›ื™ื•ื•ืŸ ืฉืขื•ืžืก ื“ื™ืกืง ื—ืฉื•ื‘ ืžืื•ื“ ืขื‘ื•ืจ etcd. ืื‘ืœ ืœืžื˜ืจื•ืช ื—ื™ื ื•ื›ื™ื•ืช, ืื ื—ื ื• ื ืขืฉื” ื‘ื“ื™ื•ืง ืืช ื–ื”.
ื‘ื•ืื• ื ืชืงื™ืŸ ื•ื›ื•'.

#!/bin/bash
apt-get update
apt-get install etcd

ื”ื•ืกืฃ ืชื•ื›ืŸ ืœืงื•ื‘ืฅ /etc/default/etcd

[ื—ื‘ืจ]

ETCD_NAME=datanode1 # ืฉื ืžืืจื— ืฉืœ ื”ืžื—ืฉื‘ ืฉืœืš
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"

ื›ืœ ื›ืชื•ื‘ื•ืช ื”-IP ืฆืจื™ื›ื•ืช ืœื”ื™ื•ืช ืชืงืคื•ืช. LISTER PEER, ืœืงื•ื— ื•ื›ื•' ืฆืจื™ื›ื™ื ืœื”ื™ื•ืช ืžื•ื’ื“ืจื™ื ืœื›ืชื•ื‘ืช ื”-IP ืฉืœ ื”ืžืืจื—

ETCD_LISTEN_PEER_URLS="http://192.168.0.143:2380ยป ื›ืชื•ื‘ืช # ืฉืœ ื”ืžื›ื•ื ื™ืช ืฉืœืš
ETCD_LISTEN_CLIENT_URLS="http://192.168.0.143:2379,http://127.0.0.1:2379ยป ื›ืชื•ื‘ืช # ืฉืœ ื”ืžื›ื•ื ื™ืช ืฉืœืš

[ืึถืฉืื›ึผื•ึนืœ]

ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.0.143:2380ยป ื›ืชื•ื‘ืช # ืฉืœ ื”ืžื›ื•ื ื™ืช ืฉืœืš
ETCD_INITIAL_CLUSTER=ยปnode data1=http://192.168.0.143:2380,datanode2=http://192.168.0.144:2380,datanode3=http://192.168.0.145:2380ยป # ื›ืชื•ื‘ื•ืช ืฉืœ ื›ืœ ื”ืžื›ื•ื ื•ืช ื‘ืืฉื›ื•ืœ etcd
ETCD_INITIAL_CLUSTER_STATE="ื—ื“ืฉ"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-1"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.0.143:2379ยป ื›ืชื•ื‘ืช # ืฉืœ ื”ืžื›ื•ื ื™ืช ืฉืœืš

ื”ืคืขืœ ืืช ื”ืคืงื•ื“ื”

systemctl restart etcd

PostgreSQL 9.6 + ืคื˜ืจื•ื ื™

ื”ื“ื‘ืจ ื”ืจืืฉื•ืŸ ืฉืขืœื™ืš ืœืขืฉื•ืช ื”ื•ื ืœื”ื’ื“ื™ืจ ืฉืœื•ืฉ ืžื›ื•ื ื•ืช ื•ื™ืจื˜ื•ืืœื™ื•ืช ื›ื“ื™ ืœื”ืชืงื™ืŸ ืขืœื™ื”ืŸ ืืช ื”ืชื•ื›ื ื” ื”ื“ืจื•ืฉื”. ืœืื—ืจ ื”ืชืงื ืช ื”ืžื›ื•ื ื•ืช, ืื ืชืขืงื‘ื• ืื—ืจ ื”ืžื“ืจื™ืš ืฉืœื™, ืชื•ื›ืœื• ืœื”ืจื™ืฅ ืืช ื”ืกืงืจื™ืคื˜ ื”ืคืฉื•ื˜ ื”ื–ื” ืฉื™ืขืฉื” (ื›ืžืขื˜) ื”ื›ืœ ื‘ืฉื‘ื™ืœื›ื. ืคื•ืขืœ ื›ืฉื•ืจืฉ.

ืฉื™ืžื• ืœื‘ ืฉื”ืกืงืจื™ืคื˜ ืžืฉืชืžืฉ ื‘-PostgreSQL ื’ืจืกื” 9.6, ื–ื” ื ื•ื‘ืข ืžื”ื“ืจื™ืฉื•ืช ื”ืคื ื™ืžื™ื•ืช ืฉืœ ื”ื—ื‘ืจื” ืฉืœื ื•. ื”ืคืชืจื•ืŸ ืœื ื ื‘ื“ืง ืขืœ ื’ืจืกืื•ืช ืื—ืจื•ืช ืฉืœ PostgreSQL.

#!/bin/bash
apt-get install gnupg -y
echo "deb http://apt.postgresql.org/pub/repos/apt/ buster-pgdg main" >> /etc/apt/sources.list
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
apt-get update
apt-get install postgresql-9.6 python3-pip python3-dev libpq-dev -y
systemctl stop postgresql
pip3 install --upgrade pip
pip install psycopg2
pip install patroni[etcd]
echo "
[Unit]
Description=Runners to orchestrate a high-availability PostgreSQL
After=syslog.target network.target

[Service]
Type=simple

User=postgres
Group=postgres

ExecStart=/usr/local/bin/patroni /etc/patroni.yml

KillMode=process

TimeoutSec=30

Restart=no

[Install]
WantedBy=multi-user.targ
" > /etc/systemd/system/patroni.service
mkdir -p /data/patroni
chown postgres:postgres /data/patroni
chmod 700 /data/patroniะฟะพ
touch /etc/patroni.yml

ืœืื—ืจ ืžื›ืŸ, ื‘ืงื•ื‘ืฅ /etc/patroni.yml ืฉื™ืฆืจืช ื–ื” ืขืชื”, ืขืœื™ืš ืœืžืงื ืืช ื”ืชื›ื ื™ื ื”ื‘ืื™ื, ื›ืžื•ื‘ืŸ ืœืฉื ื•ืช ืืช ื›ืชื•ื‘ื•ืช ื”-IP ื‘ื›ืœ ื”ืžืงื•ืžื•ืช ืœื›ืชื•ื‘ื•ืช ื‘ื”ืŸ ืืชื” ืžืฉืชืžืฉ.
ืฉื™ืžื• ืœื‘ ืœื”ืขืจื•ืช ื‘-yaml ื”ื–ื”. ืฉื ื” ืืช ื”ื›ืชื•ื‘ื•ืช ืœืฉืœืš ื‘ื›ืœ ืžื—ืฉื‘ ื‘ืืฉื›ื•ืœ.

/etc/patroni.yml

scope: pgsql # ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ ะพะดะธะฝะฐะบะพะฒั‹ะผ ะฝะฐ ะฒัะตั… ะฝะพะดะฐั…
namespace: /cluster/ # ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ ะพะดะธะฝะฐะบะพะฒั‹ะผ ะฝะฐ ะฒัะตั… ะฝะพะดะฐั…
name: postgres1 # ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ ั€ะฐะทะฝั‹ะผ ะฝะฐ ะฒัะตั… ะฝะพะดะฐั…

restapi:
    listen: 192.168.0.143:8008 # ะฐะดั€ะตั ั‚ะพะน ะฝะพะดั‹, ะฒ ะบะพั‚ะพั€ะพะน ะฝะฐั…ะพะดะธั‚ัั ัั‚ะพั‚ ั„ะฐะนะป
    connect_address: 192.168.0.143:8008 # ะฐะดั€ะตั ั‚ะพะน ะฝะพะดั‹, ะฒ ะบะพั‚ะพั€ะพะน ะฝะฐั…ะพะดะธั‚ัั ัั‚ะพั‚ ั„ะฐะนะป

etcd:
    hosts: 192.168.0.143:2379,192.168.0.144:2379,192.168.0.145:2379 # ะฟะตั€ะตั‡ะธัะปะธั‚ะต ะทะดะตััŒ ะฒัะต ะฒะฐัˆะธ ะฝะพะดั‹, ะฒ ัะปัƒั‡ะฐะต ะตัะปะธ ะฒั‹ ัƒัั‚ะฐะฝะฐะฒะปะธะฒะฐะตั‚ะต etcd ะฝะฐ ะฝะธั… ะถะต

# 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: 5120
                    max_wal_senders: 5
                    max_replication_slots: 5
                    checkpoint_timeout: 30

    initdb:
    - encoding: UTF8
    - data-checksums
    - locale: en_US.UTF8
    # init pg_hba.conf ะดะพะปะถะตะฝ ัะพะดะตั€ะถะฐั‚ัŒ ะฐะดั€ะตัะฐ ะ’ะกะ•ะฅ ะผะฐัˆะธะฝ, ะธัะฟะพะปัŒะทัƒะตะผั‹ั… ะฒ ะบะปะฐัั‚ะตั€ะต
    pg_hba:
    - host replication postgres ::1/128 md5
    - host replication postgres 127.0.0.1/8 md5
    - host replication postgres 192.168.0.143/24 md5
    - host replication postgres 192.168.0.144/24 md5
    - host replication postgres 192.168.0.145/24 md5
    - host all all 0.0.0.0/0 md5

    users:
        admin:
            password: admin
            options:
                - createrole
                - createdb

postgresql:
    listen: 192.168.0.143:5432 # ะฐะดั€ะตั ั‚ะพะน ะฝะพะดั‹, ะฒ ะบะพั‚ะพั€ะพะน ะฝะฐั…ะพะดะธั‚ัั ัั‚ะพั‚ ั„ะฐะนะป
    connect_address: 192.168.0.143:5432 # ะฐะดั€ะตั ั‚ะพะน ะฝะพะดั‹, ะฒ ะบะพั‚ะพั€ะพะน ะฝะฐั…ะพะดะธั‚ัั ัั‚ะพั‚ ั„ะฐะนะป
    data_dir: /data/patroni # ัั‚ัƒ ะดะธั€ะตะบั‚ะพั€ะธัŽ ัะพะทะดะฐัั‚ ัะบั€ะธะฟั‚, ะพะฟะธัะฐะฝะฝั‹ะน ะฒั‹ัˆะต ะธ ัƒัั‚ะฐะฝะพะฒะธั‚ ะฝัƒะถะฝั‹ะต ะฟั€ะฐะฒะฐ
    bin_dir:  /usr/lib/postgresql/9.6/bin # ัƒะบะฐะถะธั‚ะต ะฟัƒั‚ัŒ ะดะพ ะฒะฐัˆะตะน ะดะธั€ะตะบั‚ะพั€ะธะธ ั postgresql
    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

ื™ืฉ ืœื”ืคืขื™ืœ ืืช ื”ืกืงืจื™ืคื˜ ื‘ื›ืœ ืฉืœื•ืฉืช ื”ืžื›ื•ื ื•ืช ืฉืœ ื”ืืฉื›ื•ืœ, ื•ื™ืฉ ืœืžืงื ืืช ื”ืชืฆื•ืจื” ืฉืœืขื™ืœ ื’ื ื‘ืงื•ื‘ืฅ /etc/patroni.yml ื‘ื›ืœ ื”ืžื›ื•ื ื•ืช.

ืœืื—ืจ ื”ืฉืœืžืช ืคืขื•ืœื•ืช ืืœื” ื‘ื›ืœ ื”ืžื—ืฉื‘ื™ื ื‘ืืฉื›ื•ืœ, ื”ืคืขืœ ืืช ื”ืคืงื•ื“ื” ื”ื‘ืื” ื‘ื›ืœ ืื—ืช ืžื”ืŸ

systemctl start patroni
systemctl start postgresql

ื”ืžืชืŸ ื›-30 ืฉื ื™ื•ืช, ื•ืื– ื”ืคืขืœ ืืช ื”ืคืงื•ื“ื” ื”ื–ื• ื‘ืžื›ื•ื ื•ืช ื”ื ื•ืชืจื•ืช ื‘ืืฉื›ื•ืœ.

HAproxy

ืื ื• ืžืฉืชืžืฉื™ื ื‘-HAproxy ื”ื ืคืœื ื›ื“ื™ ืœืกืคืง ื ืงื•ื“ืช ื›ื ื™ืกื” ืื—ืช. ื”ืฉืจืช ื”ืจืืฉื™ ื™ื”ื™ื” ืชืžื™ื“ ื–ืžื™ืŸ ื‘ื›ืชื•ื‘ืช ืฉืœ ื”ืžื—ืฉื‘ ืฉืขืœื™ื• ืคืจื•ืกื™ื HAproxy.

ื›ื“ื™ ืœื ืœื”ืคื•ืš ืืช ื”ืžื›ื•ื ื” ืขื HAproxy ืœื ืงื•ื“ืช ื›ืฉืœ ื‘ื•ื“ื“ืช, ื ืฉื™ืง ืื•ืชื” ื‘ืงื•ื ื˜ื™ื™ื ืจ Docker; ื‘ืขืชื™ื“ ื ื™ืชืŸ ื™ื”ื™ื” ืœื”ืฉื™ืง ืื•ืชื” ืœืืฉื›ื•ืœ ื”-K8 ื•ืœื”ืคื•ืš ืืช ืืฉื›ื•ืœ ื”ื›ืฉืœ ืฉืœื ื• ืœืืžื™ืŸ ืขื•ื“ ื™ื•ืชืจ.

ืฆื•ืจ ืกืคืจื™ื™ื” ืฉื‘ื” ืชื•ื›ืœ ืœืื—ืกืŸ ืฉื ื™ ืงื‘ืฆื™ื - Dockerfile ื•-haproxy.cfg. ืœืš ืœื–ื”.

ื“ื•ืงืจืคื™ืœ

FROM ubuntu:latest

RUN apt-get update 
    && apt-get install -y haproxy rsyslog 
    && rm -rf /var/lib/apt/lists/*

RUN mkdir /run/haproxy

COPY haproxy.cfg /etc/haproxy/haproxy.cfg

CMD haproxy -f /etc/haproxy/haproxy.cfg && tail -F /var/log/haproxy.log

ื”ื™ื–ื”ืจ, ืฉืœื•ืฉ ื”ืฉื•ืจื•ืช ื”ืื—ืจื•ื ื•ืช ืฉืœ ื”ืงื•ื‘ืฅ haproxy.cfg ืฆืจื™ื›ื•ืช ืœืจืฉื•ื ืืช ื”ื›ืชื•ื‘ื•ืช ืฉืœ ื”ืžื›ื•ื ื•ืช ืฉืœืš. HAproxy ืชื™ืฆื•ืจ ืงืฉืจ ืขื Patroni, ื‘ื›ื•ืชืจื•ืช HTTP ื”ืฉืจืช ื”ืจืืฉื™ ืชืžื™ื“ ื™ื—ื–ื™ืจ 200, ื•ื”ืขืชืง ืชืžื™ื“ ื™ื—ื–ื™ืจ 503.

haproxy.cfg

global
    maxconn 100

defaults
    log global
    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 postgres
    bind *:5000
    option httpchk
    http-check expect status 200
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server postgresql1 192.168.0.143:5432 maxconn 100 check port 8008
    server postgresql2 192.168.0.144:5432 maxconn 100 check port 8008
    server postgresql3 192.168.0.145:5432 maxconn 100 check port 8008

ื‘ื”ื™ื•ืชื ื• ื‘ืกืคืจื™ื™ื” ืฉื‘ื” ืฉื ื™ ื”ืงื‘ืฆื™ื ืฉืœื ื• "ืฉื•ื›ื‘ื™ื", ื‘ื•ืื• ื ื‘ืฆืข ื‘ืจืฆืฃ ืืช ื”ืคืงื•ื“ื•ืช ืœืืจื™ื–ืช ื”ืžื™ื›ืœ, ื›ืžื• ื’ื ืœื”ืคืขื™ืœ ืื•ืชื• ืขื ื”ืขื‘ืจืช ื”ื™ืฆื™ืื•ืช ื”ื ื—ื•ืฆื•ืช:

docker build -t my-haproxy .
docker run -d -p5000:5000 -p7000:7000 my-haproxy 

ื›ืขืช, ืขืœ ื™ื“ื™ ืคืชื™ื—ืช ื”ื›ืชื•ื‘ืช ืฉืœ ื”ืžื—ืฉื‘ ืฉืœืš ืขื HAproxy ื‘ื“ืคื“ืคืŸ ื•ืฆื™ื•ืŸ ื™ืฆื™ืื” 7000, ืชืจืื” ื ืชื•ื ื™ื ืกื˜ื˜ื™ืกื˜ื™ื™ื ืขืœ ื”ืืฉื›ื•ืœ ืฉืœืš.

ื”ืฉืจืช ืฉื”ื•ื ื”ืžืืกื˜ืจ ื™ื”ื™ื” ื‘ืžืฆื‘ UP, ื•ื”ืขื•ืชืงื™ื ื™ื”ื™ื• ื‘ืžืฆื‘ DOWN. ื–ื” ื ื•ืจืžืœื™, ืœืžืขืฉื” ื”ื ืขื•ื‘ื“ื™ื, ืื‘ืœ ื”ื ืžื•ืคื™ืขื™ื ื›ืš ืžื›ื™ื•ื•ืŸ ืฉื”ื ืžื—ื–ื™ืจื™ื 503 ืœื‘ืงืฉื•ืช ืž-HAproxy. ื–ื” ืžืืคืฉืจ ืœื ื• ืชืžื™ื“ ืœื“ืขืช ื‘ื“ื™ื•ืง ืžื™ ืžืฉืœื•ืฉืช ื”ืฉืจืชื™ื ื”ื•ื ื”ืžืืกื˜ืจ ื”ื ื•ื›ื—ื™.

ืžืกืงื ื”

ืืช ื™ืคื™ืคื™ื”! ืชื•ืš 30 ื“ืงื•ืช ื‘ืœื‘ื“ ืคืจืกืช ืืฉื›ื•ืœ ืžืกื“ ื ืชื•ื ื™ื ืžืขื•ืœื” ืขืžื™ื“ ืœืชืงืœื•ืช ื•ื‘ื™ืฆื•ืขื™ื ื’ื‘ื•ื”ื™ื ืขื ืฉื›ืคื•ืœ ืกื˜ืจื™ืžื™ื ื’ ื•-fallback ืื•ื˜ื•ืžื˜ื™. ืื ืืชื” ืžืชื›ื ืŸ ืœื”ืฉืชืžืฉ ื‘ืคืชืจื•ืŸ ื–ื”, ื‘ื“ื•ืง ืขื ืชื™ืขื•ื“ ืจืฉืžื™ ืฉืœ ืคื˜ืจื•ื ื™, ื•ื‘ืžื™ื•ื—ื“ ื‘ื—ืœืงื• ื”ื ื•ื’ืข ืœื›ืœื™ ื”ืฉื™ืจื•ืช patronictl, ื”ืžืกืคืง ื’ื™ืฉื” ื ื•ื—ื” ืœื ื™ื”ื•ืœ ื”ืืฉื›ื•ืœ ืฉืœืš.

ืžื–ืœ ื˜ื•ื‘!

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”