Tip
- Etcd是CoreOS基于Raft开发的 分布式key-value存储 可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)
- 在分布式系统中,如何管理节点间的状态一直是一个难题,etcd像是专门为集群环境的服务发现 和注册而设计,它提供了数据TTL失效、数据改变监视、多值、目录监听、分布式锁原子操作等功能,可以方便的跟踪并管理集群节点的状态
1 raft 协议
2 安装
ETCD_VER=v3.4.17
# DOWNLOAD_URL=https://github.com/etcd-io/etcd/releases/download
DOWNLOAD_URL=https://repo.huaweicloud.com/etcd/
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
rm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-test
curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1
#rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
#rm -rf /tmp/etcd-download-test
# client 相关的 是给客户端 用的url
# peer 是给集群节点之间通信用的
#我们可以 启动, 使用别的端口, 因为这里我们 k8s已经启动了etcd 了.
# 会在当前目录下创建 一个 default.etcd , 来存储数据
etcd --listen-client-urls 'http://localhost:12379' \
--advertise-client-urls 'http://localhost:12379' \
--listen-peer-urls 'http://localhost:12380' \
--initial-advertise-peer-urls 'http://localhost:12380' \
--initial-cluster 'default=http://localhost:12380'
# 其他参数
# 节点名称, 不指定的话,默认是default
--name 'default'
--data-dir #不指定的话,默认会在当前目录下 的 default.etcd 目录
2.1 集群
3 etcdctl使用
别名配置
# etcdctl --endpoints=http://localhost:12379 put a b
# pod 安装的etcd ,我们的宿主机上 连接
export ETCDCTL_API=3
etcdctl member list -w table --endpoints=https://localhost:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key
cat >> /etc/profile <<EOF
export ETCDCTL_API=3
alias e="etcdctl --endpoints=https://localhost:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/peer.crt --key=/etc/kubernetes/pki/etcd/peer.key"
EOF
# 启动一个测试用etcd, 使用这个别名来测试
alias ee="etcdctl --endpoints=http://localhost:12379"4 版本管理
4.1 各个版本号的含义
# 全新,没有添加过任何数据的etcd
# 我们删除 启动etcd的目录下的 default.etcd 然后重新启动etcd 即可
# 随便 get 一个key, 下面的 key a 是不存在的
ee get a -w json
{"header":
{
"cluster_id":17478742799590499669,
"member_id":14532165781622267127,
"revision":1, #作用域为集群,逻辑时间戳,全局单调递增,任何 key 的增删改都会使其自增
"raft_term":2
}
}
# 添加
ee put a b
ee get a -w json
{
"header": {
"cluster_id": 17478742799590499669,
"member_id": 14532165781622267127,
"revision": 2, #全局 版本+1, 任何添加修改的操作都会自增, 即使值没有修改,比如2次 ee put a bb
"raft_term": 2
},
"kvs": [
{
"key": "YQ==", # echo YQ== |base64 -d ==> a
#作用域为 key, 值为: 创建这个key时集群的全局Revision, 直到删除前都保持不变
"create_revision": 2,
#作用域为 key, 值为: 最后修改这个key时 集群的全局Revision
"mod_revision": 2,
# 作用域为 key, 这个key刚创建时Version为1,之后每次更新都会自增,即这个key从创建以来更新的总次数
"version": 1,
"value": "Yg==" # echo Yg== |base64 -d ==> b
}
],
"count": 1
}
# 修改
ee put a abc
ee get a -w json
{
"header": {
"cluster_id": 17478742799590499669,
"member_id": 14532165781622267127,
"revision": 3,
"raft_term": 2
},
"kvs": [
{
"key": "YQ==",
"create_revision": 2,
"mod_revision": 3,
"version": 2, #这个key的第2个版本
"value": "YWJj"
}
],
"count": 1
}
ee put a hello
ee get a -w json
{
"header": {
"cluster_id": 17478742799590499669,
"member_id": 14532165781622267127,
"revision": 4,
"raft_term": 2
},
"kvs": [
{
"key": "YQ==",
"create_revision": 2,
"mod_revision": 4,
"version": 3,
"value": "aGVsbG8="
}
],
"count": 1
}
ee put hello world
ee get hello -w json
{
"header": {
"cluster_id": 17478742799590499669,
"member_id": 14532165781622267127,
"revision": 5,
"raft_term": 2
},
"kvs": [
{
"key": "aGVsbG8=",
"create_revision": 5, #等于 当前的全局revision
"mod_revision": 5, #等于 当前的全局revision
"version": 1,
"value": "d29ybGQ="
}
],
"count": 1
}
ee put b bb4.2 获取对应版本的数据
4.3 从指定版本号起监听
5 容量管理
# 删除 default.etcd
# 启动时我们 设置etcd存储大小 16M
etcd --listen-client-urls 'http://localhost:12379' \
--advertise-client-urls 'http://localhost:12379' \
--listen-peer-urls 'http://localhost:12380' \
--initial-advertise-peer-urls 'http://localhost:12380' \
--initial-cluster 'default=http://localhost:12380' \
--quota-backend-bytes=$((16*1024*1024))
ee put a b
# 修改key x ,因为版本的原因,每次修改数据都会保存,这样存储就满了
# 满了后再put ,会报错
while true
do
dd if=/dev/urandom bs=1M count=1 | ee put x || break
done
# 查看状态 , 可以看到Errors alarm:NOSPACE
ee endpoint status -w table
ee alarm list # 查看报警信息
memberID:14532165781622267127 alarm:NOSPACE
# 压缩版本
# 表示压缩到 全局版本的第10个版本, 也就是, 10版本前的key,只保留里面最新版本的那个值
# 然后版本归为 10
# 如果是compact 当前版本, 那么就是压缩成到最新的版本,key对应旧版本的数据就都删除了,只保留最新版本的值.
ee compact 10
ee get a --rev 10 # 如果指定版本的话, 是指定10 不是2
# 清理碎片
ee defrag
# 清理alarm 解除报警,没有errors
ee alarm disarm5.1 compact配置
单独的etcd
k8s中的etcd
上面那样修改是无效的, 这个压缩的操作,k8s代码里给写了1
staging/src/k8s.io/apiserver/pkg/storage/storagebackend/factory/etcd3.go#startCompactorOnce
cmd/kube-apiserver/app/options/options.go
func NewServerRunOptions() *ServerRunOptions {
s := ServerRunOptions{
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
Etcd: genericoptions.NewEtcdOptions(
// NewDefaultConfig() 里会看到 DefaultCompactInterval = 5 * time.Minute
storagebackend.NewDefaultConfig(kubeoptions.DefaultEtcdPathPrefix, nil)
),
..
}
}