如何使用Etcdctl与Etcd——CoreOS的分布式键-值存储

时间:2022-06-03 06:06:10

提供:ZStack云计算

系列教程

本教程为CoreOS上手指南系列九篇中的第四篇。

内容介绍

作为CoreOS的实现根基之一,etcd能够为我们提供一套全局分布式键-值存储机制。此服务可由各CoreOS设备使用,从而构建起一套集群并作为全局可访问数据的存储平台。

在本教程中,我们将探讨etcd守护程序、etcdctl工具以及用于对其加以控制的HTTP/JSON API。

先决条件

要完成本教程,大家需要参阅在DigitalOcean上设置CoreOS集群建立起一套CoreOS集群,其中包含三套服务器:

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

完成之后,即可进一步遵循本教程中的各个步骤。

Etcd集群发现模式

etcd的一项根本性作用在于将多*立设备构建为单一集群。在这一过程中,CoreOS会在引导时检查cloud-config文件内提供的发现地址。

此发现服务可通过https://discovery.etcd.io进行访问。访问其/new页面能够获取一份新令牌。接下来,我们可以使用此令牌帮助设备发现其它集群内节点。令牌内容如下:

https://discovery.etcd.io/dcadc5d4d42328488ecdcd7afae5f57c

大家必须为每套新集群提供新令牌。其中包括使用可能拥有相同IP地址的节点进行集群重构的情况。否则,etcd实例会无法正确识别使用相同IP的节点,因此导致功能失效。

在浏览器中查看此发现地址,大家会获得一个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扩展获取更多与其相关的元数据。其属于全局选项,因此必须放在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命令。大家可以将其视为mk与update命令的结合:

etcdctl set /example/key new

new

其中可包含不存在的路径。其路径组成部分可进行动态创建:

etcdctl set /a/b/c here

here

要对目录实现同样的“若不存在则创建”功能,可使用setdir命令:

etcdctl setdir /x/y/z

注意:setdir命令目前尚未实装。在目前的build中,其直接照搬updatedir命令,且如果目录不存在则会运行失败。目前GitHub中已经有在公开讨论其解决办法。

移除条目

要移除已有键,可以使用rm或者rmdir命令。

其中rm命令用于移除一条键:

etcdctl rm /a/b/c

其可用于确保只递归删除某一目录及其下各子目录:

etcdctl rm /a --recursive

要仅移除某个空目录或者某条键,则使用rmdir命令:

etcdctl rmdir /x/y/z

其可确保只移除目录结构下的特定端点。

观察变化

大家可以留意特定键或者完整目录的全部变化。使用etcdctl命令会导致其挂起,直到所关注的事件执行完成。

要观察特定键,则直接使用此命令且不加任何标记:

etcdctl watch /example/hello

要停止观察,按下CTRL-C。如果观察过程中发现了变化,则返回新值。

要观察完整的目录结构,则使用–recursive标记:

etcdctl watch --recursive /example

大家可以看到其如何利用简单的循环结构不断监测各值状态:

whiletrue; 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,大家可以使用curl等简单的HTTP命令。大家也可以添加-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配置

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会将其翻译为stub单元文件中的环境变量,并利用其启动该服务。

另一种etcd设置调整方式为通过API。其使用端口7001而非4001。

例如,大家可以通过以下命令获取部分当前配置值:

curl -L http://127.0.0.1:7001/v2/admin/config

{"activeSize":9,"removeDelay":1800,"syncInterval":5}

而后将新的JSON作为数据载荷,同时配合PUT操作实现值变更:

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存储或者检索集群内各设备上的信息。通过这种方式,我们可以同步数据并为服务提供查找配置数据及连接信息所必需的位置。

这种作法特别适合用于构建分布式系统,因为我们可以提供一套简单端点,并保证其适用于集群内的任意位置。通过发挥这一优势,我们的服务将能够以动态方式实现自我配置。

本文来源自DigitalOcean Community。英文原文:How To Use Etcdctl and Etcd, CoreOS’s Distributed Key-Value Store By Justin Ellingwood

翻译:diradw