Перейти к основному содержимому

Задание 2: Запуск etcd

Ранее в «Задание 3: Сертификаты TLS» мы уже создали сертификаты.

В этом задании мы развернем кластер etcd, подключим к нему TLS-сертификаты и выполним подготовку к первому запуску. Затем мы запустим службу на узлах кластера, проверим ее работоспособность и настроим аутентификацию для защиты доступа.

Развертывание etcd​

Скопируем установочный пакет RPM etcd с узла srv1 на другие узлы кластера (эта версия доказала свою работоспособность при автоматической развертывании с помощью Ansible):

[student@srv1 ~]$ sudo find / -name etcd-*.rpm 2>/dev/null
/opt/pangolin-local-repos/pangolin_deps/etcd-3.5.21.x86_64.rpm
[student@srv1 ~]$ scp /opt/pangolin-local-repos/pangolin_deps/etcd-3.5.21.x86_64.rpm srv2:~/
etcd-3.5.21.x86_64.rpm 100% 17MB 99.5MB/s 00:00
[student@srv1 ~]$ scp /opt/pangolin-local-repos/pangolin_deps/etcd-3.5.21.x86_64.rpm srv3:~/
etcd-3.5.21.x86_64.rpm 100% 17MB 84.3MB/s 00:00

Установим etcd на первом узле кластера srv1:

[student@srv1 ~]$ sudo dnf install -y /opt/pangolin-local-repos/pangolin_deps/etcd-3.5.21.x86_64.rpm
Вывод команды:

Updating Subscription Management repositories.
redos8.0-for-x86_64-powertools-rpms 8.8 kB/s | 2.6 kB 00:00
redos8.0-for-x86_64-baseos-rpms 7.6 kB/s | 2.3 kB 00:00
redos8.0-for-x86_64-baseos-debug-rpms 6.8 kB/s | 2.0 kB 00:00
redos8.0-for-x86_64-appstream-rpms 8.7 kB/s | 2.6 kB 00:00
redos8.0-for-x86_64-appstream-debug-rpms 6.5 kB/s | 2.0 kB 00:00
Dependencies resolved.
======================================================================================================================================================================================================
Package Architecture Version Repository Size
======================================================================================================================================================================================================
Installing:
etcd x86_64 3.5.21-2.sl9 @commandline 17 M

Transaction Summary
======================================================================================================================================================================================================
Install 1 Package

Total size: 17 M
Installed size: 56 M
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Running scriptlet: etcd-3.5.21-2.sl9.x86_64 1/1
Installing : etcd-3.5.21-2.sl9.x86_64 1/1
Running scriptlet: etcd-3.5.21-2.sl9.x86_64 1/1
Verifying : etcd-3.5.21-2.sl9.x86_64 1/1
Installed products updated.

Installed:
etcd-3.5.21-2.sl9.x86_64

Complete!

Конфигурация etcd на узле srv1​

Демон etcd использует файл конфигурации, большинство настроек в котором закомментированы:

[student@srv1 ~]$ rpm -qc etcd
/etc/etcd/etcd.conf
[student@srv1 ~]$ cat /etc/etcd/etcd.conf
Вывод команды:

# [member]
ETCD_NAME=default
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
#ETCD_WAL_DIR=""
#ETCD_SNAPSHOT_COUNT="10000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_LISTEN_PEER_URLS="http://localhost:2380"
ETCD_LISTEN_CLIENT_URLS="http://localhost:2379"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
#ETCD_CORS=""
#
#[cluster]
#ETCD_INITIAL_ADVERTISE_PEER_URLS="http://localhost:2380"
# if you use different ETCD_NAME (e.g. test), set ETCD_INITIAL_CLUSTER value for this name, i.e. "test=http://..."
#ETCD_INITIAL_CLUSTER="default=http://localhost:2380"
#ETCD_INITIAL_CLUSTER_STATE="new"
#ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://localhost:2379"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_SRV=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_STRICT_RECONFIG_CHECK="false"
#ETCD_AUTO_COMPACTION_RETENTION="0"
#
#[proxy]
#ETCD_PROXY="off"
#ETCD_PROXY_FAILURE_WAIT="5000"
#ETCD_PROXY_REFRESH_INTERVAL="30000"
#ETCD_PROXY_DIAL_TIMEOUT="1000"
#ETCD_PROXY_WRITE_TIMEOUT="5000"
#ETCD_PROXY_READ_TIMEOUT="0"
#
#[security]
#ETCD_CERT_FILE=""
#ETCD_KEY_FILE=""
#ETCD_CLIENT_CERT_AUTH="false"
#ETCD_TRUSTED_CA_FILE=""
#ETCD_AUTO_TLS="false"
#ETCD_PEER_CERT_FILE=""
#ETCD_PEER_KEY_FILE=""
#ETCD_PEER_CLIENT_CERT_AUTH="false"
#ETCD_PEER_TRUSTED_CA_FILE=""
#ETCD_PEER_AUTO_TLS="false"
#
#[logging]
#ETCD_DEBUG="false"
# examples for -log-package-levels etcdserver=WARNING,security=DEBUG
#ETCD_LOG_PACKAGE_LEVELS=""

Настроим в etcd параметры:

[student@srv1 ~]$ cat << EOF | sudo tee /etc/etcd/etcd.conf
ETCD_NAME="srv1"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://srv1:2379"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://srv1:2380"
ETCD_INITIAL_CLUSTER_TOKEN="single"
ETCD_INITIAL_CLUSTER="srv1=http://srv1:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_ELECTION_TIMEOUT="5000"
ETCD_HEARTBEAT_INTERVAL="1000"
ETCD_ENABLE_V2="true"
EOF

Проверим содержимое /etc/etcd/etcd.conf:

[student@srv1 ~]$ sudo egrep -v '^(#|$)' /etc/etcd/etcd.conf
ETCD_NAME="srv1"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://srv1:2379"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://srv1:2380"
ETCD_INITIAL_CLUSTER_TOKEN="single"
ETCD_INITIAL_CLUSTER="srv1=http://srv1:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_ELECTION_TIMEOUT="5000"
ETCD_HEARTBEAT_INTERVAL="1000"
ETCD_ENABLE_V2="true"

Выведем настройку сервиса etcd, заданную в его файле конфигурации systemd:

[student@srv1 ~]$ systemctl cat etcd | egrep '^(ExecStart|User)'
User=etcd
ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd"

Эту настройку необходимо несколько изменить в соответствии с рекомендациями, приведенными в документации «Создание service-файла etcd».

В рекомендациях указано, что etcd необходимо запускать, применяя специальную утилиту ionice, устанавливающую класс обслуживания (планирования выполнения) и приоритет (Смотрите man ionice).

Перенастроим сервис в соответствии с рекомендациями:

[student@srv1 ~]$ sudo sed -i.bak -e 's/^.*User=.*$/User=postgres/' \
-e 's/^.*ExecStart.*$/ExecStart=\/bin\/bash -c "GOMAXPROCS=$(nproc) ionice -c2 -n0 \/usr\/bin\/etcd"/' \
/usr/lib/systemd/system/etcd.service

Проверим изменения:

[student@srv1 ~]$ diff /usr/lib/systemd/system/etcd.service*
11c11
< User=postgres
---
> User=etcd
13c13
< ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) ionice -c2 -n0 /usr/bin/etcd"
---
> ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd"

Изменим владельца рабочего каталога etcd:

[student@srv2 ~]$ sudo chown -R postgres:postgres /var/lib/etcd/

Перечитаем настройки служб systemd:

[student@srv1 ~]$ sudo systemctl daemon-reload

Проверим настройку службы etcd:

[student@srv1 ~]$ sudo systemctl cat etcd | egrep '^(ExecStart|User)'
User=postgres
ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) ionice -c2 -n0 /usr/bin/etcd"

Активируем сервис etcd:

[student@srv1 ~]$ sudo systemctl enable etcd
Created symlink /etc/systemd/system/multi-user.target.wants/etcd.service → /usr/lib/systemd/system/etcd.service.

Запустим сервис etcd:

[student@srv1 ~]$ sudo systemctl start etcd

Пока что srv1 единственный узел кластера:

[student@srv1 ~]$ etcdctl --endpoints=http://$(hostname -i):2379 -w table member list
+------------------+---------+------+------------------+------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+------+------------------+------------------+------------+
| 98d57be5fdf696bb | started | srv1 | http://srv1:2380 | http://srv1:2379 | false |
+------------------+---------+------+------------------+------------------+------------+

Конфигурация etcd на узле srv2​

Подключимся к узлу srv2:

[student@srv1 ~]$ ssh srv2
Last login: Sun Jan 4 22:27:54 2026 from <IP-Address1>

Установим пакет etcd на узле srv2:

[student@srv1 ~]$ sudo find / -name etcd-*.rpm 2>/dev/null
/opt/pangolin-local-repos/pangolin_deps/etcd-3.5.21.x86_64.rpm
[student@srv1 ~]$ sudo dnf install -y /opt/pangolin-local-repos/pangolin_deps/etcd-3.5.21.x86_64.rpm
Вывод команды:

Updating Subscription Management repositories.
redos8.0-for-x86_64-powertools-rpms 8.8 kB/s | 2.6 kB 00:00
redos8.0-for-x86_64-baseos-rpms 7.6 kB/s | 2.3 kB 00:00
redos8.0-for-x86_64-baseos-debug-rpms 6.8 kB/s | 2.0 kB 00:00
redos8.0-for-x86_64-appstream-rpms 8.7 kB/s | 2.6 kB 00:00
redos8.0-for-x86_64-appstream-debug-rpms 6.5 kB/s | 2.0 kB 00:00
Dependencies resolved.
======================================================================================================================================================================================================
Package Architecture Version Repository Size
======================================================================================================================================================================================================
Installing:
etcd x86_64 3.5.21-2.sl9 @commandline 17 M

Transaction Summary
======================================================================================================================================================================================================
Install 1 Package

Total size: 17 M
Installed size: 56 M
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Running scriptlet: etcd-3.5.21-2.sl9.x86_64 1/1
Installing : etcd-3.5.21-2.sl9.x86_64 1/1
Running scriptlet: etcd-3.5.21-2.sl9.x86_64 1/1
Verifying : etcd-3.5.21-2.sl9.x86_64 1/1
Installed products updated.

Installed:
etcd-3.5.21-2.sl9.x86_64

Complete!

Изменим настройки сервиса в systemd:

[student@srv2 ~]$ sudo sed -i.bak -e 's/^.*User=.*$/User=postgres/' \
-e 's/^.*ExecStart.*$/ExecStart=\/bin\/bash -c "GOMAXPROCS=$(nproc) ionice -c2 -n0 \/usr\/bin\/etcd"/' \
/usr/lib/systemd/system/etcd.service

Проверим изменения, полученные в результате редактирования:

[student@srv2 ~]$ diff /usr/lib/systemd/system/etcd.service*
11c11
< User=postgres
---
> User=etcd
13c13
< ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) ionice -c2 -n0 /usr/bin/etcd"
---
> ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd"

Изменим владельца рабочего каталога etcd:

[student@srv2 ~]$ sudo chown -R postgres:postgres /var/lib/etcd/

Перечитаем конфигурацию сервисов systemd:

[student@srv2 ~]$ sudo systemctl daemon-reload

Активируем и запустим сервис etcd:

[student@srv2 ~]$ sudo systemctl enable --now etcd

Выйдем из сеанса srv2 и вернемся на srv1:

[student@srv2 ~]$ exit

Добавим узел srv2 в кластер:

[student@srv1 ~]$ etcdctl --endpoints=http://$(hostname -i):2379 member add srv2 --peer-urls="http://srv2:2380"
Member a6780fd56d74e380 added to cluster d111160a072854f5

ETCD_NAME="srv2"
ETCD_INITIAL_CLUSTER="srv1=http://srv1:2380,srv2=http://srv2:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://srv2:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"

Откроем сеанс на srv2:

[student@srv1 ~]$ ssh srv2
Last login: Mon Jan 5 16:30:24 2026 from <IP-Address1>

В конфигурационном файле etcd текстовым редактором внесем изменения в конфигурацию. Используйте строки, возвращенные предыдущей командой:

[student@srv2 ~]$ cat << EOF | sudo tee /etc/etcd/etcd.conf
ETCD_NAME="srv2"
ETCD_INITIAL_CLUSTER="srv1=http://srv1:2380,srv2=http://srv2:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://srv2:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://srv2:2379"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
EOF

Перезапустим etcd на узле srv2:

[student@srv2 ~]$ sudo systemctl restart etcd
[student@srv2 ~]$ sudo systemctl status etcd
Вывод команды:

● etcd.service - Etcd Server
Loaded: loaded (/usr/lib/systemd/system/etcd.service; enabled; preset: disabled)
Active: active (running) since Sat 2026-09-26 09:08:12 UTC; 21s ago
Main PID: 89641 (etcd)
Tasks: 8 (limit: 22804)
Memory: 11.7M (peak: 12.2M)
CPU: 128ms
CGroup: /system.slice/etcd.service
└─89641 /usr/bin/etcd

Sep 26 09:08:12 srv2 bash[89641]: {"level":"info","ts":"2026-09-26T09:08:12.507410Z","caller":"api/capability.go:75","msg":"enabled capabilities for version">
Sep 26 09:08:12 srv2 bash[89641]: {"level":"info","ts":"2026-09-26T09:08:12.507442Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"b243e6538cd8>
Sep 26 09:08:12 srv2 bash[89641]: {"level":"info","ts":"2026-09-26T09:08:12.507464Z","caller":"membership/cluster.go:421","msg":"added member","cluster-id":">
Sep 26 09:08:12 srv2 bash[89641]: {"level":"info","ts":"2026-09-26T09:08:12.507743Z","caller":"etcdserver/server.go:2140","msg":"published local member to cl>
Sep 26 09:08:12 srv2 bash[89641]: {"level":"info","ts":"2026-09-26T09:08:12.507753Z","caller":"embed/serve.go:103","msg":"ready to serve client requests"}
Sep 26 09:08:12 srv2 bash[89641]: {"level":"info","ts":"2026-09-26T09:08:12.507885Z","caller":"etcdmain/main.go:44","msg":"notifying init daemon"}
Sep 26 09:08:12 srv2 systemd[1]: Started Etcd Server.
Sep 26 09:08:12 srv2 bash[89641]: {"level":"info","ts":"2026-09-26T09:08:12.508286Z","caller":"v3rpc/health.go:61","msg":"grpc service status changed","serv >
Sep 26 09:08:12 srv2 bash[89641]: {"level":"info","ts":"2026-09-26T09:08:12.508626Z","caller":"embed/serve.go:187","msg":"serving client traffic insecurely; >
Sep 26 09:08:12 srv2 bash[89641]: {"level":"info","ts":"2026-09-26T09:08:12.509345Z","caller":"etcdmain/main.go:50","msg":"successfully notified init daemon"}

Выведем список членов кластера:

[student@srv2 ~]$ etcdctl --endpoints=http://<IP-Address1>:2379,http://<IP-Address2>:2379 -w table member list
+------------------+---------+------+------------------+------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+------+------------------+------------------+------------+
| 98d57be5fdf696bb | started | srv1 | http://srv1:2380 | http://srv1:2379 | false |
| b243e6538cd89a26 | started | srv2 | http://srv2:2380 | http://srv2:2379 | false |
+------------------+---------+------+------------------+------------------+------------+

Проверим исправность узлов etcd:

[student@srv2 ~]$ etcdctl --endpoints=http://<IP-Address1>:2379,http://<IP-Address2>:2379 -w table endpoint health
+---------------------------+--------+------------+-------+
| ENDPOINT | HEALTH | TOOK | ERROR |
+---------------------------+--------+------------+-------+
| http://<IP-Address2>:2379 | true | 2.120936ms | |
| http://<IP-Address1>:2379 | true | 2.062881ms | |
+---------------------------+--------+------------+-------+

Проверим то же самое на srv1:

[student@srv2 ~]$ exit
logout
Connection to srv2 closed.
[student@srv1 ~]$ etcdctl --endpoints=http://<IP-Address1>:2379,http://<IP-Address2>:2379 -w table member list
+------------------+---------+------+------------------+------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+------+------------------+------------------+------------+
| 98d57be5fdf696bb | started | srv1 | http://srv1:2380 | http://srv1:2379 | false |
| b243e6538cd89a26 | started | srv2 | http://srv2:2380 | http://srv2:2379 | false |
+------------------+---------+------+------------------+------------------+------------+

Конфигурация etcd на узле srv3​

Узел srv3, хоть и должен являться членом кластера etcd, но он будет арбитром.

Подключитесь к узлу srv3:

[student@srv1 ~]$ ssh srv3

Установим etcd:

[student@srv1 ~]$ sudo find / -name etcd-*.rpm 2>/dev/null
/opt/pangolin-local-repos/pangolin_deps/etcd-3.5.21.x86_64.rpm
[student@srv3 ~]$ sudo dnf install -y etcd-3.5.21.redos8.0.x86_64.rpm
Вывод команды:

Last metadata expiration check: 1:44:14 ago on Mon 05 Jan 2026 04:14:30 PM MSK.
Dependencies resolved.
==================================================================================================================================================
Package Architecture Version Repository Size
==================================================================================================================================================
Installing:
etcd x86_64 3.5.21.redos8.0 @commandline 17 M

Transaction Summary
==================================================================================================================================================
Install 1 Package

Total size: 17 M
Installed size: 58 M
Downloading Packages:
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Running scriptlet: etcd-3.5.21.redos8.0.x86_64 1/1
Installing : etcd-3.5.21.redos8.0.x86_64 1/1
Running scriptlet: etcd-3.5.21.redos8.0.x86_64 1/1
Verifying : etcd-3.5.21.redos8.0.x86_64 1/1

Installed:
etcd-3.5.21.redos8.0.x86_64

Complete!

Ранее мы создавали пользователя postgres:

[student@srv3 ~]$ id postgres
uid=992(postgres) gid=992(postgres) groups=992(postgres),991(pangolin_users)

Изменим файл конфигурации службы etcd в systemd:

[student@srv3 ~]$ sudo sed -i.bak -e 's/^.*User=.*$/User=postgres/' \
-e 's/^.*ExecStart.*$/ExecStart=\/bin\/bash -c "GOMAXPROCS=$(nproc) ionice -c2 -n0 \/usr\/bin\/etcd"/' \
/usr/lib/systemd/system/etcd.service

Проверим изменения:

[student@srv3 ~]$ diff /usr/lib/systemd/system/etcd.service*
11c11
< User=postgres
---
> User=etcd
13c13
< ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) ionice -c2 -n0 /usr/bin/etcd"
---
> ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd"

Изменим владельца рабочего каталога etcd:

[student@srv3 ~]$ sudo chown -cR postgres:postgres /var/lib/etcd/
changed ownership of '/var/lib/etcd/' from etcd:etcd to postgres:postgres

Перечитаем конфигурацию сервисов systemd:

[student@srv2 ~]$ sudo systemctl daemon-reload

Запустим etcd:

[student@srv3 ~]$ sudo systemctl enable --now etcd
Created symlink /etc/systemd/system/multi-user.target.wants/etcd.service → /usr/lib/systemd/system/etcd.service.
[student@srv3 ~]$ sudo systemctl status etcd
Вывод команды:

● etcd.service - Etcd Server
Loaded: loaded (/usr/lib/systemd/system/etcd.service; enabled; preset: disabled)
Active: active (running) since Sat 2026-09-26 09:20:26 UTC; 7s ago
Main PID: 46236 (etcd)
Tasks: 7 (limit: 22804)
Memory: 8.2M (peak: 8.7M)
CPU: 45ms
CGroup: /system.slice/etcd.service
└─46236 /usr/bin/etcd

Sep 26 09:20:26 srv3 bash[46236]: {"level":"info","ts":"2026-09-26T09:20:26.168001Z","caller":"embed/serve.go:103","msg":"ready to serve client requests"}
Sep 26 09:20:26 srv3 bash[46236]: {"level":"info","ts":"2026-09-26T09:20:26.168153Z","caller":"etcdserver/server.go:2651","msg":"setting up initial cluster version using v2 API","clu>
Sep 26 09:20:26 srv3 bash[46236]: {"level":"info","ts":"2026-09-26T09:20:26.168413Z","caller":"v3rpc/health.go:61","msg":"grpc service status changed","service":"","status":"SERVING"}
Sep 26 09:20:26 srv3 bash[46236]: {"level":"info","ts":"2026-09-26T09:20:26.168689Z","caller":"embed/serve.go:187","msg":"serving client traffic insecurely; this is strongly discoura>
Sep 26 09:20:26 srv3 bash[46236]: {"level":"info","ts":"2026-09-26T09:20:26.168745Z","caller":"etcdmain/main.go:44","msg":"notifying init daemon"}
Sep 26 09:20:26 srv3 bash[46236]: {"level":"info","ts":"2026-09-26T09:20:26.168820Z","caller":"etcdmain/main.go:50","msg":"successfully notified init daemon"}
Sep 26 09:20:26 srv3 bash[46236]: {"level":"info","ts":"2026-09-26T09:20:26.168874Z","caller":"membership/cluster.go:584","msg":"set initial cluster version","cluster-id":"cdf818194e>
Sep 26 09:20:26 srv3 bash[46236]: {"level":"info","ts":"2026-09-26T09:20:26.168917Z","caller":"api/capability.go:75","msg":"enabled capabilities for version","cluster-version":"3.5"}
Sep 26 09:20:26 srv3 bash[46236]: {"level":"info","ts":"2026-09-26T09:20:26.168932Z","caller":"etcdserver/server.go:2675","msg":"cluster version is updated","cluster-version":"3.5"}
Sep 26 09:20:26 srv3 systemd[1]: Started Etcd Server.

Вернемся на srv1 и добавим узел srv3 в кластер:

[student@srv1 ~]$ etcdctl --endpoints=http://$(hostname -i):2379,http://<IP-Address2>:2379 member add srv3 --peer-urls="http://srv3:2380"
Member 25cdae636c67ae99 added to cluster d111160a072854f5

ETCD_NAME="srv3"
ETCD_INITIAL_CLUSTER="srv3=http://srv3:2380,srv1=http://srv1:2380,srv2=http://srv2:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://srv3:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"

Откроем сеанс с srv3. На srv3 внесем изменения в конфигурационный файл etcd (показан результат изменения конфигурации): БЮ

[student@srv3 ~]$ cat << EOF | sudo tee /etc/etcd/etcd.conf
ETCD_NAME="srv3"
ETCD_INITIAL_CLUSTER="srv3=http://srv3:2380,srv1=http://srv1:2380,srv2=http://srv2:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://srv3:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://srv3:2379"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
EOF

Перезапустим etcd:

[student@srv3 ~]$ sudo systemctl restart etcd
[student@srv3 ~]$ sudo systemctl status etcd
Вывод команды:

● etcd.service - Etcd Server
Loaded: loaded (/usr/lib/systemd/system/etcd.service; enabled; preset: disabled)
Active: active (running) since Sat 2026-09-26 09:25:10 UTC; 5s ago
Main PID: 46272 (etcd)
Tasks: 7 (limit: 22804)
Memory: 10.5M (peak: 11.0M)
CPU: 64ms
CGroup: /system.slice/etcd.service
└─46272 /usr/bin/etcd

Sep 26 09:25:10 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:10.618880Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"25cdae636c67ae99 became follower at term 3"}
Sep 26 09:25:10 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:10.618921Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"raft.node: 25cdae636c67ae99 elected leader >
Sep 26 09:25:11 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:11.543620Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"25cdae636c67ae99 is starting a new election>
Sep 26 09:25:11 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:11.543683Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"25cdae636c67ae99 became pre-candidate at te>
Sep 26 09:25:11 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:11.543697Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"25cdae636c67ae99 received MsgPreVoteResp fr>
Sep 26 09:25:11 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:11.543711Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"25cdae636c67ae99 [logterm: 3, index: 11] se>
Sep 26 09:25:11 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:11.543721Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"25cdae636c67ae99 [logterm: 3, index: 11] se>
Sep 26 09:25:11 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:11.543728Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"raft.node: 25cdae636c67ae99 lost leader 98d>
Sep 26 09:25:11 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:11.618999Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"25cdae636c67ae99 became follower at term 3"}
Sep 26 09:25:11 srv3 bash[46272]: {"level":"info","ts":"2026-09-26T09:25:11.619039Z","logger":"raft","caller":"etcdserver/zap_raft.go:77","msg":"raft.node: 25cdae636c67ae99 elected leader >

Получим список членов кластера:

[student@srv3 ~]$ etcdctl --endpoints=http://<IP-Address1>:2379,http://<IP-Address2>:2379,http://<IP-Address3>:2379 -w table member list
+------------------+---------+------+------------------+------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+------+------------------+------------------+------------+
| 25cdae636c67ae99 | started | srv3 | http://srv3:2380 | http://srv3:2379 | false |
| 98d57be5fdf696bb | started | srv1 | http://srv1:2380 | http://srv1:2379 | false |
| b243e6538cd89a26 | started | srv2 | http://srv2:2380 | http://srv2:2379 | false |
+------------------+---------+------+------------------+------------------+------------+

Вернемся на srv1:

[student@srv3 ~]$ exit
[student@srv1 ~]$ etcdctl --endpoints=http://<IP-Address1>:2379,http://<IP-Address2>:2379,http://<IP-Address3>:2379 -w table member list
+------------------+---------+------+------------------+------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+------+------------------+------------------+------------+
| 25cdae636c67ae99 | started | srv3 | http://srv3:2380 | http://srv3:2379 | false |
| 98d57be5fdf696bb | started | srv1 | http://srv1:2380 | http://srv1:2379 | false |
| b243e6538cd89a26 | started | srv2 | http://srv2:2380 | http://srv2:2379 | false |
+------------------+---------+------+------------------+------------------+------------+

Проверим исправность членов кластера:

[student@srv1 ~]$ etcdctl --endpoints=http://<IP-Address1>:2379,http://<IP-Address2>:2379,http://<IP-Address3>:2379 -w table endpoint health
+---------------------------+--------+------------+-------+
| ENDPOINT | HEALTH | TOOK | ERROR |
+---------------------------+--------+------------+-------+
| http://<IP-Address1>:2379 | true | 3.303445ms | |
| http://<IP-Address2>:2379 | true | 3.263331ms | |
| http://<IP-Address3>:2379 | true | 3.48808ms | |
+---------------------------+--------+------------+-------+

Получим общее состояние узлов кластера:

[student@srv1 ~]$ etcdctl --endpoints=http://<IP-Address1>:2379,http://<IP-Address2>:2379,http://<IP-Address3>:2379 -w table endpoint status
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| http://<IP-Address1>:2379 | 98d57be5fdf696bb | 3.5.16 | 20 kB | true | false | 3 | 14 | 14 | |
| http://<IP-Address2>:2379 | b243e6538cd89a26 | 3.5.16 | 20 kB | false | false | 3 | 14 | 14 | |
| http://<IP-Address3>:2379 | 25cdae636c67ae99 | 3.5.16 | 20 kB | false | false | 3 | 14 | 14 | |
+---------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

Подключение сертификатов к etcd​

На всех узлах остановим etcd:

[student@srv1 ~]$ for comp in srv{3,2,1}; do echo -e "\n$comp"; ssh $comp sudo systemctl stop etcd; done
srv3

srv2

srv1

Запишем следующие настройки в конфигурационный файл etcd.conf на первом узле:

[student@srv1 ~]$ vi /etc/etcd/etcd.conf

[student@srv1 ~]$ cat << EOF | sudo tee /etc/etcd/etcd.conf
ETCD_NAME="srv1"
ETCD_LISTEN_CLIENT_URLS="https://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="https://srv1:2379"
ETCD_LISTEN_PEER_URLS="https://0.0.0.0:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://srv1:2380"
ETCD_INITIAL_CLUSTER_TOKEN="single"
ETCD_INITIAL_CLUSTER="srv1=https://srv1:2380,srv2=https://srv2:2380,srv3=https://srv3:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_ELECTION_TIMEOUT="5000"
ETCD_HEARTBEAT_INTERVAL="1000"
ETCD_ENABLE_V2="true"
ETCD_LOG_OUTPUTS="/pgerrorlogs/06/etcd/etcd.log"
# SSL/TLS
ETCD_CIPHER_SUITES="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
ETCD_TRUSTED_CA_FILE="/pg_ssl/root.crt"
ETCD_CERT_FILE="/pg_ssl/server.crt"
ETCD_KEY_FILE="/pg_ssl/server.key"
ETCD_PEER_TRUSTED_CA_FILE="/pg_ssl/root.crt"
ETCD_PEER_CERT_FILE="/pg_ssl/server.crt"
ETCD_PEER_KEY_FILE="/pg_ssl/server.key"
ETCD_PEER_CLIENT_CERT_AUTH="true"
EOF

Скопируем конфигурацию etcd.conf с узла srv1 на srv2, заменив соответствующим образом значения параметров:

  • ETCD_NAME
  • ETCD_ADVERTISE_CLIENT_URLS
  • ETCD_INITIAL_ADVERTISE_PEER_URLS
[student@srv1 ~]$ sed -e '/^ETCD_NAME/s/srv1/srv2/' -e '/^ETCD_ADVERTISE_CLIENT_URLS/s/srv1/srv2/' -e '/^ETCD_INITIAL_ADVERTISE_PEER_URLS/s/srv1/srv2/' /etc/etcd/etcd.conf | ssh srv2 sudo tee /etc/etcd/etcd.conf
ETCD_NAME="srv2"
ETCD_LISTEN_CLIENT_URLS="https://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="https://srv2:2379"
ETCD_LISTEN_PEER_URLS="https://0.0.0.0:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://srv2:2380"
ETCD_INITIAL_CLUSTER_TOKEN="single"
ETCD_INITIAL_CLUSTER="srv1=https://srv1:2380,srv2=https://srv2:2380,srv3=https://srv3:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_ELECTION_TIMEOUT="5000"
ETCD_HEARTBEAT_INTERVAL="1000"
ETCD_ENABLE_V2="true"
ETCD_LOG_OUTPUTS="/pgerrorlogs/06/etcd/etcd.log"
# SSL/TLS
ETCD_CIPHER_SUITES="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
ETCD_TRUSTED_CA_FILE="/pg_ssl/root.crt"
ETCD_CERT_FILE="/pg_ssl/server.crt"
ETCD_KEY_FILE="/pg_ssl/server.key"
ETCD_PEER_TRUSTED_CA_FILE="/pg_ssl/root.crt"
ETCD_PEER_CERT_FILE="/pg_ssl/server.crt"
ETCD_PEER_KEY_FILE="/pg_ssl/server.key"
ETCD_PEER_CLIENT_CERT_AUTH="true"

Аналогичным образом запишем отредактированные настройки на узел srv3:

[student@srv1 ~]$ sed -e '/^ETCD_NAME/s/srv1/srv3/' -e '/^ETCD_ADVERTISE_CLIENT_URLS/s/srv1/srv3/' -e '/^ETCD_INITIAL_ADVERTISE_PEER_URLS/s/srv1/srv3/' /etc/etcd/etcd.conf | ssh srv3 sudo tee /etc/etcd/etcd.conf
ETCD_NAME="srv3"
ETCD_LISTEN_CLIENT_URLS="https://0.0.0.0:2379"
ETCD_ADVERTISE_CLIENT_URLS="https://srv3:2379"
ETCD_LISTEN_PEER_URLS="https://0.0.0.0:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://srv3:2380"
ETCD_INITIAL_CLUSTER_TOKEN="single"
ETCD_INITIAL_CLUSTER="srv1=https://srv1:2380,srv2=https://srv2:2380,srv3=https://srv3:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_ELECTION_TIMEOUT="5000"
ETCD_HEARTBEAT_INTERVAL="1000"
ETCD_ENABLE_V2="true"
ETCD_LOG_OUTPUTS="/pgerrorlogs/06/etcd/etcd.log"
# SSL/TLS
ETCD_CIPHER_SUITES="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
ETCD_TRUSTED_CA_FILE="/pg_ssl/root.crt"
ETCD_CERT_FILE="/pg_ssl/server.crt"
ETCD_KEY_FILE="/pg_ssl/server.key"
ETCD_PEER_TRUSTED_CA_FILE="/pg_ssl/root.crt"
ETCD_PEER_CERT_FILE="/pg_ssl/server.crt"
ETCD_PEER_KEY_FILE="/pg_ssl/server.key"
ETCD_PEER_CLIENT_CERT_AUTH="true"

Подготовка к первому запуску etcd​

На всех трех узлах создадим каталог /pgerrorlogs/06/etcd/ и предоставим владение им пользователю postgres, установив права для владельца и группы:

[student@srv1 ~]$ for comp in srv{1..3}; do echo -e "\n$comp"; ssh $comp sudo rm -rf /pgerrorlogs/06/etcd; ssh $comp sudo mkdir -p /pgerrorlogs/06/etcd; ssh $comp sudo chown postgres:postgres /pgerrorlogs/06/etcd; ssh $comp sudo chmod 770 /pgerrorlogs/06/etcd; done
srv1

srv2

srv3
[student@srv1 ~]$ for comp in srv{1..3}; do echo -e "\n$comp"; ssh $comp sudo ls -ld /pgerrorlogs/06/etcd; done
srv1
drwxrwx--- 2 postgres postgres 6 Sep 26 21:56 /pgerrorlogs/06/etcd

srv2
drwxrwx--- 2 postgres postgres 6 Sep 26 21:56 /pgerrorlogs/06/etcd

srv3
drwxrwx--- 2 postgres postgres 6 Sep 26 21:56 /pgerrorlogs/06/etcd

На всех трех узлах удалим и заново создадим каталог /var/lib/etcd, принадлежащий postgres, доступный только этому пользователю:

[student@srv1 ~]$ for comp in srv{1..3}; do echo -e "\n$comp"; ssh $comp sudo rm -rf /var/lib/etcd; ssh $comp sudo mkdir -p /var/lib/etcd; ssh $comp sudo chown postgres:postgres /var/lib/etcd; ssh $comp sudo chmod 700 /var/lib/etcd; done
srv1

srv2

srv3
[student@srv1 ~]$ for comp in srv{1..3}; do echo -e "\n$comp"; ssh $comp sudo ls -ld /var/lib/etcd; done
srv1
drwx------ 2 postgres postgres 6 Sep 26 21:58 /var/lib/etcd

srv2
drwx------ 2 postgres postgres 6 Sep 26 21:58 /var/lib/etcd

srv3
drwx------ 2 postgres postgres 6 Sep 26 21:58 /var/lib/etcd

Запуск etcd на узлах кластера​

Подключитесь, например, по ssh в эмуляторах терминала, ко всем трем узлам кластера.

На всех трех узлах кластера подготовим к будущему запуску, но не выполняйте, следующую команду:

[student@srv1 ~]$ sudo systemctl enable --now etcd
Внимание!

Эту команду необходимо выполнить максимально одновременно на всех узлах кластера (для чего и необходимы подключения к узлам кластера). Запуск в цикле for, как это неоднократно выполнялось в этой теме ранее, не подходит, так как в этом случае запуск etcd будет производиться на узлах последовательно.

Запускаем команду на всех трех узлах кластера, не дожидаясь завершения этих команд:

[student@srv1 ~]$ sudo systemctl enable --now etcd
[student@srv2 ~]$ sudo systemctl enable --now etcd
[student@srv3 ~]$ sudo systemctl enable --now etcd

При наличии ошибок, изучая вывод journalctl -u etcd и журнал в /pgerrorlogs/06/etcd, можно устранить проблемы.

Если сообщений об ошибках не получено, проверяем статус в цикле for:

[student@srv1 ~]$ for comp in srv{1..3}; do echo -e "\n${comp}"; ssh $comp sudo systemctl status etcd; done
Вывод команды:

srv1
● etcd.service - Etcd Server
Loaded: loaded (/usr/lib/systemd/system/etcd.service; enabled; preset: disabled)
Drop-In: /usr/lib/systemd/system/service.d
└─10-timeout-abort.conf
Active: active (running) since Sat 2026-09-26 09:11:58 MSK; 6min ago
Main PID: 16130 (etcd)
Tasks: 7 (limit: 7078)
Memory: 22.9M
CPU: 1.746s
CGroup: /system.slice/etcd.service
└─16130 /usr/bin/etcd

...
Sep 26 09:39:54 srv3 systemd[1]: Started Etcd Server.

srv2
● etcd.service - Etcd Server
Loaded: loaded (/usr/lib/systemd/system/etcd.service; enabled; preset: disabled)
Drop-In: /usr/lib/systemd/system/service.d
└─10-timeout-abort.conf
Active: active (running) since Sat 2026-09-26 09:11:58 MSK; 6min ago
Main PID: 3219 (etcd)
Tasks: 7 (limit: 7079)
Memory: 24.2M
CPU: 1.795s
CGroup: /system.slice/etcd.service
└─3219 /usr/bin/etcd

...
Sep 26 09:39:54 srv3 systemd[1]: Started Etcd Server.

srv3
● etcd.service - Etcd Server
Loaded: loaded (/usr/lib/systemd/system/etcd.service; enabled; preset: disabled)
Drop-In: /usr/lib/systemd/system/service.d
└─10-timeout-abort.conf
Active: active (running) since Sat 2026-09-26 09:11:58 MSK; 6min ago
Main PID: 2997 (etcd)
Tasks: 6 (limit: 7079)
Memory: 22.7M
CPU: 1.759s
CGroup: /system.slice/etcd.service
└─2997 /usr/bin/etcd

...
Sep 26 09:39:54 srv3 systemd[1]: Started Etcd Server.

Проверка работоспособности etcd​

В сеансе postgres получим состояние узлов кластера:

[student@srv1 ~]$ sudo su - postgres
[postgres@srv1 ~]$ ETCDCTL_API=3 etcdctl --endpoints=https://srv1:2379,https://srv2:2379,https://srv3:2379 --cert=/pg_ssl/server.crt --key=/pg_ssl/server.key --cacert=/pg_ssl/root.crt endpoint health -w table --cluster
+-------------------+--------+-------------+-------+
| ENDPOINT | HEALTH | TOOK | ERROR |
+-------------------+--------+-------------+-------+
| https://srv3:2379 | true | 10.183379ms | |
| https://srv2:2379 | true | 9.873636ms | |
| https://srv1:2379 | true | 11.014852ms | |
+-------------------+--------+-------------+-------+

Получим также состояние узлов кластера:

[postgres@srv1 ~]$ ETCDCTL_API=3 etcdctl --endpoints=https://srv1:2379,https://srv2:2379,https://srv3:2379 --cert=/pg_ssl/server.crt --key=/pg_ssl/server.key --cacert=/pg_ssl/root.crt endpoint status -w table --cluster
+-------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+-------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| https://srv2:2379 | 616d2b43638b0d8b | 3.5.16 | 20 kB | false | false | 2 | 11 | 11 | |
| https://srv3:2379 | 75927458d4c613d5 | 3.5.16 | 20 kB | false | false | 2 | 11 | 11 | |
| https://srv1:2379 | aae180bda5024aa2 | 3.5.16 | 20 kB | true | false | 2 | 11 | 11 | |
+-------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

А также получим список узлов кластера:

[postgres@srv1 ~]$ ETCDCTL_API=3 etcdctl --endpoints=https://srv1:2379,https://srv2:2379,https://srv3:2379 --cert=/pg_ssl/server.crt --key=/pg_ssl/server.key --cacert=/pg_ssl/root.crt member list -w table
+------------------+---------+------+-------------------+-------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+------+-------------------+-------------------+------------+
| 616d2b43638b0d8b | started | srv2 | https://srv2:2380 | https://srv2:2379 | false |
| 75927458d4c613d5 | started | srv3 | https://srv3:2380 | https://srv3:2379 | false |
| aae180bda5024aa2 | started | srv1 | https://srv1:2380 | https://srv1:2379 | false |
+------------------+---------+------+-------------------+-------------------+------------+

Включение аутентификации в etcd​

Зарегистрируем пользователя root с произвольным паролем, например root123:

[postgres@srv1 ~]$ ETCDCTL_API=3 etcdctl --endpoints=https://srv1:2379,https://srv2:2379,https://srv3:2379 --cert=/pg_ssl/server.crt --key=/pg_ssl/server.key --cacert=/pg_ssl/root.crt user add root
Password of root:
Type password of root again for confirmation:
User root created

Зарегистрируем пользователя patronietcd с произвольным паролем, например patronietcd123:

[postgres@srv1 ~]$ ETCDCTL_API=3 etcdctl --endpoints=https://srv1:2379,https://srv2:2379,https://srv3:2379 --cert=/pg_ssl/server.crt --key=/pg_ssl/server.key --cacert=/pg_ssl/root.crt user add patronietcd
Password of patronietcd:
Type password of patronietcd again for confirmation:
User patronietcd created

Зарегистрируем роль patroni:

[postgres@srv1 ~]$ ETCDCTL_API=3 etcdctl --endpoints=https://srv1:2379,https://srv2:2379,https://srv3:2379 --cert=/pg_ssl/server.crt --key=/pg_ssl/server.key --cacert=/pg_ssl/root.crt role add patroni
Role patroni created

Предоставим роли patroni разрешение на чтение и запись в каталог /service:

[postgres@srv1 ~]$ ETCDCTL_API=3 etcdctl --endpoints=https://srv1:2379,https://srv2:2379,https://srv3:2379 --cert=/pg_ssl/server.crt --key=/pg_ssl/server.key --cacert=/pg_ssl/root.crt role grant-permission patroni readwrite '/service/*'
Role patroni updated

Назначим роль patroni пользователю patronietcd:

[postgres@srv1 ~]$ ETCDCTL_API=3 etcdctl --endpoints=https://srv1:2379,https://srv2:2379,https://srv3:2379 --cert=/pg_ssl/server.crt --key=/pg_ssl/server.key --cacert=/pg_ssl/root.crt user grant-role patronietcd patroni
Role patroni is granted to user patronietcd

Включим аутентификацию:

[postgres@srv1 ~]$ ETCDCTL_API=3 etcdctl --endpoints=https://srv1:2379,https://srv2:2379,https://srv3:2379 --cert=/pg_ssl/server.crt --key=/pg_ssl/server.key --cacert=/pg_ssl/root.crt auth enable
{"level":"warn","ts":"2026-09-26T09:51:07.087025Z","logger":"etcd-client","caller":"v3/retry_interceptor.go:63","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc00001e000/srv1:2379","attempt":0,"error":"rpc error: code = FailedPrecondition desc = etcdserver: root user does not have root role"}
Authentication Enabled
[postgres@srv1 ~]$ exit

Подведем итоги​

Вопрос 1

Вопрос 1: Взгляните на приведенные команды:

[student@srv1 ~]$ sudo su - postgres
===============================================================
 You are connected to Pangolin Cluster (clustername)
 - Hostname             : srv1
 - IP Address           : <IP-Address1> 
---------------------------------------------------------------
 - node ( master )      : srv1 
 - node ( replica )     : srv2 
 - arbiter              : srv3 
 - Manager version      : 2.1.13
 - Pangolin version     : 6.7.0
===============================================================

[postgres@srv1 ~]$ members 
+------------------+---------+------+-------------------+-------------------+------------+
|        ID        | STATUS  | NAME |    PEER ADDRS     |   CLIENT ADDRS    | IS LEARNER |
+------------------+---------+------+-------------------+-------------------+------------+
|   dd06a5adfd1a43 | started | srv1 | https://srv1:2380 | https://srv1:2379 |      false |
| af5a3cfa2efd90a2 | started | srv3 | https://srv3:2380 | https://srv3:2379 |      false |
| bd70183ad55cefc0 | started | srv2 | https://srv2:2380 | https://srv2:2379 |      false |
+------------------+---------+------+-------------------+-------------------+------------+

Исходя из приведенной информации, на каких узлах кластера каталог, заданный ETCD_DATA_DIR, отсутствует?

Вопрос 2

Вопрос 2: Изменены настройки в файле /usr/lib/systemd/system/etcd.service следующим образом:

[student@srv1 ~]$ diff /usr/lib/systemd/system/etcd.service*
11c11
< User=postgres
---
> User=etcd
13c13
< ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) ionice -c2 -n0 /usr/bin/etcd"
---
> ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd"

Что следует сделать сразу после этого?