6.1 Etcd—高可用的键值数据库
6.1.1 etcd概述
Etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)仓库,遵循Apache v2许可,基于Go语言实现。
Etcd专门为集群环境设计,采用了更为简洁的Raft共识算法,同样可以实现数据强一致。
通常情况下,用户使用Etcd可以在多个节点上启动多个实例,并将它们添加为一个集群。同一个集群中的Etcd实例将会自动保持彼此信息的一致性,这意味着分布在各个节点上的应用也将获取到一致的信息。
6.1.2 安装并启动etcd
yum install etcd -y
启动etcd,并指定数据目录为/root/dockerlab/etcd-data
etcd --data-dir /root/dockerlab/etcd-data &
注:后面加一个&,是让它在后台运行
启动以后,会监听两个端口
2379:客户端请求端口
2380:其他节点连接端口
查看群康健康状态
etcdctl cluster-health
以上状态说明是正常的。
6.1.3 etcd基本操作
1)设置键值对
etcdctl set myetcd "hello word"
设置键值对myetcd的内容为hello word
如在此命令后加:-ttl time,则表示键值的生存时间,单位为秒。
2)获取键值对内容
etcdctl get myetcd
会把键值对的内容打印出来
也可以用curl来获取键值对的内容
curl http://127.0.0.1/2379/v2/keys/myetcd
3)更新键值的内容
etcdctl update myetcd world
将myetcd的内容更新为world
4)如果给定的键不存在,则创建一个新的键值,如果该键值存在,则报错。
etcdctl mk
5)删除键值
etcdctl rm
6)监测一个键值的变化,一旦键值发生更新,就会输出最新的值并退出。
etcdctl watch
etcdctl watch –f #一直监测,不退出。
7)监测一个键值的变化,一旦键值发生更新,监测一个键值的变化,一旦键值发生更新。
etcdctl exec –watch key -- ‘command’
以上命令:etcdctl extc-watch myetcd --‘ls’的意思是当myetcd这个键值改变时,就执行ls命令。
8)列出所有键值和目录
etcdctl ls
etcdctl ls –r #同时显示子目录下的内容
9)创建一个目录
etcdctl mkdirDirectory
10)删除一个空目录,如果目录为非空,则会报错
etcdctl rmdir Directory
创建一个键目录,无论存在与否。
etcdctl setdir Directory
11)备份etcd
etcdctl backup --data-dir /root/dockerlab/etcd-data --backup-dir /tmp/etcd-data.bak
将当前目录下的etcd数据库备份到/tmp下面
6.1.4用户管理
etcdctl user command [command options] [arguments...]
command:
add: 添加用户
list: 查看用户
remove: 删除用户
grant:添加用户到角色;
revoke:删除用户的角色;
passwd:修改用户的密码。
默认情况下,需要先创建(启用)root用户作为etcd集群的最高权限管理员:
etcdctl user add root
再创建两个普通用户:
etcdctl user add user1
etcdctl user add user2
查看用户:
etcdctl user list
将user2删除:
etcdctl user remov user2
6.1.5用户角色role
etcdctl role command [command options] [arguments...]
·add:添加一个角色;
·get:查询角色详细信息;
·list:列出所有用户角色;
·remove:删除用户角色;
·grant:添加路径到角色控制,可以为read、write或者readwrite;
·revoke:删除某路径的用户角色信息。
查看用户角色,默认只有root一个角色
etcdctl role list
查询root角色详细信息
etcdctl role get root
我们看到,root这个角色对所有内容都有读和写的权限。
添加一个角色guest,并设置此角色可以所有内容具有只读权限。
etcdctl role add guest
查看一下该角色的详细信息
它是没有任何权限的
etcdctl role grant guest -path '/*' –read
加上权限后,再来看:
它已经对根目录下所有内容,具有只读权限,但没有写的权限。
将user1这个用户赋予guest角色
etcdctl user grant user1 -roles guest
我们发现这个user1 的角色已经是guest了。
启用访问验证:
etcdctl auth enable
此时,已经不能添加键值了。
需要加入--username user这个参数,比如我们用root用户来操作
etcdctl --username root set test1 'yang'
这里会让我们输入密码
这样才能创建成功。
6.1.6使用systemd方式启动并管理etcd
启动etcd
systemctl start etcd
将etcd设为自启动
systemctl enable etcd
查看etcd服务的状态
systemctl status etcd
etcd的配置文件
/etc/etcd/etcd.conf
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"#默认是将数据库放在这个目录下
#ETCD_WAL_DIR=""
#ETCD_LISTEN_PEER_URLS="http://localhost:2380"
ETCD_LISTEN_CLIENT_URLS="http://localhost:2379"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
ETCD_NAME="default"
#ETCD_SNAPSHOT_COUNT="100000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_QUOTA_BACKEND_BYTES="0"
#ETCD_MAX_REQUEST_BYTES="1572864"
#ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
#ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s"
#ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"
6.1.7 etcd集群
Etcd的集群也采用了典型的“主-从”模型,通过Raft协议来保证在一段时间内有一个节点为主节点,其他节点为从节点。一旦主节点发生故障,其他节点可以自动再重新选举出新的主节点。
与其他分布式系统类似,集群中节点个数推荐为奇数个,最少为3个,此时quorum为2,越多节点个数自然能提供更多的冗余性,但同时会带来写数据性能的下降。
Etcd支持两种模式来构建集群:静态配置和动态发现。
6.1.7.1静态方式构建集群
Step1:准备三个NODE
etcd_node1:192.168.0.191
etcd_node2:192.168.0.192
etcd_node3:192.168.0.193
并将三个NODE的hosts文件配置好,保证网络互通。
step 2:在三个NODE上启动 etcd
配置/etc/etcd/etcd.conf文件
vim /etc/etcd/etcd.conf
node1:
[Member]
ETCD_DATA_DIR="/var/lib/etcd/default.etcd" #定义数据库目录
ETCD_LISTEN_PEER_URLS=http://localhost:2380,http://192.168.0.191:2380#监听端口(给集群内其它成员的)
ETCD_LISTEN_CLIENT_URLS=http://localhost:2379,http://192.168.0.191:2379#监听端口(给客户端的)
ETCD_NAME="n1"#集群成员名字
[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd_node1:2380#给集群内其它成员访问的URL
ETCD_ADVERTISE_CLIENT_URLS=http://etcd_node1:2379#给客户端访问的URL
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"#定义集群标记(所有node需一至)
ETCD_INITIAL_CLUSTER_STATE="new"#定义集群状态(new|existing)
ETCD_INITIAL_CLUSTER="n1=http://etcd_node1:2380,n2=http://etcd_node2:2380,n3=http://etcd_node3:2380"#定义群成员
node2:
[Member]
ETCD_DATA_DIR="/var/lib/etcd/default.etcd" #定义数据库目录
ETCD_LISTEN_PEER_URLS=http://localhost:2380,http://192.168.0.192:2380#监听端口(给集群内其它成员的)
ETCD_LISTEN_CLIENT_URLS=http://localhost:2379,http://192.168.0.192:2379#监听端口(给客户端的)
ETCD_NAME="n2"#集群成员名字
[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd_node2:2380#给集群内其它成员访问的URL
ETCD_ADVERTISE_CLIENT_URLS=http://etcd_node2:2379#给客户端访问的URL
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"#定义集群标记(所有node需一至)
ETCD_INITIAL_CLUSTER_STATE="new"#定义集群状态(new|existing)
ETCD_INITIAL_CLUSTER="n1=http://etcd_node1:2380,n2=http://etcd_node2:2380,n3=http://etcd_node3:2380"#定义群成员
node3:
[Member]
ETCD_DATA_DIR="/var/lib/etcd/default.etcd" #定义数据库目录
ETCD_LISTEN_PEER_URLS=http://localhost:2380,http://192.168.0.193:2380#监听端口(给集群内其它成员的)
ETCD_LISTEN_CLIENT_URLS=http://localhost:2379,http://192.168.0.193:2379#监听端口(给客户端的)
ETCD_NAME="n2"#集群成员名字
[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd_node3:2380#给集群内其它成员访问的URL
ETCD_ADVERTISE_CLIENT_URLS=http://etcd_node3:2379#给客户端访问的URL
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"#定义集群标记(所有node需一至)
ETCD_INITIAL_CLUSTER_STATE="new"#定义集群状态(new|existing)
ETCD_INITIAL_CLUSTER="n1=http://etcd_node1:2380,n2=http://etcd_node2:2380,n3=http://etcd_node3:2380"#定义群成员
放通三个NODE上的2379/tcp和2380/tcp端口
firewall-cmd --add-port 2379/tcp
firewall-cmd --add-port 2379/tcp –permanent
firewall-cmd --add-port 2380/tcp
firewall-cmd --add-port 2380/tcp –permanent
在三个NODE上启动 etcd
systemctl start etcd
检查集群的康健度:
etcdctl cluster-health
会出现三个NODE,说明配置正确
在任意一个NODE上查看member
etcdctl member list
会出现三个member,说明配置正确
在node1设置一个键值:
etcdctl set test “11111”
我们会发现在任何一个其它NODE上,都能看到这个键值
说明集群已经建立起来了。
6.1.7.2 动态发现方式构建集群
静态配置的方法虽然简单,但是如果节点信息需要变动的时候,就需要手动进行修改。
很自然想到,可以通过动态发现的方法,让集群自动更新节点信息。要实现动态发现,首先需要一套支持动态发现的服务。
CoreOS提供了一个公开的Etcd发现服务,地址在https://discovery.etcd.io。
在公共etcd公共服务上获取一个UUID
curl https://discovery.etcd.io/new?size=3
修改各NODE的etcd配置文件 /etc/etcd/etcd.conf
vim /etc/etcd/etcd.conf
[Member]
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://localhost:2380,http://192.168.0.191:2380"
ETCD_LISTEN_CLIENT_URLS="http://localhost:2379,http://192.168.0.191:2379"
ETCD_NAME="n1"
[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://etcd_node1:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://etcd_node1:2379"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_DISCOVERY="https://discovery.etcd.io/8bd738db9f21a7c6b59e1a217bdf0f27"
只需要将6.1.6.1小节中的配置文件的最后一行删除,然后新增一行,像红框里一样。
ETCD_DISCOVERY这个值的内容,就是上面我们通过curl https://discovery.etcd.io/new?size=3
获取到的UUID。
集群创建成功。
6.1.7.3集群参数配置
1)时钟同步
对于分布式集群来说,各个节点上的同步时钟十分重要,Etcd集群需要各个节点时钟差异不超过1s,否则可能会导致Raft协议的异常。
在各节点安装NTP服务。
yum install ntp
配置NTP
vim /etc/ntpd.conf
# For more information about this file, see the man pages
# ntp.conf(5), ntp_acc(5), ntp_auth(5), ntp_clock(5), ntp_misc(5), ntp_mon(5).
driftfile /var/lib/ntp/drift
# Permit time synchronization with our time source, but do not
# permit the source to query or modify the service on this system.
restrict default nomodify notrap nopeer noquery
# Permit all access over the loopback interface. This could
# be tightened as well, but to do so would effect some of
# the administrative functions.
restrict 127.0.0.1
restrict ::1
# Hosts on local network are less restricted.
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst
红框的就是ntp服务器,可以选用网上的公共ntp服务器,也可以自己架设ntp服务器。
架设ntp服务器,不在本项目讲解范围之同,大家可以自己去参考相关资料。
总之,是要让群集内的NODE的时间保持一致。
启动,并将ntp服务设为自动启动
systemctl start ntpd
systemctl enable ntpd
- 配置心跳时间
心跳消息时间间隔:主节点多久发一次心跳消息
选举时间间隔:从节点多久没收到心跳消息后发起重新选举
这两个参数可以在/etc/etcd/etcd.conf里面配置
正在上传…重新上传取消
红框里的两个参数就是心跳时间间隔和选举时间间隔。通过选举时间间隔为心跳时间间隔的5倍以上。
- 修改snapshot频率
Etcd会定期将数据的修改存储为snapshot,默认情况下每10 000次修改才会存一个snapshot。
正在上传…重新上传取消
在存储为snap的时候会有大量数据进行写入,影响Etcd的性能。建议将这个值调整的小一些,例如将这个数字改为2000。
6.1.8 Docker主机连接etcd
我们准备两台 docker主机,去连接etcd.
Docker主机1:192.168.0.197
Docker主机2:192.168.0.198
Etcd服务器:192.168.0.191
Step 1 按照之前的操作步骤,部署好etcd主机
防火墙放通2379/tcp端口
firewall-cmd --add-port=2379/tcp --permanent
firewall-cmd --add-port=2379/tcp
Step 2 修改docker的DOCKER_OPTS文件
Vim /etc/default/docker
--cluster-store=etcd://192.168.0.191:2379
--cluster-advertise=192.168.0.191:2379
这两个参数都指向etcd服务器。
Step 3重载服务配置,并重启docker
systemctl daemon-reload
systemctl restart docker
红框内,就是我们刚刚配的docker opts
Step 4 查看etcd服务器上数据
etcdctl ls -r
正在上传…重新上传取消
可以看到,etcd上已有生成了很多docker的变量数据
我们在197这台docker主机上创建一个overlay 网络
docker network create mynet1 -d overlay
在etcd服务器上会出现相应的键值
etcd lr –r
这时候,在198那台docker上,也会出现刚刚新建的那个网络
说明两台主机的数据是同步的。
6.1.9利用etcd+flannel实现容器跨主机通讯
Flannel是kubernetes的CNI网络插件之一,是一种主机侧的 overlay网络方案。flannel常用的网络转发模式是vxlan、udp、hostgw等,在实际的生产环境中,最常用的还是vxlan模式。
Step 1 安装flannel
Yum install flannel –y
Step 2 修改flannel配置文件
vim /etc/sysconfig/flanneld
第一个红框内是etcd的服务地址
第二个红框内是etcd的键值目录。
Step 3 在etcd服务器上创建flannel所需的键值
etcdctl mk /atomic.io/network/config '{"Network":"172.20.0.0/16","SubnetMin":"172.20.1.0","SubnetMax":"172.20.254.0"}'
这里的网段是将要分配给flannel虚拟网卡的。
键值创建成功。
Step 4重启etcd服务
Systemctl restart etcd
Step 5 重载服务配置,并重启flanneld服务
systemctl daemon-reload
systemctl restart flanneld
确保两台docker主机的flanneld服务都正常。
Step 6 检查网络
此时,在两台docker主机上会生成两个名为flannl0的虚拟网卡
注意两个虚拟网卡的IP
还会生成两个配置文件:/run/flannel/subnet.env /run/flannel/docker
这个IP范围是由flannel自动分配的,由flannel通过保存在etcd服务中的记录确保它们不会重复
并且还会监听一个udp 8258的端口。
Step 7 防火墙放通8258/udp端口
firewall-cmd --add-port=8285/udp
firewall-cmd --add-port=8285/udp –permanent
step 8 修改两台docker主机的docker服务配置文件
vim /usr/lib/systemd/system/docker.service
增加红框中内容。
第一红框中是指定环境变量文件。
第二个框是指定环境变量文件中的DOCKER_NETWORK_OPTIONS这个变量。
Step 9重载服务配置,并重启docker服务
systemctl daemon-reload
systemctl restart docker
确保两台docker主机的docker服务正常。
这样配置好以后,flannel0和docker0就处理同一个网段了
Step 10 在两台docker主机上各创建一个容器
发现是可以通的。