如何使用Etcdctl和Etcd,CoreOS的分布式键值存储

来自菜鸟教程
跳转至:导航、​搜索

介绍

使 CoreOS 成为可能的技术之一是 etcd,一种全球分布式键值存储。 各个 CoreOS 机器使用此服务来形成集群并作为存储全球可访问数据的平台。

在本指南中,我们将探索 etcd 守护进程以及 etcdctl 实用程序和可用于控制它的 HTTP/JSON API。

先决条件

为了遵循本指南,我们假设您有一个 CoreOS 机器集群作为我们在 在 DigitalOcean 轮廓上设置 CoreOS 集群的指南。 这将使您在一个集群中拥有三台服务器:

  • coreos-1
  • coreos-2
  • coreos-3

启动并运行这些机器后,您可以继续阅读本指南。

Etcd 集群发现模型

etcd 负责的最基本任务之一是将单个机器组织成一个集群。 这是通过在创建时传入的 cloud-config 文件中提供的发现地址签入来引导 CoreOS 时完成的。

CoreOS 运行的发现服务可在 https://discovery.etcd.io 访问。 您可以通过访问/new页面获取新的token。 在那里,您将获得一个令牌,您的机器可以使用它来发现它们的同伴节点。 它看起来像这样:

https://discovery.etcd.io/dcadc5d4d42328488ecdcd7afae5f57c

必须 为每个新集群提供一个新令牌。 这包括当您必须使用可能具有相同 IP 地址的节点重建集群时。 如果您重用发现地址,etcd 实例将被此混淆,并且将无法正常运行以构建集群。

在 Web 浏览器中访问发现地址,您将返回一个描述已知机器的 JSON 对象。 当你第一次开始时,这不会有任何节点:

{"action":"get","node":{"key":"/_etcd/registry/dcadc5d4d42328488ecdcd7afae5f57c","dir":true,"modifiedIndex":102511104,"createdIndex":102511104}}

引导集群后,您将能够在此处查看更多信息:

{"action":"get","node":{"key":"/_etcd/registry/1edee33e6b03e75d9428eacf0ff94fda","dir":true,"nodes":[{"key":"/_etcd/registry/1edee33e6b03e75d9428eacf0ff94fda/2ddbdb7c872b4bc59dd1969ac166501e","value":"http://10.132.252.38:7001","expiration":"2014-09-19T13:41:26.912303668Z","ttl":598881,"modifiedIndex":102453704,"createdIndex":102453704},{"key":"/_etcd/registry/1edee33e6b03e75d9428eacf0ff94fda/921a7241c31a499a97d43f785108b17c","value":"http://10.132.248.118:7001","expiration":"2014-09-19T13:41:29.602508981Z","ttl":598884,"modifiedIndex":102453736,"createdIndex":102453736},{"key":"/_etcd/registry/1edee33e6b03e75d9428eacf0ff94fda/27987f5eaac243f88ca6823b47012c5b","value":"http://10.132.248.121:7001","expiration":"2014-09-19T13:41:41.817958205Z","ttl":598896,"modifiedIndex":102453860,"createdIndex":102453860}],"modifiedIndex":101632353,"createdIndex":101632353}}

如果您需要查找集群的发现 URL,您可以从任何一台作为成员的机器上执行此操作。 可以从 /run 层次结构中检索此信息:

cat /run/systemd/system/etcd.service.d/20-cloudinit.conf
[Service]
Environment="ETCD_ADDR=10.132.248.118:4001"
Environment="ETCD_DISCOVERY=https://discovery.etcd.io/dcadc5d4d42328488ecdcd7afae5f57c"
Environment="ETCD_NAME=921a7241c31a499a97d43f785108b17c"
Environment="ETCD_PEER_ADDR=10.132.248.118:7001"

URL 存储在 ETCD_DISCOVERY 条目中。

当运行 etcd 的机器启动时,它们将检查此 URL 处的信息。 它将提交自己的信息和关于其他成员的查询。 集群中的第一个节点显然不会找到其他节点的信息,因此它将自己指定为集群领导者。

后续机器也将使用其信息联系发现 URL。 他们将收到有关已签入机器的信息。 然后他们将选择其中一台机器并直接连接,在那里他们将获得健康集群成员的完整列表。 数据的复制和分发是通过Raft共识算法完成的。

每台机器的数据都存储在 etcd 内的隐藏目录结构中。 您可以通过键入以下命令查看有关 etcd 知道的机器的信息:

etcdctl ls /_etcd/machines --recursive
/_etcd/machines/2ddbdb7c872b4bc59dd1969ac166501e
/_etcd/machines/921a7241c31a499a97d43f785108b17c
/_etcd/machines/27987f5eaac243f88ca6823b47012c5b

etcd 传递给新集群成员的详细信息包含在这些键中。 您可以通过请求带有 etcdctl 的值来查看各个值:

etcdctl get /_etcd/machines/2ddbdb7c872b4bc59dd1969ac166501e
etcd=http%3A%2F%2F10.132.252.38%3A4001&raft=http%3A%2F%2F10.132.252.38%3A7001

稍后我们将更深入地讨论 etcdctl 命令。

etcdctl 用法

etcd 交互有两种基本方式。 通过 HTTP/JSON API 和客户端,例如包含的 etcdctl 实用程序。 我们将首先介绍 etcdctl

查看密钥和目录

首先,让我们看一下 etcdctl 当前存储的内容。 我们可以通过键入以下内容来查看顶级键:

etcdctl ls /
/coreos.com

如您所见,我们有一个结果。 此时,不清楚这是目录还是键。 我们可以尝试 get 节点来查看键的值或查看它是一个目录:

etcdctl get /coreos.com
/coreos.com: is a directory

为了避免这种手动递归过程,我们可以告诉 etcdctl 通过键入以下内容列出其可见信息的整个层次结构:

etcdctl ls / --recursive
/coreos.com
/coreos.com/updateengine
/coreos.com/updateengine/rebootlock
/coreos.com/updateengine/rebootlock/semaphore

如您所见,最初的 /coreos.com 节点下有很多目录。 我们可以通过在最终端点询问信息来了解从节点获取实际数据的情况:

etcdctl get /coreos.com/updateengine/rebootlock/semaphore
{"semaphore":1,"max":1,"holders":null}

这不包含对我们非常有用的信息。 我们可以通过传入 -o extended 选项来获取有关此条目的一些附加元数据。 这是一个全局选项,所以它必须在 get 命令之前:

etcdctl -o extended get /coreos.com/updateengine/rebootlock/semaphore
Key: /coreos.com/updateengine/rebootlock/semaphore
Created-Index: 6
Modified-Index: 6
TTL: 0
Etcd-Index: 170387
Raft-Index: 444099
Raft-Term: 8

{"semaphore":1,"max":1,"holders":null}

设置键和创建节点

要创建一个新目录,您可以像这样使用 mkdir 命令:

etcdctl mkdir /example

要制作密钥,您可以使用 mk 命令:

etcdctl mk /example/key data
data

这仅在密钥不存在时才有效。 如果我们询问我们创建的键的值,我们可以检索我们设置的数据:

etcdctl get /example/key
data

要更新现有密钥,请使用 update 命令:

etcdctl update /example/key turtles
turtles

用于目录的配套 updatedir 命令可能仅在您设置了 TTL 或目录的生存时间时才有用。 这将使用经过的时间更新 TTL 时间。 您可以通过传递 --ttl # 参数为目录或键设置 TTL,其中“#”是要保留的秒数:

etcdctl mkdir /here/you/go --ttl 120

然后您可以使用 updatedir 更新 TTL:

etcdctl updatedir /here/you/go --ttl 500

要更改现有密钥的值,或在密钥不存在时创建密钥,请使用 set 命令。 将此视为 mkupdate 命令的组合:

etcdctl set /example/key new
new

这可以包括不存在的路径。 路径组件将动态创建:

etcdctl set /a/b/c here
here

要为目录获得相同的 create-if-does-not-exist 功能,您可以使用 setdir 命令:

etcdctl setdir /x/y/z

注意setdir 命令当前不按所述运行。 在当前构建中,它的用法反映了 updatedir 命令,如果目录已经存在,它将失败。 GitHub 存储库上有一个未解决的问题来解决这个问题。

删除条目

要删除现有密钥,您可以使用 rmrmdir 命令。

rm 命令可用于删除密钥:

etcdctl rm /a/b/c

它也可以递归地用于删除目录和每个子目录:

etcdctl rm /a --recursive

要仅删除一个空目录 一个键,请使用 rmdir 命令:

etcdctl rmdir /x/y/z

这可用于确保您只删除层次结构的端点。

关注变化

您可以查看特定键或整个目录的更改。 用 etcdctl 观看这些将导致操作挂起,直到正在观看的任何事件发生某些事件。

要查看密钥,请在没有任何标志的情况下使用它:

etcdctl watch /example/hello

要停止观看,您可以按 CTRL-C。 如果在 watch 期间检测到变化,则返回新值。

要查看整个目录结构,请使用 --recursive 标志:

etcdctl watch --recursive /example

您可以通过将其放置在一个简单的循环结构中以不断监视值的状态来了解这将如何有用:

while true; do etcdctl watch --recursive /example; done

如果您想在检测到更改时执行命令,请使用 exec-watch 命令:

etcdctl exec-watch --recursive  /example -- echo "hello"

每当该目录中的值更改时,这将在屏幕上回显“hello”。

隐藏的价值

一件不是很明显的事情是 etcd 中有隐藏的目录结构。 这些是以下划线开头的目录或键。

传统的 etcdctl 工具没有列出这些,您必须知道要查找的内容才能找到它们。

例如,有一个名为 /_coreos.com 的隐藏目录包含一些关于 fleet 的内部信息。 您可以通过明确要求来查看层次结构:

etcdctl ls --recursive /_coreos.com 
/_coreos.com/fleet
/_coreos.com/fleet/states
/_coreos.com/fleet/states/apache@6666.service
/_coreos.com/fleet/states/apache@6666.service/2ddbdb7c872b4bc59dd1969ac166501e
/_coreos.com/fleet/states/apache@7777.service
/_coreos.com/fleet/states/apache@7777.service/921a7241c31a499a97d43f785108b17c
. . .

另一个这样的目录结构位于 /_etcd 中:

etcdctl ls --recursive /_etcd
/_etcd/machines
/_etcd/machines/27987f5eaac243f88ca6823b47012c5b
/_etcd/machines/2ddbdb7c872b4bc59dd1969ac166501e
/_etcd/machines/921a7241c31a499a97d43f785108b17c
/_etcd/config

这些功能与任何其他条目完全相同,唯一的区别是它们不会出现在一般列表中。 您可以通过简单地用下划线开始您的键或目录名称来创建它们。

Etcd HTTP/JSON API 使用

etcd 交互的另一种方式是使用简单的 HTTP/JSON API。

要访问 API,您可以使用简单的 HTTP 程序,例如 curl。 您必须提供 -L 标志以遵循任何传回的重定向。 在集群中,您可以使用本地 127.0.0.1 接口和端口 4001 进行大多数查询。

注意:要从Docker容器内连接到etcd,可以使用地址http://172.17.42.1:4001。 这对于应用程序根据注册信息更新其配置很有用。

可以通过在任何主机上转到 http://127.0.0.1:4001/v2/keys/ 来访问普通键空间。 例如,要获取顶级键/目录的列表,请键入:

curl -L http://127.0.0.1:4001/v2/keys/
{"action":"get","node":{"key":"/","dir":true,"nodes":[{"key":"/coreos.com","dir":true,"modifiedIndex":6,"createdIndex":6},{"key":"/services","dir":true,"modifiedIndex":333,"createdIndex":333}]}}

请求中的尾部斜杠是强制性的。 没有它,它将无法正确解决。

您可以使用普通 HTTP 动词设置或检索值。

要修改这些操作的行为,您可以使用 ?flag=value 语法在请求结束时传入标志。 多个标志可以用 & 字符分隔。

例如,要递归列出所有键,我们可以键入:

curl -L http://127.0.0.1:4001/v2/keys/?recursive=true
{"action":"get","node":{"key":"/","dir":true,"nodes":[{"key":"/coreos.com","dir":true,"nodes":[{"key":"/coreos.com/updateengine","dir":true,"nodes":[{"key":"/coreos.com/updateengine/rebootlock","dir":true,"nodes":[{"key":"/coreos.com/updateengine/rebootlock/semaphore","value":"{\"semaphore\":1,\"max\":1,\"holders\":null}","modifiedIndex":6,"createdIndex":6}],"modifiedIndex":6,"createdIndex":6}],"modifiedIndex":6,"createdIndex":6}],"modifiedIndex":6,"createdIndex":6}. . .

可以在普通键空间之外访问的另一条有用信息是版本信息,可在此处访问:

curl -L http://127.0.0.1:4001/version
etcd 0.4.6

您可以通过访问此端点查看有关每个集群领导者与每个追随者关系的统计信息:

curl -L http://127.0.0.1:4001/v2/stats/leader
{"leader":"921a7241c31a499a97d43f785108b17c","followers":{"27987f5eaac243f88ca6823b47012c5b":{"latency":{"current":1.607038,"average":1.3762888642395448,"standardDeviation":1.4404313533578545,"minimum":0.471432,"maximum":322.728852},"counts":{"fail":0,"success":98718}},"2ddbdb7c872b4bc59dd1969ac166501e":{"latency":{"current":1.584985,"average":1.1554367141497013,"standardDeviation":0.6872303198242179,"minimum":0.427485,"maximum":31.959235},"counts":{"fail":0,"success":98723}}}}

可以使用类似的操作来检测有关您当前所在机器的统计信息:

curl -L http://127.0.0.1:4001/v2/stats/self
{"name":"921a7241c31a499a97d43f785108b17c","state":"leader","startTime":"2014-09-11T16:42:03.035382298Z","leaderInfo":{"leader":"921a7241c31a499a97d43f785108b17c","uptime":"1h19m11.469872568s","startTime":"2014-09-12T19:47:25.242151859Z"},"recvAppendRequestCnt":1944480,"sendAppendRequestCnt":201817,"sendPkgRate":40.403374523779064,"sendBandwidthRate":3315.096879676072}

要查看有关已执行操作的统计信息,请键入:

curl -L http://127.0.0.1:4001/v2/stats/store
{"getsSuccess":78823,"getsFail":14,"setsSuccess":121370,"setsFail":4,"deleteSuccess":28,"deleteFail":32,"updateSuccess":20468,"updateFail":4,"createSuccess":39,"createFail":102340,"compareAndSwapSuccess":51169,"compareAndSwapFail":0,"compareAndDeleteSuccess":0,"compareAndDeleteFail":0,"expireCount":3,"watchers":6}

这些只是可用于通过 API 控制 etcd 的一些操作。

等配置

etcd 服务可以通过几种不同的方式进行配置。

第一种方法是使用用于引导节点的 cloud-config 文件传入参数。 在引导指南中,您看到了一些有关如何执行此操作的信息:

#cloud-config

coreos:
  etcd:
    discovery: https://discovery.etcd.io/<token>
    addr: $private_ipv4:4001
    peer-addr: $private_ipv4:7001
. . .

要查看可用的选项,请将 -h 标志与 etcd 一起使用:

etcd -h

要在 cloud-config 中包含这些选项,只需去掉前导破折号并用冒号而不是等号将键与值分开。 所以 -peer-addr=<host:port> 变成 peer-addr: <host:port>

在读取 cloud-config 文件后,CoreOS 会将这些转换为存根单元文件中的环境变量,用于启动服务。

调整 etcd 设置的另一种方法是通过 API。 这通常使用 7001 端口而不是用于键查询的标准 4001 来完成。

例如,您可以通过键入以下内容获取一些当前配置值:

curl -L http://127.0.0.1:7001/v2/admin/config
{"activeSize":9,"removeDelay":1800,"syncInterval":5}

您可以通过使用 PUT 操作将新 JSON 作为数据负载传入来更改这些值:

curl -L http://127.0.0.1:7001/v2/admin/config -XPUT -d '{"activeSize":9,"removeDelay":1800,"syncInterval":5}'
{"activeSize":9,"removeDelay":1800,"syncInterval":5}

要获取机器列表,您可以转到 /v2/admin/machines 端点:

curl -L http://127.0.0.1:7001/v2/admin/machines
[{"name":"27987f5eaac243f88ca6823b47012c5b","state":"follower","clientURL":"http://10.132.248.121:4001","peerURL":"http://10.132.248.121:7001"},{"name":"2ddbdb7c872b4bc59dd1969ac166501e","state":"follower","clientURL":"http://10.132.252.38:4001","peerURL":"http://10.132.252.38:7001"},{"name":"921a7241c31a499a97d43f785108b17c","state":"leader","clientURL":"http://10.132.248.118:4001","peerURL":"http://10.132.248.118:7001"}]

这可用于使用 DELETE 方法从集群中强制删除机器。

结论

如您所见,etcd 可用于从集群中的任何机器存储或检索信息。 这允许您同步数据并为服务提供查找配置数据和连接详细信息的位置。

这在构建分布式系统时特别有用,因为您可以提供一个简单的端点,该端点在集群中的任何位置都有效。 通过利用此资源,您的服务可以动态配置自己。