gRPC proxy
gRPC proxy — це stateless зворотний проксі-сервер etcd, що працює на рівні gRPC (L7). Проксі-сервер призначений для зменшення загального навантаження на основний кластер etcd. Для горизонтальної масштабованості він обʼєднує запити API спостереження та оренди. Щоб захистити кластер від зловмисних клієнтів, він кешує запити діапазону ключів.
gRPC proxy підтримує кілька точок доступу сервера etcd. Коли проксі-сервер запускається, він випадковим чином вибирає одну точку доступу сервера etcd для використання. Ця точка доступу обслуговує всі запити, доки проксі-сервер не виявить збій точки доступу. Якщо gRPC proxy виявляє збій точки доступу, він перемикається на іншу точку доступу, якщо вона доступна, щоб приховати збої від своїх клієнтів. Інші політики повторних спроб, такі як зважений круговий алгоритм, можуть бути підтримані в майбутньому.
Масштабований API спостереження
gRPC proxy обʼєднує кілька клієнтських спостерігачів (c-watchers
) за одним ключем або діапазоном в одного спостерігача (s-watcher
), підключеного до сервера etcd. Проксі-сервер транслює всі події від s-watcher
до своїх c-watchers
.
Припустимо, що N клієнтів спостерігають за одним і тим же ключем, один gRPC proxy може зменшити навантаження на сервер спостереження з N до 1. Користувачі можуть розгорнути кілька gRPC proxy для подальшого розподілу навантаження на сервер.
У наступному прикладі три клієнти спостерігають за ключем A. gRPC proxy обʼєднує трьох спостерігачів, створюючи одного спостерігача, підключеного до сервера etcd.
+-------------+
| etcd server |
+------+------+
^ watch key A (s-watcher)
|
+-------+-----+
| gRPC proxy | <-------+
| | |
++-----+------+ |watch key A (c-watcher)
watch key A ^ ^ watch key A |
(c-watcher) | | (c-watcher) |
+-------+-+ ++--------+ +----+----+
| client | | client | | client |
| | | | | |
+---------+ +---------+ +---------+
Обмеження
Щоб ефективно обʼєднати кілька клієнтських спостерігачів в одного спостерігача, gRPC proxy обʼєднує нових c-watchers
в наявного s-watcher
, коли це можливо. Цей обʼєднаний s-watcher
може бути не синхронізований з сервером etcd через затримки в мережі або буферизовані недоставлені події. Коли ревізія спостереження не вказана, gRPC proxy не гарантує, що c-watcher
почне спостерігати з найновішої ревізії сховища. Наприклад, якщо клієнт спостерігає з сервера etcd з ревізією 1000, цей спостерігач почне з ревізії 1000. Якщо клієнт спостерігає з gRPC proxy, він може почати спостерігати з ревізії 990.
Подібні обмеження застосовуються до скасування. Коли спостерігач скасовується, ревізія сервера etcd може бути більшою за ревізію відповіді на скасування.
Ці два обмеження не повинні викликати проблем для більшості випадків використання. У майбутньому можуть бути додаткові опції для примусового обходу gRPC proxy для більш точних відповідей ревізії.
Масштабований API оренди
Щоб підтримувати свої оренди в активному стані, клієнт повинен встановити принаймні один gRPC потік до сервера etcd для надсилання періодичних сигналів. Якщо робоче навантаження etcd включає інтенсивну активність оренди, розподілену між багатьма клієнтами, ці потоки можуть сприяти надмірному використанню ЦП. Щоб зменшити загальну кількість потоків на основному кластері, проксі-сервер підтримує обʼєднання потоків оренди.
Припустимо, що N клієнтів оновлюють оренди, один gRPC proxy зменшує навантаження на потоки на сервері etcd з N до 1. Розгортання може мати додаткові gRPC proxy для подальшого розподілу потоків між кількома проксі-серверами.
У наступному прикладі три клієнти оновлюють три незалежні оренди (L1
, L2
та L3
). gRPC proxy обʼєднує три клієнтські потоки оренди (c-streams
) в один потік підтримки оренди (s-stream
), підключений до сервера etcd. Проксі-сервер пересилає клієнтські сигнали оренди з c-streams до s-stream, а потім повертає відповіді до відповідних c-streams.
+-------------+
| etcd server |
+------+------+
^
| heartbeat L1, L2, L3
| (s-stream)
v
+-------+-----+
| gRPC proxy +<-----------+
+---+------+--+ | heartbeat L3
^ ^ | (c-stream)
heartbeat L1 | | heartbeat L2 |
(c-stream) v v (c-stream) v
+------+-+ +-+------+ +-----+--+
| client | | client | | client |
+--------+ +--------+ +--------+
Захист від зловмисних клієнтів
gRPC proxy кешує відповіді на запити, коли це не порушує вимоги до узгодженості. Це може захистити сервер etcd від зловмисних клієнтів у щільних циклах for.
Запуск etcd gRPC proxy
Розглянемо кластер etcd з наступними статичними точками доступу:
Імʼя | Адреса | Хост |
---|---|---|
infra0 | 10.0.1.10 | infra0.example.com |
infra1 | 10.0.1.11 | infra1.example.com |
infra2 | 10.0.1.12 | infra2.example.com |
Запустіть etcd gRPC proxy для використання цих статичних точок доступу за допомогою команди:
$ etcd grpc-proxy start --endpoints=infra0.example.com,infra1.example.com,infra2.example.com --listen-addr=127.0.0.1:2379
etcd gRPC proxy запускається і слухає на порту 2379. Він пересилає клієнтські запити на одну з трьох точок доступу, наведених вище.
Надсилання запитів через проксі-сервер:
$ ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 put foo bar
OK
$ ETCDCTL_API=3 etcdctl --endpoints=127.0.0.1:2379 get foo
foo
bar
Синхронізація точок доступу клієнта та розвʼязання імен
Проксі-сервер підтримує реєстрацію своїх точок доступу для виявлення шляхом запису до точки доступу, визначеної користувачем. Це служить двом цілям. По-перше, це дозволяє клієнтам синхронізувати свої точки доступу з набором точок доступу проксі-сервера для високої доступності. По-друге, це постачальник точок доступу для etcd gRPC naming.
Зареєструйте проксі-сервер(и), надавши префікс, визначений користувачем:
$ etcd grpc-proxy start --endpoints=localhost:2379 \
--listen-addr=127.0.0.1:23790 \
--advertise-client-url=127.0.0.1:23790 \
--resolver-prefix="___grpc_proxy_endpoint" \
--resolver-ttl=60
$ etcd grpc-proxy start --endpoints=localhost:2379 \
--listen-addr=127.0.0.1:23791 \
--advertise-client-url=127.0.0.1:23791 \
--resolver-prefix="___grpc_proxy_endpoint" \
--resolver-ttl=60
Проксі-сервер покаже всіх своїх членів для списку членів:
ETCDCTL_API=3 etcdctl --endpoints=http://localhost:23790 member list --write-out table
+----+---------+--------------------------------+------------+-----------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS |
+----+---------+--------------------------------+------------+-----------------+
| 0 | started | Gyu-Hos-MBP.sfo.coreos.systems | | 127.0.0.1:23791 |
| 0 | started | Gyu-Hos-MBP.sfo.coreos.systems | | 127.0.0.1:23790 |
+----+---------+--------------------------------+------------+-----------------+
Це дозволяє клієнтам автоматично виявляти точки доступу проксі-сервера через Sync:
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{"http://localhost:23790"},
})
if err != nil {
log.Fatal(err)
}
defer cli.Close()
// fetch registered grpc-proxy endpoints
if err := cli.Sync(context.Background()); err != nil {
log.Fatal(err)
}
Зверніть увагу, що якщо проксі-сервер налаштований без префікса розвʼязувача,
$ etcd grpc-proxy start --endpoints=localhost:2379 \
--listen-addr=127.0.0.1:23792 \
--advertise-client-url=127.0.0.1:23792
API списку членів для grpc-proxy повертає власний advertise-client-url
:
ETCDCTL_API=3 etcdctl --endpoints=http://localhost:23792 member list --write-out table
+----+---------+--------------------------------+------------+-----------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS |
+----+---------+--------------------------------+------------+-----------------+
| 0 | started | Gyu-Hos-MBP.sfo.coreos.systems | | 127.0.0.1:23792 |
+----+---------+--------------------------------+------------+-----------------+
Просторове розмежування
Припустимо, що застосунок очікує повного контролю над усім простором ключів, але кластер etcd спільно використовується з іншими застосунками. Щоб усі застосунки могли працювати без взаємного втручання, проксі-сервер може розділити простір ключів etcd так, щоб клієнти мали доступ до повного простору ключів. Коли проксі-сервер отримує прапорець --namespace
, всі клієнтські запити, що надходять до проксі-сервера, перетворюються на ключі з префіксом, визначеним користувачем. Доступи до кластера etcd будуть з префіксом, а відповіді від проксі-сервера будуть видаляти префікс; для клієнта це виглядає так, ніби префікса взагалі немає.
Щоб розмежувати проксі-сервер, запустіть його з прапорцем --namespace
:
$ etcd grpc-proxy start --endpoints=localhost:2379 \
--listen-addr=127.0.0.1:23790 \
--namespace=my-prefix/
Доступи до проксі-сервера тепер прозоро префіксуються у кластері etcd:
$ ETCDCTL_API=3 etcdctl --endpoints=localhost:23790 put my-key abc
# OK
$ ETCDCTL_API=3 etcdctl --endpoints=localhost:23790 get my-key
# my-key
# abc
$ ETCDCTL_API=3 etcdctl --endpoints=localhost:2379 get my-prefix/my-key
# my-prefix/my-key
# abc
Термінація TLS
Термінує TLS з захищеного кластера etcd за допомогою gRPC proxy, обслуговуючи незашифровану локальну точку доступу.
Щоб спробувати це, запустіть кластер etcd з одним учасником з клієнтським https:
$ etcd --listen-client-urls https://localhost:2379 --advertise-client-urls https://localhost:2379 --cert-file=peer.crt --key-file=peer.key --trusted-ca-file=ca.crt --client-cert-auth
Переконайтеся, що клієнтський порт обслуговує https:
# fails
$ ETCDCTL_API=3 etcdctl --endpoints=http://localhost:2379 endpoint status
# works
$ ETCDCTL_API=3 etcdctl --endpoints=https://localhost:2379 --cert=client.crt --key=client.key --cacert=ca.crt endpoint status
Далі, запустіть gRPC proxy на localhost:12379
, підключившись до точки доступу etcd https://localhost:2379
за допомогою клієнтських сертифікатів:
$ etcd grpc-proxy start --endpoints=https://localhost:2379 --listen-addr localhost:12379 --cert client.crt --key client.key --cacert=ca.crt --insecure-skip-tls-verify &
Нарешті, перевірте термінування TLS, вставивши ключ у проксі-сервер через http:
$ ETCDCTL_API=3 etcdctl --endpoints=http://localhost:12379 put abc def
# OK
Метрики та справність
gRPC proxy експонує точки доступу /health
та Prometheus /metrics
для учасників etcd, визначених за допомогою --endpoints
. Альтернативно, можна визначити додаткову URL-адресу, яка буде відповідати як на /metrics
, так і на /health
за допомогою прапорця --metrics-addr
.
$ etcd grpc-proxy start \
--endpoints https://localhost:2379 \
--metrics-addr https://0.0.0.0:4443 \
--listen-addr 127.0.0.1:23790 \
--key client.key \
--key-file proxy-server.key \
--cert client.crt \
--cert-file proxy-server.crt \
--cacert ca.pem \
--trusted-ca-file proxy-ca.pem
Відомі проблеми
Основний інтерфейс проксі-сервера обслуговує як HTTP2, так і HTTP/1.1. Якщо проксі-сервер налаштований з TLS, як показано в наведеному вище прикладі, при використанні клієнта, такого як cURL, для інтерфейсу прослуховування потрібно буде явно встановити протокол HTTP/1.1 у запиті для повернення /metrics
або /health
. Використовуючи прапорець --metrics-addr
, вторинний інтерфейс не матиме цієї вимоги.
$ curl --cacert proxy-ca.pem --key proxy-client.key --cert proxy-client.crt https://127.0.0.1:23790/metrics --http1.1
Відгук
Чи це було корисним?
Раді чути! Будь ласка, повідомте нам, як ми можемо зробити краще.
Дуже шкода це чути. Будь ласка, повідомте нам, як ми можемо зробити краще.