使用etcd来存储配置信息

目录

作者:杨冬 欢迎转载,也请保留这段声明。谢谢!
出处:https://andyyoung01.github.io/http://andyyoung01.16mb.com/

Docker镜像被设计为可以部署在任何地方,不过人们经常想在部署之后添加一些额外信息来设置程序运行时的行为。而且,运行docker的机器的配置通常需要保持不变,所以就需要将这些额外信息保存到其它地方。etcd就是为了解决这个问题的。

Etcd是一个分布式的键值对存储数据库。它和其它键-值存储数据库如ZooKeeper和Consul类似,每个存储的值适合于小于512KB,如果大于这个值可能会影响性能。下面我们来看看如何使用etcd。我们这里在一台机器上运行三个etcd的容器实例,来模拟三个物理节点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ IMG=quay.io/coreos/etcd:v2.0.10
$ docker pull $IMG
[...]
$ HTTPIP=http://192.168.71.131
$ CLUSTER="etcd0=$HTTPIP:2380,etcd1=$HTTPIP:2480,etcd2=$HTTPIP:2580"
$ ARGS=
$ ARGS="$ARGS -listen-client-urls http://0.0.0.0:2379"
$ ARGS="$ARGS -listen-peer-urls http://0.0.0.0:2380"
$ ARGS="$ARGS -initial-cluster-state new"
$ ARGS="$ARGS -initial-cluster $CLUSTER"
$ docker run -d -p 2379:2379 -p 2380:2380 --name etcd0 $IMG \
$ARGS -name etcd0 -advertise-client-urls $HTTPIP:2379 \
-initial-advertise-peer-urls $HTTPIP:2380
$ docker run -d -p 2479:2379 -p 2480:2380 --name etcd1 $IMG \
$ARGS -name etcd1 -advertise-client-urls $HTTPIP:2479 \
-initial-advertise-peer-urls $HTTPIP:2480
$ docker run -d -p 2579:2379 -p 2580:2380 --name etcd2 $IMG \
$ARGS -name etcd2 -advertise-client-urls $HTTPIP:2579 \
-initial-advertise-peer-urls $HTTPIP:2580

上面的几行命令启动了3个节点的etcd集群。上面命令的参数中带有peer的是控制etcd节点如何寻找及如何与其它节点通信的;参数中带有client的是控制其它程序如何连接到etcd的。我们可以用curl -L $HTTPIP:2579/version命令来验证etcd是否启动,如果命令返回etcd的版本号则说明etcd正常启动。

下面我们使用curl命令与etcd交互,并且测试一下其分布式的特性:

1
2
3
4
5
6
7
8
[yangdong@centos7 ~]$ curl -L $HTTPIP:2579/v2/keys/mykey -XPUT -d value="testkey"
{"action":"set","node":{"key":"/mykey","value":"testkey","modifiedIndex":7,"createdIndex":7}}
[yangdong@centos7 ~]$ docker stop etcd2
etcd2
[yangdong@centos7 ~]$ curl -L $HTTPIP:2579/v2/keys/mykey
curl: (7) Failed connect to 192.168.71.131:2579; 拒绝连接
[yangdong@centos7 ~]$ curl -L $HTTPIP:2379/v2/keys/mykey
{"action":"get","node":{"key":"/mykey","value":"testkey","modifiedIndex":7,"createdIndex":7}}

上述代码,第1行将一个key添加到了etcd2中。因为我们启动了3个分布式的节点,所以这个key被etcd自动复制到其它节点上。第3行将etcd2停止,第5行确认其已经停止,无法访问。第7行从etcd0上取的了这个key的信息。
通过上面的测试,可以发现如果一个节点停止,依然可以访问到集群中的数据,只是不太方便,必须选择另外一个正常工作的节点来连接。幸运的是etcd提供了一个解决这个问题的方案:你可以以“proxy”模式启动一个节点,这个节点并不复制任何数据,只是简单得将访问请求转发到另外的节点上:

1
2
3
$ docker run -d -p 8080:8080 --restart always --name etcd-proxy $IMG \
-proxy on -listen-client-urls http://0.0.0.0:8080 \
-initial-cluster $CLUSTER

上面的命令启动了一个etcd容器,其模式为proxy模式。将刚才停止的etcd2容器再启动起来,这个proxy开始将请求转发到一开始的3个节点的集群。通过下面的命令测试一下:

1
2
[yangdong@centos7 ~]$ curl -L $HTTPIP:8080/v2/keys/mykey2 -X PUT -d value="t"
{"action":"set","node":{"key":"/mykey2","value":"t","modifiedIndex":9,"createdIndex":9}}

下面将两个etcd节点停用,测试集群是否还能正常工作:

1
2
3
4
5
[yangdong@centos7 ~]$ docker stop etcd1 etcd2
etcd1
etcd2
[yangdong@centos7 ~]$ curl -L $HTTPIP:8080/v2/keys/mykey2
{"action":"get","node":{"key":"/mykey2","value":"t","modifiedIndex":9,"createdIndex":9}}

发现仍然可以从集群读取数据,测试一下写入:

1
2
[yangdong@centos7 ~]$ curl -L $HTTPIP:8080/v2/keys/mykey3 -XPUT -d value="t"
{"message":"proxy: unable to get response from 3 endpoint(s)"}

写入数据失败。再启动一个节点,现在集群中有2个节点了,测试一下能否写入:

1
2
3
4
[yangdong@centos7 ~]$ docker start etcd2
etcd2
[yangdong@centos7 ~]$ curl -L $HTTPIP:8080/v2/keys/mykey3 -XPUT -d value="t"
{"action":"set","node":{"key":"/mykey3","value":"t","modifiedIndex":11,"createdIndex":11}}

写入成功。从上面的测试可见,当一半以上的节点不可用时,etcd允许读取但不允许写入数据。

可以在集群中的每个节点上都启动一个etcd proxy,便可以在任何节点上访问到etcd数据库,从而得到集群中集中存储的配置信息,这种模式称为“ambassador container”模式。通过如下方式使用:

1
2
3
[yangdong@centos7 ~]$ docker run -it --rm --link etcd-proxy:etcd gliderlabs/alpine sh
/ # wget -q -O- http://etcd:8080/v2/keys/mykey3
{"action":"get","node":{"key":"/mykey3","value":"t","modifiedIndex":11,"createdIndex":11}}

上述命令启动了一个连接到etcd-proxy的容器,此容器可以访问到etcd的数据库信息。所以,如果有一个etcd数据库运行在所有环境中,在某个环境中创建一个机器,可以简单得将其启动并连接到etcd-proxy的容器上,这台机器就可以得到该环境中的正确的配置信息了。