etcd gateway 介绍
etcd 网关
- etcd 网关是一个简单的 TCP 代理,可将网络数据转发到 etcd 集群
- 网关是无状态且透明的,它既不会检查客户端请求,也不会干扰集群响应,支持多个 etcd 服务器实例,并采用简单的循环策略
- etcd 网关位于 etcd 集群和应用程序之间,使客户端应用不会感知 etcd 集群实例的变化;发生 etcd 集群实例的变更时,只需要更新其端点接口
- 作用
- 性能提示:etcd 网关不是为提高 etcd 集群性能设计的
- 在集群上运行关系系统
- 为自动传播集群端点更改
启动服务
启动参数
$ etcd gateway start --help
start the gateway
Usage:
etcd gateway start [flags]
Flags:
--discovery-srv string DNS domain used to bootstrap initial cluster
--discovery-srv-name string service name to query when using DNS discovery
--endpoints strings comma separated etcd cluster endpoints (default [127.0.0.1:2379])
-h, --help help for start
--insecure-discovery accept insecure SRV records
--listen-addr string listen address (default "127.0.0.1:23790") 默认监听端口
--retry-delay duration duration of delay before retrying failed endpoints (default 1m0s) 重试连接到失败的端点延迟时间,默认为 1m0s
--trusted-ca-file string path to the client server TLS CA file for verifying the discovered endpoints when discovery-srv is provided.
$ etcd gateway start --endpoints=http://172.20.0.2:2379,http://172.20.0.3:2379,http://172.20.0.3:2379
{"level":"info","ts":"2022-10-02T09:50:44.185929Z","caller":"etcdmain/gateway.go:103","msg":"Running: ","args":["etcd","gateway","start","--endpoints=http://172.20.0.2:2379,http://172.20.0.3:2379,http://172.20.0.3:2379"]}
{"level":"info","ts":"2022-10-02T09:50:44.186437Z","caller":"etcdmain/main.go:44","msg":"notifying init daemon"}
{"level":"info","ts":"2022-10-02T09:50:44.18651Z","caller":"etcdmain/main.go:50","msg":"successfully notified init daemon"}
{"level":"info","ts":"2022-10-02T09:50:44.186544Z","caller":"tcpproxy/userspace.go:87","msg":"ready to proxy client requests","endpoints":["172.20.0.2:2379","172.20.0.3:2379","172.20.0.3:2379"]}
- etcd v3 使用 gRPC 作为消息传输协议,包括
- Go client
- 命令行 etcdctl 客户端通过 gRPC 框架与 etcd 集群通讯
gRPC-Gateway
- gRPC-Gateway 是对于 etcd 的 gRPC 通信协议的补充
- 有些语言的客户端不支持 gRPC 通信协议,此时可以使用 gRPC-Gateway 对外提供 HTTP API 接口,通过 HTTP 请求,实现与 gRPC 调用协议相同的功能
HTTP 简单使用
# put 写
$ curl -L http://localhost:2379/v3/kv/put -X POST -d '{"key": "Zm9v", "value": "YmFy"}'
{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"2","raft_term":"5"}}
# range 读
$ curl -L http://localhost:2379/v3/kv/range -X POST -d '{"key": "Zm9v"}'
{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"2","raft_term":"5"},"kvs":[{"key":"Zm9v","create_revision":"2","mod_revision":"2","version":"1","value":"YmFy"}],"count":"1"}
# watch HTTP 请求客户端与 etcd 服务端建立长连接,当监听的键值对发生变化时,会将监听事件通知给客户端
$ curl -N http://localhost:2379/v3/watch -X POST -d '{"create_request": {"key": "Zm9v"}}'
{"result":{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"3","raft_term":"5"},"created":true}}
etcd 事务的实现
- 事务用于完成一组操作,通过对比指定的条件,成功的情况下执行相应的操作,否则回滚
$ curl -L http://localhost:2379/v3/kv/txn -X POST -d '{"compare": [{"target": "CREATE", "key": "Zm9v", "createRevision": "4"}], "success": [{"requestPut": {"key": "Zm9v", "value": "YmFy"}}]}'
{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"4","raft_term":"5"}
###s 基于角色的授权
HTTP 方式访问 etcd 服务端,需要考虑安全问题,gRPC-Gateway
中提供的 API 接口支持开发安全认证
# 创建用户
$ curl -L http://localhost:2379/v3/auth/user/add -X POST -d '{"name": "root", "password": "123456"}'
{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"4","raft_term":"5"}}
# 创建角色
$ curl -L http://localhost:2379/v3/auth/role/add -X POST -d '{"name": "root"}'
{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"4","raft_term":"5"}}
# 用户授权角色
$ curl -L http://localhost:2379/v3/auth/user/grant -X POST -d '{"user": "root", "role": "root"}'
{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"4","raft_term":"5"}}
# 开启认证
$ curl -L http://localhost:2379/v3/auth/enable -X POST -d '{}'
{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"4","raft_term":"5"}}
# 获取 token
$ curl -L http://localhost:2379/v3/auth/authenticate -X POST -d '{"name": "root", "password": "123456"}'
{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"4","raft_term":"5"},"token":"mbgsVGCWITJmJvmo.22"}
# 使用 token 更新数据
$ curl -L http://localhost:2379/v3/kv/put -H "Authorization: mbgsVGCWITJmJvmo.22" -X POST -d '{"key": "Zm9v", "value": "YmFy"}'
{"header":{"cluster_id":"10316109323310759371","member_id":"12530464223947363063","revision":"5","raft_term":"5"}}
$ 错误 token 示例
$ curl -L http://localhost:2379/v3/kv/put -H "Authorization: xxx" -X POST -d '{"key": "Zm9v", "value": "YmFy"}'
{"error":"etcdserver: invalid auth token","code":16,"message":"etcdserver: invalid auth token"}
gRPC Proxy
- gRPC 代理模式:实现可伸缩的 etcd API,它是在 gRPC 层(L7)运行的无状态 etcd 反向代理,旨在减少核心 etcd 集群上的总处理负载
启动服务
$ etcd grpc-proxy start --help
start the grpc proxy
Usage:
etcd grpc-proxy start [flags]
Flags:
--advertise-client-url string advertise address to register (must be reachable by client) (default "127.0.0.1:23790")
--auto-tls proxy TLS using generated certificates
--cacert string verify certificates of TLS-enabled secure etcd servers using this CA bundle
--cert string identify secure connections with etcd servers using this TLS certificate file
--cert-file string identify secure connections to the proxy using this TLS certificate file
--client-crl-file string proxy client certificate revocation list file.
--data-dir string Data directory for persistent data (default "default.proxy")
--debug Enable debug-level logging for grpc-proxy.
--dial-keepalive-time duration keepalive time for client(grpc-proxy) connections (default 0, disable).
--dial-keepalive-timeout duration keepalive timeout for client(grpc-proxy) connections (default 20s). (default 20s)
--discovery-srv string domain name to query for SRV records describing cluster endpoints
--discovery-srv-name string service name to query when using DNS discovery
--enable-pprof Enable runtime profiling data via HTTP server. Address is at client URL + "/debug/pprof/"
--endpoints strings comma separated etcd cluster endpoints (default [127.0.0.1:2379])
--endpoints-auto-sync-interval duration etcd endpoints auto sync interval (disabled by default)
--experimental-leasing-prefix string leasing metadata prefix for disconnected linearized reads.
--experimental-serializable-ordering Ensure serializable reads have monotonically increasing store revisions across endpoints.
--grpc-keepalive-interval duration Frequency duration of server-to-client ping to check if a connection is alive (0 to disable). (default 2h0m0s)
--grpc-keepalive-min-time duration Minimum interval duration that a client should wait before pinging proxy. (default 5s)
--grpc-keepalive-timeout duration Additional duration of wait before closing a non-responsive connection (0 to disable). (default 20s)
-h, --help help for start
--insecure-discovery accept insecure SRV records
--insecure-skip-tls-verify skip authentication of etcd server TLS certificates (CAUTION: this option should be enabled only for testing purposes)
--key string identify secure connections with etcd servers using this TLS key file
--key-file string identify secure connections to the proxy using this TLS key file
--listen-addr string listen address (default "127.0.0.1:23790") 默认监听端口
--listen-cipher-suites strings Comma-separated list of supported TLS cipher suites between client/proxy (empty will be auto-populated by Go).
--max-concurrent-streams uint32 Maximum concurrent streams that each client can open at a time. (default 4294967295)
--max-recv-bytes int message receive limits in bytes (default value is math.MaxInt32) (default 2147483647)
--max-send-bytes int message send limits in bytes (default value is 1.5 MiB) (default 1572864)
--metrics-addr string listen for endpoint /metrics requests on an additional interface
--namespace string string to prefix to all keys for namespacing requests
--permit-without-stream Enable client(grpc-proxy) to send keepalive pings even with no active RPCs.
--resolver-prefix string prefix to use for registering proxy (must be shared with other grpc-proxy members)
--resolver-ttl int specify TTL, in seconds, when registering proxy endpoints
--self-signed-cert-validity uint The validity period of the proxy certificates, unit is year (default 1)
--trusted-ca-file string verify certificates of TLS-enabled secure proxy using this CA bundle
$ etcd grpc-proxy start --endpoints=http://172.20.0.2:2379,http://172.20.0.3:2379,http://172.20.0.3:2379
...
{"level":"info","ts":"2024-06-30T10:51:53.632251Z","caller":"zapgrpc/zapgrpc.go:174","msg":"[roundrobin] roundrobinPicker: Build called with info: {map[SubConn(id:5):{{Addr: \"127.0.0.1:23790\", ServerName: \"127.0.0.1:23790\", }}]}"}
{"level":"info","ts":"2024-06-30T10:51:53.632282Z","caller":"zapgrpc/zapgrpc.go:174","msg":"[core] [Channel #4] Channel Connectivity change to READY"}
$ ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:23790 put foo bar
$ ETCDCTL_API=3 etcdctl --endpoints=http://127.0.0.1:23790 get foo
# 不指定 --resolver-prefix 时,获取成员列表只能显示当前的节点信息
$ etcd grpc-proxy start --endpoints=http://172.20.0.2:2379 --listen-addr 127.0.0.1:23790 --advertise-client-url 127.0.0.1:23790 --resolver-prefix="__grpc_proxy_endpoint" --resolver-ttl=60
$ etcdctl --endpoints=127.0.0.1:23790 member list --write-out table
# 上述方式,支持golang lib通过 Sync 方法自动发现代理的端点
可伸缩的 watch API
- 如果客户端监听同一键或某一范围内的键,gRPC-Proxy 代理可以将这些
客户端监视程序(c-watcher)
合并为连接到 etcd 服务器的单个监听程序(s-watcher
) - 当 watch 事件发生时,代理讲所有事件从
s-watcher
广播到其 c-watcher
可伸缩的 rease API
- 如果 etcd 工作负载涉及很多的客户端租约活动,这些流可能导致 CPU 使用率过高,为减少核心集群上流的总数,gRPC Proxy支持将 lease 流合并
- 该功能可以保护 etcd 服务器免遭恶意 for 循环中滥用客户端的工具
命名空间的实现
- 当应用程序期望对整个键空间有完全控制,etcd 集群与其他应用程序共享的情况下,为了使所有应用程序都不会相互干扰地运行,Proxy 可以对 etcd 键
空间(namespace)
进行分区,以便客户端大概率访问完整的键空间 - 启动 proxy 时,提供
--namespace
参数,所有进入该 Proxy 的客户端请求都将转化为在键上具有用户定义的前缀
其他
- /health 、:6633/metrics 健康和 prometheus 检测接口